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

Function stringEndConfig

parser.go:301–364  ·  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 c := data[i]
344 if c == quote {
345 if !escaped {
346 return i + 1, false
347 }
348 j := i - 1
349 for {
350 if j < 0 || data[j] != '\\' {
351 return i + 1, true // even run of backslashes
352 }
353 j--
354 if j < 0 || data[j] != '\\' {
355 break // odd run of backslashes -> quote is escaped
356 }
357 j--
358 }

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