github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/pkg/list/list.go (about) 1 // Copyright 2019 CUE Authors 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 15 // Package list contains functions for manipulating and examining lists. 16 package list 17 18 import ( 19 "fmt" 20 "sort" 21 22 "github.com/joomcode/cue/cue" 23 ) 24 25 // Drop reports the suffix of list x after the first n elements, 26 // or [] if n > len(x). 27 // 28 // For instance: 29 // 30 // Drop([1, 2, 3, 4], 2) 31 // 32 // results in 33 // 34 // [3, 4] 35 // 36 func Drop(x []cue.Value, n int) ([]cue.Value, error) { 37 if n < 0 { 38 return nil, fmt.Errorf("negative index") 39 } 40 41 if n > len(x) { 42 return []cue.Value{}, nil 43 } 44 45 return x[n:], nil 46 } 47 48 // TODO: disable Flatten until we know the right default for depth. 49 // The right time to determine is at least some point after the query 50 // extensions are introduced, which may provide flatten functionality 51 // natively. 52 // 53 // // Flatten reports a flattend sequence of the list xs by expanding any elements 54 // // that are lists. 55 // // 56 // // For instance: 57 // // 58 // // Flatten([1, [[2, 3], []], [4]]) 59 // // 60 // // results in 61 // // 62 // // [1, 2, 3, 4] 63 // // 64 // func Flatten(xs cue.Value) ([]cue.Value, error) { 65 // var flatten func(cue.Value) ([]cue.Value, error) 66 // flatten = func(xs cue.Value) ([]cue.Value, error) { 67 // var res []cue.Value 68 // iter, err := xs.List() 69 // if err != nil { 70 // return nil, err 71 // } 72 // for iter.Next() { 73 // val := iter.Value() 74 // if val.Kind() == cue.ListKind { 75 // vals, err := flatten(val) 76 // if err != nil { 77 // return nil, err 78 // } 79 // res = append(res, vals...) 80 // } else { 81 // res = append(res, val) 82 // } 83 // } 84 // return res, nil 85 // } 86 // return flatten(xs) 87 // } 88 89 // FlattenN reports a flattend sequence of the list xs by expanding any elements 90 // depth levels deep. If depth is negative all elements are expanded. 91 // 92 // For instance: 93 // 94 // FlattenN([1, [[2, 3], []], [4]], 1) 95 // 96 // results in 97 // 98 // [1, [2, 3], [], 4] 99 // 100 func FlattenN(xs cue.Value, depth int) ([]cue.Value, error) { 101 var flattenN func(cue.Value, int) ([]cue.Value, error) 102 flattenN = func(xs cue.Value, depth int) ([]cue.Value, error) { 103 var res []cue.Value 104 iter, err := xs.List() 105 if err != nil { 106 return nil, err 107 } 108 for iter.Next() { 109 val, _ := iter.Value().Default() 110 if val.Kind() == cue.ListKind && depth != 0 { 111 d := depth - 1 112 values, err := flattenN(val, d) 113 if err != nil { 114 return nil, err 115 } 116 res = append(res, values...) 117 } else { 118 res = append(res, val) 119 } 120 } 121 return res, nil 122 } 123 return flattenN(xs, depth) 124 } 125 126 // Repeat returns a new list consisting of count copies of list x. 127 // 128 // For instance: 129 // 130 // Repeat([1, 2], 2) 131 // 132 // results in 133 // 134 // [1, 2, 1, 2] 135 // 136 func Repeat(x []cue.Value, count int) ([]cue.Value, error) { 137 if count < 0 { 138 return nil, fmt.Errorf("negative count") 139 } 140 var a []cue.Value 141 for i := 0; i < count; i++ { 142 a = append(a, x...) 143 } 144 return a, nil 145 } 146 147 // Concat takes a list of lists and concatenates them. 148 // 149 // Concat([a, b, c]) is equivalent to 150 // 151 // [ for x in a {x}, for x in b {x}, for x in c {x} ] 152 // 153 func Concat(a []cue.Value) ([]cue.Value, error) { 154 var res []cue.Value 155 for _, e := range a { 156 iter, err := e.List() 157 if err != nil { 158 return nil, err 159 } 160 for iter.Next() { 161 res = append(res, iter.Value()) 162 } 163 } 164 return res, nil 165 } 166 167 // Take reports the prefix of length n of list x, or x itself if n > len(x). 168 // 169 // For instance: 170 // 171 // Take([1, 2, 3, 4], 2) 172 // 173 // results in 174 // 175 // [1, 2] 176 // 177 func Take(x []cue.Value, n int) ([]cue.Value, error) { 178 if n < 0 { 179 return nil, fmt.Errorf("negative index") 180 } 181 182 if n > len(x) { 183 return x, nil 184 } 185 186 return x[:n], nil 187 } 188 189 // Slice extracts the consecutive elements from list x starting from position i 190 // up till, but not including, position j, where 0 <= i < j <= len(x). 191 // 192 // For instance: 193 // 194 // Slice([1, 2, 3, 4], 1, 3) 195 // 196 // results in 197 // 198 // [2, 3] 199 // 200 func Slice(x []cue.Value, i, j int) ([]cue.Value, error) { 201 if i < 0 { 202 return nil, fmt.Errorf("negative index") 203 } 204 205 if i > j { 206 return nil, fmt.Errorf("invalid index: %v > %v", i, j) 207 } 208 209 if i > len(x) { 210 return nil, fmt.Errorf("slice bounds out of range") 211 } 212 213 if j > len(x) { 214 return nil, fmt.Errorf("slice bounds out of range") 215 } 216 217 return x[i:j], nil 218 } 219 220 // MinItems reports whether a has at least n items. 221 func MinItems(a []cue.Value, n int) bool { 222 return len(a) >= n 223 } 224 225 // MaxItems reports whether a has at most n items. 226 func MaxItems(a []cue.Value, n int) bool { 227 return len(a) <= n 228 } 229 230 // UniqueItems reports whether all elements in the list are unique. 231 func UniqueItems(a []cue.Value) bool { 232 b := []string{} 233 for _, v := range a { 234 b = append(b, fmt.Sprintf("%+v", v)) 235 } 236 sort.Strings(b) 237 for i := 1; i < len(b); i++ { 238 if b[i-1] == b[i] { 239 return false 240 } 241 } 242 return true 243 } 244 245 // Contains reports whether v is contained in a. The value must be a 246 // comparable value. 247 func Contains(a []cue.Value, v cue.Value) bool { 248 for _, w := range a { 249 if v.Equals(w) { 250 return true 251 } 252 } 253 return false 254 }