blob: f7a3437c3ee10d89372bd7a2be50d76dc3e28de5 [file] [log] [blame]
Colin Crossc0b06f12015-04-08 13:03:43 -07001// Copyright 2015 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Colin Cross635c3b02016-05-18 15:37:25 -070015package android
Colin Crossc0b06f12015-04-08 13:03:43 -070016
Dan Willemsenb1957a52016-06-23 23:44:54 -070017import (
Colin Cross3020fee2019-03-19 15:05:17 -070018 "fmt"
19 "regexp"
Dan Willemsenb1957a52016-06-23 23:44:54 -070020 "runtime"
21 "sort"
22 "strings"
23)
Colin Cross1f8c52b2015-06-16 16:38:17 -070024
Colin Cross454c0872019-02-15 23:03:34 -080025// CopyOf returns a new slice that has the same contents as s.
26func CopyOf(s []string) []string {
27 return append([]string(nil), s...)
28}
29
Colin Crossc0b06f12015-04-08 13:03:43 -070030func JoinWithPrefix(strs []string, prefix string) string {
31 if len(strs) == 0 {
32 return ""
33 }
34
35 if len(strs) == 1 {
36 return prefix + strs[0]
37 }
38
39 n := len(" ") * (len(strs) - 1)
40 for _, s := range strs {
41 n += len(prefix) + len(s)
42 }
43
44 ret := make([]byte, 0, n)
45 for i, s := range strs {
46 if i != 0 {
47 ret = append(ret, ' ')
48 }
49 ret = append(ret, prefix...)
50 ret = append(ret, s...)
51 }
52 return string(ret)
53}
Colin Cross9b6826f2015-04-10 15:47:33 -070054
Inseob Kim1f086e22019-05-09 13:29:15 +090055func JoinWithSuffix(strs []string, suffix string, separator string) string {
56 if len(strs) == 0 {
57 return ""
58 }
59
60 if len(strs) == 1 {
61 return strs[0] + suffix
62 }
63
64 n := len(" ") * (len(strs) - 1)
65 for _, s := range strs {
66 n += len(suffix) + len(s)
67 }
68
69 ret := make([]byte, 0, n)
70 for i, s := range strs {
71 if i != 0 {
72 ret = append(ret, separator...)
73 }
74 ret = append(ret, s...)
75 ret = append(ret, suffix...)
76 }
77 return string(ret)
78}
79
Colin Cross1f8c52b2015-06-16 16:38:17 -070080func sortedKeys(m map[string][]string) []string {
81 s := make([]string, 0, len(m))
82 for k := range m {
83 s = append(s, k)
84 }
85 sort.Strings(s)
86 return s
87}
Dan Willemsenb1957a52016-06-23 23:44:54 -070088
Colin Crossb4330e22017-12-22 15:47:09 -080089func IndexList(s string, list []string) int {
Dan Willemsenb1957a52016-06-23 23:44:54 -070090 for i, l := range list {
91 if l == s {
92 return i
93 }
94 }
95
96 return -1
97}
98
Colin Crossb4330e22017-12-22 15:47:09 -080099func InList(s string, list []string) bool {
100 return IndexList(s, list) != -1
Dan Willemsenb1957a52016-06-23 23:44:54 -0700101}
102
Colin Crossb4330e22017-12-22 15:47:09 -0800103func PrefixInList(s string, list []string) bool {
Ivan Lozano5f595532017-07-13 14:46:05 -0700104 for _, prefix := range list {
105 if strings.HasPrefix(s, prefix) {
106 return true
107 }
108 }
109 return false
110}
111
Colin Crossb4330e22017-12-22 15:47:09 -0800112func FilterList(list []string, filter []string) (remainder []string, filtered []string) {
113 for _, l := range list {
114 if InList(l, filter) {
115 filtered = append(filtered, l)
116 } else {
117 remainder = append(remainder, l)
118 }
119 }
120
121 return
122}
123
124func RemoveListFromList(list []string, filter_out []string) (result []string) {
125 result = make([]string, 0, len(list))
126 for _, l := range list {
127 if !InList(l, filter_out) {
128 result = append(result, l)
129 }
130 }
131 return
132}
133
134func RemoveFromList(s string, list []string) (bool, []string) {
135 i := IndexList(s, list)
Logan Chien7922ab82018-03-06 18:29:27 +0800136 if i == -1 {
Colin Crossb4330e22017-12-22 15:47:09 -0800137 return false, list
138 }
Logan Chien7922ab82018-03-06 18:29:27 +0800139
140 result := make([]string, 0, len(list)-1)
141 result = append(result, list[:i]...)
142 for _, l := range list[i+1:] {
143 if l != s {
144 result = append(result, l)
145 }
146 }
147 return true, result
Colin Crossb4330e22017-12-22 15:47:09 -0800148}
149
Colin Crossb6715442017-10-24 11:13:31 -0700150// FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of
151// each. It modifies the slice contents in place, and returns a subslice of the original slice.
152func FirstUniqueStrings(list []string) []string {
153 k := 0
154outer:
155 for i := 0; i < len(list); i++ {
156 for j := 0; j < k; j++ {
157 if list[i] == list[j] {
158 continue outer
159 }
160 }
161 list[k] = list[i]
162 k++
163 }
164 return list[:k]
165}
166
167// LastUniqueStrings returns all unique elements of a slice of strings, keeping the last copy of
168// each. It modifies the slice contents in place, and returns a subslice of the original slice.
169func LastUniqueStrings(list []string) []string {
170 totalSkip := 0
171 for i := len(list) - 1; i >= totalSkip; i-- {
172 skip := 0
173 for j := i - 1; j >= totalSkip; j-- {
174 if list[i] == list[j] {
175 skip++
176 } else {
177 list[j+skip] = list[j]
178 }
179 }
180 totalSkip += skip
181 }
182 return list[totalSkip:]
183}
184
Dan Willemsenb1957a52016-06-23 23:44:54 -0700185// checkCalledFromInit panics if a Go package's init function is not on the
186// call stack.
187func checkCalledFromInit() {
188 for skip := 3; ; skip++ {
189 _, funcName, ok := callerName(skip)
190 if !ok {
191 panic("not called from an init func")
192 }
193
Colin Cross3020fee2019-03-19 15:05:17 -0700194 if funcName == "init" || strings.HasPrefix(funcName, "init·") ||
195 strings.HasPrefix(funcName, "init.") {
Dan Willemsenb1957a52016-06-23 23:44:54 -0700196 return
197 }
198 }
199}
200
Colin Cross3020fee2019-03-19 15:05:17 -0700201// A regex to find a package path within a function name. It finds the shortest string that is
202// followed by '.' and doesn't have any '/'s left.
203var pkgPathRe = regexp.MustCompile(`^(.*?)\.([^/]+)$`)
204
Dan Willemsenb1957a52016-06-23 23:44:54 -0700205// callerName returns the package path and function name of the calling
206// function. The skip argument has the same meaning as the skip argument of
207// runtime.Callers.
208func callerName(skip int) (pkgPath, funcName string, ok bool) {
209 var pc [1]uintptr
210 n := runtime.Callers(skip+1, pc[:])
211 if n != 1 {
212 return "", "", false
213 }
214
Colin Cross3020fee2019-03-19 15:05:17 -0700215 f := runtime.FuncForPC(pc[0]).Name()
216 s := pkgPathRe.FindStringSubmatch(f)
217 if len(s) < 3 {
218 panic(fmt.Errorf("failed to extract package path and function name from %q", f))
Dan Willemsenb1957a52016-06-23 23:44:54 -0700219 }
220
Colin Cross3020fee2019-03-19 15:05:17 -0700221 return s[1], s[2], true
Dan Willemsenb1957a52016-06-23 23:44:54 -0700222}
Sundong Ahn0926fae2017-10-17 16:34:51 +0900223
224func GetNumericSdkVersion(v string) string {
225 if strings.Contains(v, "system_") {
226 return strings.Replace(v, "system_", "", 1)
227 }
228 return v
229}
Jiyong Park7f67f482019-01-05 12:57:48 +0900230
231// copied from build/kati/strutil.go
232func substPattern(pat, repl, str string) string {
233 ps := strings.SplitN(pat, "%", 2)
234 if len(ps) != 2 {
235 if str == pat {
236 return repl
237 }
238 return str
239 }
240 in := str
241 trimed := str
242 if ps[0] != "" {
243 trimed = strings.TrimPrefix(in, ps[0])
244 if trimed == in {
245 return str
246 }
247 }
248 in = trimed
249 if ps[1] != "" {
250 trimed = strings.TrimSuffix(in, ps[1])
251 if trimed == in {
252 return str
253 }
254 }
255
256 rs := strings.SplitN(repl, "%", 2)
257 if len(rs) != 2 {
258 return repl
259 }
260 return rs[0] + trimed + rs[1]
261}
262
263// copied from build/kati/strutil.go
264func matchPattern(pat, str string) bool {
265 i := strings.IndexByte(pat, '%')
266 if i < 0 {
267 return pat == str
268 }
269 return strings.HasPrefix(str, pat[:i]) && strings.HasSuffix(str, pat[i+1:])
270}