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
}
}
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .