...

Source file src/github.com/dop251/goja/array_sparse.go

Documentation: github.com/dop251/goja

     1  package goja
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"math/bits"
     7  	"reflect"
     8  	"sort"
     9  	"strconv"
    10  
    11  	"github.com/dop251/goja/unistring"
    12  )
    13  
    14  type sparseArrayItem struct {
    15  	idx   uint32
    16  	value Value
    17  }
    18  
    19  type sparseArrayObject struct {
    20  	baseObject
    21  	items          []sparseArrayItem
    22  	length         uint32
    23  	propValueCount int
    24  	lengthProp     valueProperty
    25  }
    26  
    27  func (a *sparseArrayObject) findIdx(idx uint32) int {
    28  	return sort.Search(len(a.items), func(i int) bool {
    29  		return a.items[i].idx >= idx
    30  	})
    31  }
    32  
    33  func (a *sparseArrayObject) _setLengthInt(l uint32, throw bool) bool {
    34  	ret := true
    35  	if l <= a.length {
    36  		if a.propValueCount > 0 {
    37  			// Slow path
    38  			for i := len(a.items) - 1; i >= 0; i-- {
    39  				item := a.items[i]
    40  				if item.idx <= l {
    41  					break
    42  				}
    43  				if prop, ok := item.value.(*valueProperty); ok {
    44  					if !prop.configurable {
    45  						l = item.idx + 1
    46  						ret = false
    47  						break
    48  					}
    49  					a.propValueCount--
    50  				}
    51  			}
    52  		}
    53  	}
    54  
    55  	idx := a.findIdx(l)
    56  
    57  	aa := a.items[idx:]
    58  	for i := range aa {
    59  		aa[i].value = nil
    60  	}
    61  	a.items = a.items[:idx]
    62  	a.length = l
    63  	if !ret {
    64  		a.val.runtime.typeErrorResult(throw, "Cannot redefine property: length")
    65  	}
    66  	return ret
    67  }
    68  
    69  func (a *sparseArrayObject) setLengthInt(l uint32, throw bool) bool {
    70  	if l == a.length {
    71  		return true
    72  	}
    73  	if !a.lengthProp.writable {
    74  		a.val.runtime.typeErrorResult(throw, "length is not writable")
    75  		return false
    76  	}
    77  	return a._setLengthInt(l, throw)
    78  }
    79  
    80  func (a *sparseArrayObject) setLength(v uint32, throw bool) bool {
    81  	if !a.lengthProp.writable {
    82  		a.val.runtime.typeErrorResult(throw, "length is not writable")
    83  		return false
    84  	}
    85  	return a._setLengthInt(v, throw)
    86  }
    87  
    88  func (a *sparseArrayObject) _getIdx(idx uint32) Value {
    89  	i := a.findIdx(idx)
    90  	if i < len(a.items) && a.items[i].idx == idx {
    91  		return a.items[i].value
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  func (a *sparseArrayObject) getStr(name unistring.String, receiver Value) Value {
    98  	return a.getStrWithOwnProp(a.getOwnPropStr(name), name, receiver)
    99  }
   100  
   101  func (a *sparseArrayObject) getIdx(idx valueInt, receiver Value) Value {
   102  	prop := a.getOwnPropIdx(idx)
   103  	if prop == nil {
   104  		if a.prototype != nil {
   105  			if receiver == nil {
   106  				return a.prototype.self.getIdx(idx, a.val)
   107  			}
   108  			return a.prototype.self.getIdx(idx, receiver)
   109  		}
   110  	}
   111  	if prop, ok := prop.(*valueProperty); ok {
   112  		if receiver == nil {
   113  			return prop.get(a.val)
   114  		}
   115  		return prop.get(receiver)
   116  	}
   117  	return prop
   118  }
   119  
   120  func (a *sparseArrayObject) getLengthProp() *valueProperty {
   121  	a.lengthProp.value = intToValue(int64(a.length))
   122  	return &a.lengthProp
   123  }
   124  
   125  func (a *sparseArrayObject) getOwnPropStr(name unistring.String) Value {
   126  	if idx := strToArrayIdx(name); idx != math.MaxUint32 {
   127  		return a._getIdx(idx)
   128  	}
   129  	if name == "length" {
   130  		return a.getLengthProp()
   131  	}
   132  	return a.baseObject.getOwnPropStr(name)
   133  }
   134  
   135  func (a *sparseArrayObject) getOwnPropIdx(idx valueInt) Value {
   136  	if idx := toIdx(idx); idx != math.MaxUint32 {
   137  		return a._getIdx(idx)
   138  	}
   139  	return a.baseObject.getOwnPropStr(idx.string())
   140  }
   141  
   142  func (a *sparseArrayObject) add(idx uint32, val Value) {
   143  	i := a.findIdx(idx)
   144  	a.items = append(a.items, sparseArrayItem{})
   145  	copy(a.items[i+1:], a.items[i:])
   146  	a.items[i] = sparseArrayItem{
   147  		idx:   idx,
   148  		value: val,
   149  	}
   150  }
   151  
   152  func (a *sparseArrayObject) _setOwnIdx(idx uint32, val Value, throw bool) bool {
   153  	var prop Value
   154  	i := a.findIdx(idx)
   155  	if i < len(a.items) && a.items[i].idx == idx {
   156  		prop = a.items[i].value
   157  	}
   158  
   159  	if prop == nil {
   160  		if proto := a.prototype; proto != nil {
   161  			// we know it's foreign because prototype loops are not allowed
   162  			if res, ok := proto.self.setForeignIdx(valueInt(idx), val, a.val, throw); ok {
   163  				return res
   164  			}
   165  		}
   166  
   167  		// new property
   168  		if !a.extensible {
   169  			a.val.runtime.typeErrorResult(throw, "Cannot add property %d, object is not extensible", idx)
   170  			return false
   171  		}
   172  
   173  		if idx >= a.length {
   174  			if !a.setLengthInt(idx+1, throw) {
   175  				return false
   176  			}
   177  		}
   178  
   179  		if a.expand(idx) {
   180  			a.items = append(a.items, sparseArrayItem{})
   181  			copy(a.items[i+1:], a.items[i:])
   182  			a.items[i] = sparseArrayItem{
   183  				idx:   idx,
   184  				value: val,
   185  			}
   186  		} else {
   187  			ar := a.val.self.(*arrayObject)
   188  			ar.values[idx] = val
   189  			ar.objCount++
   190  			return true
   191  		}
   192  	} else {
   193  		if prop, ok := prop.(*valueProperty); ok {
   194  			if !prop.isWritable() {
   195  				a.val.runtime.typeErrorResult(throw)
   196  				return false
   197  			}
   198  			prop.set(a.val, val)
   199  		} else {
   200  			a.items[i].value = val
   201  		}
   202  	}
   203  	return true
   204  }
   205  
   206  func (a *sparseArrayObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
   207  	if idx := strToArrayIdx(name); idx != math.MaxUint32 {
   208  		return a._setOwnIdx(idx, val, throw)
   209  	} else {
   210  		if name == "length" {
   211  			return a.setLength(a.val.runtime.toLengthUint32(val), throw)
   212  		} else {
   213  			return a.baseObject.setOwnStr(name, val, throw)
   214  		}
   215  	}
   216  }
   217  
   218  func (a *sparseArrayObject) setOwnIdx(idx valueInt, val Value, throw bool) bool {
   219  	if idx := toIdx(idx); idx != math.MaxUint32 {
   220  		return a._setOwnIdx(idx, val, throw)
   221  	}
   222  
   223  	return a.baseObject.setOwnStr(idx.string(), val, throw)
   224  }
   225  
   226  func (a *sparseArrayObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
   227  	return a._setForeignStr(name, a.getOwnPropStr(name), val, receiver, throw)
   228  }
   229  
   230  func (a *sparseArrayObject) setForeignIdx(name valueInt, val, receiver Value, throw bool) (bool, bool) {
   231  	return a._setForeignIdx(name, a.getOwnPropIdx(name), val, receiver, throw)
   232  }
   233  
   234  type sparseArrayPropIter struct {
   235  	a   *sparseArrayObject
   236  	idx int
   237  }
   238  
   239  func (i *sparseArrayPropIter) next() (propIterItem, iterNextFunc) {
   240  	for i.idx < len(i.a.items) {
   241  		name := asciiString(strconv.Itoa(int(i.a.items[i.idx].idx)))
   242  		prop := i.a.items[i.idx].value
   243  		i.idx++
   244  		if prop != nil {
   245  			return propIterItem{name: name, value: prop}, i.next
   246  		}
   247  	}
   248  
   249  	return i.a.baseObject.iterateStringKeys()()
   250  }
   251  
   252  func (a *sparseArrayObject) iterateStringKeys() iterNextFunc {
   253  	return (&sparseArrayPropIter{
   254  		a: a,
   255  	}).next
   256  }
   257  
   258  func (a *sparseArrayObject) stringKeys(all bool, accum []Value) []Value {
   259  	if all {
   260  		for _, item := range a.items {
   261  			accum = append(accum, asciiString(strconv.FormatUint(uint64(item.idx), 10)))
   262  		}
   263  	} else {
   264  		for _, item := range a.items {
   265  			if prop, ok := item.value.(*valueProperty); ok && !prop.enumerable {
   266  				continue
   267  			}
   268  			accum = append(accum, asciiString(strconv.FormatUint(uint64(item.idx), 10)))
   269  		}
   270  	}
   271  
   272  	return a.baseObject.stringKeys(all, accum)
   273  }
   274  
   275  func (a *sparseArrayObject) setValues(values []Value, objCount int) {
   276  	a.items = make([]sparseArrayItem, 0, objCount)
   277  	for i, val := range values {
   278  		if val != nil {
   279  			a.items = append(a.items, sparseArrayItem{
   280  				idx:   uint32(i),
   281  				value: val,
   282  			})
   283  		}
   284  	}
   285  }
   286  
   287  func (a *sparseArrayObject) hasOwnPropertyStr(name unistring.String) bool {
   288  	if idx := strToArrayIdx(name); idx != math.MaxUint32 {
   289  		i := a.findIdx(idx)
   290  		return i < len(a.items) && a.items[i].idx == idx
   291  	} else {
   292  		return a.baseObject.hasOwnPropertyStr(name)
   293  	}
   294  }
   295  
   296  func (a *sparseArrayObject) hasOwnPropertyIdx(idx valueInt) bool {
   297  	if idx := toIdx(idx); idx != math.MaxUint32 {
   298  		i := a.findIdx(idx)
   299  		return i < len(a.items) && a.items[i].idx == idx
   300  	}
   301  
   302  	return a.baseObject.hasOwnPropertyStr(idx.string())
   303  }
   304  
   305  func (a *sparseArrayObject) hasPropertyIdx(idx valueInt) bool {
   306  	if a.hasOwnPropertyIdx(idx) {
   307  		return true
   308  	}
   309  
   310  	if a.prototype != nil {
   311  		return a.prototype.self.hasPropertyIdx(idx)
   312  	}
   313  
   314  	return false
   315  }
   316  
   317  func (a *sparseArrayObject) expand(idx uint32) bool {
   318  	if l := len(a.items); l >= 1024 {
   319  		if ii := a.items[l-1].idx; ii > idx {
   320  			idx = ii
   321  		}
   322  		if (bits.UintSize == 64 || idx < math.MaxInt32) && int(idx)>>3 < l {
   323  			//log.Println("Switching sparse->standard")
   324  			ar := &arrayObject{
   325  				baseObject:     a.baseObject,
   326  				length:         a.length,
   327  				propValueCount: a.propValueCount,
   328  			}
   329  			ar.setValuesFromSparse(a.items, int(idx))
   330  			ar.val.self = ar
   331  			ar.lengthProp.writable = a.lengthProp.writable
   332  			a._put("length", &ar.lengthProp)
   333  			return false
   334  		}
   335  	}
   336  	return true
   337  }
   338  
   339  func (a *sparseArrayObject) _defineIdxProperty(idx uint32, desc PropertyDescriptor, throw bool) bool {
   340  	var existing Value
   341  	i := a.findIdx(idx)
   342  	if i < len(a.items) && a.items[i].idx == idx {
   343  		existing = a.items[i].value
   344  	}
   345  	prop, ok := a.baseObject._defineOwnProperty(unistring.String(strconv.FormatUint(uint64(idx), 10)), existing, desc, throw)
   346  	if ok {
   347  		if idx >= a.length {
   348  			if !a.setLengthInt(idx+1, throw) {
   349  				return false
   350  			}
   351  		}
   352  		if i >= len(a.items) || a.items[i].idx != idx {
   353  			if a.expand(idx) {
   354  				a.items = append(a.items, sparseArrayItem{})
   355  				copy(a.items[i+1:], a.items[i:])
   356  				a.items[i] = sparseArrayItem{
   357  					idx:   idx,
   358  					value: prop,
   359  				}
   360  				if idx >= a.length {
   361  					a.length = idx + 1
   362  				}
   363  			} else {
   364  				a.val.self.(*arrayObject).values[idx] = prop
   365  			}
   366  		} else {
   367  			a.items[i].value = prop
   368  		}
   369  		if _, ok := prop.(*valueProperty); ok {
   370  			a.propValueCount++
   371  		}
   372  	}
   373  	return ok
   374  }
   375  
   376  func (a *sparseArrayObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
   377  	if idx := strToArrayIdx(name); idx != math.MaxUint32 {
   378  		return a._defineIdxProperty(idx, descr, throw)
   379  	}
   380  	if name == "length" {
   381  		return a.val.runtime.defineArrayLength(a.getLengthProp(), descr, a.setLength, throw)
   382  	}
   383  	return a.baseObject.defineOwnPropertyStr(name, descr, throw)
   384  }
   385  
   386  func (a *sparseArrayObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
   387  	if idx := toIdx(idx); idx != math.MaxUint32 {
   388  		return a._defineIdxProperty(idx, descr, throw)
   389  	}
   390  	return a.baseObject.defineOwnPropertyStr(idx.string(), descr, throw)
   391  }
   392  
   393  func (a *sparseArrayObject) _deleteIdxProp(idx uint32, throw bool) bool {
   394  	i := a.findIdx(idx)
   395  	if i < len(a.items) && a.items[i].idx == idx {
   396  		if p, ok := a.items[i].value.(*valueProperty); ok {
   397  			if !p.configurable {
   398  				a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.toString())
   399  				return false
   400  			}
   401  			a.propValueCount--
   402  		}
   403  		copy(a.items[i:], a.items[i+1:])
   404  		a.items[len(a.items)-1].value = nil
   405  		a.items = a.items[:len(a.items)-1]
   406  	}
   407  	return true
   408  }
   409  
   410  func (a *sparseArrayObject) deleteStr(name unistring.String, throw bool) bool {
   411  	if idx := strToArrayIdx(name); idx != math.MaxUint32 {
   412  		return a._deleteIdxProp(idx, throw)
   413  	}
   414  	return a.baseObject.deleteStr(name, throw)
   415  }
   416  
   417  func (a *sparseArrayObject) deleteIdx(idx valueInt, throw bool) bool {
   418  	if idx := toIdx(idx); idx != math.MaxUint32 {
   419  		return a._deleteIdxProp(idx, throw)
   420  	}
   421  	return a.baseObject.deleteStr(idx.string(), throw)
   422  }
   423  
   424  func (a *sparseArrayObject) sortLen() int {
   425  	if len(a.items) > 0 {
   426  		return toIntStrict(int64(a.items[len(a.items)-1].idx) + 1)
   427  	}
   428  
   429  	return 0
   430  }
   431  
   432  func (a *sparseArrayObject) export(ctx *objectExportCtx) interface{} {
   433  	if v, exists := ctx.get(a.val); exists {
   434  		return v
   435  	}
   436  	arr := make([]interface{}, a.length)
   437  	ctx.put(a.val, arr)
   438  	var prevIdx uint32
   439  	for _, item := range a.items {
   440  		idx := item.idx
   441  		for i := prevIdx; i < idx; i++ {
   442  			if a.prototype != nil {
   443  				if v := a.prototype.self.getIdx(valueInt(i), nil); v != nil {
   444  					arr[i] = exportValue(v, ctx)
   445  				}
   446  			}
   447  		}
   448  		v := item.value
   449  		if v != nil {
   450  			if prop, ok := v.(*valueProperty); ok {
   451  				v = prop.get(a.val)
   452  			}
   453  			arr[idx] = exportValue(v, ctx)
   454  		}
   455  		prevIdx = idx + 1
   456  	}
   457  	for i := prevIdx; i < a.length; i++ {
   458  		if a.prototype != nil {
   459  			if v := a.prototype.self.getIdx(valueInt(i), nil); v != nil {
   460  				arr[i] = exportValue(v, ctx)
   461  			}
   462  		}
   463  	}
   464  	return arr
   465  }
   466  
   467  func (a *sparseArrayObject) exportType() reflect.Type {
   468  	return reflectTypeArray
   469  }
   470  
   471  func (a *sparseArrayObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
   472  	r := a.val.runtime
   473  	if iter := a.getSym(SymIterator, nil); iter == r.getArrayValues() || iter == nil {
   474  		l := toIntStrict(int64(a.length))
   475  		if typ.Kind() == reflect.Array {
   476  			if dst.Len() != l {
   477  				return fmt.Errorf("cannot convert an Array into an array, lengths mismatch (have %d, need %d)", l, dst.Len())
   478  			}
   479  		} else {
   480  			dst.Set(reflect.MakeSlice(typ, l, l))
   481  		}
   482  		ctx.putTyped(a.val, typ, dst.Interface())
   483  		for _, item := range a.items {
   484  			val := item.value
   485  			if p, ok := val.(*valueProperty); ok {
   486  				val = p.get(a.val)
   487  			}
   488  			idx := toIntStrict(int64(item.idx))
   489  			if idx >= l {
   490  				break
   491  			}
   492  			err := r.toReflectValue(val, dst.Index(idx), ctx)
   493  			if err != nil {
   494  				return fmt.Errorf("could not convert array element %v to %v at %d: %w", item.value, typ, idx, err)
   495  			}
   496  		}
   497  		return nil
   498  	}
   499  	return a.baseObject.exportToArrayOrSlice(dst, typ, ctx)
   500  }
   501  

View as plain text