123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- package lua
- const defaultArrayCap = 32
- const defaultHashCap = 32
- type lValueArraySorter struct {
- L *LState
- Fn *LFunction
- Values []LValue
- }
- func (lv lValueArraySorter) Len() int {
- return len(lv.Values)
- }
- func (lv lValueArraySorter) Swap(i, j int) {
- lv.Values[i], lv.Values[j] = lv.Values[j], lv.Values[i]
- }
- func (lv lValueArraySorter) Less(i, j int) bool {
- if lv.Fn != nil {
- lv.L.Push(lv.Fn)
- lv.L.Push(lv.Values[i])
- lv.L.Push(lv.Values[j])
- lv.L.Call(2, 1)
- return LVAsBool(lv.L.reg.Pop())
- }
- return lessThan(lv.L, lv.Values[i], lv.Values[j])
- }
- func newLTable(acap int, hcap int) *LTable {
- if acap < 0 {
- acap = 0
- }
- if hcap < 0 {
- hcap = 0
- }
- tb := <able{}
- tb.Metatable = LNil
- if acap != 0 {
- tb.array = make([]LValue, 0, acap)
- }
- if hcap != 0 {
- tb.strdict = make(map[string]LValue, hcap)
- }
- return tb
- }
- // Len returns length of this LTable without using __len.
- func (tb *LTable) Len() int {
- if tb.array == nil {
- return 0
- }
- var prev LValue = LNil
- for i := len(tb.array) - 1; i >= 0; i-- {
- v := tb.array[i]
- if prev == LNil && v != LNil {
- return i + 1
- }
- prev = v
- }
- return 0
- }
- // Append appends a given LValue to this LTable.
- func (tb *LTable) Append(value LValue) {
- if value == LNil {
- return
- }
- if tb.array == nil {
- tb.array = make([]LValue, 0, defaultArrayCap)
- }
- if len(tb.array) == 0 || tb.array[len(tb.array)-1] != LNil {
- tb.array = append(tb.array, value)
- } else {
- i := len(tb.array) - 2
- for ; i >= 0; i-- {
- if tb.array[i] != LNil {
- break
- }
- }
- tb.array[i+1] = value
- }
- }
- // Insert inserts a given LValue at position `i` in this table.
- func (tb *LTable) Insert(i int, value LValue) {
- if tb.array == nil {
- tb.array = make([]LValue, 0, defaultArrayCap)
- }
- if i > len(tb.array) {
- tb.RawSetInt(i, value)
- return
- }
- if i <= 0 {
- tb.RawSet(LNumber(i), value)
- return
- }
- i -= 1
- tb.array = append(tb.array, LNil)
- copy(tb.array[i+1:], tb.array[i:])
- tb.array[i] = value
- }
- // MaxN returns a maximum number key that nil value does not exist before it.
- func (tb *LTable) MaxN() int {
- if tb.array == nil {
- return 0
- }
- for i := len(tb.array) - 1; i >= 0; i-- {
- if tb.array[i] != LNil {
- return i + 1
- }
- }
- return 0
- }
- // Remove removes from this table the element at a given position.
- func (tb *LTable) Remove(pos int) LValue {
- if tb.array == nil {
- return LNil
- }
- larray := len(tb.array)
- if larray == 0 {
- return LNil
- }
- i := pos - 1
- oldval := LNil
- switch {
- case i >= larray:
- // nothing to do
- case i == larray-1 || i < 0:
- oldval = tb.array[larray-1]
- tb.array = tb.array[:larray-1]
- default:
- oldval = tb.array[i]
- copy(tb.array[i:], tb.array[i+1:])
- tb.array[larray-1] = nil
- tb.array = tb.array[:larray-1]
- }
- return oldval
- }
- // RawSet sets a given LValue to a given index without the __newindex metamethod.
- // It is recommended to use `RawSetString` or `RawSetInt` for performance
- // if you already know the given LValue is a string or number.
- func (tb *LTable) RawSet(key LValue, value LValue) {
- switch v := key.(type) {
- case LNumber:
- if isArrayKey(v) {
- if tb.array == nil {
- tb.array = make([]LValue, 0, defaultArrayCap)
- }
- index := int(v) - 1
- alen := len(tb.array)
- switch {
- case index == alen:
- tb.array = append(tb.array, value)
- case index > alen:
- for i := 0; i < (index - alen); i++ {
- tb.array = append(tb.array, LNil)
- }
- tb.array = append(tb.array, value)
- case index < alen:
- tb.array[index] = value
- }
- return
- }
- case LString:
- tb.RawSetString(string(v), value)
- return
- }
- tb.RawSetH(key, value)
- }
- // RawSetInt sets a given LValue at a position `key` without the __newindex metamethod.
- func (tb *LTable) RawSetInt(key int, value LValue) {
- if key < 1 || key >= MaxArrayIndex {
- tb.RawSetH(LNumber(key), value)
- return
- }
- if tb.array == nil {
- tb.array = make([]LValue, 0, 32)
- }
- index := key - 1
- alen := len(tb.array)
- switch {
- case index == alen:
- tb.array = append(tb.array, value)
- case index > alen:
- for i := 0; i < (index - alen); i++ {
- tb.array = append(tb.array, LNil)
- }
- tb.array = append(tb.array, value)
- case index < alen:
- tb.array[index] = value
- }
- }
- // RawSetString sets a given LValue to a given string index without the __newindex metamethod.
- func (tb *LTable) RawSetString(key string, value LValue) {
- if tb.strdict == nil {
- tb.strdict = make(map[string]LValue, defaultHashCap)
- }
- if tb.keys == nil {
- tb.keys = []LValue{}
- tb.k2i = map[LValue]int{}
- }
- if value == LNil {
- // TODO tb.keys and tb.k2i should also be removed
- delete(tb.strdict, key)
- } else {
- tb.strdict[key] = value
- lkey := LString(key)
- if _, ok := tb.k2i[lkey]; !ok {
- tb.k2i[lkey] = len(tb.keys)
- tb.keys = append(tb.keys, lkey)
- }
- }
- }
- // RawSetH sets a given LValue to a given index without the __newindex metamethod.
- func (tb *LTable) RawSetH(key LValue, value LValue) {
- if s, ok := key.(LString); ok {
- tb.RawSetString(string(s), value)
- return
- }
- if tb.dict == nil {
- tb.dict = make(map[LValue]LValue, len(tb.strdict))
- }
- if tb.keys == nil {
- tb.keys = []LValue{}
- tb.k2i = map[LValue]int{}
- }
- if value == LNil {
- // TODO tb.keys and tb.k2i should also be removed
- delete(tb.dict, key)
- } else {
- tb.dict[key] = value
- if _, ok := tb.k2i[key]; !ok {
- tb.k2i[key] = len(tb.keys)
- tb.keys = append(tb.keys, key)
- }
- }
- }
- // RawGet returns an LValue associated with a given key without __index metamethod.
- func (tb *LTable) RawGet(key LValue) LValue {
- switch v := key.(type) {
- case LNumber:
- if isArrayKey(v) {
- if tb.array == nil {
- return LNil
- }
- index := int(v) - 1
- if index >= len(tb.array) {
- return LNil
- }
- return tb.array[index]
- }
- case LString:
- if tb.strdict == nil {
- return LNil
- }
- if ret, ok := tb.strdict[string(v)]; ok {
- return ret
- }
- return LNil
- }
- if tb.dict == nil {
- return LNil
- }
- if v, ok := tb.dict[key]; ok {
- return v
- }
- return LNil
- }
- // RawGetInt returns an LValue at position `key` without __index metamethod.
- func (tb *LTable) RawGetInt(key int) LValue {
- if tb.array == nil {
- return LNil
- }
- index := int(key) - 1
- if index >= len(tb.array) || index < 0 {
- return LNil
- }
- return tb.array[index]
- }
- // RawGet returns an LValue associated with a given key without __index metamethod.
- func (tb *LTable) RawGetH(key LValue) LValue {
- if s, sok := key.(LString); sok {
- if tb.strdict == nil {
- return LNil
- }
- if v, vok := tb.strdict[string(s)]; vok {
- return v
- }
- return LNil
- }
- if tb.dict == nil {
- return LNil
- }
- if v, ok := tb.dict[key]; ok {
- return v
- }
- return LNil
- }
- // RawGetString returns an LValue associated with a given key without __index metamethod.
- func (tb *LTable) RawGetString(key string) LValue {
- if tb.strdict == nil {
- return LNil
- }
- if v, vok := tb.strdict[string(key)]; vok {
- return v
- }
- return LNil
- }
- // ForEach iterates over this table of elements, yielding each in turn to a given function.
- func (tb *LTable) ForEach(cb func(LValue, LValue)) {
- if tb.array != nil {
- for i, v := range tb.array {
- if v != LNil {
- cb(LNumber(i+1), v)
- }
- }
- }
- if tb.strdict != nil {
- for k, v := range tb.strdict {
- if v != LNil {
- cb(LString(k), v)
- }
- }
- }
- if tb.dict != nil {
- for k, v := range tb.dict {
- if v != LNil {
- cb(k, v)
- }
- }
- }
- }
- // This function is equivalent to lua_next ( http://www.lua.org/manual/5.1/manual.html#lua_next ).
- func (tb *LTable) Next(key LValue) (LValue, LValue) {
- init := false
- if key == LNil {
- key = LNumber(0)
- init = true
- }
- if init || key != LNumber(0) {
- if kv, ok := key.(LNumber); ok && isInteger(kv) && int(kv) >= 0 && kv < LNumber(MaxArrayIndex) {
- index := int(kv)
- if tb.array != nil {
- for ; index < len(tb.array); index++ {
- if v := tb.array[index]; v != LNil {
- return LNumber(index + 1), v
- }
- }
- }
- if tb.array == nil || index == len(tb.array) {
- if (tb.dict == nil || len(tb.dict) == 0) && (tb.strdict == nil || len(tb.strdict) == 0) {
- return LNil, LNil
- }
- key = tb.keys[0]
- if v := tb.RawGetH(key); v != LNil {
- return key, v
- }
- }
- }
- }
- for i := tb.k2i[key] + 1; i < len(tb.keys); i++ {
- key := tb.keys[i]
- if v := tb.RawGetH(key); v != LNil {
- return key, v
- }
- }
- return LNil, LNil
- }
|