1
2
3
4
5 package json
6
7 import (
8 "math"
9 "strconv"
10 )
11
12 var (
13 errMissingName = &SyntacticError{str: "missing string for object name"}
14 errMissingColon = &SyntacticError{str: "missing character ':' after object name"}
15 errMissingValue = &SyntacticError{str: "missing value after object name"}
16 errMissingComma = &SyntacticError{str: "missing character ',' after object or array value"}
17 errMismatchDelim = &SyntacticError{str: "mismatching structural token for object or array"}
18 )
19
20 const errInvalidNamespace = jsonError("object namespace is in an invalid state")
21
22 type state struct {
23
24 tokens stateMachine
25
26
27
28 names objectNameStack
29
30
31
32
33
34
35 namespaces objectNamespaceStack
36 }
37
38 func (s *state) reset() {
39 s.tokens.reset()
40 s.names.reset()
41 s.namespaces.reset()
42 }
43
44
45
46
47
48
49 func (s state) appendStackPointer(b []byte) []byte {
50 var objectDepth int
51 for i := 1; i < s.tokens.depth(); i++ {
52 e := s.tokens.index(i)
53 if e.length() == 0 {
54 break
55 }
56 b = append(b, '/')
57 switch {
58 case e.isObject():
59 if objectDepth < s.names.length() {
60 for _, c := range s.names.getUnquoted(objectDepth) {
61
62 switch c {
63 case '~':
64 b = append(b, "~0"...)
65 case '/':
66 b = append(b, "~1"...)
67 default:
68 b = append(b, c)
69 }
70 }
71 } else {
72
73
74
75 b = strconv.AppendUint(b, uint64((e.length()-1)/2), 10)
76 }
77 objectDepth++
78 case e.isArray():
79 b = strconv.AppendUint(b, uint64(e.length()-1), 10)
80 }
81 }
82 return b
83 }
84
85
86
87
88
89
90
91
92
93
94
95
96
97 type stateMachine struct {
98 stack []stateEntry
99 last stateEntry
100 }
101
102
103
104 func (m *stateMachine) reset() {
105 m.stack = m.stack[:0]
106 if cap(m.stack) > 1<<10 {
107 m.stack = nil
108 }
109 m.last = stateTypeArray
110 }
111
112
113
114 func (m stateMachine) depth() int {
115 return len(m.stack) + 1
116 }
117
118
119
120 func (m *stateMachine) index(i int) *stateEntry {
121 if i == len(m.stack) {
122 return &m.last
123 }
124 return &m.stack[i]
125 }
126
127
128
129 func (m stateMachine) depthLength() (int, int) {
130 return m.depth(), m.last.length()
131 }
132
133
134
135 func (m *stateMachine) appendLiteral() error {
136 switch {
137 case m.last.needObjectName():
138 return errMissingName
139 case !m.last.isValidNamespace():
140 return errInvalidNamespace
141 default:
142 m.last.increment()
143 return nil
144 }
145 }
146
147
148
149 func (m *stateMachine) appendString() error {
150 switch {
151 case !m.last.isValidNamespace():
152 return errInvalidNamespace
153 default:
154 m.last.increment()
155 return nil
156 }
157 }
158
159
160
161 func (m *stateMachine) appendNumber() error {
162 return m.appendLiteral()
163 }
164
165
166
167 func (m *stateMachine) pushObject() error {
168 switch {
169 case m.last.needObjectName():
170 return errMissingName
171 case !m.last.isValidNamespace():
172 return errInvalidNamespace
173 default:
174 m.last.increment()
175 m.stack = append(m.stack, m.last)
176 m.last = stateTypeObject
177 return nil
178 }
179 }
180
181
182
183 func (m *stateMachine) popObject() error {
184 switch {
185 case !m.last.isObject():
186 return errMismatchDelim
187 case m.last.needObjectValue():
188 return errMissingValue
189 case !m.last.isValidNamespace():
190 return errInvalidNamespace
191 default:
192 m.last = m.stack[len(m.stack)-1]
193 m.stack = m.stack[:len(m.stack)-1]
194 return nil
195 }
196 }
197
198
199
200 func (m *stateMachine) pushArray() error {
201 switch {
202 case m.last.needObjectName():
203 return errMissingName
204 case !m.last.isValidNamespace():
205 return errInvalidNamespace
206 default:
207 m.last.increment()
208 m.stack = append(m.stack, m.last)
209 m.last = stateTypeArray
210 return nil
211 }
212 }
213
214
215
216 func (m *stateMachine) popArray() error {
217 switch {
218 case !m.last.isArray() || len(m.stack) == 0:
219 return errMismatchDelim
220 case !m.last.isValidNamespace():
221 return errInvalidNamespace
222 default:
223 m.last = m.stack[len(m.stack)-1]
224 m.stack = m.stack[:len(m.stack)-1]
225 return nil
226 }
227 }
228
229
230
231
232
233 func (m stateMachine) needIndent(next Kind) (n int) {
234 willEnd := next == '}' || next == ']'
235 switch {
236 case m.depth() == 1:
237 return 0
238 case m.last.length() == 0 && willEnd:
239 return 0
240 case m.last.length() == 0 || m.last.needImplicitComma(next):
241 return m.depth()
242 case willEnd:
243 return m.depth() - 1
244 default:
245 return 0
246 }
247 }
248
249
250 func (m stateMachine) mayAppendDelim(b []byte, next Kind) []byte {
251 switch {
252 case m.last.needImplicitColon():
253 return append(b, ':')
254 case m.last.needImplicitComma(next) && len(m.stack) != 0:
255 return append(b, ',')
256 default:
257 return b
258 }
259 }
260
261
262
263
264 func (m stateMachine) needDelim(next Kind) (delim byte) {
265 switch {
266 case m.last.needImplicitColon():
267 return ':'
268 case m.last.needImplicitComma(next) && len(m.stack) != 0:
269 return ','
270 default:
271 return 0
272 }
273 }
274
275
276
277 func (m stateMachine) checkDelim(delim byte, next Kind) error {
278 switch needDelim := m.needDelim(next); {
279 case needDelim == delim:
280 return nil
281 case needDelim == ':':
282 return errMissingColon
283 case needDelim == ',':
284 return errMissingComma
285 default:
286 return newInvalidCharacterError([]byte{delim}, "before next token")
287 }
288 }
289
290
291
292
293
294
295
296
297 func (m *stateMachine) invalidateDisabledNamespaces() {
298 for i := 0; i < m.depth(); i++ {
299 e := m.index(i)
300 if !e.isActiveNamespace() {
301 e.invalidateNamespace()
302 }
303 }
304 }
305
306
307
308
309
310 type stateEntry uint64
311
312 const (
313
314 stateTypeMask stateEntry = 0x8000_0000_0000_0000
315 stateTypeObject stateEntry = 0x8000_0000_0000_0000
316 stateTypeArray stateEntry = 0x0000_0000_0000_0000
317
318
319
320
321 stateNamespaceMask stateEntry = 0x6000_0000_0000_0000
322 stateDisableNamespace stateEntry = 0x4000_0000_0000_0000
323 stateInvalidNamespace stateEntry = 0x2000_0000_0000_0000
324
325
326 stateCountMask stateEntry = 0x1fff_ffff_ffff_ffff
327 stateCountLSBMask stateEntry = 0x0000_0000_0000_0001
328 stateCountOdd stateEntry = 0x0000_0000_0000_0001
329 stateCountEven stateEntry = 0x0000_0000_0000_0000
330 )
331
332
333
334 func (e stateEntry) length() int {
335 return int(e & stateCountMask)
336 }
337
338
339 func (e stateEntry) isObject() bool {
340 return e&stateTypeMask == stateTypeObject
341 }
342
343
344 func (e stateEntry) isArray() bool {
345 return e&stateTypeMask == stateTypeArray
346 }
347
348
349
350 func (e stateEntry) needObjectName() bool {
351 return e&(stateTypeMask|stateCountLSBMask) == stateTypeObject|stateCountEven
352 }
353
354
355
356 func (e stateEntry) needImplicitColon() bool {
357 return e.needObjectValue()
358 }
359
360
361
362 func (e stateEntry) needObjectValue() bool {
363 return e&(stateTypeMask|stateCountLSBMask) == stateTypeObject|stateCountOdd
364 }
365
366
367
368
369 func (e stateEntry) needImplicitComma(next Kind) bool {
370 return !e.needObjectValue() && e.length() > 0 && next != '}' && next != ']'
371 }
372
373
374
375
376 func (e *stateEntry) increment() {
377 (*e)++
378 }
379
380
381
382 func (e *stateEntry) decrement() {
383 (*e)--
384 }
385
386
387
388 func (e *stateEntry) disableNamespace() {
389 *e |= stateDisableNamespace
390 }
391
392
393
394 func (e stateEntry) isActiveNamespace() bool {
395 return e&(stateDisableNamespace) == 0
396 }
397
398
399 func (e *stateEntry) invalidateNamespace() {
400 *e |= stateInvalidNamespace
401 }
402
403
404 func (e stateEntry) isValidNamespace() bool {
405 return e&(stateInvalidNamespace) == 0
406 }
407
408
409
410
411
412
413
414
415
416
417
418 type objectNameStack struct {
419
420
421
422
423
424
425 offsets []int
426
427 unquotedNames []byte
428 }
429
430 func (ns *objectNameStack) reset() {
431 ns.offsets = ns.offsets[:0]
432 ns.unquotedNames = ns.unquotedNames[:0]
433 if cap(ns.offsets) > 1<<6 {
434 ns.offsets = nil
435 }
436 if cap(ns.unquotedNames) > 1<<10 {
437 ns.unquotedNames = nil
438 }
439 }
440
441 func (ns *objectNameStack) length() int {
442 return len(ns.offsets)
443 }
444
445
446
447
448
449 func (ns *objectNameStack) getUnquoted(i int) []byte {
450 ns.ensureCopiedBuffer()
451 if i == 0 {
452 return ns.unquotedNames[:ns.offsets[0]]
453 } else {
454 return ns.unquotedNames[ns.offsets[i-1]:ns.offsets[i-0]]
455 }
456 }
457
458
459 const invalidOffset = math.MinInt
460
461
462 func (ns *objectNameStack) push() {
463 ns.offsets = append(ns.offsets, invalidOffset)
464 }
465
466
467
468
469 func (ns *objectNameStack) replaceLastQuotedOffset(i int) {
470
471
472
473
474
475 ns.offsets[len(ns.offsets)-1] = ^i
476 }
477
478
479
480
481 func (ns *objectNameStack) replaceLastUnquotedName(s string) {
482 ns.ensureCopiedBuffer()
483 var startOffset int
484 if len(ns.offsets) > 1 {
485 startOffset = ns.offsets[len(ns.offsets)-2]
486 }
487 ns.unquotedNames = append(ns.unquotedNames[:startOffset], s...)
488 ns.offsets[len(ns.offsets)-1] = len(ns.unquotedNames)
489 }
490
491
492
493 func (ns *objectNameStack) clearLast() {
494 ns.offsets[len(ns.offsets)-1] = invalidOffset
495 }
496
497
498 func (ns *objectNameStack) pop() {
499 ns.offsets = ns.offsets[:len(ns.offsets)-1]
500 }
501
502
503
504
505
506 func (ns *objectNameStack) copyQuotedBuffer(b []byte) {
507
508 var i int
509 for i = len(ns.offsets) - 1; i >= 0 && ns.offsets[i] < 0; i-- {
510 continue
511 }
512
513
514 for i = i + 1; i < len(ns.offsets); i++ {
515 if i == len(ns.offsets)-1 && ns.offsets[i] == invalidOffset {
516 if i == 0 {
517 ns.offsets[i] = 0
518 } else {
519 ns.offsets[i] = ns.offsets[i-1]
520 }
521 break
522 }
523
524
525
526
527 quotedName := b[^ns.offsets[i]:]
528 if quotedName[0] == invalidateBufferByte {
529 quotedName[0] = '"'
530 }
531
532
533 var startOffset int
534 if i > 0 {
535 startOffset = ns.offsets[i-1]
536 }
537 if n := consumeSimpleString(quotedName); n > 0 {
538 ns.unquotedNames = append(ns.unquotedNames[:startOffset], quotedName[len(`"`):n-len(`"`)]...)
539 } else {
540 ns.unquotedNames, _ = unescapeString(ns.unquotedNames[:startOffset], quotedName)
541 }
542 ns.offsets[i] = len(ns.unquotedNames)
543 }
544 }
545
546 func (ns *objectNameStack) ensureCopiedBuffer() {
547 if len(ns.offsets) > 0 && ns.offsets[len(ns.offsets)-1] < 0 {
548 panic("BUG: copyQuotedBuffer not called beforehand")
549 }
550 }
551
552
553
554 type objectNamespaceStack []objectNamespace
555
556
557 func (nss *objectNamespaceStack) reset() {
558 if cap(*nss) > 1<<10 {
559 *nss = nil
560 }
561 *nss = (*nss)[:0]
562 }
563
564
565 func (nss *objectNamespaceStack) push() {
566 if cap(*nss) > len(*nss) {
567 *nss = (*nss)[:len(*nss)+1]
568 nss.last().reset()
569 } else {
570 *nss = append(*nss, objectNamespace{})
571 }
572 }
573
574
575 func (nss objectNamespaceStack) last() *objectNamespace {
576 return &nss[len(nss)-1]
577 }
578
579
580 func (nss *objectNamespaceStack) pop() {
581 *nss = (*nss)[:len(*nss)-1]
582 }
583
584
585
586
587
588
589 type objectNamespace struct {
590
591
592
593
594
595 endOffsets []uint
596
597 allUnquotedNames []byte
598
599
600 mapNames map[string]struct{}
601 }
602
603
604 func (ns *objectNamespace) reset() {
605 ns.endOffsets = ns.endOffsets[:0]
606 ns.allUnquotedNames = ns.allUnquotedNames[:0]
607 ns.mapNames = nil
608 if cap(ns.endOffsets) > 1<<6 {
609 ns.endOffsets = nil
610 }
611 if cap(ns.allUnquotedNames) > 1<<10 {
612 ns.allUnquotedNames = nil
613 }
614 }
615
616
617 func (ns *objectNamespace) length() int {
618 return len(ns.endOffsets)
619 }
620
621
622 func (ns *objectNamespace) getUnquoted(i int) []byte {
623 if i == 0 {
624 return ns.allUnquotedNames[:ns.endOffsets[0]]
625 } else {
626 return ns.allUnquotedNames[ns.endOffsets[i-1]:ns.endOffsets[i-0]]
627 }
628 }
629
630
631 func (ns *objectNamespace) lastUnquoted() []byte {
632 return ns.getUnquoted(ns.length() - 1)
633 }
634
635
636
637
638 func (ns *objectNamespace) insertQuoted(name []byte, isVerbatim bool) bool {
639 if isVerbatim {
640 name = name[len(`"`) : len(name)-len(`"`)]
641 }
642 return ns.insert(name, !isVerbatim)
643 }
644 func (ns *objectNamespace) insertUnquoted(name []byte) bool {
645 return ns.insert(name, false)
646 }
647 func (ns *objectNamespace) insert(name []byte, quoted bool) bool {
648 var allNames []byte
649 if quoted {
650 allNames, _ = unescapeString(ns.allUnquotedNames, name)
651 } else {
652 allNames = append(ns.allUnquotedNames, name...)
653 }
654 name = allNames[len(ns.allUnquotedNames):]
655
656
657
658 if ns.mapNames == nil && (ns.length() > 64 || len(ns.allUnquotedNames) > 1024) {
659 ns.mapNames = make(map[string]struct{})
660 var startOffset uint
661 for _, endOffset := range ns.endOffsets {
662 name := ns.allUnquotedNames[startOffset:endOffset]
663 ns.mapNames[string(name)] = struct{}{}
664 startOffset = endOffset
665 }
666 }
667
668 if ns.mapNames == nil {
669
670
671 var startOffset uint
672 for _, endOffset := range ns.endOffsets {
673 if string(ns.allUnquotedNames[startOffset:endOffset]) == string(name) {
674 return false
675 }
676 startOffset = endOffset
677 }
678 } else {
679
680
681 if _, ok := ns.mapNames[string(name)]; ok {
682 return false
683 }
684 ns.mapNames[string(name)] = struct{}{}
685 }
686
687 ns.allUnquotedNames = allNames
688 ns.endOffsets = append(ns.endOffsets, uint(len(ns.allUnquotedNames)))
689 return true
690 }
691
692
693 func (ns *objectNamespace) removeLast() {
694 if ns.mapNames != nil {
695 delete(ns.mapNames, string(ns.lastUnquoted()))
696 }
697 if ns.length()-1 == 0 {
698 ns.endOffsets = ns.endOffsets[:0]
699 ns.allUnquotedNames = ns.allUnquotedNames[:0]
700 } else {
701 ns.endOffsets = ns.endOffsets[:ns.length()-1]
702 ns.allUnquotedNames = ns.allUnquotedNames[:ns.endOffsets[ns.length()-1]]
703 }
704 }
705
706 type uintSet64 uint64
707
708 func (s uintSet64) has(i uint) bool { return s&(1<<i) > 0 }
709 func (s *uintSet64) set(i uint) { *s |= 1 << i }
710
711
712
713 type uintSet struct {
714 lo uintSet64
715 hi []uintSet64
716 }
717
718
719 func (s *uintSet) has(i uint) bool {
720 if i < 64 {
721 return s.lo.has(i)
722 } else {
723 i -= 64
724 iHi, iLo := int(i/64), i%64
725 return iHi < len(s.hi) && s.hi[iHi].has(iLo)
726 }
727 }
728
729
730 func (s *uintSet) insert(i uint) bool {
731
732 if i < 64 {
733 has := s.lo.has(i)
734 s.lo.set(i)
735 return !has
736 } else {
737 i -= 64
738 iHi, iLo := int(i/64), i%64
739 if iHi >= len(s.hi) {
740 s.hi = append(s.hi, make([]uintSet64, iHi+1-len(s.hi))...)
741 s.hi = s.hi[:cap(s.hi)]
742 }
743 has := s.hi[iHi].has(iLo)
744 s.hi[iHi].set(iLo)
745 return !has
746 }
747 }
748
View as plain text