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