1*333d2b36SAndroid Build Coastguard Worker// Copyright 2015 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage android 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "cmp" 19*333d2b36SAndroid Build Coastguard Worker "fmt" 20*333d2b36SAndroid Build Coastguard Worker "path/filepath" 21*333d2b36SAndroid Build Coastguard Worker "reflect" 22*333d2b36SAndroid Build Coastguard Worker "regexp" 23*333d2b36SAndroid Build Coastguard Worker "runtime" 24*333d2b36SAndroid Build Coastguard Worker "sort" 25*333d2b36SAndroid Build Coastguard Worker "strings" 26*333d2b36SAndroid Build Coastguard Worker "sync" 27*333d2b36SAndroid Build Coastguard Worker 28*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint/proptools" 29*333d2b36SAndroid Build Coastguard Worker) 30*333d2b36SAndroid Build Coastguard Worker 31*333d2b36SAndroid Build Coastguard Worker// CopyOf returns a new slice that has the same contents as s. 32*333d2b36SAndroid Build Coastguard Workerfunc CopyOf[T any](s []T) []T { 33*333d2b36SAndroid Build Coastguard Worker // If the input is nil, return nil and not an empty list 34*333d2b36SAndroid Build Coastguard Worker if s == nil { 35*333d2b36SAndroid Build Coastguard Worker return s 36*333d2b36SAndroid Build Coastguard Worker } 37*333d2b36SAndroid Build Coastguard Worker return append([]T{}, s...) 38*333d2b36SAndroid Build Coastguard Worker} 39*333d2b36SAndroid Build Coastguard Worker 40*333d2b36SAndroid Build Coastguard Worker// Concat returns a new slice concatenated from the two input slices. It does not change the input 41*333d2b36SAndroid Build Coastguard Worker// slices. 42*333d2b36SAndroid Build Coastguard Workerfunc Concat[T any](s1, s2 []T) []T { 43*333d2b36SAndroid Build Coastguard Worker res := make([]T, 0, len(s1)+len(s2)) 44*333d2b36SAndroid Build Coastguard Worker res = append(res, s1...) 45*333d2b36SAndroid Build Coastguard Worker res = append(res, s2...) 46*333d2b36SAndroid Build Coastguard Worker return res 47*333d2b36SAndroid Build Coastguard Worker} 48*333d2b36SAndroid Build Coastguard Worker 49*333d2b36SAndroid Build Coastguard Worker// JoinPathsWithPrefix converts the paths to strings, prefixes them 50*333d2b36SAndroid Build Coastguard Worker// with prefix and then joins them separated by " ". 51*333d2b36SAndroid Build Coastguard Workerfunc JoinPathsWithPrefix(paths []Path, prefix string) string { 52*333d2b36SAndroid Build Coastguard Worker strs := make([]string, len(paths)) 53*333d2b36SAndroid Build Coastguard Worker for i := range paths { 54*333d2b36SAndroid Build Coastguard Worker strs[i] = paths[i].String() 55*333d2b36SAndroid Build Coastguard Worker } 56*333d2b36SAndroid Build Coastguard Worker return JoinWithPrefixAndSeparator(strs, prefix, " ") 57*333d2b36SAndroid Build Coastguard Worker} 58*333d2b36SAndroid Build Coastguard Worker 59*333d2b36SAndroid Build Coastguard Worker// JoinWithPrefix prepends the prefix to each string in the list and 60*333d2b36SAndroid Build Coastguard Worker// returns them joined together with " " as separator. 61*333d2b36SAndroid Build Coastguard Workerfunc JoinWithPrefix(strs []string, prefix string) string { 62*333d2b36SAndroid Build Coastguard Worker return JoinWithPrefixAndSeparator(strs, prefix, " ") 63*333d2b36SAndroid Build Coastguard Worker} 64*333d2b36SAndroid Build Coastguard Worker 65*333d2b36SAndroid Build Coastguard Worker// JoinWithPrefixAndSeparator prepends the prefix to each string in the list and 66*333d2b36SAndroid Build Coastguard Worker// returns them joined together with the given separator. 67*333d2b36SAndroid Build Coastguard Workerfunc JoinWithPrefixAndSeparator(strs []string, prefix string, sep string) string { 68*333d2b36SAndroid Build Coastguard Worker return JoinWithPrefixSuffixAndSeparator(strs, prefix, "", sep) 69*333d2b36SAndroid Build Coastguard Worker} 70*333d2b36SAndroid Build Coastguard Worker 71*333d2b36SAndroid Build Coastguard Worker// JoinWithSuffixAndSeparator appends the suffix to each string in the list and 72*333d2b36SAndroid Build Coastguard Worker// returns them joined together with the given separator. 73*333d2b36SAndroid Build Coastguard Workerfunc JoinWithSuffixAndSeparator(strs []string, suffix string, sep string) string { 74*333d2b36SAndroid Build Coastguard Worker return JoinWithPrefixSuffixAndSeparator(strs, "", suffix, sep) 75*333d2b36SAndroid Build Coastguard Worker} 76*333d2b36SAndroid Build Coastguard Worker 77*333d2b36SAndroid Build Coastguard Worker// JoinWithPrefixSuffixAndSeparator appends the prefix/suffix to each string in the list and 78*333d2b36SAndroid Build Coastguard Worker// returns them joined together with the given separator. 79*333d2b36SAndroid Build Coastguard Workerfunc JoinWithPrefixSuffixAndSeparator(strs []string, prefix, suffix, sep string) string { 80*333d2b36SAndroid Build Coastguard Worker if len(strs) == 0 { 81*333d2b36SAndroid Build Coastguard Worker return "" 82*333d2b36SAndroid Build Coastguard Worker } 83*333d2b36SAndroid Build Coastguard Worker 84*333d2b36SAndroid Build Coastguard Worker // Pre-calculate the length of the result 85*333d2b36SAndroid Build Coastguard Worker length := 0 86*333d2b36SAndroid Build Coastguard Worker for _, s := range strs { 87*333d2b36SAndroid Build Coastguard Worker length += len(s) 88*333d2b36SAndroid Build Coastguard Worker } 89*333d2b36SAndroid Build Coastguard Worker length += (len(prefix)+len(suffix))*len(strs) + len(sep)*(len(strs)-1) 90*333d2b36SAndroid Build Coastguard Worker 91*333d2b36SAndroid Build Coastguard Worker var buf strings.Builder 92*333d2b36SAndroid Build Coastguard Worker buf.Grow(length) 93*333d2b36SAndroid Build Coastguard Worker buf.WriteString(prefix) 94*333d2b36SAndroid Build Coastguard Worker buf.WriteString(strs[0]) 95*333d2b36SAndroid Build Coastguard Worker buf.WriteString(suffix) 96*333d2b36SAndroid Build Coastguard Worker for i := 1; i < len(strs); i++ { 97*333d2b36SAndroid Build Coastguard Worker buf.WriteString(sep) 98*333d2b36SAndroid Build Coastguard Worker buf.WriteString(prefix) 99*333d2b36SAndroid Build Coastguard Worker buf.WriteString(strs[i]) 100*333d2b36SAndroid Build Coastguard Worker buf.WriteString(suffix) 101*333d2b36SAndroid Build Coastguard Worker } 102*333d2b36SAndroid Build Coastguard Worker return buf.String() 103*333d2b36SAndroid Build Coastguard Worker} 104*333d2b36SAndroid Build Coastguard Worker 105*333d2b36SAndroid Build Coastguard Worker// SortedStringKeys returns the keys of the given map in the ascending order. 106*333d2b36SAndroid Build Coastguard Worker// 107*333d2b36SAndroid Build Coastguard Worker// Deprecated: Use SortedKeys instead. 108*333d2b36SAndroid Build Coastguard Workerfunc SortedStringKeys[V any](m map[string]V) []string { 109*333d2b36SAndroid Build Coastguard Worker return SortedKeys(m) 110*333d2b36SAndroid Build Coastguard Worker} 111*333d2b36SAndroid Build Coastguard Worker 112*333d2b36SAndroid Build Coastguard Worker// SortedKeys returns the keys of the given map in the ascending order. 113*333d2b36SAndroid Build Coastguard Workerfunc SortedKeys[T cmp.Ordered, V any](m map[T]V) []T { 114*333d2b36SAndroid Build Coastguard Worker if len(m) == 0 { 115*333d2b36SAndroid Build Coastguard Worker return nil 116*333d2b36SAndroid Build Coastguard Worker } 117*333d2b36SAndroid Build Coastguard Worker ret := make([]T, 0, len(m)) 118*333d2b36SAndroid Build Coastguard Worker for k := range m { 119*333d2b36SAndroid Build Coastguard Worker ret = append(ret, k) 120*333d2b36SAndroid Build Coastguard Worker } 121*333d2b36SAndroid Build Coastguard Worker sort.Slice(ret, func(i, j int) bool { 122*333d2b36SAndroid Build Coastguard Worker return ret[i] < ret[j] 123*333d2b36SAndroid Build Coastguard Worker }) 124*333d2b36SAndroid Build Coastguard Worker return ret 125*333d2b36SAndroid Build Coastguard Worker} 126*333d2b36SAndroid Build Coastguard Worker 127*333d2b36SAndroid Build Coastguard Worker// stringValues returns the values of the given string-valued map in randomized map order. 128*333d2b36SAndroid Build Coastguard Workerfunc stringValues(m interface{}) []string { 129*333d2b36SAndroid Build Coastguard Worker v := reflect.ValueOf(m) 130*333d2b36SAndroid Build Coastguard Worker if v.Kind() != reflect.Map { 131*333d2b36SAndroid Build Coastguard Worker panic(fmt.Sprintf("%#v is not a map", m)) 132*333d2b36SAndroid Build Coastguard Worker } 133*333d2b36SAndroid Build Coastguard Worker if v.Len() == 0 { 134*333d2b36SAndroid Build Coastguard Worker return nil 135*333d2b36SAndroid Build Coastguard Worker } 136*333d2b36SAndroid Build Coastguard Worker iter := v.MapRange() 137*333d2b36SAndroid Build Coastguard Worker s := make([]string, 0, v.Len()) 138*333d2b36SAndroid Build Coastguard Worker for iter.Next() { 139*333d2b36SAndroid Build Coastguard Worker s = append(s, iter.Value().String()) 140*333d2b36SAndroid Build Coastguard Worker } 141*333d2b36SAndroid Build Coastguard Worker return s 142*333d2b36SAndroid Build Coastguard Worker} 143*333d2b36SAndroid Build Coastguard Worker 144*333d2b36SAndroid Build Coastguard Worker// SortedStringValues returns the values of the given string-valued map in the ascending order. 145*333d2b36SAndroid Build Coastguard Workerfunc SortedStringValues(m interface{}) []string { 146*333d2b36SAndroid Build Coastguard Worker s := stringValues(m) 147*333d2b36SAndroid Build Coastguard Worker sort.Strings(s) 148*333d2b36SAndroid Build Coastguard Worker return s 149*333d2b36SAndroid Build Coastguard Worker} 150*333d2b36SAndroid Build Coastguard Worker 151*333d2b36SAndroid Build Coastguard Worker// SortedUniqueStringValues returns the values of the given string-valued map in the ascending order 152*333d2b36SAndroid Build Coastguard Worker// with duplicates removed. 153*333d2b36SAndroid Build Coastguard Workerfunc SortedUniqueStringValues(m interface{}) []string { 154*333d2b36SAndroid Build Coastguard Worker s := stringValues(m) 155*333d2b36SAndroid Build Coastguard Worker return SortedUniqueStrings(s) 156*333d2b36SAndroid Build Coastguard Worker} 157*333d2b36SAndroid Build Coastguard Worker 158*333d2b36SAndroid Build Coastguard Worker// IndexList returns the index of the first occurrence of the given string in the list or -1 159*333d2b36SAndroid Build Coastguard Workerfunc IndexList[T comparable](t T, list []T) int { 160*333d2b36SAndroid Build Coastguard Worker for i, l := range list { 161*333d2b36SAndroid Build Coastguard Worker if l == t { 162*333d2b36SAndroid Build Coastguard Worker return i 163*333d2b36SAndroid Build Coastguard Worker } 164*333d2b36SAndroid Build Coastguard Worker } 165*333d2b36SAndroid Build Coastguard Worker return -1 166*333d2b36SAndroid Build Coastguard Worker} 167*333d2b36SAndroid Build Coastguard Worker 168*333d2b36SAndroid Build Coastguard Workerfunc InList[T comparable](t T, list []T) bool { 169*333d2b36SAndroid Build Coastguard Worker return IndexList(t, list) != -1 170*333d2b36SAndroid Build Coastguard Worker} 171*333d2b36SAndroid Build Coastguard Worker 172*333d2b36SAndroid Build Coastguard Workerfunc setFromList[T comparable](l []T) map[T]bool { 173*333d2b36SAndroid Build Coastguard Worker m := make(map[T]bool, len(l)) 174*333d2b36SAndroid Build Coastguard Worker for _, t := range l { 175*333d2b36SAndroid Build Coastguard Worker m[t] = true 176*333d2b36SAndroid Build Coastguard Worker } 177*333d2b36SAndroid Build Coastguard Worker return m 178*333d2b36SAndroid Build Coastguard Worker} 179*333d2b36SAndroid Build Coastguard Worker 180*333d2b36SAndroid Build Coastguard Worker// PrettyConcat returns the formatted concatenated string suitable for displaying user-facing 181*333d2b36SAndroid Build Coastguard Worker// messages. 182*333d2b36SAndroid Build Coastguard Workerfunc PrettyConcat(list []string, quote bool, lastSep string) string { 183*333d2b36SAndroid Build Coastguard Worker if len(list) == 0 { 184*333d2b36SAndroid Build Coastguard Worker return "" 185*333d2b36SAndroid Build Coastguard Worker } 186*333d2b36SAndroid Build Coastguard Worker 187*333d2b36SAndroid Build Coastguard Worker quoteStr := func(v string) string { 188*333d2b36SAndroid Build Coastguard Worker if !quote { 189*333d2b36SAndroid Build Coastguard Worker return v 190*333d2b36SAndroid Build Coastguard Worker } 191*333d2b36SAndroid Build Coastguard Worker return fmt.Sprintf("%q", v) 192*333d2b36SAndroid Build Coastguard Worker } 193*333d2b36SAndroid Build Coastguard Worker 194*333d2b36SAndroid Build Coastguard Worker if len(list) == 1 { 195*333d2b36SAndroid Build Coastguard Worker return quoteStr(list[0]) 196*333d2b36SAndroid Build Coastguard Worker } 197*333d2b36SAndroid Build Coastguard Worker 198*333d2b36SAndroid Build Coastguard Worker var sb strings.Builder 199*333d2b36SAndroid Build Coastguard Worker for i, val := range list { 200*333d2b36SAndroid Build Coastguard Worker if i > 0 { 201*333d2b36SAndroid Build Coastguard Worker sb.WriteString(", ") 202*333d2b36SAndroid Build Coastguard Worker } 203*333d2b36SAndroid Build Coastguard Worker if i == len(list)-1 { 204*333d2b36SAndroid Build Coastguard Worker sb.WriteString(lastSep) 205*333d2b36SAndroid Build Coastguard Worker if lastSep != "" { 206*333d2b36SAndroid Build Coastguard Worker sb.WriteString(" ") 207*333d2b36SAndroid Build Coastguard Worker } 208*333d2b36SAndroid Build Coastguard Worker } 209*333d2b36SAndroid Build Coastguard Worker sb.WriteString(quoteStr(val)) 210*333d2b36SAndroid Build Coastguard Worker } 211*333d2b36SAndroid Build Coastguard Worker 212*333d2b36SAndroid Build Coastguard Worker return sb.String() 213*333d2b36SAndroid Build Coastguard Worker} 214*333d2b36SAndroid Build Coastguard Worker 215*333d2b36SAndroid Build Coastguard Worker// ListSetDifference checks if the two lists contain the same elements. It returns 216*333d2b36SAndroid Build Coastguard Worker// a boolean which is true if there is a difference, and then returns lists of elements 217*333d2b36SAndroid Build Coastguard Worker// that are in l1 but not l2, and l2 but not l1. 218*333d2b36SAndroid Build Coastguard Workerfunc ListSetDifference[T comparable](l1, l2 []T) (bool, []T, []T) { 219*333d2b36SAndroid Build Coastguard Worker listsDiffer := false 220*333d2b36SAndroid Build Coastguard Worker diff1 := []T{} 221*333d2b36SAndroid Build Coastguard Worker diff2 := []T{} 222*333d2b36SAndroid Build Coastguard Worker m1 := setFromList(l1) 223*333d2b36SAndroid Build Coastguard Worker m2 := setFromList(l2) 224*333d2b36SAndroid Build Coastguard Worker for t := range m1 { 225*333d2b36SAndroid Build Coastguard Worker if _, ok := m2[t]; !ok { 226*333d2b36SAndroid Build Coastguard Worker diff1 = append(diff1, t) 227*333d2b36SAndroid Build Coastguard Worker listsDiffer = true 228*333d2b36SAndroid Build Coastguard Worker } 229*333d2b36SAndroid Build Coastguard Worker } 230*333d2b36SAndroid Build Coastguard Worker for t := range m2 { 231*333d2b36SAndroid Build Coastguard Worker if _, ok := m1[t]; !ok { 232*333d2b36SAndroid Build Coastguard Worker diff2 = append(diff2, t) 233*333d2b36SAndroid Build Coastguard Worker listsDiffer = true 234*333d2b36SAndroid Build Coastguard Worker } 235*333d2b36SAndroid Build Coastguard Worker } 236*333d2b36SAndroid Build Coastguard Worker return listsDiffer, diff1, diff2 237*333d2b36SAndroid Build Coastguard Worker} 238*333d2b36SAndroid Build Coastguard Worker 239*333d2b36SAndroid Build Coastguard Worker// Returns true if the two lists have common elements. 240*333d2b36SAndroid Build Coastguard Workerfunc HasIntersection[T comparable](l1, l2 []T) bool { 241*333d2b36SAndroid Build Coastguard Worker _, a, b := ListSetDifference(l1, l2) 242*333d2b36SAndroid Build Coastguard Worker return len(a)+len(b) < len(setFromList(l1))+len(setFromList(l2)) 243*333d2b36SAndroid Build Coastguard Worker} 244*333d2b36SAndroid Build Coastguard Worker 245*333d2b36SAndroid Build Coastguard Worker// Returns true if the given string s is prefixed with any string in the given prefix list. 246*333d2b36SAndroid Build Coastguard Workerfunc HasAnyPrefix(s string, prefixList []string) bool { 247*333d2b36SAndroid Build Coastguard Worker for _, prefix := range prefixList { 248*333d2b36SAndroid Build Coastguard Worker if strings.HasPrefix(s, prefix) { 249*333d2b36SAndroid Build Coastguard Worker return true 250*333d2b36SAndroid Build Coastguard Worker } 251*333d2b36SAndroid Build Coastguard Worker } 252*333d2b36SAndroid Build Coastguard Worker return false 253*333d2b36SAndroid Build Coastguard Worker} 254*333d2b36SAndroid Build Coastguard Worker 255*333d2b36SAndroid Build Coastguard Worker// Returns true if any string in the given list has the given substring. 256*333d2b36SAndroid Build Coastguard Workerfunc SubstringInList(list []string, substr string) bool { 257*333d2b36SAndroid Build Coastguard Worker for _, s := range list { 258*333d2b36SAndroid Build Coastguard Worker if strings.Contains(s, substr) { 259*333d2b36SAndroid Build Coastguard Worker return true 260*333d2b36SAndroid Build Coastguard Worker } 261*333d2b36SAndroid Build Coastguard Worker } 262*333d2b36SAndroid Build Coastguard Worker return false 263*333d2b36SAndroid Build Coastguard Worker} 264*333d2b36SAndroid Build Coastguard Worker 265*333d2b36SAndroid Build Coastguard Worker// Returns true if any string in the given list has the given prefix. 266*333d2b36SAndroid Build Coastguard Workerfunc PrefixInList(list []string, prefix string) bool { 267*333d2b36SAndroid Build Coastguard Worker for _, s := range list { 268*333d2b36SAndroid Build Coastguard Worker if strings.HasPrefix(s, prefix) { 269*333d2b36SAndroid Build Coastguard Worker return true 270*333d2b36SAndroid Build Coastguard Worker } 271*333d2b36SAndroid Build Coastguard Worker } 272*333d2b36SAndroid Build Coastguard Worker return false 273*333d2b36SAndroid Build Coastguard Worker} 274*333d2b36SAndroid Build Coastguard Worker 275*333d2b36SAndroid Build Coastguard Worker// Returns true if any string in the given list has the given suffix. 276*333d2b36SAndroid Build Coastguard Workerfunc SuffixInList(list []string, suffix string) bool { 277*333d2b36SAndroid Build Coastguard Worker for _, s := range list { 278*333d2b36SAndroid Build Coastguard Worker if strings.HasSuffix(s, suffix) { 279*333d2b36SAndroid Build Coastguard Worker return true 280*333d2b36SAndroid Build Coastguard Worker } 281*333d2b36SAndroid Build Coastguard Worker } 282*333d2b36SAndroid Build Coastguard Worker return false 283*333d2b36SAndroid Build Coastguard Worker} 284*333d2b36SAndroid Build Coastguard Worker 285*333d2b36SAndroid Build Coastguard Worker// IndexListPred returns the index of the element which in the given `list` satisfying the predicate, or -1 if there is no such element. 286*333d2b36SAndroid Build Coastguard Workerfunc IndexListPred(pred func(s string) bool, list []string) int { 287*333d2b36SAndroid Build Coastguard Worker for i, l := range list { 288*333d2b36SAndroid Build Coastguard Worker if pred(l) { 289*333d2b36SAndroid Build Coastguard Worker return i 290*333d2b36SAndroid Build Coastguard Worker } 291*333d2b36SAndroid Build Coastguard Worker } 292*333d2b36SAndroid Build Coastguard Worker 293*333d2b36SAndroid Build Coastguard Worker return -1 294*333d2b36SAndroid Build Coastguard Worker} 295*333d2b36SAndroid Build Coastguard Worker 296*333d2b36SAndroid Build Coastguard Worker// FilterList divides the string list into two lists: one with the strings belonging 297*333d2b36SAndroid Build Coastguard Worker// to the given filter list, and the other with the remaining ones 298*333d2b36SAndroid Build Coastguard Workerfunc FilterList(list []string, filter []string) (remainder []string, filtered []string) { 299*333d2b36SAndroid Build Coastguard Worker // InList is O(n). May be worth using more efficient lookup for longer lists. 300*333d2b36SAndroid Build Coastguard Worker for _, l := range list { 301*333d2b36SAndroid Build Coastguard Worker if InList(l, filter) { 302*333d2b36SAndroid Build Coastguard Worker filtered = append(filtered, l) 303*333d2b36SAndroid Build Coastguard Worker } else { 304*333d2b36SAndroid Build Coastguard Worker remainder = append(remainder, l) 305*333d2b36SAndroid Build Coastguard Worker } 306*333d2b36SAndroid Build Coastguard Worker } 307*333d2b36SAndroid Build Coastguard Worker 308*333d2b36SAndroid Build Coastguard Worker return 309*333d2b36SAndroid Build Coastguard Worker} 310*333d2b36SAndroid Build Coastguard Worker 311*333d2b36SAndroid Build Coastguard Worker// FilterListPred returns the elements of the given list for which the predicate 312*333d2b36SAndroid Build Coastguard Worker// returns true. Order is kept. 313*333d2b36SAndroid Build Coastguard Workerfunc FilterListPred(list []string, pred func(s string) bool) (filtered []string) { 314*333d2b36SAndroid Build Coastguard Worker for _, l := range list { 315*333d2b36SAndroid Build Coastguard Worker if pred(l) { 316*333d2b36SAndroid Build Coastguard Worker filtered = append(filtered, l) 317*333d2b36SAndroid Build Coastguard Worker } 318*333d2b36SAndroid Build Coastguard Worker } 319*333d2b36SAndroid Build Coastguard Worker return 320*333d2b36SAndroid Build Coastguard Worker} 321*333d2b36SAndroid Build Coastguard Worker 322*333d2b36SAndroid Build Coastguard Worker// RemoveListFromList removes the strings belonging to the filter list from the 323*333d2b36SAndroid Build Coastguard Worker// given list and returns the result 324*333d2b36SAndroid Build Coastguard Workerfunc RemoveListFromList(list []string, filter_out []string) (result []string) { 325*333d2b36SAndroid Build Coastguard Worker result = make([]string, 0, len(list)) 326*333d2b36SAndroid Build Coastguard Worker for _, l := range list { 327*333d2b36SAndroid Build Coastguard Worker if !InList(l, filter_out) { 328*333d2b36SAndroid Build Coastguard Worker result = append(result, l) 329*333d2b36SAndroid Build Coastguard Worker } 330*333d2b36SAndroid Build Coastguard Worker } 331*333d2b36SAndroid Build Coastguard Worker return 332*333d2b36SAndroid Build Coastguard Worker} 333*333d2b36SAndroid Build Coastguard Worker 334*333d2b36SAndroid Build Coastguard Worker// RemoveFromList removes given string from the string list. 335*333d2b36SAndroid Build Coastguard Workerfunc RemoveFromList(s string, list []string) (bool, []string) { 336*333d2b36SAndroid Build Coastguard Worker result := make([]string, 0, len(list)) 337*333d2b36SAndroid Build Coastguard Worker var removed bool 338*333d2b36SAndroid Build Coastguard Worker for _, item := range list { 339*333d2b36SAndroid Build Coastguard Worker if item != s { 340*333d2b36SAndroid Build Coastguard Worker result = append(result, item) 341*333d2b36SAndroid Build Coastguard Worker } else { 342*333d2b36SAndroid Build Coastguard Worker removed = true 343*333d2b36SAndroid Build Coastguard Worker } 344*333d2b36SAndroid Build Coastguard Worker } 345*333d2b36SAndroid Build Coastguard Worker return removed, result 346*333d2b36SAndroid Build Coastguard Worker} 347*333d2b36SAndroid Build Coastguard Worker 348*333d2b36SAndroid Build Coastguard Worker// FirstUniqueFunc returns all unique elements of a slice, keeping the first copy of 349*333d2b36SAndroid Build Coastguard Worker// each. It does not modify the input slice. The eq function should return true 350*333d2b36SAndroid Build Coastguard Worker// if two elements can be considered equal. 351*333d2b36SAndroid Build Coastguard Workerfunc FirstUniqueFunc[SortableList ~[]Sortable, Sortable any](list SortableList, eq func(a, b Sortable) bool) SortableList { 352*333d2b36SAndroid Build Coastguard Worker k := 0 353*333d2b36SAndroid Build Coastguard Workerouter: 354*333d2b36SAndroid Build Coastguard Worker for i := 0; i < len(list); i++ { 355*333d2b36SAndroid Build Coastguard Worker for j := 0; j < k; j++ { 356*333d2b36SAndroid Build Coastguard Worker if eq(list[i], list[j]) { 357*333d2b36SAndroid Build Coastguard Worker continue outer 358*333d2b36SAndroid Build Coastguard Worker } 359*333d2b36SAndroid Build Coastguard Worker } 360*333d2b36SAndroid Build Coastguard Worker list[k] = list[i] 361*333d2b36SAndroid Build Coastguard Worker k++ 362*333d2b36SAndroid Build Coastguard Worker } 363*333d2b36SAndroid Build Coastguard Worker return list[:k] 364*333d2b36SAndroid Build Coastguard Worker} 365*333d2b36SAndroid Build Coastguard Worker 366*333d2b36SAndroid Build Coastguard Worker// FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of 367*333d2b36SAndroid Build Coastguard Worker// each. It does not modify the input slice. 368*333d2b36SAndroid Build Coastguard Workerfunc FirstUniqueStrings(list []string) []string { 369*333d2b36SAndroid Build Coastguard Worker return firstUnique(list) 370*333d2b36SAndroid Build Coastguard Worker} 371*333d2b36SAndroid Build Coastguard Worker 372*333d2b36SAndroid Build Coastguard Worker// firstUnique returns all unique elements of a slice, keeping the first copy of each. It 373*333d2b36SAndroid Build Coastguard Worker// does not modify the input slice. 374*333d2b36SAndroid Build Coastguard Workerfunc firstUnique[T comparable](slice []T) []T { 375*333d2b36SAndroid Build Coastguard Worker // Do not modify the input in-place, operate on a copy instead. 376*333d2b36SAndroid Build Coastguard Worker slice = CopyOf(slice) 377*333d2b36SAndroid Build Coastguard Worker return firstUniqueInPlace(slice) 378*333d2b36SAndroid Build Coastguard Worker} 379*333d2b36SAndroid Build Coastguard Worker 380*333d2b36SAndroid Build Coastguard Worker// firstUniqueInPlace returns all unique elements of a slice, keeping the first copy of 381*333d2b36SAndroid Build Coastguard Worker// each. It modifies the slice contents in place, and returns a subslice of the original 382*333d2b36SAndroid Build Coastguard Worker// slice. 383*333d2b36SAndroid Build Coastguard Workerfunc firstUniqueInPlace[T comparable](slice []T) []T { 384*333d2b36SAndroid Build Coastguard Worker // 128 was chosen based on BenchmarkFirstUniqueStrings results. 385*333d2b36SAndroid Build Coastguard Worker if len(slice) > 128 { 386*333d2b36SAndroid Build Coastguard Worker return firstUniqueMap(slice) 387*333d2b36SAndroid Build Coastguard Worker } 388*333d2b36SAndroid Build Coastguard Worker return firstUniqueList(slice) 389*333d2b36SAndroid Build Coastguard Worker} 390*333d2b36SAndroid Build Coastguard Worker 391*333d2b36SAndroid Build Coastguard Worker// firstUniqueList is an implementation of firstUnique using an O(N^2) list comparison to look for 392*333d2b36SAndroid Build Coastguard Worker// duplicates. 393*333d2b36SAndroid Build Coastguard Workerfunc firstUniqueList[T any](in []T) []T { 394*333d2b36SAndroid Build Coastguard Worker writeIndex := 0 395*333d2b36SAndroid Build Coastguard Workerouter: 396*333d2b36SAndroid Build Coastguard Worker for readIndex := 0; readIndex < len(in); readIndex++ { 397*333d2b36SAndroid Build Coastguard Worker for compareIndex := 0; compareIndex < writeIndex; compareIndex++ { 398*333d2b36SAndroid Build Coastguard Worker if interface{}(in[readIndex]) == interface{}(in[compareIndex]) { 399*333d2b36SAndroid Build Coastguard Worker // The value at readIndex already exists somewhere in the output region 400*333d2b36SAndroid Build Coastguard Worker // of the slice before writeIndex, skip it. 401*333d2b36SAndroid Build Coastguard Worker continue outer 402*333d2b36SAndroid Build Coastguard Worker } 403*333d2b36SAndroid Build Coastguard Worker } 404*333d2b36SAndroid Build Coastguard Worker if readIndex != writeIndex { 405*333d2b36SAndroid Build Coastguard Worker in[writeIndex] = in[readIndex] 406*333d2b36SAndroid Build Coastguard Worker } 407*333d2b36SAndroid Build Coastguard Worker writeIndex++ 408*333d2b36SAndroid Build Coastguard Worker } 409*333d2b36SAndroid Build Coastguard Worker return in[0:writeIndex] 410*333d2b36SAndroid Build Coastguard Worker} 411*333d2b36SAndroid Build Coastguard Worker 412*333d2b36SAndroid Build Coastguard Worker// firstUniqueMap is an implementation of firstUnique using an O(N) hash set lookup to look for 413*333d2b36SAndroid Build Coastguard Worker// duplicates. 414*333d2b36SAndroid Build Coastguard Workerfunc firstUniqueMap[T comparable](in []T) []T { 415*333d2b36SAndroid Build Coastguard Worker writeIndex := 0 416*333d2b36SAndroid Build Coastguard Worker seen := make(map[T]bool, len(in)) 417*333d2b36SAndroid Build Coastguard Worker for readIndex := 0; readIndex < len(in); readIndex++ { 418*333d2b36SAndroid Build Coastguard Worker if _, exists := seen[in[readIndex]]; exists { 419*333d2b36SAndroid Build Coastguard Worker continue 420*333d2b36SAndroid Build Coastguard Worker } 421*333d2b36SAndroid Build Coastguard Worker seen[in[readIndex]] = true 422*333d2b36SAndroid Build Coastguard Worker if readIndex != writeIndex { 423*333d2b36SAndroid Build Coastguard Worker in[writeIndex] = in[readIndex] 424*333d2b36SAndroid Build Coastguard Worker } 425*333d2b36SAndroid Build Coastguard Worker writeIndex++ 426*333d2b36SAndroid Build Coastguard Worker } 427*333d2b36SAndroid Build Coastguard Worker return in[0:writeIndex] 428*333d2b36SAndroid Build Coastguard Worker} 429*333d2b36SAndroid Build Coastguard Worker 430*333d2b36SAndroid Build Coastguard Worker// ReverseSliceInPlace reverses the elements of a slice in place and returns it. 431*333d2b36SAndroid Build Coastguard Workerfunc ReverseSliceInPlace[T any](in []T) []T { 432*333d2b36SAndroid Build Coastguard Worker for i, j := 0, len(in)-1; i < j; i, j = i+1, j-1 { 433*333d2b36SAndroid Build Coastguard Worker in[i], in[j] = in[j], in[i] 434*333d2b36SAndroid Build Coastguard Worker } 435*333d2b36SAndroid Build Coastguard Worker return in 436*333d2b36SAndroid Build Coastguard Worker} 437*333d2b36SAndroid Build Coastguard Worker 438*333d2b36SAndroid Build Coastguard Worker// ReverseSlice returns a copy of a slice in reverse order. 439*333d2b36SAndroid Build Coastguard Workerfunc ReverseSlice[T any](in []T) []T { 440*333d2b36SAndroid Build Coastguard Worker if in == nil { 441*333d2b36SAndroid Build Coastguard Worker return in 442*333d2b36SAndroid Build Coastguard Worker } 443*333d2b36SAndroid Build Coastguard Worker out := make([]T, len(in)) 444*333d2b36SAndroid Build Coastguard Worker for i := 0; i < len(in); i++ { 445*333d2b36SAndroid Build Coastguard Worker out[i] = in[len(in)-1-i] 446*333d2b36SAndroid Build Coastguard Worker } 447*333d2b36SAndroid Build Coastguard Worker return out 448*333d2b36SAndroid Build Coastguard Worker} 449*333d2b36SAndroid Build Coastguard Worker 450*333d2b36SAndroid Build Coastguard Worker// LastUniqueStrings returns all unique elements of a slice of strings, keeping the last copy of 451*333d2b36SAndroid Build Coastguard Worker// each. It modifies the slice contents in place, and returns a subslice of the original slice. 452*333d2b36SAndroid Build Coastguard Workerfunc LastUniqueStrings(list []string) []string { 453*333d2b36SAndroid Build Coastguard Worker totalSkip := 0 454*333d2b36SAndroid Build Coastguard Worker for i := len(list) - 1; i >= totalSkip; i-- { 455*333d2b36SAndroid Build Coastguard Worker skip := 0 456*333d2b36SAndroid Build Coastguard Worker for j := i - 1; j >= totalSkip; j-- { 457*333d2b36SAndroid Build Coastguard Worker if list[i] == list[j] { 458*333d2b36SAndroid Build Coastguard Worker skip++ 459*333d2b36SAndroid Build Coastguard Worker } else { 460*333d2b36SAndroid Build Coastguard Worker list[j+skip] = list[j] 461*333d2b36SAndroid Build Coastguard Worker } 462*333d2b36SAndroid Build Coastguard Worker } 463*333d2b36SAndroid Build Coastguard Worker totalSkip += skip 464*333d2b36SAndroid Build Coastguard Worker } 465*333d2b36SAndroid Build Coastguard Worker return list[totalSkip:] 466*333d2b36SAndroid Build Coastguard Worker} 467*333d2b36SAndroid Build Coastguard Worker 468*333d2b36SAndroid Build Coastguard Worker// SortedUniqueStrings returns what the name says 469*333d2b36SAndroid Build Coastguard Workerfunc SortedUniqueStrings(list []string) []string { 470*333d2b36SAndroid Build Coastguard Worker // FirstUniqueStrings creates a copy of `list`, so the input remains untouched. 471*333d2b36SAndroid Build Coastguard Worker unique := FirstUniqueStrings(list) 472*333d2b36SAndroid Build Coastguard Worker sort.Strings(unique) 473*333d2b36SAndroid Build Coastguard Worker return unique 474*333d2b36SAndroid Build Coastguard Worker} 475*333d2b36SAndroid Build Coastguard Worker 476*333d2b36SAndroid Build Coastguard Worker// checkCalledFromInit panics if a Go package's init function is not on the 477*333d2b36SAndroid Build Coastguard Worker// call stack. 478*333d2b36SAndroid Build Coastguard Workerfunc checkCalledFromInit() { 479*333d2b36SAndroid Build Coastguard Worker for skip := 3; ; skip++ { 480*333d2b36SAndroid Build Coastguard Worker _, funcName, ok := callerName(skip) 481*333d2b36SAndroid Build Coastguard Worker if !ok { 482*333d2b36SAndroid Build Coastguard Worker panic("not called from an init func") 483*333d2b36SAndroid Build Coastguard Worker } 484*333d2b36SAndroid Build Coastguard Worker 485*333d2b36SAndroid Build Coastguard Worker if funcName == "init" || strings.HasPrefix(funcName, "init·") || 486*333d2b36SAndroid Build Coastguard Worker strings.HasPrefix(funcName, "init.") { 487*333d2b36SAndroid Build Coastguard Worker return 488*333d2b36SAndroid Build Coastguard Worker } 489*333d2b36SAndroid Build Coastguard Worker } 490*333d2b36SAndroid Build Coastguard Worker} 491*333d2b36SAndroid Build Coastguard Worker 492*333d2b36SAndroid Build Coastguard Worker// A regex to find a package path within a function name. It finds the shortest string that is 493*333d2b36SAndroid Build Coastguard Worker// followed by '.' and doesn't have any '/'s left. 494*333d2b36SAndroid Build Coastguard Workervar pkgPathRe = regexp.MustCompile(`^(.*?)\.([^/]+)$`) 495*333d2b36SAndroid Build Coastguard Worker 496*333d2b36SAndroid Build Coastguard Worker// callerName returns the package path and function name of the calling 497*333d2b36SAndroid Build Coastguard Worker// function. The skip argument has the same meaning as the skip argument of 498*333d2b36SAndroid Build Coastguard Worker// runtime.Callers. 499*333d2b36SAndroid Build Coastguard Workerfunc callerName(skip int) (pkgPath, funcName string, ok bool) { 500*333d2b36SAndroid Build Coastguard Worker var pc [1]uintptr 501*333d2b36SAndroid Build Coastguard Worker n := runtime.Callers(skip+1, pc[:]) 502*333d2b36SAndroid Build Coastguard Worker if n != 1 { 503*333d2b36SAndroid Build Coastguard Worker return "", "", false 504*333d2b36SAndroid Build Coastguard Worker } 505*333d2b36SAndroid Build Coastguard Worker 506*333d2b36SAndroid Build Coastguard Worker f := runtime.FuncForPC(pc[0]).Name() 507*333d2b36SAndroid Build Coastguard Worker s := pkgPathRe.FindStringSubmatch(f) 508*333d2b36SAndroid Build Coastguard Worker if len(s) < 3 { 509*333d2b36SAndroid Build Coastguard Worker panic(fmt.Errorf("failed to extract package path and function name from %q", f)) 510*333d2b36SAndroid Build Coastguard Worker } 511*333d2b36SAndroid Build Coastguard Worker 512*333d2b36SAndroid Build Coastguard Worker return s[1], s[2], true 513*333d2b36SAndroid Build Coastguard Worker} 514*333d2b36SAndroid Build Coastguard Worker 515*333d2b36SAndroid Build Coastguard Worker// GetNumericSdkVersion removes the first occurrence of system_ in a string, 516*333d2b36SAndroid Build Coastguard Worker// which is assumed to be something like "system_1.2.3" 517*333d2b36SAndroid Build Coastguard Workerfunc GetNumericSdkVersion(v string) string { 518*333d2b36SAndroid Build Coastguard Worker return strings.Replace(v, "system_", "", 1) 519*333d2b36SAndroid Build Coastguard Worker} 520*333d2b36SAndroid Build Coastguard Worker 521*333d2b36SAndroid Build Coastguard Worker// copied from build/kati/strutil.go 522*333d2b36SAndroid Build Coastguard Workerfunc substPattern(pat, repl, str string) string { 523*333d2b36SAndroid Build Coastguard Worker ps := strings.SplitN(pat, "%", 2) 524*333d2b36SAndroid Build Coastguard Worker if len(ps) != 2 { 525*333d2b36SAndroid Build Coastguard Worker if str == pat { 526*333d2b36SAndroid Build Coastguard Worker return repl 527*333d2b36SAndroid Build Coastguard Worker } 528*333d2b36SAndroid Build Coastguard Worker return str 529*333d2b36SAndroid Build Coastguard Worker } 530*333d2b36SAndroid Build Coastguard Worker in := str 531*333d2b36SAndroid Build Coastguard Worker trimmed := str 532*333d2b36SAndroid Build Coastguard Worker if ps[0] != "" { 533*333d2b36SAndroid Build Coastguard Worker trimmed = strings.TrimPrefix(in, ps[0]) 534*333d2b36SAndroid Build Coastguard Worker if trimmed == in { 535*333d2b36SAndroid Build Coastguard Worker return str 536*333d2b36SAndroid Build Coastguard Worker } 537*333d2b36SAndroid Build Coastguard Worker } 538*333d2b36SAndroid Build Coastguard Worker in = trimmed 539*333d2b36SAndroid Build Coastguard Worker if ps[1] != "" { 540*333d2b36SAndroid Build Coastguard Worker trimmed = strings.TrimSuffix(in, ps[1]) 541*333d2b36SAndroid Build Coastguard Worker if trimmed == in { 542*333d2b36SAndroid Build Coastguard Worker return str 543*333d2b36SAndroid Build Coastguard Worker } 544*333d2b36SAndroid Build Coastguard Worker } 545*333d2b36SAndroid Build Coastguard Worker 546*333d2b36SAndroid Build Coastguard Worker rs := strings.SplitN(repl, "%", 2) 547*333d2b36SAndroid Build Coastguard Worker if len(rs) != 2 { 548*333d2b36SAndroid Build Coastguard Worker return repl 549*333d2b36SAndroid Build Coastguard Worker } 550*333d2b36SAndroid Build Coastguard Worker return rs[0] + trimmed + rs[1] 551*333d2b36SAndroid Build Coastguard Worker} 552*333d2b36SAndroid Build Coastguard Worker 553*333d2b36SAndroid Build Coastguard Worker// copied from build/kati/strutil.go 554*333d2b36SAndroid Build Coastguard Workerfunc matchPattern(pat, str string) bool { 555*333d2b36SAndroid Build Coastguard Worker i := strings.IndexByte(pat, '%') 556*333d2b36SAndroid Build Coastguard Worker if i < 0 { 557*333d2b36SAndroid Build Coastguard Worker return pat == str 558*333d2b36SAndroid Build Coastguard Worker } 559*333d2b36SAndroid Build Coastguard Worker return strings.HasPrefix(str, pat[:i]) && strings.HasSuffix(str, pat[i+1:]) 560*333d2b36SAndroid Build Coastguard Worker} 561*333d2b36SAndroid Build Coastguard Worker 562*333d2b36SAndroid Build Coastguard Workervar shlibVersionPattern = regexp.MustCompile("(?:\\.\\d+(?:svn)?)+") 563*333d2b36SAndroid Build Coastguard Worker 564*333d2b36SAndroid Build Coastguard Worker// splitFileExt splits a file name into root, suffix and ext. root stands for the file name without 565*333d2b36SAndroid Build Coastguard Worker// the file extension and the version number (e.g. "libexample"). suffix stands for the 566*333d2b36SAndroid Build Coastguard Worker// concatenation of the file extension and the version number (e.g. ".so.1.0"). ext stands for the 567*333d2b36SAndroid Build Coastguard Worker// file extension after the version numbers are trimmed (e.g. ".so"). 568*333d2b36SAndroid Build Coastguard Workerfunc SplitFileExt(name string) (string, string, string) { 569*333d2b36SAndroid Build Coastguard Worker // Extract and trim the shared lib version number if the file name ends with dot digits. 570*333d2b36SAndroid Build Coastguard Worker suffix := "" 571*333d2b36SAndroid Build Coastguard Worker matches := shlibVersionPattern.FindAllStringIndex(name, -1) 572*333d2b36SAndroid Build Coastguard Worker if len(matches) > 0 { 573*333d2b36SAndroid Build Coastguard Worker lastMatch := matches[len(matches)-1] 574*333d2b36SAndroid Build Coastguard Worker if lastMatch[1] == len(name) { 575*333d2b36SAndroid Build Coastguard Worker suffix = name[lastMatch[0]:lastMatch[1]] 576*333d2b36SAndroid Build Coastguard Worker name = name[0:lastMatch[0]] 577*333d2b36SAndroid Build Coastguard Worker } 578*333d2b36SAndroid Build Coastguard Worker } 579*333d2b36SAndroid Build Coastguard Worker 580*333d2b36SAndroid Build Coastguard Worker // Extract the file name root and the file extension. 581*333d2b36SAndroid Build Coastguard Worker ext := filepath.Ext(name) 582*333d2b36SAndroid Build Coastguard Worker root := strings.TrimSuffix(name, ext) 583*333d2b36SAndroid Build Coastguard Worker suffix = ext + suffix 584*333d2b36SAndroid Build Coastguard Worker 585*333d2b36SAndroid Build Coastguard Worker return root, suffix, ext 586*333d2b36SAndroid Build Coastguard Worker} 587*333d2b36SAndroid Build Coastguard Worker 588*333d2b36SAndroid Build Coastguard Worker// ShardPaths takes a Paths, and returns a slice of Paths where each one has at most shardSize paths. 589*333d2b36SAndroid Build Coastguard Workerfunc ShardPaths(paths Paths, shardSize int) []Paths { 590*333d2b36SAndroid Build Coastguard Worker return proptools.ShardBySize(paths, shardSize) 591*333d2b36SAndroid Build Coastguard Worker} 592*333d2b36SAndroid Build Coastguard Worker 593*333d2b36SAndroid Build Coastguard Worker// ShardString takes a string and returns a slice of strings where the length of each one is 594*333d2b36SAndroid Build Coastguard Worker// at most shardSize. 595*333d2b36SAndroid Build Coastguard Workerfunc ShardString(s string, shardSize int) []string { 596*333d2b36SAndroid Build Coastguard Worker if len(s) == 0 { 597*333d2b36SAndroid Build Coastguard Worker return nil 598*333d2b36SAndroid Build Coastguard Worker } 599*333d2b36SAndroid Build Coastguard Worker ret := make([]string, 0, (len(s)+shardSize-1)/shardSize) 600*333d2b36SAndroid Build Coastguard Worker for len(s) > shardSize { 601*333d2b36SAndroid Build Coastguard Worker ret = append(ret, s[0:shardSize]) 602*333d2b36SAndroid Build Coastguard Worker s = s[shardSize:] 603*333d2b36SAndroid Build Coastguard Worker } 604*333d2b36SAndroid Build Coastguard Worker if len(s) > 0 { 605*333d2b36SAndroid Build Coastguard Worker ret = append(ret, s) 606*333d2b36SAndroid Build Coastguard Worker } 607*333d2b36SAndroid Build Coastguard Worker return ret 608*333d2b36SAndroid Build Coastguard Worker} 609*333d2b36SAndroid Build Coastguard Worker 610*333d2b36SAndroid Build Coastguard Worker// ShardStrings takes a slice of strings, and returns a slice of slices of strings where each one has at most shardSize 611*333d2b36SAndroid Build Coastguard Worker// elements. 612*333d2b36SAndroid Build Coastguard Workerfunc ShardStrings(s []string, shardSize int) [][]string { 613*333d2b36SAndroid Build Coastguard Worker return proptools.ShardBySize(s, shardSize) 614*333d2b36SAndroid Build Coastguard Worker} 615*333d2b36SAndroid Build Coastguard Worker 616*333d2b36SAndroid Build Coastguard Worker// CheckDuplicate checks if there are duplicates in given string list. 617*333d2b36SAndroid Build Coastguard Worker// If there are, it returns first such duplicate and true. 618*333d2b36SAndroid Build Coastguard Workerfunc CheckDuplicate(values []string) (duplicate string, found bool) { 619*333d2b36SAndroid Build Coastguard Worker seen := make(map[string]string) 620*333d2b36SAndroid Build Coastguard Worker for _, v := range values { 621*333d2b36SAndroid Build Coastguard Worker if duplicate, found = seen[v]; found { 622*333d2b36SAndroid Build Coastguard Worker return duplicate, true 623*333d2b36SAndroid Build Coastguard Worker } 624*333d2b36SAndroid Build Coastguard Worker seen[v] = v 625*333d2b36SAndroid Build Coastguard Worker } 626*333d2b36SAndroid Build Coastguard Worker return "", false 627*333d2b36SAndroid Build Coastguard Worker} 628*333d2b36SAndroid Build Coastguard Worker 629*333d2b36SAndroid Build Coastguard Workerfunc AddToStringSet(set map[string]bool, items []string) { 630*333d2b36SAndroid Build Coastguard Worker for _, item := range items { 631*333d2b36SAndroid Build Coastguard Worker set[item] = true 632*333d2b36SAndroid Build Coastguard Worker } 633*333d2b36SAndroid Build Coastguard Worker} 634*333d2b36SAndroid Build Coastguard Worker 635*333d2b36SAndroid Build Coastguard Worker// SyncMap is a wrapper around sync.Map that provides type safety via generics. 636*333d2b36SAndroid Build Coastguard Workertype SyncMap[K comparable, V any] struct { 637*333d2b36SAndroid Build Coastguard Worker sync.Map 638*333d2b36SAndroid Build Coastguard Worker} 639*333d2b36SAndroid Build Coastguard Worker 640*333d2b36SAndroid Build Coastguard Worker// Load returns the value stored in the map for a key, or the zero value if no 641*333d2b36SAndroid Build Coastguard Worker// value is present. 642*333d2b36SAndroid Build Coastguard Worker// The ok result indicates whether value was found in the map. 643*333d2b36SAndroid Build Coastguard Workerfunc (m *SyncMap[K, V]) Load(key K) (value V, ok bool) { 644*333d2b36SAndroid Build Coastguard Worker v, ok := m.Map.Load(key) 645*333d2b36SAndroid Build Coastguard Worker if !ok { 646*333d2b36SAndroid Build Coastguard Worker return *new(V), false 647*333d2b36SAndroid Build Coastguard Worker } 648*333d2b36SAndroid Build Coastguard Worker return v.(V), true 649*333d2b36SAndroid Build Coastguard Worker} 650*333d2b36SAndroid Build Coastguard Worker 651*333d2b36SAndroid Build Coastguard Worker// Store sets the value for a key. 652*333d2b36SAndroid Build Coastguard Workerfunc (m *SyncMap[K, V]) Store(key K, value V) { 653*333d2b36SAndroid Build Coastguard Worker m.Map.Store(key, value) 654*333d2b36SAndroid Build Coastguard Worker} 655*333d2b36SAndroid Build Coastguard Worker 656*333d2b36SAndroid Build Coastguard Worker// LoadOrStore returns the existing value for the key if present. 657*333d2b36SAndroid Build Coastguard Worker// Otherwise, it stores and returns the given value. 658*333d2b36SAndroid Build Coastguard Worker// The loaded result is true if the value was loaded, false if stored. 659*333d2b36SAndroid Build Coastguard Workerfunc (m *SyncMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) { 660*333d2b36SAndroid Build Coastguard Worker v, loaded := m.Map.LoadOrStore(key, value) 661*333d2b36SAndroid Build Coastguard Worker return v.(V), loaded 662*333d2b36SAndroid Build Coastguard Worker} 663*333d2b36SAndroid Build Coastguard Worker 664*333d2b36SAndroid Build Coastguard Worker// AppendIfNotZero append the given value to the slice if it is not the zero value 665*333d2b36SAndroid Build Coastguard Worker// for its type. 666*333d2b36SAndroid Build Coastguard Workerfunc AppendIfNotZero[T comparable](slice []T, value T) []T { 667*333d2b36SAndroid Build Coastguard Worker var zeroValue T // Get the zero value of the type T 668*333d2b36SAndroid Build Coastguard Worker if value != zeroValue { 669*333d2b36SAndroid Build Coastguard Worker return append(slice, value) 670*333d2b36SAndroid Build Coastguard Worker } 671*333d2b36SAndroid Build Coastguard Worker return slice 672*333d2b36SAndroid Build Coastguard Worker} 673