github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/internal/tables/table.go (about) 1 package tables 2 3 import ( 4 "fmt" 5 6 "github.com/hirochachacha/plua/internal/limits" 7 "github.com/hirochachacha/plua/object" 8 ) 9 10 type table struct { 11 a []object.Value 12 m *luaMap 13 14 mt object.Table 15 } 16 17 func NewTableSize(asize, msize int) object.Table { 18 return &table{ 19 a: make([]object.Value, 0, asize), 20 m: newMapSize(msize), 21 } 22 } 23 24 func NewTableArray(a []object.Value) object.Table { 25 return &table{ 26 a: a, 27 m: newMapSize(0), 28 } 29 } 30 31 func (t *table) Type() object.Type { 32 return object.TTABLE 33 } 34 35 func (t *table) String() string { 36 return fmt.Sprintf("table: %p", t) 37 } 38 39 func (t *table) Len() int { 40 return len(t.a) 41 } 42 43 func (t *table) Get(key object.Value) object.Value { 44 return t.get(normKey(key)) 45 } 46 47 func (t *table) Set(key, val object.Value) { 48 t.set(normKey(key), val) 49 } 50 51 func (t *table) Del(key object.Value) { 52 t.del(normKey(key)) 53 } 54 55 func (t *table) Next(key object.Value) (nkey, nval object.Value, ok bool) { 56 return t.next(normKey(key)) 57 } 58 59 func (t *table) ikey(key object.Value) (object.Integer, bool) { 60 if ikey, ok := key.(object.Integer); ok { 61 return ikey, !(int64(ikey) > limits.MaxInt || int64(ikey) < limits.MinInt) 62 } 63 64 if nkey, ok := key.(object.Number); ok { 65 if ikey, ok := object.ToInteger(nkey); ok { 66 return ikey, !(int64(ikey) > limits.MaxInt || int64(ikey) < limits.MinInt) 67 } 68 } 69 70 return 0, false 71 } 72 73 func (t *table) get(key object.Value) object.Value { 74 if ikey, ok := t.ikey(key); ok { 75 return t.iget(ikey) 76 } 77 return t.m.Get(key) 78 } 79 80 func (t *table) iget(ikey object.Integer) object.Value { 81 i := int(ikey) 82 if 0 < i && i <= len(t.a) { 83 return t.a[i-1] 84 } 85 return t.m.Get(ikey) 86 } 87 88 func (t *table) set(key, val object.Value) { 89 if val == nil { 90 t.del(key) 91 92 return 93 } 94 95 if ikey, ok := t.ikey(key); ok { 96 t.iset(ikey, val) 97 } else { 98 t.m.Set(key, val) 99 } 100 } 101 102 func (t *table) iset(ikey object.Integer, val object.Value) { 103 i := int(ikey) 104 switch { 105 case 0 < i && i <= len(t.a): 106 t.a[i-1] = val 107 case i == len(t.a)+1: 108 t.a = append(t.a, val) 109 110 // migration from map to array 111 for { 112 ikey++ 113 val := t.m.Get(ikey) 114 if val == nil { 115 break 116 } 117 t.a = append(t.a, val) 118 t.m.Delete(ikey) 119 } 120 default: 121 t.m.Set(ikey, val) 122 } 123 } 124 125 func (t *table) del(key object.Value) { 126 if ikey, ok := t.ikey(key); ok { 127 t.idel(ikey) 128 } else { 129 t.m.Delete(key) 130 } 131 } 132 133 func (t *table) idel(ikey object.Integer) { 134 i := int(ikey) 135 switch { 136 case 0 < i && i < len(t.a): 137 t.a[i-1] = nil 138 case 0 < i && i == len(t.a): 139 t.a = t.a[:len(t.a)-1] 140 for len(t.a) > 0 && t.a[len(t.a)-1] == nil { 141 t.a = t.a[:len(t.a)-1] 142 } 143 case i == len(t.a)+1: 144 // do nothing 145 default: 146 t.m.Delete(ikey) 147 } 148 } 149 150 func (t *table) next(key object.Value) (nkey, nval object.Value, ok bool) { 151 if key == nil { 152 for i := 0; i < len(t.a); i++ { 153 v := t.a[i] 154 if v != nil { 155 return object.Integer(i + 1), v, true 156 } 157 } 158 return t.m.Next(nil) 159 } 160 161 if ikey, ok := t.ikey(key); ok { 162 if i := int(ikey); i > 0 { 163 for ; i < len(t.a); i++ { 164 v := t.a[i] 165 if v != nil { 166 return object.Integer(i + 1), t.a[i], true 167 } 168 } 169 if i == len(t.a) { 170 return t.m.Next(nil) 171 } 172 } 173 } 174 175 return t.m.Next(key) 176 } 177 178 func (t *table) SetList(base int, src []object.Value) { 179 if len(src) < len(t.a)-base { 180 copy(t.a[base:], src) 181 } else { 182 t.a = append(t.a[:base], src...) 183 } 184 } 185 186 func (t *table) SetMetatable(mt object.Table) { 187 t.mt = mt 188 } 189 190 func (t *table) Metatable() object.Table { 191 return t.mt 192 }