Source file src/encoding/json/v2/fold.go

     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  //go:build goexperiment.jsonv2
     6  
     7  package json
     8  
     9  import (
    10  	"unicode"
    11  	"unicode/utf8"
    12  )
    13  
    14  // foldName returns a folded string such that foldName(x) == foldName(y)
    15  // is similar to strings.EqualFold(x, y), but ignores underscore and dashes.
    16  // This allows foldName to match common naming conventions.
    17  func foldName(in []byte) []byte {
    18  	// This is inlinable to take advantage of "function outlining".
    19  	// See https://blog.filippo.io/efficient-go-apis-with-the-inliner/
    20  	var arr [32]byte // large enough for most JSON names
    21  	return appendFoldedName(arr[:0], in)
    22  }
    23  func appendFoldedName(out, in []byte) []byte {
    24  	for i := 0; i < len(in); {
    25  		// Handle single-byte ASCII.
    26  		if c := in[i]; c < utf8.RuneSelf {
    27  			if c != '_' && c != '-' {
    28  				if 'a' <= c && c <= 'z' {
    29  					c -= 'a' - 'A'
    30  				}
    31  				out = append(out, c)
    32  			}
    33  			i++
    34  			continue
    35  		}
    36  		// Handle multi-byte Unicode.
    37  		r, n := utf8.DecodeRune(in[i:])
    38  		out = utf8.AppendRune(out, foldRune(r))
    39  		i += n
    40  	}
    41  	return out
    42  }
    43  
    44  // foldRune is a variation on unicode.SimpleFold that returns the same rune
    45  // for all runes in the same fold set.
    46  //
    47  // Invariant:
    48  //
    49  //	foldRune(x) == foldRune(y) ⇔ strings.EqualFold(string(x), string(y))
    50  func foldRune(r rune) rune {
    51  	for {
    52  		r2 := unicode.SimpleFold(r)
    53  		if r2 <= r {
    54  			return r2 // smallest character in the fold set
    55  		}
    56  		r = r2
    57  	}
    58  }
    59  

View as plain text