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  }