diff --git a/json/filter.go b/json/filter.go index d8d01c1..4ca7481 100644 --- a/json/filter.go +++ b/json/filter.go @@ -6,7 +6,6 @@ import ( ) func Filter(w *bytes.Buffer, b []byte, keys []string) error { - s := 0 state := expectKey var err error @@ -19,10 +18,29 @@ func Filter(w *bytes.Buffer, b []byte, keys []string) error { } } + // is an list isList := false + + // list item item := 0 + + // field in an object field := 0 + + s, e, d := 0, 0, 0 + + kf := false + for i := 0; i < len(b); i++ { + if state == expectObjClose || state == expectListClose { + switch b[i] { + case '{', '[': + d++ + case '}', ']': + d-- + } + } + switch { case state == expectKey: switch b[i] { @@ -35,7 +53,7 @@ func Filter(w *bytes.Buffer, b []byte, keys []string) error { if item == 0 { err = w.WriteByte('{') } else { - _, err = w.WriteString("},{") + _, err = w.Write([]byte("},{")) } item++ field = 0 @@ -44,115 +62,98 @@ func Filter(w *bytes.Buffer, b []byte, keys []string) error { s = i i++ } + if err != nil { + return err + } case state == expectKeyClose && b[i] == '"': state = expectColon - i++ + k := b[(s + 1):i] + _, kf = kmap[sha1.Sum(k)] + + case state == expectColon && b[i] == ':': + state = expectValue + + case state == expectValue && b[i] == '"': + state = expectString + + case state == expectString && b[i] == '"': + e = i + + case state == expectValue && b[i] == '[': + state = expectListClose + d++ + + case state == expectListClose && d == 0 && b[i] == ']': + e = i + + case state == expectValue && b[i] == '{': + state = expectObjClose + d++ + + case state == expectObjClose && d == 0 && b[i] == '}': + e = i + + case state == expectValue && (b[i] >= '0' && b[i] <= '9'): + state = expectNumClose + + case state == expectNumClose && + ((b[i] < '0' || b[i] > '9') && + (b[i] != '.' && b[i] != 'e' && b[i] != 'E' && b[i] != '+' && b[i] != '-')): + i-- + e = i + + case state == expectValue && + (b[i] == 'f' || b[i] == 'F' || b[i] == 't' || b[i] == 'T'): + state = expectBoolClose + + case state == expectBoolClose && (b[i] == 'e' || b[i] == 'E'): + e = i } - if err != nil { - return nil - } + if e != 0 { + state = expectKey + cb := b[s:(e + 1)] + e = 0 - if state != expectColon { - continue - } + if !kf { + continue + } - k := b[(s + 1):(i - 1)] - h := sha1.Sum(k) - _, kf := kmap[h] - - e := 0 - d := 0 - for ; i < len(b); i++ { - if state == expectObjClose || state == expectListClose { - switch b[i] { - case '{', '[': - d++ - case '}', ']': - d-- + if field != 0 { + if err := w.WriteByte(','); err != nil { + return err } } - switch { - case state == expectColon && b[i] == ':': - state = expectValue - - case state == expectValue && b[i] == '"': - state = expectString - - case state == expectString && b[i] == '"': - e = i - - case state == expectValue && b[i] == '[': - state = expectListClose - d++ - - case state == expectListClose && d == 0 && b[i] == ']': - e = i - - case state == expectValue && b[i] == '{': - state = expectObjClose - d++ - - case state == expectObjClose && d == 0 && b[i] == '}': - e = i - - case state == expectValue && (b[i] >= '0' && b[i] <= '9'): - state = expectNumClose - - case state == expectNumClose && - ((b[i] < '0' || b[i] > '9') && - (b[i] != '.' && b[i] != 'e' && b[i] != 'E' && b[i] != '+' && b[i] != '-')): - i-- - e = i - - case state == expectValue && - (b[i] == 'f' || b[i] == 'F' || b[i] == 't' || b[i] == 'T'): - state = expectBoolClose - - case state == expectBoolClose && (b[i] == 'e' || b[i] == 'E'): - e = i - } - - if e != 0 { - if kf { - if field != 0 { - if err := w.WriteByte(','); err != nil { - return err - } - } - - cb := b[s:(e + 1)] - sk := 0 - for i := 0; i < len(cb); i++ { - if cb[i] == '\n' || cb[i] == '\t' { - if _, err := w.Write(cb[sk:i]); err != nil { - return err - } - sk = i + 1 - } - } - - if sk > 0 && sk < len(cb) { - _, err = w.Write(cb[sk:len(cb)]) - } else { - _, err = w.Write(cb) - } - if err != nil { + sk := 0 + for i := 0; i < len(cb); i++ { + if cb[i] == '\n' || cb[i] == '\t' { + if _, err := w.Write(cb[sk:i]); err != nil { return err } - field++ + sk = i + 1 } - state = expectKey - break } + + if sk > 0 && sk < len(cb) { + _, err = w.Write(cb[sk:len(cb)]) + } else { + _, err = w.Write(cb) + } + + if err != nil { + return err + } + field++ } } + if item != 0 { if err := w.WriteByte('}'); err != nil { return err } } + if isList { if err := w.WriteByte(']'); err != nil { return err diff --git a/json/get.go b/json/get.go index a9e5636..ef37cfa 100644 --- a/json/get.go +++ b/json/get.go @@ -34,104 +34,93 @@ func Get(b []byte, keys [][]byte) []Field { } } - l := 10 - res := make([]Field, l) + prealloc := 20 + res := make([]Field, prealloc) + + s, e, d := 0, 0, 0 + + var kf bool + var k []byte for i := 0; i < len(b); i++ { + if state == expectObjClose || state == expectListClose { + switch b[i] { + case '{', '[': + d++ + case '}', ']': + d-- + } + } + switch { case state == expectKey && b[i] == '"': state = expectKeyClose - s = i + 1 - continue + s = i case state == expectKeyClose && b[i] == '"': state = expectColon + k = b[(s + 1):i] + _, kf = kmap[sha1.Sum(k)] + + case state == expectColon && b[i] == ':': + state = expectValue + + case state == expectValue && b[i] == '"': + state = expectString + s = i + + case state == expectString && b[i] == '"': + e = i + + case state == expectValue && b[i] == '[': + state = expectListClose + s = i + d++ + + case state == expectListClose && d == 0 && b[i] == ']': + e = i + i = s + + case state == expectValue && b[i] == '{': + state = expectObjClose + s = i + d++ + + case state == expectObjClose && d == 0 && b[i] == '}': + e = i + i = s + + case state == expectValue && (b[i] >= '0' && b[i] <= '9'): + state = expectNumClose + s = i + + case state == expectNumClose && + ((b[i] < '0' || b[i] > '9') && + (b[i] != '.' && b[i] != 'e' && b[i] != 'E' && b[i] != '+' && b[i] != '-')): + i-- + e = i + + case state == expectValue && + (b[i] == 'f' || b[i] == 'F' || b[i] == 't' || b[i] == 'T'): + state = expectBoolClose + s = i + + case state == expectBoolClose && (b[i] == 'e' || b[i] == 'E'): + e = i } - if state != expectColon { - continue - } - - k := b[s:i] - h := sha1.Sum(k) - _, kf := kmap[h] - - e := 0 - d := 0 - for ; i < len(b); i++ { - if state == expectObjClose || state == expectListClose { - switch b[i] { - case '{', '[': - d++ - case '}', ']': - d-- + if e != 0 { + if kf { + if len(res) == cap(res) { + r := make([]Field, 0, (len(res) * 2)) + copy(r, res) + res = r } + res = append(res, Field{k, b[s:(e + 1)]}) } - switch { - case state == expectColon && b[i] == ':': - state = expectValue - - case state == expectValue && b[i] == '"': - state = expectString - s = i - - case state == expectString && b[i] == '"': - e = i - - case state == expectValue && b[i] == '[': - state = expectListClose - s = i - d++ - - case state == expectListClose && d == 0 && b[i] == ']': - e = i - i = s - - case state == expectValue && b[i] == '{': - state = expectObjClose - s = i - d++ - - case state == expectObjClose && d == 0 && b[i] == '}': - e = i - i = s - - case state == expectValue && (b[i] >= '0' && b[i] <= '9'): - state = expectNumClose - s = i - - case state == expectNumClose && - ((b[i] < '0' || b[i] > '9') && - (b[i] != '.' && b[i] != 'e' && b[i] != 'E' && b[i] != '+' && b[i] != '-')): - i-- - e = i - - case state == expectValue && - (b[i] == 'f' || b[i] == 'F' || b[i] == 't' || b[i] == 'T'): - state = expectBoolClose - s = i - - case state == expectBoolClose && (b[i] == 'e' || b[i] == 'E'): - e = i - } - - if e != 0 { - e++ - - if kf { - if len(res) == cap(res) { - r := make([]Field, 0, (len(res) + l)) - copy(r, res) - res = r - } - - res = append(res, Field{k, b[s:e]}) - } - - state = expectKey - break - } + state = expectKey + e = 0 } } diff --git a/json/replace.go b/json/replace.go index 197e3e6..a8d3709 100644 --- a/json/replace.go +++ b/json/replace.go @@ -11,12 +11,6 @@ func Replace(w *bytes.Buffer, b []byte, from, to []Field) error { return errors.New("'from' and 'to' must be of the same length") } - state := expectKey - ws, we := 0, len(b) - - s := 0 - fi := -1 - fmap := make(map[[20]byte]int, (len(from) * 2)) tmap := make(map[[20]byte]int, (len(from))) @@ -33,124 +27,122 @@ func Replace(w *bytes.Buffer, b []byte, from, to []Field) error { tmap[h2] = i } - for i := 0; i < len(b); i++ { - switch { - case ws == 0 && b[i] == '{' || b[i] == '[': - ws = i + state := expectKey + ws, we := 0, len(b) + s, e, d := 0, 0, 0 + fi := -1 + + for i := 0; i < len(b); i++ { + // skip any left padding whitespace + if ws == 0 && (b[i] == '{' || b[i] == '[') { + ws = i + } + + if state == expectObjClose || state == expectListClose { + switch b[i] { + case '{', '[': + d++ + case '}', ']': + d-- + } + } + + switch { case state == expectKey && b[i] == '"': state = expectKeyClose - s = i + 1 - continue + s = i case state == expectKeyClose && b[i] == '"': state = expectColon - - default: - continue - } - - if state != expectColon { - continue - } - - h1 := sha1.Sum(b[s:i]) - if n, ok := fmap[h1]; ok { - we = s - fi = n - } - - e := 0 - d := 0 - for ; i < len(b); i++ { - if state == expectObjClose || state == expectListClose { - switch b[i] { - case '{', '[': - d++ - case '}', ']': - d-- - } + h1 := sha1.Sum(b[(s + 1):i]) + if n, ok := fmap[h1]; ok { + we = s + fi = n } - switch { - case state == expectColon && b[i] == ':': - state = expectValue + case state == expectColon && b[i] == ':': + state = expectValue - case state == expectValue && b[i] == '"': - state = expectString - s = i + case state == expectValue && b[i] == '"': + state = expectString + s = i - case state == expectString && b[i] == '"': - e = i + case state == expectString && b[i] == '"': + e = i - case state == expectValue && b[i] == '[': - state = expectListClose - s = i - d++ + case state == expectValue && b[i] == '[': + state = expectListClose + s = i + d++ - case state == expectListClose && d == 0 && b[i] == ']': - e = i + case state == expectListClose && d == 0 && b[i] == ']': + e = i - case state == expectValue && b[i] == '{': - state = expectObjClose - s = i - d++ + case state == expectValue && b[i] == '{': + state = expectObjClose + s = i + d++ - case state == expectObjClose && d == 0 && b[i] == '}': - e = i + case state == expectObjClose && d == 0 && b[i] == '}': + e = i - case state == expectValue && (b[i] >= '0' && b[i] <= '9'): - state = expectNumClose - s = i + case state == expectValue && (b[i] >= '0' && b[i] <= '9'): + state = expectNumClose + s = i - case state == expectNumClose && - ((b[i] < '0' || b[i] > '9') && - (b[i] != '.' && b[i] != 'e' && b[i] != 'E' && b[i] != '+' && b[i] != '-')): - i-- - e = i + case state == expectNumClose && + ((b[i] < '0' || b[i] > '9') && + (b[i] != '.' && b[i] != 'e' && b[i] != 'E' && b[i] != '+' && b[i] != '-')): + i-- + e = i - case state == expectValue && - (b[i] == 'f' || b[i] == 'F' || b[i] == 't' || b[i] == 'T'): - state = expectBoolClose - s = i + case state == expectValue && + (b[i] == 'f' || b[i] == 'F' || b[i] == 't' || b[i] == 'T'): + state = expectBoolClose + s = i - case state == expectBoolClose && (b[i] == 'e' || b[i] == 'E'): - e = i - } + case state == expectBoolClose && (b[i] == 'e' || b[i] == 'E'): + e = i + } - if e != 0 { - e++ - h2 := sha1.Sum(b[s:e]) + if e != 0 { + e++ - if n, ok1 := fmap[h2]; ok1 && n == fi { - ti, ok2 := tmap[h2] + h2 := sha1.Sum(b[s:e]) + replace := false - if ok2 { - if _, err := w.Write(b[ws:we]); err != nil { - return err - } - if _, err := w.Write(to[ti].Key); err != nil { - return err - } - if _, err := w.WriteString(`":`); err != nil { - return err - } - if _, err := w.Write(to[ti].Value); err != nil { - return err - } - ws = e + if n, ok1 := fmap[h2]; ok1 && n == fi { + ti, ok2 := tmap[h2] + + if ok2 { + if _, err := w.Write(b[ws:(we + 1)]); err != nil { + return err } + if _, err := w.Write(to[ti].Key); err != nil { + return err + } + if _, err := w.WriteString(`":`); err != nil { + return err + } + if _, err := w.Write(to[ti].Value); err != nil { + return err + } + replace = true + ws = e } - - if ws != e && (b[s] == '[' || b[s] == '{') { - i = s - 1 - } - - state = expectKey - we = len(b) - fi = -1 - break } + + if !replace && (b[s] == '[' || b[s] == '{') { + // the i++ in the for loop will add 1 so we account for that (s - 1) + i = s - 1 + } + + state = expectKey + we = len(b) + fi = -1 + e = 0 + d = 0 } } diff --git a/json/strip.go b/json/strip.go index 19392be..881cc97 100644 --- a/json/strip.go +++ b/json/strip.go @@ -9,108 +9,96 @@ func Strip(b []byte, path []string) []byte { state := expectKey kb := make([][]byte, 0, len(path)) - ki := 0 for _, k := range path { kb = append(kb, []byte(k)) } + s, e, d := 0, 0, 0 + ki := 0 + pm := false + for i := 0; i < len(b); i++ { + if state == expectObjClose || state == expectListClose { + switch b[i] { + case '{', '[': + d++ + case '}', ']': + d-- + } + } + switch { case state == expectKey && b[i] == '"': state = expectKeyClose - s = i + 1 - continue + s = i case state == expectKeyClose && b[i] == '"': state = expectColon - } - - if state != expectColon { - continue - } - - if ki >= len(kb) { - return nil - } - - if !bytes.Equal(b[s:i], kb[ki]) { - state = expectKey - continue - } - - ki++ - - e := 0 - d := 0 - s := 0 - for ; i < len(b); i++ { - if state == expectObjClose || state == expectListClose { - switch b[i] { - case '{', '[': - d++ - case '}', ']': - d-- - } + if ki == len(kb) { + ki = 0 + } + pm = bytes.Equal(b[(s+1):i], kb[ki]) + if pm { + ki++ } - switch { - case state == expectColon && b[i] == ':': - state = expectValue + case state == expectColon && b[i] == ':': + state = expectValue - case state == expectValue && b[i] == '"': - state = expectString - s = i + case state == expectValue && b[i] == '"': + state = expectString + s = i - case state == expectString && b[i] == '"': - e = i + case state == expectString && b[i] == '"': + e = i - case state == expectValue && b[i] == '[': - state = expectListClose - s = i - d++ + case state == expectValue && b[i] == '[': + state = expectListClose + s = i + d++ - case state == expectListClose && d == 0 && b[i] == ']': - e = i + case state == expectListClose && d == 0 && b[i] == ']': + e = i - case state == expectValue && b[i] == '{': - state = expectObjClose - s = i - d++ + case state == expectValue && b[i] == '{': + state = expectObjClose + s = i + d++ - case state == expectObjClose && d == 0 && b[i] == '}': - e = i + case state == expectObjClose && d == 0 && b[i] == '}': + e = i - case state == expectValue && (b[i] >= '0' && b[i] <= '9'): - state = expectNumClose - s = i + case state == expectValue && (b[i] >= '0' && b[i] <= '9'): + state = expectNumClose + s = i - case state == expectNumClose && - ((b[i] < '0' || b[i] > '9') && - (b[i] != '.' && b[i] != 'e' && b[i] != 'E' && b[i] != '+' && b[i] != '-')): - i-- - e = i + case state == expectNumClose && + ((b[i] < '0' || b[i] > '9') && + (b[i] != '.' && b[i] != 'e' && b[i] != 'E' && b[i] != '+' && b[i] != '-')): + i-- + e = i - case state == expectValue && - (b[i] == 'f' || b[i] == 'F' || b[i] == 't' || b[i] == 'T'): - state = expectBoolClose - s = i + case state == expectValue && + (b[i] == 'f' || b[i] == 'F' || b[i] == 't' || b[i] == 'T'): + state = expectBoolClose + s = i - case state == expectBoolClose && (b[i] == 'e' || b[i] == 'E'): - e = i - } + case state == expectBoolClose && (b[i] == 'e' || b[i] == 'E'): + e = i + } - if e != 0 && (b[s] == '[' || b[s] == '{') { - e++ - b = b[s:e] + if e != 0 { + if pm && (b[s] == '[' || b[s] == '{') { + b = b[s:(e + 1)] i = 0 if ki == len(kb) { return b } - - state = expectKey - break } + + state = expectKey + e = 0 } }