github.com/xyproto/gopher-lua@v1.0.2/table.go (about) 1 package lua 2 3 const ( 4 defaultArrayCap = 32 5 defaultHashCap = 32 6 ) 7 8 type lValueArraySorter struct { 9 L *LState 10 Fn *LFunction 11 Values []LValue 12 } 13 14 func (lv lValueArraySorter) Len() int { 15 return len(lv.Values) 16 } 17 18 func (lv lValueArraySorter) Swap(i, j int) { 19 lv.Values[i], lv.Values[j] = lv.Values[j], lv.Values[i] 20 } 21 22 func (lv lValueArraySorter) Less(i, j int) bool { 23 if lv.Fn != nil { 24 lv.L.Push(lv.Fn) 25 lv.L.Push(lv.Values[i]) 26 lv.L.Push(lv.Values[j]) 27 lv.L.Call(2, 1) 28 return LVAsBool(lv.L.reg.Pop()) 29 } 30 return lessThan(lv.L, lv.Values[i], lv.Values[j]) 31 } 32 33 func newLTable(acap int, hcap int) *LTable { 34 if acap < 0 { 35 acap = 0 36 } 37 if hcap < 0 { 38 hcap = 0 39 } 40 tb := <able{} 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 without using __len. 52 func (tb *LTable) Len() int { 53 if tb.array == nil { 54 return 0 55 } 56 tb.mut.RLock() 57 defer tb.mut.RUnlock() 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 tb.mut.Lock() 75 defer tb.mut.Unlock() 76 if tb.array == nil { 77 tb.array = make([]LValue, 0, defaultArrayCap) 78 } 79 if len(tb.array) == 0 || tb.array[len(tb.array)-1] != LNil { 80 tb.array = append(tb.array, value) 81 } else { 82 i := len(tb.array) - 2 83 for ; i >= 0; i-- { 84 if tb.array[i] != LNil { 85 break 86 } 87 } 88 tb.array[i+1] = value 89 } 90 } 91 92 // Insert inserts a given LValue at position `i` in this table. 93 func (tb *LTable) Insert(i int, value LValue) { 94 if tb.array == nil { 95 tb.array = make([]LValue, 0, defaultArrayCap) 96 } 97 if i > len(tb.array) { 98 tb.RawSetInt(i, value) 99 return 100 } 101 if i <= 0 { 102 tb.RawSet(LNumber(i), value) 103 return 104 } 105 tb.mut.Lock() 106 defer tb.mut.Unlock() 107 i -= 1 108 tb.array = append(tb.array, LNil) 109 copy(tb.array[i+1:], tb.array[i:]) 110 tb.array[i] = value 111 } 112 113 // MaxN returns a maximum number key that nil value does not exist before it. 114 func (tb *LTable) MaxN() int { 115 if tb.array == nil { 116 return 0 117 } 118 tb.mut.RLock() 119 defer tb.mut.RUnlock() 120 for i := len(tb.array) - 1; i >= 0; i-- { 121 if tb.array[i] != LNil { 122 return i + 1 123 } 124 } 125 return 0 126 } 127 128 // Remove removes from this table the element at a given position. 129 func (tb *LTable) Remove(pos int) LValue { 130 if tb.array == nil { 131 return LNil 132 } 133 tb.mut.Lock() 134 defer tb.mut.Unlock() 135 larray := len(tb.array) 136 if larray == 0 { 137 return LNil 138 } 139 i := pos - 1 140 oldval := LNil 141 switch { 142 case i >= larray: 143 // nothing to do 144 case i == larray-1 || i < 0: 145 oldval = tb.array[larray-1] 146 tb.array = tb.array[:larray-1] 147 default: 148 oldval = tb.array[i] 149 copy(tb.array[i:], tb.array[i+1:]) 150 tb.array[larray-1] = nil 151 tb.array = tb.array[:larray-1] 152 } 153 return oldval 154 } 155 156 // RawSet sets a given LValue to a given index without the __newindex metamethod. 157 // It is recommended to use `RawSetString` or `RawSetInt` for performance 158 // if you already know the given LValue is a string or number. 159 func (tb *LTable) RawSet(key LValue, value LValue) { 160 switch v := key.(type) { 161 case LNumber: 162 if isArrayKey(v) { 163 tb.mut.Lock() 164 if tb.array == nil { 165 tb.array = make([]LValue, 0, defaultArrayCap) 166 } 167 index := int(v) - 1 168 alen := len(tb.array) 169 switch { 170 case index == alen: 171 tb.array = append(tb.array, value) 172 case index > alen: 173 for i := 0; i < (index - alen); i++ { 174 tb.array = append(tb.array, LNil) 175 } 176 tb.array = append(tb.array, value) 177 case index < alen: 178 tb.array[index] = value 179 } 180 tb.mut.Unlock() 181 return 182 } 183 case LString: 184 tb.RawSetString(string(v), value) 185 return 186 } 187 tb.RawSetH(key, value) 188 } 189 190 // RawSetInt sets a given LValue at a position `key` without the __newindex metamethod. 191 func (tb *LTable) RawSetInt(key int, value LValue) { 192 if key < 1 || key >= MaxArrayIndex { 193 tb.RawSetH(LNumber(key), value) 194 return 195 } 196 if tb.array == nil { 197 tb.array = make([]LValue, 0, 32) 198 } 199 tb.mut.Lock() 200 defer tb.mut.Unlock() 201 index := key - 1 202 alen := len(tb.array) 203 switch { 204 case index == alen: 205 tb.array = append(tb.array, value) 206 case index > alen: 207 for i := 0; i < (index - alen); i++ { 208 tb.array = append(tb.array, LNil) 209 } 210 tb.array = append(tb.array, value) 211 case index < alen: 212 tb.array[index] = value 213 } 214 } 215 216 // RawSetString sets a given LValue to a given string index without the __newindex metamethod. 217 func (tb *LTable) RawSetString(key string, value LValue) { 218 if tb.strdict == nil { 219 tb.strdict = make(map[string]LValue, defaultHashCap) 220 } 221 if tb.keys == nil { 222 tb.keys = []LValue{} 223 tb.k2i = map[LValue]int{} 224 } 225 226 tb.mut.Lock() 227 defer tb.mut.Unlock() 228 229 if value == LNil { 230 // TODO tb.keys and tb.k2i should also be removed 231 delete(tb.strdict, key) 232 } else { 233 tb.strdict[key] = value 234 lkey := LString(key) 235 if _, ok := tb.k2i[lkey]; !ok { 236 tb.k2i[lkey] = len(tb.keys) 237 tb.keys = append(tb.keys, lkey) 238 } 239 } 240 } 241 242 // RawSetH sets a given LValue to a given index without the __newindex metamethod. 243 func (tb *LTable) RawSetH(key LValue, value LValue) { 244 if s, ok := key.(LString); ok { 245 tb.RawSetString(string(s), value) 246 return 247 } 248 if tb.dict == nil { 249 tb.dict = make(map[LValue]LValue, len(tb.strdict)) 250 } 251 if tb.keys == nil { 252 tb.keys = []LValue{} 253 tb.k2i = map[LValue]int{} 254 } 255 256 tb.mut.Lock() 257 defer tb.mut.Unlock() 258 259 if value == LNil { 260 // TODO tb.keys and tb.k2i should also be removed 261 delete(tb.dict, key) 262 } else { 263 tb.dict[key] = value 264 if _, ok := tb.k2i[key]; !ok { 265 tb.k2i[key] = len(tb.keys) 266 tb.keys = append(tb.keys, key) 267 } 268 } 269 } 270 271 // RawGet returns an LValue associated with a given key without __index metamethod. 272 func (tb *LTable) RawGet(key LValue) LValue { 273 switch v := key.(type) { 274 case LNumber: 275 if isArrayKey(v) { 276 if tb.array == nil { 277 return LNil 278 } 279 tb.mut.RLock() 280 defer tb.mut.RUnlock() 281 index := int(v) - 1 282 if index >= len(tb.array) { 283 return LNil 284 } 285 return tb.array[index] 286 } 287 case LString: 288 if tb.strdict == nil { 289 return LNil 290 } 291 tb.mut.RLock() 292 defer tb.mut.RUnlock() 293 if ret, ok := tb.strdict[string(v)]; ok { 294 return ret 295 } 296 return LNil 297 } 298 if tb.dict == nil { 299 return LNil 300 } 301 tb.mut.RLock() 302 defer tb.mut.RUnlock() 303 if v, ok := tb.dict[key]; ok { 304 return v 305 } 306 return LNil 307 } 308 309 // RawGetInt returns an LValue at position `key` without __index metamethod. 310 func (tb *LTable) RawGetInt(key int) LValue { 311 if tb.array == nil { 312 return LNil 313 } 314 index := int(key) - 1 315 tb.mut.RLock() 316 defer tb.mut.RUnlock() 317 if index >= len(tb.array) || index < 0 { 318 return LNil 319 } 320 return tb.array[index] 321 } 322 323 // RawGet returns an LValue associated with a given key without __index metamethod. 324 func (tb *LTable) RawGetH(key LValue) LValue { 325 if s, sok := key.(LString); sok { 326 if tb.strdict == nil { 327 return LNil 328 } 329 tb.mut.RLock() 330 defer tb.mut.RUnlock() 331 if v, vok := tb.strdict[string(s)]; vok { 332 return v 333 } 334 return LNil 335 } 336 if tb.dict == nil { 337 return LNil 338 } 339 tb.mut.RLock() 340 defer tb.mut.RUnlock() 341 if v, ok := tb.dict[key]; ok { 342 return v 343 } 344 return LNil 345 } 346 347 // RawGetString returns an LValue associated with a given key without __index metamethod. 348 func (tb *LTable) RawGetString(key string) LValue { 349 if tb.strdict == nil { 350 return LNil 351 } 352 tb.mut.RLock() 353 defer tb.mut.RUnlock() 354 if v, vok := tb.strdict[string(key)]; vok { 355 return v 356 } 357 return LNil 358 } 359 360 // ForEach iterates over this table of elements, yielding each in turn to a given function. 361 func (tb *LTable) ForEach(cb func(LValue, LValue)) { 362 //tb.mut.RLock() 363 //defer tb.mut.RUnlock() 364 if tb.array != nil { 365 for i, v := range tb.array { 366 if v != LNil { 367 cb(LNumber(i+1), v) 368 } 369 } 370 } 371 if tb.strdict != nil { 372 for k, v := range tb.strdict { 373 if v != LNil { 374 cb(LString(k), v) 375 } 376 } 377 } 378 if tb.dict != nil { 379 for k, v := range tb.dict { 380 if v != LNil { 381 cb(k, v) 382 } 383 } 384 } 385 } 386 387 // This function is equivalent to lua_next ( http://www.lua.org/manual/5.1/manual.html#lua_next ). 388 func (tb *LTable) Next(key LValue) (LValue, LValue) { 389 init := false 390 if key == LNil { 391 key = LNumber(0) 392 init = true 393 } 394 395 //tb.mut.RLock() 396 //defer tb.mut.RUnlock() 397 if init || key != LNumber(0) { 398 if kv, ok := key.(LNumber); ok && isInteger(kv) && int(kv) >= 0 && kv < LNumber(MaxArrayIndex) { 399 index := int(kv) 400 if tb.array != nil { 401 for ; index < len(tb.array); index++ { 402 if v := tb.array[index]; v != LNil { 403 return LNumber(index + 1), v 404 } 405 } 406 } 407 if tb.array == nil || index == len(tb.array) { 408 if (tb.dict == nil || len(tb.dict) == 0) && (tb.strdict == nil || len(tb.strdict) == 0) { 409 return LNil, LNil 410 } 411 key = tb.keys[0] 412 if v := tb.RawGetH(key); v != LNil { 413 return key, v 414 } 415 } 416 } 417 } 418 419 for i := tb.k2i[key] + 1; i < len(tb.keys); i++ { 420 key := tb.keys[i] 421 if v := tb.RawGetH(key); v != LNil { 422 return key, v 423 } 424 } 425 return LNil, LNil 426 }