github.com/minio/simdjson-go@v0.4.6-0.20231116094823-04d21cddf993/parsed_array.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2020 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package simdjson 18 19 import ( 20 "errors" 21 "fmt" 22 "math" 23 ) 24 25 // Array represents a JSON array. 26 // There are methods that allows to get full arrays if the value type is the same. 27 // Otherwise an iterator can be retrieved. 28 type Array struct { 29 tape ParsedJson 30 off int 31 } 32 33 // Iter returns the array as an iterator. 34 // This can be used for parsing mixed content arrays. 35 // The first value is ready with a call to Advance. 36 // Calling after last element should have TypeNone. 37 func (a *Array) Iter() Iter { 38 i := Iter{ 39 tape: a.tape, 40 off: a.off, 41 } 42 return i 43 } 44 45 // ForEach calls the provided function for every element. 46 func (a *Array) ForEach(fn func(i Iter)) { 47 i := a.Iter() 48 for { 49 t := i.Advance() 50 if t == TypeNone { 51 break 52 } 53 fn(i) 54 } 55 return 56 } 57 58 // DeleteElems calls the provided function for every element. 59 // If the function returns true the element is deleted in the array. 60 func (a *Array) DeleteElems(fn func(i Iter) bool) { 61 i := a.Iter() 62 for { 63 t := i.Advance() 64 if t == TypeNone { 65 break 66 } 67 if fn(i) { 68 startO := i.off - 1 69 end := i.off + i.addNext 70 skip := uint64(end - startO) 71 for off := startO; off < end; off++ { 72 i.tape.Tape[off] = (uint64(TagNop) << JSONTAGOFFSET) | skip 73 skip-- 74 } 75 } 76 } 77 return 78 } 79 80 // FirstType will return the type of the first element. 81 // If there are no elements, TypeNone is returned. 82 func (a *Array) FirstType() Type { 83 iter := a.Iter() 84 return iter.PeekNext() 85 } 86 87 // MarshalJSON will marshal the entire remaining scope of the iterator. 88 func (a *Array) MarshalJSON() ([]byte, error) { 89 return a.MarshalJSONBuffer(nil) 90 } 91 92 // MarshalJSONBuffer will marshal all elements. 93 // An optional buffer can be provided for fewer allocations. 94 // Output will be appended to the destination. 95 func (a *Array) MarshalJSONBuffer(dst []byte) ([]byte, error) { 96 dst = append(dst, '[') 97 i := a.Iter() 98 var elem Iter 99 for { 100 t, err := i.AdvanceIter(&elem) 101 if err != nil { 102 return nil, err 103 } 104 if t == TypeNone { 105 break 106 } 107 dst, err = elem.MarshalJSONBuffer(dst) 108 if err != nil { 109 return nil, err 110 } 111 if i.PeekNextTag() == TagArrayEnd { 112 break 113 } 114 dst = append(dst, ',') 115 } 116 if i.PeekNextTag() != TagArrayEnd { 117 return nil, errors.New("expected TagArrayEnd as final tag in array") 118 } 119 dst = append(dst, ']') 120 return dst, nil 121 } 122 123 // Interface returns the array as a slice of interfaces. 124 // See Iter.Interface() for a reference on value types. 125 func (a *Array) Interface() ([]interface{}, error) { 126 // Estimate length. Assume one value per element. 127 lenEst := (len(a.tape.Tape) - a.off - 1) / 2 128 if lenEst < 0 { 129 lenEst = 0 130 } 131 dst := make([]interface{}, 0, lenEst) 132 i := a.Iter() 133 for i.Advance() != TypeNone { 134 elem, err := i.Interface() 135 if err != nil { 136 return nil, err 137 } 138 dst = append(dst, elem) 139 } 140 return dst, nil 141 } 142 143 // AsFloat returns the array values as float. 144 // Integers are automatically converted to float. 145 func (a *Array) AsFloat() ([]float64, error) { 146 // Estimate length 147 lenEst := (len(a.tape.Tape) - a.off - 1) / 2 148 if lenEst < 0 { 149 lenEst = 0 150 } 151 dst := make([]float64, 0, lenEst) 152 153 readArray: 154 for { 155 tag := Tag(a.tape.Tape[a.off] >> 56) 156 a.off++ 157 switch tag { 158 case TagFloat: 159 if len(a.tape.Tape) <= a.off { 160 return nil, errors.New("corrupt input: expected float, but no more values") 161 } 162 dst = append(dst, math.Float64frombits(a.tape.Tape[a.off])) 163 case TagInteger: 164 if len(a.tape.Tape) <= a.off { 165 return nil, errors.New("corrupt input: expected integer, but no more values") 166 } 167 dst = append(dst, float64(int64(a.tape.Tape[a.off]))) 168 case TagUint: 169 if len(a.tape.Tape) <= a.off { 170 return nil, errors.New("corrupt input: expected integer, but no more values") 171 } 172 dst = append(dst, float64(a.tape.Tape[a.off])) 173 case TagArrayEnd: 174 break readArray 175 default: 176 return nil, fmt.Errorf("unable to convert type %v to float", tag) 177 } 178 a.off++ 179 } 180 return dst, nil 181 } 182 183 // AsInteger returns the array values as int64 values. 184 // Uints/Floats are automatically converted to int64 if they fit within the range. 185 func (a *Array) AsInteger() ([]int64, error) { 186 // Estimate length 187 lenEst := (len(a.tape.Tape) - a.off - 1) / 2 188 if lenEst < 0 { 189 lenEst = 0 190 } 191 dst := make([]int64, 0, lenEst) 192 readArray: 193 for { 194 tag := Tag(a.tape.Tape[a.off] >> 56) 195 a.off++ 196 switch tag { 197 case TagFloat: 198 if len(a.tape.Tape) <= a.off { 199 return nil, errors.New("corrupt input: expected float, but no more values") 200 } 201 val := math.Float64frombits(a.tape.Tape[a.off]) 202 if val > math.MaxInt64 { 203 return nil, errors.New("float value overflows int64") 204 } 205 if val < math.MinInt64 { 206 return nil, errors.New("float value underflows int64") 207 } 208 dst = append(dst, int64(val)) 209 case TagInteger: 210 if len(a.tape.Tape) <= a.off { 211 return nil, errors.New("corrupt input: expected integer, but no more values") 212 } 213 dst = append(dst, int64(a.tape.Tape[a.off])) 214 case TagUint: 215 if len(a.tape.Tape) <= a.off { 216 return nil, errors.New("corrupt input: expected integer, but no more values") 217 } 218 219 val := a.tape.Tape[a.off] 220 if val > math.MaxInt64 { 221 return nil, errors.New("unsigned integer value overflows int64") 222 } 223 224 dst = append(dst) 225 case TagArrayEnd: 226 break readArray 227 default: 228 return nil, fmt.Errorf("unable to convert type %v to integer", tag) 229 } 230 a.off++ 231 } 232 return dst, nil 233 } 234 235 // AsUint64 returns the array values as float. 236 // Uints/Floats are automatically converted to uint64 if they fit within the range. 237 func (a *Array) AsUint64() ([]uint64, error) { 238 // Estimate length 239 lenEst := (len(a.tape.Tape) - a.off - 1) / 2 240 if lenEst < 0 { 241 lenEst = 0 242 } 243 dst := make([]uint64, 0, lenEst) 244 readArray: 245 for { 246 tag := Tag(a.tape.Tape[a.off] >> 56) 247 a.off++ 248 switch tag { 249 case TagFloat: 250 if len(a.tape.Tape) <= a.off { 251 return nil, errors.New("corrupt input: expected float, but no more values") 252 } 253 val := math.Float64frombits(a.tape.Tape[a.off]) 254 if val > math.MaxInt64 { 255 return nil, errors.New("float value overflows uint64") 256 } 257 if val < 0 { 258 return nil, errors.New("float value is negative") 259 } 260 dst = append(dst, uint64(val)) 261 case TagInteger: 262 if len(a.tape.Tape) <= a.off { 263 return nil, errors.New("corrupt input: expected integer, but no more values") 264 } 265 val := int64(a.tape.Tape[a.off]) 266 if val < 0 { 267 return nil, errors.New("int64 value is negative") 268 } 269 dst = append(dst, uint64(val)) 270 case TagUint: 271 if len(a.tape.Tape) <= a.off { 272 return nil, errors.New("corrupt input: expected integer, but no more values") 273 } 274 275 dst = append(dst, a.tape.Tape[a.off]) 276 case TagArrayEnd: 277 break readArray 278 default: 279 return nil, fmt.Errorf("unable to convert type %v to integer", tag) 280 } 281 a.off++ 282 } 283 return dst, nil 284 } 285 286 // AsString returns the array values as a slice of strings. 287 // No conversion is done. 288 func (a *Array) AsString() ([]string, error) { 289 // Estimate length 290 lenEst := len(a.tape.Tape) - a.off - 1 291 if lenEst < 0 { 292 lenEst = 0 293 } 294 dst := make([]string, 0, lenEst) 295 i := a.Iter() 296 var elem Iter 297 for { 298 t, err := i.AdvanceIter(&elem) 299 if err != nil { 300 return nil, err 301 } 302 switch t { 303 case TypeNone: 304 return dst, nil 305 case TypeString: 306 s, err := elem.String() 307 if err != nil { 308 return nil, err 309 } 310 dst = append(dst, s) 311 default: 312 return nil, fmt.Errorf("element in array is not string, but %v", t) 313 } 314 } 315 } 316 317 // AsStringCvt returns the array values as a slice of strings. 318 // Scalar types are converted. 319 // Root, Object and Arrays are not supported an will return an error if found. 320 func (a *Array) AsStringCvt() ([]string, error) { 321 // Estimate length 322 lenEst := len(a.tape.Tape) - a.off - 1 323 if lenEst < 0 { 324 lenEst = 0 325 } 326 dst := make([]string, 0, lenEst) 327 i := a.Iter() 328 var elem Iter 329 for { 330 t, err := i.AdvanceIter(&elem) 331 if err != nil { 332 return nil, err 333 } 334 switch t { 335 case TypeNone: 336 return dst, nil 337 default: 338 s, err := elem.StringCvt() 339 if err != nil { 340 return nil, err 341 } 342 dst = append(dst, s) 343 } 344 } 345 }