123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- package goja
- import (
- "reflect"
- "strconv"
- "github.com/dop251/goja/unistring"
- )
- type objectGoArrayReflect struct {
- objectGoReflect
- lengthProp valueProperty
- valueCache valueArrayCache
- putIdx func(idx int, v Value, throw bool) bool
- }
- type valueArrayCache []reflectValueWrapper
- func (c *valueArrayCache) get(idx int) reflectValueWrapper {
- if idx < len(*c) {
- return (*c)[idx]
- }
- return nil
- }
- func (c *valueArrayCache) grow(newlen int) {
- oldcap := cap(*c)
- if oldcap < newlen {
- a := make([]reflectValueWrapper, newlen, growCap(newlen, len(*c), oldcap))
- copy(a, *c)
- *c = a
- } else {
- *c = (*c)[:newlen]
- }
- }
- func (c *valueArrayCache) put(idx int, w reflectValueWrapper) {
- if len(*c) <= idx {
- c.grow(idx + 1)
- }
- (*c)[idx] = w
- }
- func (c *valueArrayCache) shrink(newlen int) {
- if len(*c) > newlen {
- tail := (*c)[newlen:]
- for i, item := range tail {
- if item != nil {
- copyReflectValueWrapper(item)
- tail[i] = nil
- }
- }
- *c = (*c)[:newlen]
- }
- }
- func (o *objectGoArrayReflect) _init() {
- o.objectGoReflect.init()
- o.class = classArray
- o.prototype = o.val.runtime.getArrayPrototype()
- o.baseObject._put("length", &o.lengthProp)
- }
- func (o *objectGoArrayReflect) init() {
- o._init()
- o.updateLen()
- o.putIdx = o._putIdx
- }
- func (o *objectGoArrayReflect) updateLen() {
- o.lengthProp.value = intToValue(int64(o.fieldsValue.Len()))
- }
- func (o *objectGoArrayReflect) _hasIdx(idx valueInt) bool {
- if idx := int64(idx); idx >= 0 && idx < int64(o.fieldsValue.Len()) {
- return true
- }
- return false
- }
- func (o *objectGoArrayReflect) _hasStr(name unistring.String) bool {
- if idx := strToIdx64(name); idx >= 0 && idx < int64(o.fieldsValue.Len()) {
- return true
- }
- return false
- }
- func (o *objectGoArrayReflect) _getIdx(idx int) Value {
- if v := o.valueCache.get(idx); v != nil {
- return v.esValue()
- }
- v := o.fieldsValue.Index(idx)
- res, w := o.elemToValue(v)
- if w != nil {
- o.valueCache.put(idx, w)
- }
- return res
- }
- func (o *objectGoArrayReflect) getIdx(idx valueInt, receiver Value) Value {
- if idx := toIntStrict(int64(idx)); idx >= 0 && idx < o.fieldsValue.Len() {
- return o._getIdx(idx)
- }
- return o.objectGoReflect.getStr(idx.string(), receiver)
- }
- func (o *objectGoArrayReflect) getStr(name unistring.String, receiver Value) Value {
- var ownProp Value
- if idx := strToGoIdx(name); idx >= 0 && idx < o.fieldsValue.Len() {
- ownProp = o._getIdx(idx)
- } else if name == "length" {
- if o.fieldsValue.Kind() == reflect.Slice {
- o.updateLen()
- }
- ownProp = &o.lengthProp
- } else {
- ownProp = o.objectGoReflect.getOwnPropStr(name)
- }
- return o.getStrWithOwnProp(ownProp, name, receiver)
- }
- func (o *objectGoArrayReflect) getOwnPropStr(name unistring.String) Value {
- if idx := strToGoIdx(name); idx >= 0 {
- if idx < o.fieldsValue.Len() {
- return &valueProperty{
- value: o._getIdx(idx),
- writable: true,
- enumerable: true,
- }
- }
- return nil
- }
- if name == "length" {
- if o.fieldsValue.Kind() == reflect.Slice {
- o.updateLen()
- }
- return &o.lengthProp
- }
- return o.objectGoReflect.getOwnPropStr(name)
- }
- func (o *objectGoArrayReflect) getOwnPropIdx(idx valueInt) Value {
- if idx := toIntStrict(int64(idx)); idx >= 0 && idx < o.fieldsValue.Len() {
- return &valueProperty{
- value: o._getIdx(idx),
- writable: true,
- enumerable: true,
- }
- }
- return nil
- }
- func (o *objectGoArrayReflect) _putIdx(idx int, v Value, throw bool) bool {
- cached := o.valueCache.get(idx)
- if cached != nil {
- copyReflectValueWrapper(cached)
- }
- rv := o.fieldsValue.Index(idx)
- err := o.val.runtime.toReflectValue(v, rv, &objectExportCtx{})
- if err != nil {
- if cached != nil {
- cached.setReflectValue(rv)
- }
- o.val.runtime.typeErrorResult(throw, "Go type conversion error: %v", err)
- return false
- }
- if cached != nil {
- o.valueCache[idx] = nil
- }
- return true
- }
- func (o *objectGoArrayReflect) setOwnIdx(idx valueInt, val Value, throw bool) bool {
- if i := toIntStrict(int64(idx)); i >= 0 {
- if i >= o.fieldsValue.Len() {
- if res, ok := o._setForeignIdx(idx, nil, val, o.val, throw); ok {
- return res
- }
- }
- return o.putIdx(i, val, throw)
- } else {
- name := idx.string()
- if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok {
- o.val.runtime.typeErrorResult(throw, "Can't set property '%s' on Go slice", name)
- return false
- } else {
- return res
- }
- }
- }
- func (o *objectGoArrayReflect) setOwnStr(name unistring.String, val Value, throw bool) bool {
- if idx := strToGoIdx(name); idx >= 0 {
- if idx >= o.fieldsValue.Len() {
- if res, ok := o._setForeignStr(name, nil, val, o.val, throw); ok {
- return res
- }
- }
- return o.putIdx(idx, val, throw)
- } else {
- if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok {
- o.val.runtime.typeErrorResult(throw, "Can't set property '%s' on Go slice", name)
- return false
- } else {
- return res
- }
- }
- }
- func (o *objectGoArrayReflect) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
- return o._setForeignIdx(idx, trueValIfPresent(o._hasIdx(idx)), val, receiver, throw)
- }
- func (o *objectGoArrayReflect) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
- return o._setForeignStr(name, trueValIfPresent(o.hasOwnPropertyStr(name)), val, receiver, throw)
- }
- func (o *objectGoArrayReflect) hasOwnPropertyIdx(idx valueInt) bool {
- return o._hasIdx(idx)
- }
- func (o *objectGoArrayReflect) hasOwnPropertyStr(name unistring.String) bool {
- if o._hasStr(name) || name == "length" {
- return true
- }
- return o.objectGoReflect.hasOwnPropertyStr(name)
- }
- func (o *objectGoArrayReflect) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
- if i := toIntStrict(int64(idx)); i >= 0 {
- if !o.val.runtime.checkHostObjectPropertyDescr(idx.string(), descr, throw) {
- return false
- }
- val := descr.Value
- if val == nil {
- val = _undefined
- }
- return o.putIdx(i, val, throw)
- }
- o.val.runtime.typeErrorResult(throw, "Cannot define property '%d' on a Go slice", idx)
- return false
- }
- func (o *objectGoArrayReflect) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
- if idx := strToGoIdx(name); idx >= 0 {
- if !o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
- return false
- }
- val := descr.Value
- if val == nil {
- val = _undefined
- }
- return o.putIdx(idx, val, throw)
- }
- o.val.runtime.typeErrorResult(throw, "Cannot define property '%s' on a Go slice", name)
- return false
- }
- func (o *objectGoArrayReflect) _deleteIdx(idx int) {
- if idx < o.fieldsValue.Len() {
- if cv := o.valueCache.get(idx); cv != nil {
- copyReflectValueWrapper(cv)
- o.valueCache[idx] = nil
- }
- o.fieldsValue.Index(idx).Set(reflect.Zero(o.fieldsValue.Type().Elem()))
- }
- }
- func (o *objectGoArrayReflect) deleteStr(name unistring.String, throw bool) bool {
- if idx := strToGoIdx(name); idx >= 0 {
- o._deleteIdx(idx)
- return true
- }
- return o.objectGoReflect.deleteStr(name, throw)
- }
- func (o *objectGoArrayReflect) deleteIdx(i valueInt, throw bool) bool {
- idx := toIntStrict(int64(i))
- if idx >= 0 {
- o._deleteIdx(idx)
- }
- return true
- }
- type goArrayReflectPropIter struct {
- o *objectGoArrayReflect
- idx, limit int
- }
- func (i *goArrayReflectPropIter) next() (propIterItem, iterNextFunc) {
- if i.idx < i.limit && i.idx < i.o.fieldsValue.Len() {
- name := strconv.Itoa(i.idx)
- i.idx++
- return propIterItem{name: asciiString(name), enumerable: _ENUM_TRUE}, i.next
- }
- return i.o.objectGoReflect.iterateStringKeys()()
- }
- func (o *objectGoArrayReflect) stringKeys(all bool, accum []Value) []Value {
- for i := 0; i < o.fieldsValue.Len(); i++ {
- accum = append(accum, asciiString(strconv.Itoa(i)))
- }
- return o.objectGoReflect.stringKeys(all, accum)
- }
- func (o *objectGoArrayReflect) iterateStringKeys() iterNextFunc {
- return (&goArrayReflectPropIter{
- o: o,
- limit: o.fieldsValue.Len(),
- }).next
- }
- func (o *objectGoArrayReflect) sortLen() int {
- return o.fieldsValue.Len()
- }
- func (o *objectGoArrayReflect) sortGet(i int) Value {
- return o.getIdx(valueInt(i), nil)
- }
- func (o *objectGoArrayReflect) swap(i int, j int) {
- vi := o.fieldsValue.Index(i)
- vj := o.fieldsValue.Index(j)
- tmp := reflect.New(o.fieldsValue.Type().Elem()).Elem()
- tmp.Set(vi)
- vi.Set(vj)
- vj.Set(tmp)
- cachedI := o.valueCache.get(i)
- cachedJ := o.valueCache.get(j)
- if cachedI != nil {
- cachedI.setReflectValue(vj)
- o.valueCache.put(j, cachedI)
- } else {
- if j < len(o.valueCache) {
- o.valueCache[j] = nil
- }
- }
- if cachedJ != nil {
- cachedJ.setReflectValue(vi)
- o.valueCache.put(i, cachedJ)
- } else {
- if i < len(o.valueCache) {
- o.valueCache[i] = nil
- }
- }
- }
|