MCPcopy Create free account
hub / github.com/buger/jsonparser / stringEndConfig

Function stringEndConfig

parser.go:301–372  ·  view source on GitHub ↗

SYS-REQ-115

(_ Config, data []byte, quote byte)

Source from the content-addressed store, hash-verified

299
300// SYS-REQ-115
301func stringEndConfig(_ Config, data []byte, quote byte) (int, bool) {
302 // SWAR (SIMD-Within-A-Register) fast path: scan 8 bytes at a time for
303 // either the closing quote or a backslash, then a per-byte tail that
304 // counts the run of '\\' before each quote candidate.
305 //
306 // Investigation: easyjson's jlexer.findStringLen
307 // (mailru/easyjson@v0.9.2/jlexer/lexer.go:247) uses a single SIMD
308 // bytes.IndexByte('"') plus a backward backslash-run count, deferring the
309 // separate backslash scan to unescapeStringToken. That style was ported
310 // and benchmarked here as "single IndexByte for the quote + a bounded
311 // bytes.IndexByte(data[:firstQuote], '\\') for the escape flag". On
312 // arm64 (Apple M4 Max, NEON) the two IndexByte *function calls* cost more
313 // than this inline 8-byte SWAR loop, because jsonparser must compute the
314 // escape flag inline (its callers gate unescapeConfig on it), so the
315 // second scan cannot be deferred the way easyjson defers it.
316 //
317 // Measured on M4 Max (BenchmarkJsonParserLarge, median of 5):
318 // SWAR (this): ~21000 ns/op
319 // two-IndexByte port: ~22600 ns/op (-7%)
320 // For reference easyjson itself is ~33200 ns/op here, so jsonparser
321 // already leads; the easyjson technique is not beneficial on arm64.
322 const swarLsb = 0x0101010101010101
323 const swarMsb = 0x8080808080808080
324 broadcastQuote := uint64(quote) * swarLsb
325 broadcastBackslash := uint64('\\') * swarLsb
326
327 i := 0
328 n := len(data)
329 for i+8 <= n {
330 w := binary.LittleEndian.Uint64(data[i:])
331 xq := w ^ broadcastQuote
332 xb := w ^ broadcastBackslash
333 quoteHit := (xq - swarLsb) & ^xq & swarMsb
334 bsHit := (xb - swarLsb) & ^xb & swarMsb
335 if quoteHit|bsHit == 0 {
336 i += 8
337 continue
338 }
339 break
340 }
341 escaped := false
342 for ; i < n; i++ {
343 // gjson trick: the only bytes this loop acts on are the closing quote
344 // and the backslash. For double-quote strings quote=0x22, for
345 // single-quote quote=0x27; backslash=0x5C. All three are <= 0x5C, so a
346 // single unsigned comparison skips every other byte (letters, digits,
347 // punctuation, high UTF-8 bytes) without touching them.
348 if data[i] > '\\' {
349 continue
350 }
351 c := data[i]
352 if c == quote {
353 if !escaped {
354 return i + 1, false
355 }
356 j := i - 1
357 for {
358 if j < 0 || data[j] != '\\' {

Callers 6

findKeyStartConfigFunction · 0.85
stringEndFunction · 0.85
blockEndConfigFunction · 0.85
searchKeysConfigFunction · 0.85
getTypeConfigFunction · 0.85
objectEachConfigFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected