github.com/sagernet/sing@v0.4.0-beta.19.0.20240518125136-f67a0988a636/common/json/internal/contextjson/fold.go (about)

     1  // Copyright 2013 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  	"unicode"
     9  	"unicode/utf8"
    10  )
    11  
    12  // foldName returns a folded string such that foldName(x) == foldName(y)
    13  // is identical to bytes.EqualFold(x, y).
    14  func foldName(in []byte) []byte {
    15  	// This is inlinable to take advantage of "function outlining".
    16  	var arr [32]byte // large enough for most JSON names
    17  	return appendFoldedName(arr[:0], in)
    18  }
    19  
    20  func appendFoldedName(out, in []byte) []byte {
    21  	for i := 0; i < len(in); {
    22  		// Handle single-byte ASCII.
    23  		if c := in[i]; c < utf8.RuneSelf {
    24  			if 'a' <= c && c <= 'z' {
    25  				c -= 'a' - 'A'
    26  			}
    27  			out = append(out, c)
    28  			i++
    29  			continue
    30  		}
    31  		// Handle multi-byte Unicode.
    32  		r, n := utf8.DecodeRune(in[i:])
    33  		out = utf8.AppendRune(out, foldRune(r))
    34  		i += n
    35  	}
    36  	return out
    37  }
    38  
    39  // foldRune is returns the smallest rune for all runes in the same fold set.
    40  func foldRune(r rune) rune {
    41  	for {
    42  		r2 := unicode.SimpleFold(r)
    43  		if r2 <= r {
    44  			return r2
    45  		}
    46  		r = r2
    47  	}
    48  }