github.com/shawnclovie/gopher-lua@v0.0.0-20200520092726-90b44ec0e2f2/table.go (about) 1 package lua 2 3 const defaultArrayCap = 32 4 const defaultHashCap = 32 5 6 type lValueArraySorter struct { 7 L *LState 8 Fn *LFunction 9 Values []LValue 10 } 11 12 func (lv lValueArraySorter) Len() int { 13 return len(lv.Values) 14 } 15 16 func (lv lValueArraySorter) Swap(i, j int) { 17 lv.Values[i], lv.Values[j] = lv.Values[j], lv.Values[i] 18 } 19 20 func (lv lValueArraySorter) Less(i, j int) bool { 21 if lv.Fn != nil { 22 lv.L.Push(lv.Fn) 23 lv.L.Push(lv.Values[i]) 24 lv.L.Push(lv.Values[j]) 25 lv.L.Call(2, 1) 26 return LVAsBool(lv.L.reg.Pop()) 27 } 28 return lessThan(lv.L, lv.Values[i], lv.Values[j]) 29 } 30 31 func newLTable(acap int, hcap int) *LTable { 32 if acap < 0 { 33 acap = 0 34 } 35 if hcap < 0 { 36 hcap = 0 37 } 38 tb := <able{Metatable: LNil} 39 if acap != 0 { 40 tb.array = make([]LValue, 0, acap) 41 } 42 if hcap != 0 { 43 tb.dict = make(map[LValue]lTableDictValue, hcap) 44 tb.keys = make([]*LValue, 0, hcap) 45 } 46 return tb 47 } 48 49 func (tb *LTable) DictionaryLen() int { 50 return len(tb.dict) 51 } 52 53 // Len returns length of this LTable. 54 func (tb *LTable) Len() int { 55 if tb.array == nil { 56 return 0 57 } 58 var prev LValue = LNil 59 for i := len(tb.array) - 1; i >= 0; i-- { 60 v := tb.array[i] 61 if prev == LNil && v != LNil { 62 return i + 1 63 } 64 prev = v 65 } 66 return 0 67 } 68 69 // Append appends a given LValue to this LTable. 70 func (tb *LTable) Append(value LValue) { 71 if value == LNil { 72 return 73 } 74 if tb.array == nil { 75 tb.array = make([]LValue, 0, defaultArrayCap) 76 } 77 if len(tb.array) == 0 || tb.array[len(tb.array)-1] != LNil { 78 tb.array = append(tb.array, value) 79 } else { 80 i := len(tb.array) - 2 81 for ; i >= 0; i-- { 82 if tb.array[i] != LNil { 83 break 84 } 85 } 86 tb.array[i+1] = value 87 } 88 } 89 90 // Insert inserts a given LValue at position `i` in this table. 91 func (tb *LTable) Insert(i int, value LValue) { 92 if tb.array == nil { 93 tb.array = make([]LValue, 0, defaultArrayCap) 94 } 95 if i > len(tb.array) { 96 tb.RawSetInt(i, value) 97 return 98 } 99 if i <= 0 { 100 tb.RawSet(LNumber(i), value) 101 return 102 } 103 i -= 1 104 tb.array = append(tb.array, LNil) 105 copy(tb.array[i+1:], tb.array[i:]) 106 tb.array[i] = value 107 } 108 109 // MaxN returns a maximum number key that nil value does not exist before it. 110 func (tb *LTable) MaxN() int { 111 if tb.array == nil { 112 return 0 113 } 114 for i := len(tb.array) - 1; i >= 0; i-- { 115 if tb.array[i] != LNil { 116 return i + 1 117 } 118 } 119 return 0 120 } 121 122 // Remove removes from this table the element at a given position. 123 func (tb *LTable) Remove(pos int) LValue { 124 if tb.array == nil { 125 return LNil 126 } 127 larray := len(tb.array) 128 if larray == 0 { 129 return LNil 130 } 131 i := pos - 1 132 oldval := LNil 133 switch { 134 case i >= larray: 135 // nothing to do 136 case i == larray-1 || i < 0: 137 oldval = tb.array[larray-1] 138 tb.array = tb.array[:larray-1] 139 default: 140 oldval = tb.array[i] 141 copy(tb.array[i:], tb.array[i+1:]) 142 tb.array[larray-1] = nil 143 tb.array = tb.array[:larray-1] 144 } 145 return oldval 146 } 147 148 // RawSet sets a given LValue to a given index without the __newindex metamethod. 149 // It is recommended to use `RawSetString` or `RawSetInt` for performance 150 // if you already know the given LValue is a string or number. 151 func (tb *LTable) RawSet(key LValue, value LValue) { 152 if v, ok := key.(LNumber); ok && isArrayKey(v) { 153 tb.RawSetInt(int(v), value) 154 } else { 155 tb.RawSetH(key, value) 156 } 157 } 158 159 // RawSetInt sets a given LValue at a position `key` without the __newindex metamethod. 160 func (tb *LTable) RawSetInt(key int, value LValue) { 161 if key < 1 || key >= MaxArrayIndex { 162 tb.RawSetH(LNumber(key), value) 163 return 164 } 165 if tb.array == nil { 166 tb.array = make([]LValue, 0, defaultArrayCap) 167 } 168 index := key - 1 169 alen := len(tb.array) 170 switch { 171 case index == alen: 172 tb.array = append(tb.array, value) 173 case index > alen: 174 for i := 0; i < (index - alen); i++ { 175 tb.array = append(tb.array, LNil) 176 } 177 tb.array = append(tb.array, value) 178 case index < alen: 179 tb.array[index] = value 180 } 181 } 182 183 // RawSetString sets a given LValue to a given string index without the __newindex metamethod. 184 func (tb *LTable) RawSetString(key string, value LValue) { 185 tb.RawSetH(LString(key), value) 186 } 187 188 // RawSetH sets a given LValue to a given index without the __newindex metamethod. 189 func (tb *LTable) RawSetH(key LValue, value LValue) { 190 if tb.dict == nil { 191 tb.dict = make(map[LValue]lTableDictValue, defaultHashCap) 192 } 193 if tb.keys == nil { 194 tb.keys = make([]*LValue, 0, defaultHashCap) 195 } 196 if value == LNil { 197 // TODO tb.keys and tb.k2i should also be removed 198 delete(tb.dict, key) 199 } else { 200 tv := lTableDictValue{value: value} 201 if oldTV, ok := tb.dict [key]; ok { 202 tv.keyIndex = oldTV.keyIndex 203 } else { 204 tv.keyIndex = len(tb.keys) 205 tb.keys = append(tb.keys, &key) 206 } 207 tb.dict[key] = tv 208 } 209 } 210 211 // RawGet returns an LValue associated with a given key without __index metamethod. 212 func (tb *LTable) RawGet(key LValue) LValue { 213 if v, ok := key.(LNumber); ok && isArrayKey(v) { 214 return tb.RawGetInt(int(v)) 215 } 216 return tb.RawGetH(key) 217 } 218 219 // RawGetInt returns an LValue at position `key` without __index metamethod. 220 func (tb *LTable) RawGetInt(key int) LValue { 221 if tb.array == nil { 222 return LNil 223 } 224 index := int(key) - 1 225 if index >= len(tb.array) || index < 0 { 226 return LNil 227 } 228 return tb.array[index] 229 } 230 231 // RawGet returns an LValue associated with a given key without __index metamethod. 232 func (tb *LTable) RawGetH(key LValue) LValue { 233 if tb.dict == nil { 234 return LNil 235 } 236 if v, ok := tb.dict[key]; ok { 237 return v.value 238 } 239 return LNil 240 } 241 242 // RawGetString returns an LValue associated with a given key without __index metamethod. 243 func (tb *LTable) RawGetString(key string) LValue { 244 return tb.RawGetH(LString(key)) 245 } 246 247 // ForEach iterates over this table of elements, yielding each in turn to a given function. 248 func (tb *LTable) ForEach(cb func(LValue, LValue)) { 249 if tb.array != nil { 250 for i, v := range tb.array { 251 if v != LNil { 252 cb(LNumber(i+1), v) 253 } 254 } 255 } 256 if tb.dict != nil { 257 for k, v := range tb.dict { 258 if v.value != LNil { 259 cb(k, v.value) 260 } 261 } 262 } 263 } 264 265 // This function is equivalent to lua_next ( http://www.lua.org/manual/5.1/manual.html#lua_next ). 266 func (tb *LTable) Next(key LValue) (LValue, LValue) { 267 init := false 268 if key == LNil { 269 key = LNumber(0) 270 init = true 271 } 272 273 if init || key != LNumber(0) { 274 if kv, ok := key.(LNumber); ok && isInteger(kv) && int(kv) >= 0 && kv < LNumber(MaxArrayIndex) { 275 index := int(kv) 276 if tb.array != nil { 277 for ; index < len(tb.array); index++ { 278 if v := tb.array[index]; v != LNil { 279 return LNumber(index + 1), v 280 } 281 } 282 } 283 if tb.array == nil || index == len(tb.array) { 284 if (tb.dict == nil || len(tb.dict) == 0) { 285 return LNil, LNil 286 } 287 key = *tb.keys[0] 288 if v := tb.RawGetH(key); v != LNil { 289 return key, v 290 } 291 } 292 } 293 } 294 295 for i := tb.dict[key].keyIndex + 1; i < len(tb.keys); i++ { 296 key := *tb.keys[i] 297 if v := tb.RawGetH(key); v != LNil { 298 return key, v 299 } 300 } 301 return LNil, LNil 302 }