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