github.com/tul/gopher-lua@v0.0.0-20181008131706-f6fcaab0c612/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{} 39 tb.Metatable = LNil 40 if acap != 0 { 41 tb.array = make([]LValue, 0, acap) 42 } 43 if hcap != 0 { 44 tb.strdict = make(map[string]LValue, hcap) 45 } 46 return tb 47 } 48 49 // Len returns length of this LTable. 50 func (tb *LTable) Len() int { 51 if tb.array == nil { 52 return 0 53 } 54 var prev LValue = LNil 55 for i := len(tb.array) - 1; i >= 0; i-- { 56 v := tb.array[i] 57 if prev == LNil && v != LNil { 58 return i + 1 59 } 60 prev = v 61 } 62 return 0 63 } 64 65 // Append appends a given LValue to this LTable. 66 func (tb *LTable) Append(value LValue) { 67 if value == LNil { 68 return 69 } 70 if tb.array == nil { 71 tb.array = make([]LValue, 0, defaultArrayCap) 72 } 73 tb.array = append(tb.array, value) 74 } 75 76 // Insert inserts a given LValue at position `i` in this table. 77 func (tb *LTable) Insert(i int, value LValue) { 78 if tb.array == nil { 79 tb.array = make([]LValue, 0, defaultArrayCap) 80 } 81 if i > len(tb.array) { 82 tb.RawSetInt(i, value) 83 return 84 } 85 if i <= 0 { 86 tb.RawSet(LNumber(i), value) 87 return 88 } 89 i -= 1 90 tb.array = append(tb.array, LNil) 91 copy(tb.array[i+1:], tb.array[i:]) 92 tb.array[i] = value 93 } 94 95 // MaxN returns a maximum number key that nil value does not exist before it. 96 func (tb *LTable) MaxN() int { 97 if tb.array == nil { 98 return 0 99 } 100 for i := len(tb.array) - 1; i >= 0; i-- { 101 if tb.array[i] != LNil { 102 return i + 1 103 } 104 } 105 return 0 106 } 107 108 // Remove removes from this table the element at a given position. 109 func (tb *LTable) Remove(pos int) LValue { 110 if tb.array == nil { 111 return LNil 112 } 113 i := pos - 1 114 larray := len(tb.array) 115 oldval := LNil 116 switch { 117 case i >= larray: 118 // nothing to do 119 case i == larray-1 || i < 0: 120 oldval = tb.array[larray-1] 121 tb.array = tb.array[:larray-1] 122 default: 123 oldval = tb.array[i] 124 copy(tb.array[i:], tb.array[i+1:]) 125 tb.array[larray-1] = nil 126 tb.array = tb.array[:larray-1] 127 } 128 return oldval 129 } 130 131 // RawSet sets a given LValue to a given index without the __newindex metamethod. 132 // It is recommended to use `RawSetString` or `RawSetInt` for performance 133 // if you already know the given LValue is a string or number. 134 func (tb *LTable) RawSet(key LValue, value LValue) { 135 switch v := key.(type) { 136 case LNumber: 137 if isArrayKey(v) { 138 if tb.array == nil { 139 tb.array = make([]LValue, 0, defaultArrayCap) 140 } 141 index := int(v) - 1 142 alen := len(tb.array) 143 switch { 144 case index == alen: 145 tb.array = append(tb.array, value) 146 case index > alen: 147 for i := 0; i < (index - alen); i++ { 148 tb.array = append(tb.array, LNil) 149 } 150 tb.array = append(tb.array, value) 151 case index < alen: 152 tb.array[index] = value 153 } 154 return 155 } 156 case LString: 157 tb.RawSetString(string(v), value) 158 return 159 } 160 161 tb.RawSetH(key, value) 162 } 163 164 // RawSetInt sets a given LValue at a position `key` without the __newindex metamethod. 165 func (tb *LTable) RawSetInt(key int, value LValue) { 166 if key < 1 || key >= MaxArrayIndex { 167 tb.RawSetH(LNumber(key), value) 168 return 169 } 170 if tb.array == nil { 171 tb.array = make([]LValue, 0, 32) 172 } 173 index := key - 1 174 alen := len(tb.array) 175 switch { 176 case index == alen: 177 tb.array = append(tb.array, value) 178 case index > alen: 179 for i := 0; i < (index - alen); i++ { 180 tb.array = append(tb.array, LNil) 181 } 182 tb.array = append(tb.array, value) 183 case index < alen: 184 tb.array[index] = value 185 } 186 } 187 188 // RawSetString sets a given LValue to a given string index without the __newindex metamethod. 189 func (tb *LTable) RawSetString(key string, value LValue) { 190 if tb.strdict == nil { 191 tb.strdict = make(map[string]LValue, defaultHashCap) 192 } 193 if tb.keys == nil { 194 tb.keys = []LValue{} 195 tb.k2i = map[LValue]int{} 196 } 197 198 if value == LNil { 199 // TODO tb.keys and tb.k2i should also be removed 200 delete(tb.strdict, key) 201 } else { 202 tb.strdict[key] = value 203 lkey := LString(key) 204 if _, ok := tb.k2i[lkey]; !ok { 205 tb.k2i[lkey] = len(tb.keys) 206 tb.keys = append(tb.keys, lkey) 207 } 208 } 209 } 210 211 // RawSetH sets a given LValue to a given index without the __newindex metamethod. 212 func (tb *LTable) RawSetH(key LValue, value LValue) { 213 if s, ok := key.(LString); ok { 214 tb.RawSetString(string(s), value) 215 return 216 } 217 if tb.dict == nil { 218 tb.dict = make(map[LValue]LValue, len(tb.strdict)) 219 } 220 if tb.keys == nil { 221 tb.keys = []LValue{} 222 tb.k2i = map[LValue]int{} 223 } 224 225 if value == LNil { 226 // TODO tb.keys and tb.k2i should also be removed 227 delete(tb.dict, key) 228 } else { 229 tb.dict[key] = value 230 if _, ok := tb.k2i[key]; !ok { 231 tb.k2i[key] = len(tb.keys) 232 tb.keys = append(tb.keys, key) 233 } 234 } 235 } 236 237 // RawGet returns an LValue associated with a given key without __index metamethod. 238 func (tb *LTable) RawGet(key LValue) LValue { 239 switch v := key.(type) { 240 case LNumber: 241 if isArrayKey(v) { 242 if tb.array == nil { 243 return LNil 244 } 245 index := int(v) - 1 246 if index >= len(tb.array) { 247 return LNil 248 } 249 return tb.array[index] 250 } 251 case LString: 252 if tb.strdict == nil { 253 return LNil 254 } 255 if ret, ok := tb.strdict[string(v)]; ok { 256 return ret 257 } 258 return LNil 259 } 260 if tb.dict == nil { 261 return LNil 262 } 263 if v, ok := tb.dict[key]; ok { 264 return v 265 } 266 return LNil 267 } 268 269 // RawGetInt returns an LValue at position `key` without __index metamethod. 270 func (tb *LTable) RawGetInt(key int) LValue { 271 if tb.array == nil { 272 return LNil 273 } 274 index := int(key) - 1 275 if index >= len(tb.array) || index < 0 { 276 return LNil 277 } 278 return tb.array[index] 279 } 280 281 // RawGet returns an LValue associated with a given key without __index metamethod. 282 func (tb *LTable) RawGetH(key LValue) LValue { 283 if s, sok := key.(LString); sok { 284 if tb.strdict == nil { 285 return LNil 286 } 287 if v, vok := tb.strdict[string(s)]; vok { 288 return v 289 } 290 return LNil 291 } 292 if tb.dict == nil { 293 return LNil 294 } 295 if v, ok := tb.dict[key]; ok { 296 return v 297 } 298 return LNil 299 } 300 301 // RawGetString returns an LValue associated with a given key without __index metamethod. 302 func (tb *LTable) RawGetString(key string) LValue { 303 if tb.strdict == nil { 304 return LNil 305 } 306 if v, vok := tb.strdict[string(key)]; vok { 307 return v 308 } 309 return LNil 310 } 311 312 // ForEach iterates over this table of elements, yielding each in turn to a given function. 313 func (tb *LTable) ForEach(cb func(LValue, LValue)) { 314 if tb.array != nil { 315 for i, v := range tb.array { 316 if v != LNil { 317 cb(LNumber(i+1), v) 318 } 319 } 320 } 321 if tb.strdict != nil { 322 for k, v := range tb.strdict { 323 if v != LNil { 324 cb(LString(k), v) 325 } 326 } 327 } 328 if tb.dict != nil { 329 for k, v := range tb.dict { 330 if v != LNil { 331 cb(k, v) 332 } 333 } 334 } 335 } 336 337 // This function is equivalent to lua_next ( http://www.lua.org/manual/5.1/manual.html#lua_next ). 338 func (tb *LTable) Next(key LValue) (LValue, LValue) { 339 init := false 340 if key == LNil { 341 key = LNumber(0) 342 init = true 343 } 344 345 if init || key != LNumber(0) { 346 if kv, ok := key.(LNumber); ok && isInteger(kv) && int(kv) >= 0 && kv < LNumber(MaxArrayIndex) { 347 index := int(kv) 348 if tb.array != nil { 349 for ; index < len(tb.array); index++ { 350 if v := tb.array[index]; v != LNil { 351 return LNumber(index + 1), v 352 } 353 } 354 } 355 if tb.array == nil || index == len(tb.array) { 356 if (tb.dict == nil || len(tb.dict) == 0) && (tb.strdict == nil || len(tb.strdict) == 0) { 357 return LNil, LNil 358 } 359 key = tb.keys[0] 360 if v := tb.RawGetH(key); v != LNil { 361 return key, v 362 } 363 } 364 } 365 } 366 367 for i := tb.k2i[key] + 1; i < len(tb.keys); i++ { 368 key := tb.keys[i] 369 if v := tb.RawGetH(key); v != LNil { 370 return key, v 371 } 372 } 373 return LNil, LNil 374 }