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  	"bytes"
    10  	"fmt"
    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  //	strings.EqualFold(s, t) iff ToFold(s) == ToFold(t)
    34  // This lets us test a large set of strings for fold-equivalent
    35  // duplicates without making a quadratic number of calls
    36  // to EqualFold. Note that strings.ToUpper and strings.ToLower
    37  // do not have the desired property in some corner cases.
    38  func ToFold(s string) string {
    39  	// Fast path: all ASCII, no upper case.
    40  	// Most paths look like this already.
    41  	for i := 0; i < len(s); i++ {
    42  		c := s[i]
    43  		if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' {
    44  			goto Slow
    45  		}
    46  	}
    47  	return s
    48  
    49  Slow:
    50  	var buf bytes.Buffer
    51  	for _, r := range s {
    52  		// SimpleFold(x) cycles to the next equivalent rune > x
    53  		// or wraps around to smaller values. Iterate until it wraps,
    54  		// and we've found the minimum value.
    55  		for {
    56  			r0 := r
    57  			r = unicode.SimpleFold(r0)
    58  			if r <= r0 {
    59  				break
    60  			}
    61  		}
    62  		// Exception to allow fast path above: A-Z => a-z
    63  		if 'A' <= r && r <= 'Z' {
    64  			r += 'a' - 'A'
    65  		}
    66  		buf.WriteRune(r)
    67  	}
    68  	return buf.String()
    69  }
    70  
    71  // FoldDup reports a pair of strings from the list that are
    72  // equal according to strings.EqualFold.
    73  // It returns "", "" if there are no such strings.
    74  func FoldDup(list []string) (string, string) {
    75  	clash := map[string]string{}
    76  	for _, s := range list {
    77  		fold := ToFold(s)
    78  		if t := clash[fold]; t != "" {
    79  			if s > t {
    80  				s, t = t, s
    81  			}
    82  			return s, t
    83  		}
    84  		clash[fold] = s
    85  	}
    86  	return "", ""
    87  }
    88  
    89  // Contains reports whether x contains s.
    90  func Contains(x []string, s string) bool {
    91  	for _, t := range x {
    92  		if t == s {
    93  			return true
    94  		}
    95  	}
    96  	return false
    97  }
    98  
    99  // Uniq removes consecutive duplicate strings from ss.
   100  func Uniq(ss *[]string) {
   101  	if len(*ss) <= 1 {
   102  		return
   103  	}
   104  	uniq := (*ss)[:1]
   105  	for _, s := range *ss {
   106  		if s != uniq[len(uniq)-1] {
   107  			uniq = append(uniq, s)
   108  		}
   109  	}
   110  	*ss = uniq
   111  }
   112  

View as plain text