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

     1  // Copyright 2022 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  	"encoding/binary"
     9  	"math/bits"
    10  )
    11  
    12  // stringCache is a cache for strings converted from a []byte.
    13  type stringCache [256]string // 256*unsafe.Sizeof(string("")) => 4KiB
    14  
    15  // make returns the string form of b.
    16  // It returns a pre-allocated string from c if present, otherwise
    17  // it allocates a new string, inserts it into the cache, and returns it.
    18  func (c *stringCache) make(b []byte) string {
    19  	const (
    20  		minCachedLen = 2   // single byte strings are already interned by the runtime
    21  		maxCachedLen = 256 // large enough for UUIDs, IPv6 addresses, SHA-256 checksums, etc.
    22  	)
    23  	if c == nil || len(b) < minCachedLen || len(b) > maxCachedLen {
    24  		return string(b)
    25  	}
    26  
    27  	// Compute a hash from the fixed-width prefix and suffix of the string.
    28  	// This ensures hashing a string is a constant time operation.
    29  	var h uint32
    30  	switch {
    31  	case len(b) >= 8:
    32  		lo := binary.LittleEndian.Uint64(b[:8])
    33  		hi := binary.LittleEndian.Uint64(b[len(b)-8:])
    34  		h = hash64(uint32(lo), uint32(lo>>32)) ^ hash64(uint32(hi), uint32(hi>>32))
    35  	case len(b) >= 4:
    36  		lo := binary.LittleEndian.Uint32(b[:4])
    37  		hi := binary.LittleEndian.Uint32(b[len(b)-4:])
    38  		h = hash64(lo, hi)
    39  	case len(b) >= 2:
    40  		lo := binary.LittleEndian.Uint16(b[:2])
    41  		hi := binary.LittleEndian.Uint16(b[len(b)-2:])
    42  		h = hash64(uint32(lo), uint32(hi))
    43  	}
    44  
    45  	// Check the cache for the string.
    46  	i := h % uint32(len(*c))
    47  	if s := (*c)[i]; s == string(b) {
    48  		return s
    49  	}
    50  	s := string(b)
    51  	(*c)[i] = s
    52  	return s
    53  }
    54  
    55  // hash64 returns the hash of two uint32s as a single uint32.
    56  func hash64(lo, hi uint32) uint32 {
    57  	// If avalanche=true, this is identical to XXH32 hash on a 8B string:
    58  	//	var b [8]byte
    59  	//	binary.LittleEndian.PutUint32(b[:4], lo)
    60  	//	binary.LittleEndian.PutUint32(b[4:], hi)
    61  	//	return xxhash.Sum32(b[:])
    62  	const (
    63  		prime1 = 0x9e3779b1
    64  		prime2 = 0x85ebca77
    65  		prime3 = 0xc2b2ae3d
    66  		prime4 = 0x27d4eb2f
    67  		prime5 = 0x165667b1
    68  	)
    69  	h := prime5 + uint32(8)
    70  	h += lo * prime3
    71  	h = bits.RotateLeft32(h, 17) * prime4
    72  	h += hi * prime3
    73  	h = bits.RotateLeft32(h, 17) * prime4
    74  	// Skip final mix (avalanche) step of XXH32 for performance reasons.
    75  	// Empirical testing shows that the improvements in unbiased distribution
    76  	// does not outweigh the extra cost in computational complexity.
    77  	const avalanche = false
    78  	if avalanche {
    79  		h ^= h >> 15
    80  		h *= prime2
    81  		h ^= h >> 13
    82  		h *= prime3
    83  		h ^= h >> 16
    84  	}
    85  	return h
    86  }