k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/internal/third_party/go-json-experiment/json/state.go (about)

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     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  	// tokens validates whether the next token kind is valid.
    24  	tokens stateMachine
    25  
    26  	// names is a stack of object names.
    27  	// Not used if AllowDuplicateNames is true.
    28  	names objectNameStack
    29  
    30  	// namespaces is a stack of object namespaces.
    31  	// For performance reasons, Encoder or Decoder may not update this
    32  	// if Marshal or Unmarshal is able to track names in a more efficient way.
    33  	// See makeMapArshaler and makeStructArshaler.
    34  	// Not used if AllowDuplicateNames is true.
    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  // appendStackPointer appends a JSON Pointer (RFC 6901) to the current value.
    45  // The returned pointer is only accurate if s.names is populated,
    46  // otherwise it uses the numeric index as the object member name.
    47  //
    48  // Invariant: Must call s.names.copyQuotedBuffer beforehand.
    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 // empty object or array
    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  					// Per RFC 6901, section 3, escape '~' and '/' characters.
    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  				// Since the names stack is unpopulated, the name is unknown.
    73  				// As a best-effort replacement, use the numeric member index.
    74  				// While inaccurate, it produces a syntactically valid pointer.
    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  // stateMachine is a push-down automaton that validates whether
    86  // a sequence of tokens is valid or not according to the JSON grammar.
    87  // It is useful for both encoding and decoding.
    88  //
    89  // It is a stack where each entry represents a nested JSON object or array.
    90  // The stack has a minimum depth of 1 where the first level is a
    91  // virtual JSON array to handle a stream of top-level JSON values.
    92  // The top-level virtual JSON array is special in that it doesn't require commas
    93  // between each JSON value.
    94  //
    95  // For performance, most methods are carefully written to be inlineable.
    96  // The zero value is a valid state machine ready for use.
    97  type stateMachine struct {
    98  	stack []stateEntry
    99  	last  stateEntry
   100  }
   101  
   102  // reset resets the state machine.
   103  // The machine always starts with a minimum depth of 1.
   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  // depth is the current nested depth of JSON objects and arrays.
   113  // It is one-indexed (i.e., top-level values have a depth of 1).
   114  func (m stateMachine) depth() int {
   115  	return len(m.stack) + 1
   116  }
   117  
   118  // index returns a reference to the ith entry.
   119  // It is only valid until the next push method call.
   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  // depthLength reports the current nested depth and
   128  // the length of the last JSON object or array.
   129  func (m stateMachine) depthLength() (int, int) {
   130  	return m.depth(), m.last.length()
   131  }
   132  
   133  // appendLiteral appends a JSON literal as the next token in the sequence.
   134  // If an error is returned, the state is not mutated.
   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  // appendString appends a JSON string as the next token in the sequence.
   148  // If an error is returned, the state is not mutated.
   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  // appendNumber appends a JSON number as the next token in the sequence.
   160  // If an error is returned, the state is not mutated.
   161  func (m *stateMachine) appendNumber() error {
   162  	return m.appendLiteral()
   163  }
   164  
   165  // pushObject appends a JSON start object token as next in the sequence.
   166  // If an error is returned, the state is not mutated.
   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  // popObject appends a JSON end object token as next in the sequence.
   182  // If an error is returned, the state is not mutated.
   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  // pushArray appends a JSON start array token as next in the sequence.
   199  // If an error is returned, the state is not mutated.
   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  // popArray appends a JSON end array token as next in the sequence.
   215  // If an error is returned, the state is not mutated.
   216  func (m *stateMachine) popArray() error {
   217  	switch {
   218  	case !m.last.isArray() || len(m.stack) == 0: // forbid popping top-level virtual JSON array
   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  // needIndent reports whether indent whitespace should be injected.
   230  // A zero value means that no whitespace should be injected.
   231  // A positive value means '\n', indentPrefix, and (n-1) copies of indentBody
   232  // should be appended to the output immediately before the next token.
   233  func (m stateMachine) needIndent(next Kind) (n int) {
   234  	willEnd := next == '}' || next == ']'
   235  	switch {
   236  	case m.depth() == 1:
   237  		return 0 // top-level values are never indented
   238  	case m.last.length() == 0 && willEnd:
   239  		return 0 // an empty object or array is never indented
   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  // mayAppendDelim appends a colon or comma that may precede the next token.
   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: // comma not needed for top-level values
   255  		return append(b, ',')
   256  	default:
   257  		return b
   258  	}
   259  }
   260  
   261  // needDelim reports whether a colon or comma token should be implicitly emitted
   262  // before the next token of the specified kind.
   263  // A zero value means no delimiter should be emitted.
   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: // comma not needed for top-level values
   269  		return ','
   270  	default:
   271  		return 0
   272  	}
   273  }
   274  
   275  // checkDelim reports whether the specified delimiter should be there given
   276  // the kind of the next token that appears immediately afterwards.
   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  // invalidateDisabledNamespaces marks all disabled namespaces as invalid.
   291  //
   292  // For efficiency, Marshal and Unmarshal may disable namespaces since there are
   293  // more efficient ways to track duplicate names. However, if an error occurs,
   294  // the namespaces in Encoder or Decoder will be left in an inconsistent state.
   295  // Mark the namespaces as invalid so that future method calls on
   296  // Encoder or Decoder will return an error.
   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  // stateEntry encodes several artifacts within a single unsigned integer:
   307  //   - whether this represents a JSON object or array,
   308  //   - whether this object should check for duplicate names, and
   309  //   - how many elements are in this JSON object or array.
   310  type stateEntry uint64
   311  
   312  const (
   313  	// The type mask (1 bit) records whether this is a JSON object or array.
   314  	stateTypeMask   stateEntry = 0x8000_0000_0000_0000
   315  	stateTypeObject stateEntry = 0x8000_0000_0000_0000
   316  	stateTypeArray  stateEntry = 0x0000_0000_0000_0000
   317  
   318  	// The name check mask (2 bit) records whether to update
   319  	// the namespaces for the current JSON object and
   320  	// whether the namespace is valid.
   321  	stateNamespaceMask    stateEntry = 0x6000_0000_0000_0000
   322  	stateDisableNamespace stateEntry = 0x4000_0000_0000_0000
   323  	stateInvalidNamespace stateEntry = 0x2000_0000_0000_0000
   324  
   325  	// The count mask (61 bits) records the number of elements.
   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  // length reports the number of elements in the JSON object or array.
   333  // Each name and value in an object entry is treated as a separate element.
   334  func (e stateEntry) length() int {
   335  	return int(e & stateCountMask)
   336  }
   337  
   338  // isObject reports whether this is a JSON object.
   339  func (e stateEntry) isObject() bool {
   340  	return e&stateTypeMask == stateTypeObject
   341  }
   342  
   343  // isArray reports whether this is a JSON array.
   344  func (e stateEntry) isArray() bool {
   345  	return e&stateTypeMask == stateTypeArray
   346  }
   347  
   348  // needObjectName reports whether the next token must be a JSON string,
   349  // which is necessary for JSON object names.
   350  func (e stateEntry) needObjectName() bool {
   351  	return e&(stateTypeMask|stateCountLSBMask) == stateTypeObject|stateCountEven
   352  }
   353  
   354  // needImplicitColon reports whether an colon should occur next,
   355  // which always occurs after JSON object names.
   356  func (e stateEntry) needImplicitColon() bool {
   357  	return e.needObjectValue()
   358  }
   359  
   360  // needObjectValue reports whether the next token must be a JSON value,
   361  // which is necessary after every JSON object name.
   362  func (e stateEntry) needObjectValue() bool {
   363  	return e&(stateTypeMask|stateCountLSBMask) == stateTypeObject|stateCountOdd
   364  }
   365  
   366  // needImplicitComma reports whether an comma should occur next,
   367  // which always occurs after a value in a JSON object or array
   368  // before the next value (or name).
   369  func (e stateEntry) needImplicitComma(next Kind) bool {
   370  	return !e.needObjectValue() && e.length() > 0 && next != '}' && next != ']'
   371  }
   372  
   373  // increment increments the number of elements for the current object or array.
   374  // This assumes that overflow won't practically be an issue since
   375  // 1<<bits.OnesCount(stateCountMask) is sufficiently large.
   376  func (e *stateEntry) increment() {
   377  	(*e)++
   378  }
   379  
   380  // decrement decrements the number of elements for the current object or array.
   381  // It is the callers responsibility to ensure that e.length > 0.
   382  func (e *stateEntry) decrement() {
   383  	(*e)--
   384  }
   385  
   386  // disableNamespace disables the JSON object namespace such that the
   387  // Encoder or Decoder no longer updates the namespace.
   388  func (e *stateEntry) disableNamespace() {
   389  	*e |= stateDisableNamespace
   390  }
   391  
   392  // isActiveNamespace reports whether the JSON object namespace is actively
   393  // being updated and used for duplicate name checks.
   394  func (e stateEntry) isActiveNamespace() bool {
   395  	return e&(stateDisableNamespace) == 0
   396  }
   397  
   398  // invalidateNamespace marks the JSON object namespace as being invalid.
   399  func (e *stateEntry) invalidateNamespace() {
   400  	*e |= stateInvalidNamespace
   401  }
   402  
   403  // isValidNamespace reports whether the JSON object namespace is valid.
   404  func (e stateEntry) isValidNamespace() bool {
   405  	return e&(stateInvalidNamespace) == 0
   406  }
   407  
   408  // objectNameStack is a stack of names when descending into a JSON object.
   409  // In contrast to objectNamespaceStack, this only has to remember a single name
   410  // per JSON object.
   411  //
   412  // This data structure may contain offsets to encodeBuffer or decodeBuffer.
   413  // It violates clean abstraction of layers, but is significantly more efficient.
   414  // This ensures that popping and pushing in the common case is a trivial
   415  // push/pop of an offset integer.
   416  //
   417  // The zero value is an empty names stack ready for use.
   418  type objectNameStack struct {
   419  	// offsets is a stack of offsets for each name.
   420  	// A non-negative offset is the ending offset into the local names buffer.
   421  	// A negative offset is the bit-wise inverse of a starting offset into
   422  	// a remote buffer (e.g., encodeBuffer or decodeBuffer).
   423  	// A math.MinInt offset at the end implies that the last object is empty.
   424  	// Invariant: Positive offsets always occur before negative offsets.
   425  	offsets []int
   426  	// unquotedNames is a back-to-back concatenation of names.
   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 // avoid pinning arbitrarily large amounts of memory
   435  	}
   436  	if cap(ns.unquotedNames) > 1<<10 {
   437  		ns.unquotedNames = nil // avoid pinning arbitrarily large amounts of memory
   438  	}
   439  }
   440  
   441  func (ns *objectNameStack) length() int {
   442  	return len(ns.offsets)
   443  }
   444  
   445  // getUnquoted retrieves the ith unquoted name in the namespace.
   446  // It returns an empty string if the last object is empty.
   447  //
   448  // Invariant: Must call copyQuotedBuffer beforehand.
   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  // invalidOffset indicates that the last JSON object currently has no name.
   459  const invalidOffset = math.MinInt
   460  
   461  // push descends into a nested JSON object.
   462  func (ns *objectNameStack) push() {
   463  	ns.offsets = append(ns.offsets, invalidOffset)
   464  }
   465  
   466  // replaceLastQuotedOffset replaces the last name with the starting offset
   467  // to the quoted name in some remote buffer. All offsets provided must be
   468  // relative to the same buffer until copyQuotedBuffer is called.
   469  func (ns *objectNameStack) replaceLastQuotedOffset(i int) {
   470  	// Use bit-wise inversion instead of naive multiplication by -1 to avoid
   471  	// ambiguity regarding zero (which is a valid offset into the names field).
   472  	// Bit-wise inversion is mathematically equivalent to -i-1,
   473  	// such that 0 becomes -1, 1 becomes -2, and so forth.
   474  	// This ensures that remote offsets are always negative.
   475  	ns.offsets[len(ns.offsets)-1] = ^i
   476  }
   477  
   478  // replaceLastUnquotedName replaces the last name with the provided name.
   479  //
   480  // Invariant: Must call copyQuotedBuffer beforehand.
   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  // clearLast removes any name in the last JSON object.
   492  // It is semantically equivalent to ns.push followed by ns.pop.
   493  func (ns *objectNameStack) clearLast() {
   494  	ns.offsets[len(ns.offsets)-1] = invalidOffset
   495  }
   496  
   497  // pop ascends out of a nested JSON object.
   498  func (ns *objectNameStack) pop() {
   499  	ns.offsets = ns.offsets[:len(ns.offsets)-1]
   500  }
   501  
   502  // copyQuotedBuffer copies names from the remote buffer into the local names
   503  // buffer so that there are no more offset references into the remote buffer.
   504  // This allows the remote buffer to change contents without affecting
   505  // the names that this data structure is trying to remember.
   506  func (ns *objectNameStack) copyQuotedBuffer(b []byte) {
   507  	// Find the first negative offset.
   508  	var i int
   509  	for i = len(ns.offsets) - 1; i >= 0 && ns.offsets[i] < 0; i-- {
   510  		continue
   511  	}
   512  
   513  	// Copy each name from the remote buffer into the local buffer.
   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 // last JSON object had a push without any names
   522  		}
   523  
   524  		// As a form of Hyrum proofing, we write an invalid character into the
   525  		// buffer to make misuse of Decoder.ReadToken more obvious.
   526  		// We need to undo that mutation here.
   527  		quotedName := b[^ns.offsets[i]:]
   528  		if quotedName[0] == invalidateBufferByte {
   529  			quotedName[0] = '"'
   530  		}
   531  
   532  		// Append the unquoted name to the local buffer.
   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  // objectNamespaceStack is a stack of object namespaces.
   553  // This data structure assists in detecting duplicate names.
   554  type objectNamespaceStack []objectNamespace
   555  
   556  // reset resets the object namespace stack.
   557  func (nss *objectNamespaceStack) reset() {
   558  	if cap(*nss) > 1<<10 {
   559  		*nss = nil
   560  	}
   561  	*nss = (*nss)[:0]
   562  }
   563  
   564  // push starts a new namespace for a nested JSON object.
   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  // last returns a pointer to the last JSON object namespace.
   575  func (nss objectNamespaceStack) last() *objectNamespace {
   576  	return &nss[len(nss)-1]
   577  }
   578  
   579  // pop terminates the namespace for a nested JSON object.
   580  func (nss *objectNamespaceStack) pop() {
   581  	*nss = (*nss)[:len(*nss)-1]
   582  }
   583  
   584  // objectNamespace is the namespace for a JSON object.
   585  // In contrast to objectNameStack, this needs to remember a all names
   586  // per JSON object.
   587  //
   588  // The zero value is an empty namespace ready for use.
   589  type objectNamespace struct {
   590  	// It relies on a linear search over all the names before switching
   591  	// to use a Go map for direct lookup.
   592  
   593  	// endOffsets is a list of offsets to the end of each name in buffers.
   594  	// The length of offsets is the number of names in the namespace.
   595  	endOffsets []uint
   596  	// allUnquotedNames is a back-to-back concatenation of every name in the namespace.
   597  	allUnquotedNames []byte
   598  	// mapNames is a Go map containing every name in the namespace.
   599  	// Only valid if non-nil.
   600  	mapNames map[string]struct{}
   601  }
   602  
   603  // reset resets the namespace to be empty.
   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 // avoid pinning arbitrarily large amounts of memory
   610  	}
   611  	if cap(ns.allUnquotedNames) > 1<<10 {
   612  		ns.allUnquotedNames = nil // avoid pinning arbitrarily large amounts of memory
   613  	}
   614  }
   615  
   616  // length reports the number of names in the namespace.
   617  func (ns *objectNamespace) length() int {
   618  	return len(ns.endOffsets)
   619  }
   620  
   621  // getUnquoted retrieves the ith unquoted name in the namespace.
   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  // lastUnquoted retrieves the last name in the namespace.
   631  func (ns *objectNamespace) lastUnquoted() []byte {
   632  	return ns.getUnquoted(ns.length() - 1)
   633  }
   634  
   635  // insertQuoted inserts a name and reports whether it was inserted,
   636  // which only occurs if name is not already in the namespace.
   637  // The provided name must be a valid JSON string.
   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  	// Switch to a map if the buffer is too large for linear search.
   657  	// This does not add the current name to the map.
   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{}{} // allocates a new string
   664  			startOffset = endOffset
   665  		}
   666  	}
   667  
   668  	if ns.mapNames == nil {
   669  		// Perform linear search over the buffer to find matching names.
   670  		// It provides O(n) lookup, but does not require any allocations.
   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  		// Use the map if it is populated.
   680  		// It provides O(1) lookup, but requires a string allocation per name.
   681  		if _, ok := ns.mapNames[string(name)]; ok {
   682  			return false
   683  		}
   684  		ns.mapNames[string(name)] = struct{}{} // allocates a new string
   685  	}
   686  
   687  	ns.allUnquotedNames = allNames
   688  	ns.endOffsets = append(ns.endOffsets, uint(len(ns.allUnquotedNames)))
   689  	return true
   690  }
   691  
   692  // removeLast removes the last name in the namespace.
   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  // uintSet is a set of unsigned integers.
   712  // It is optimized for most integers being close to zero.
   713  type uintSet struct {
   714  	lo uintSet64
   715  	hi []uintSet64
   716  }
   717  
   718  // has reports whether i is in the set.
   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  // insert inserts i into the set and reports whether it was the first insertion.
   730  func (s *uintSet) insert(i uint) bool {
   731  	// TODO: Make this inlineable at least for the lower 64-bit case.
   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  }