Source file src/cmd/go/internal/str/str.go

     1  // Copyright 2017 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 str provides string manipulation utilities.
     6  package str
     7  
     8  import (
     9  	"fmt"
    10  	"strings"
    11  	"unicode"
    12  	"unicode/utf8"
    13  )
    14  
    15  // StringList flattens its arguments into a single []string.
    16  // Each argument in args must have type string or []string.
    17  func StringList(args ...any) []string {
    18  	var x []string
    19  	for _, arg := range args {
    20  		switch arg := arg.(type) {
    21  		case []string:
    22  			x = append(x, arg...)
    23  		case string:
    24  			x = append(x, arg)
    25  		default:
    26  			panic("stringList: invalid argument of type " + fmt.Sprintf("%T", arg))
    27  		}
    28  	}
    29  	return x
    30  }
    31  
    32  // ToFold returns a string with the property that
    33  //
    34  //	strings.EqualFold(s, t) iff ToFold(s) == ToFold(t)
    35  //
    36  // This lets us test a large set of strings for fold-equivalent
    37  // duplicates without making a quadratic number of calls
    38  // to EqualFold. Note that strings.ToUpper and strings.ToLower
    39  // do not have the desired property in some corner cases.
    40  func ToFold(s string) string {
    41  	// Fast path: all ASCII, no upper case.
    42  	// Most paths look like this already.
    43  	for i := 0; i < len(s); i++ {
    44  		c := s[i]
    45  		if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' {
    46  			goto Slow
    47  		}
    48  	}
    49  	return s
    50  
    51  Slow:
    52  	var b strings.Builder
    53  	for _, r := range s {
    54  		// SimpleFold(x) cycles to the next equivalent rune > x
    55  		// or wraps around to smaller values. Iterate until it wraps,
    56  		// and we've found the minimum value.
    57  		for {
    58  			r0 := r
    59  			r = unicode.SimpleFold(r0)
    60  			if r <= r0 {
    61  				break
    62  			}
    63  		}
    64  		// Exception to allow fast path above: A-Z => a-z
    65  		if 'A' <= r && r <= 'Z' {
    66  			r += 'a' - 'A'
    67  		}
    68  		b.WriteRune(r)
    69  	}
    70  	return b.String()
    71  }
    72  
    73  // FoldDup reports a pair of strings from the list that are
    74  // equal according to strings.EqualFold.
    75  // It returns "", "" if there are no such strings.
    76  func FoldDup(list []string) (string, string) {
    77  	clash := map[string]string{}
    78  	for _, s := range list {
    79  		fold := ToFold(s)
    80  		if t := clash[fold]; t != "" {
    81  			if s > t {
    82  				s, t = t, s
    83  			}
    84  			return s, t
    85  		}
    86  		clash[fold] = s
    87  	}
    88  	return "", ""
    89  }
    90  
    91  // Contains reports whether x contains s.
    92  func Contains(x []string, s string) bool {
    93  	for _, t := range x {
    94  		if t == s {
    95  			return true
    96  		}
    97  	}
    98  	return false
    99  }
   100  
   101  // Uniq removes consecutive duplicate strings from ss.
   102  func Uniq(ss *[]string) {
   103  	if len(*ss) <= 1 {
   104  		return
   105  	}
   106  	uniq := (*ss)[:1]
   107  	for _, s := range *ss {
   108  		if s != uniq[len(uniq)-1] {
   109  			uniq = append(uniq, s)
   110  		}
   111  	}
   112  	*ss = uniq
   113  }
   114  

View as plain text