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