Mercurial Hosting > luan
comparison src/luan/LuanTable.java @ 1578:c922446f53aa
immutable threading
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Mon, 08 Feb 2021 14:16:19 -0700 |
parents | 364859d29ff5 |
children | fa066aaa068c |
comparison
equal
deleted
inserted
replaced
1577:60e5c324adf9 | 1578:c922446f53aa |
---|---|
11 import java.util.Comparator; | 11 import java.util.Comparator; |
12 import java.util.Set; | 12 import java.util.Set; |
13 import java.util.HashSet; | 13 import java.util.HashSet; |
14 | 14 |
15 | 15 |
16 public final class LuanTable implements LuanCloneable { | 16 public final class LuanTable implements LuanMutable { |
17 private Map map = null; | 17 private Map map = null; |
18 private List list = null; | 18 private List list = null; |
19 private LuanTable metatable = null; | 19 private LuanTable metatable = null; |
20 public LuanClosure closure; | 20 public LuanClosure closure; |
21 private LuanCloner cloner; | |
22 private boolean immutable = false; | 21 private boolean immutable = false; |
23 private Luan luan; | |
24 | 22 |
25 public LuanTable() {} | 23 public LuanTable() {} |
26 | 24 |
27 public LuanTable(List list) { | 25 public LuanTable(List list) { |
28 try { | 26 try { |
69 if( tbl.rawLength() > 0 ) | 67 if( tbl.rawLength() > 0 ) |
70 this.list = new ArrayList<Object>(tbl.list); | 68 this.list = new ArrayList<Object>(tbl.list); |
71 this.metatable = tbl.metatable; | 69 this.metatable = tbl.metatable; |
72 } | 70 } |
73 | 71 |
74 @Override public LuanTable shallowClone() { | 72 @Override public boolean isImmutable() { |
75 if(immutable) throw new RuntimeException(); | 73 return immutable; |
76 return new LuanTable(); | 74 } |
77 } | 75 |
78 | 76 @Override public void makeImmutable() { |
79 @Override public void deepenClone(LuanCloneable dc,LuanCloner cloner) { | 77 if(immutable) |
80 check(); | |
81 LuanTable clone = (LuanTable)dc; | |
82 switch( cloner.type ) { | |
83 case COMPLETE: | |
84 completeClone(clone,cloner); | |
85 return; | 78 return; |
86 case INCREMENTAL: | |
87 clone.cloner = cloner; | |
88 clone.map = map; | |
89 clone.list = list; | |
90 clone.metatable = metatable; | |
91 clone.closure = closure; | |
92 return; | |
93 } | |
94 } | |
95 | |
96 private void check() { | |
97 if( cloner != null ) { | |
98 completeClone(this,cloner); | |
99 cloner = null; | |
100 } | |
101 } | |
102 | |
103 private void checkLuan(Luan luan) { | |
104 check(); | |
105 if( this.luan==null ) { | |
106 this.luan = luan; | |
107 } else if( this.luan != luan ) { | |
108 throw new RuntimeException("wrong luan"); | |
109 } | |
110 } | |
111 | |
112 private void completeClone(LuanTable clone,LuanCloner cloner) { | |
113 clone.map = cloner.clone(map); | |
114 clone.list = (List)cloner.clone(list); | |
115 clone.metatable = (LuanTable)cloner.clone(metatable); | |
116 clone.closure = (LuanClosure)cloner.clone(closure); | |
117 clone.luan = (Luan)cloner.clone(luan); | |
118 } | |
119 | |
120 @Override public void makeImmutable(LuanImmutabler immutabler) throws LuanException { | |
121 check(); | |
122 immutabler.makeImmutable(map); | |
123 immutabler.makeImmutable(list); | |
124 immutabler.makeImmutable(metatable); | |
125 immutabler.makeImmutable(closure); | |
126 immutable = true; | 79 immutable = true; |
80 LuanMutable.makeImmutable(map); | |
81 LuanMutable.makeImmutable(list); | |
82 LuanMutable.makeImmutable(metatable); | |
83 LuanMutable.makeImmutable(closure); | |
84 } | |
85 | |
86 private void checkMutable() throws LuanException { | |
87 if( immutable ) | |
88 throw new LuanException("table is immutable"); | |
127 } | 89 } |
128 | 90 |
129 public boolean isList() { | 91 public boolean isList() { |
130 return map==null || map.isEmpty(); | 92 return map==null || map.isEmpty(); |
131 } | 93 } |
133 public boolean isMap() { | 95 public boolean isMap() { |
134 return map!=null || list==null; | 96 return map!=null || list==null; |
135 } | 97 } |
136 | 98 |
137 public List<Object> asList() { | 99 public List<Object> asList() { |
138 check(); | |
139 return list!=null ? list : Collections.emptyList(); | 100 return list!=null ? list : Collections.emptyList(); |
140 } | 101 } |
141 | 102 |
142 public Map rawMap() { | 103 public Map rawMap() { |
143 check(); | |
144 return map!=null ? map : Collections.emptyMap(); | 104 return map!=null ? map : Collections.emptyMap(); |
145 } | 105 } |
146 | 106 |
147 public String toStringLuan(Luan luan) throws LuanException { | 107 public String toStringLuan(Luan luan) throws LuanException { |
148 Object h = getHandler("__to_string"); | 108 Object h = getHandler(luan,"__to_string"); |
149 if( h == null ) | 109 if( h == null ) |
150 return rawToString(); | 110 return rawToString(); |
151 LuanFunction fn = Luan.checkFunction(h); | 111 LuanFunction fn = Luan.checkFunction(h); |
152 return Luan.checkString( Luan.first( fn.call(luan,this) ) ); | 112 return Luan.checkString( Luan.first( fn.call(luan,this) ) ); |
153 } | 113 } |
159 public Object get(Luan luan,Object key) throws LuanException { | 119 public Object get(Luan luan,Object key) throws LuanException { |
160 //checkLuan(luan); | 120 //checkLuan(luan); |
161 Object value = rawGet(key); | 121 Object value = rawGet(key); |
162 if( value != null ) | 122 if( value != null ) |
163 return value; | 123 return value; |
164 Object h = getHandler("__index"); | 124 Object h = getHandler(luan,"__index"); |
165 if( h==null ) | 125 if( h==null ) |
166 return null; | 126 return null; |
167 if( h instanceof LuanFunction ) { | 127 if( h instanceof LuanFunction ) { |
168 LuanFunction fn = (LuanFunction)h; | 128 LuanFunction fn = (LuanFunction)h; |
169 return Luan.first(fn.call(luan,this,key)); | 129 return Luan.first(fn.call(luan,this,key)); |
170 } | 130 } |
171 return luan.index(h,key); | 131 return luan.index(h,key); |
172 } | 132 } |
173 | 133 |
174 public Object rawGet(Object key) { | 134 public Object rawGet(Object key) { |
175 check(); | |
176 if( list != null ) { | 135 if( list != null ) { |
177 Integer iT = Luan.asInteger(key); | 136 Integer iT = Luan.asInteger(key); |
178 if( iT != null ) { | 137 if( iT != null ) { |
179 int i = iT - 1; | 138 int i = iT - 1; |
180 if( i>=0 && i<list.size() ) | 139 if( i>=0 && i<list.size() ) |
190 return map.get(key); | 149 return map.get(key); |
191 } | 150 } |
192 | 151 |
193 public void put(Luan luan,Object key,Object value) throws LuanException { | 152 public void put(Luan luan,Object key,Object value) throws LuanException { |
194 //checkLuan(luan); | 153 //checkLuan(luan); |
195 Object h = getHandler("__new_index"); | 154 Object h = getHandler(luan,"__new_index"); |
196 if( h==null || rawGet(key)!=null ) { | 155 if( h==null || rawGet(key)!=null ) { |
197 rawPut(key,value); | 156 rawPut(key,value); |
198 return; | 157 return; |
199 } | 158 } |
200 if( h instanceof LuanFunction ) { | 159 if( h instanceof LuanFunction ) { |
209 } | 168 } |
210 throw new LuanException("invalid type "+Luan.type(h)+" for metamethod __new_index"); | 169 throw new LuanException("invalid type "+Luan.type(h)+" for metamethod __new_index"); |
211 } | 170 } |
212 | 171 |
213 public Object rawPut(Object key,Object val) throws LuanException { | 172 public Object rawPut(Object key,Object val) throws LuanException { |
214 if( immutable ) | 173 checkMutable(); |
215 throw new LuanException("table is immutable"); | |
216 check(); | |
217 if( key==null ) | 174 if( key==null ) |
218 throw new LuanException("table index is nil"); | 175 throw new LuanException("table index is nil"); |
219 Integer iT = Luan.asInteger(key); | 176 Integer iT = Luan.asInteger(key); |
220 if( iT != null ) { | 177 if( iT != null ) { |
221 int i = iT - 1; | 178 int i = iT - 1; |
282 mapToList(); | 239 mapToList(); |
283 } | 240 } |
284 return list; | 241 return list; |
285 } | 242 } |
286 | 243 |
287 public void rawInsert(int pos,Object value) { | 244 public void rawInsert(int pos,Object value) throws LuanException { |
288 check(); | 245 checkMutable(); |
289 if( value==null ) | 246 if( value==null ) |
290 throw new IllegalArgumentException("can't insert a nil value"); | 247 throw new IllegalArgumentException("can't insert a nil value"); |
291 list().add(pos-1,value); | 248 list().add(pos-1,value); |
292 mapToList(); | 249 mapToList(); |
293 } | 250 } |
294 | 251 |
295 public void rawAdd(Object value) { | 252 public void rawAdd(Object value) throws LuanException { |
296 check(); | 253 checkMutable(); |
297 if( value==null ) | 254 if( value==null ) |
298 throw new IllegalArgumentException("can't insert a nil value"); | 255 throw new IllegalArgumentException("can't insert a nil value"); |
299 list().add(value); | 256 list().add(value); |
300 mapToList(); | 257 mapToList(); |
301 } | 258 } |
302 | 259 |
303 public Object removeFromList(int pos) { | 260 public Object removeFromList(int pos) throws LuanException { |
304 check(); | 261 checkMutable(); |
305 return list().remove(pos-1); | 262 return list().remove(pos-1); |
306 } | 263 } |
307 | 264 |
308 public void rawSort(Comparator<Object> cmp) { | 265 public void rawSort(Comparator<Object> cmp) throws LuanException { |
309 check(); | 266 checkMutable(); |
310 Collections.sort(list(),cmp); | 267 Collections.sort(list(),cmp); |
311 } | 268 } |
312 | 269 |
313 public int length(Luan luan) throws LuanException { | 270 public int length(Luan luan) throws LuanException { |
314 Object h = getHandler("__len"); | 271 Object h = getHandler(luan,"__len"); |
315 if( h != null ) { | 272 if( h != null ) { |
316 LuanFunction fn = Luan.checkFunction(h); | 273 LuanFunction fn = Luan.checkFunction(h); |
317 return (Integer)Luan.first(fn.call(luan,this)); | 274 return (Integer)Luan.first(fn.call(luan,this)); |
318 } | 275 } |
319 return rawLength(); | 276 return rawLength(); |
320 } | 277 } |
321 | 278 |
322 public int rawLength() { | 279 public int rawLength() { |
323 check(); | |
324 return list==null ? 0 : list.size(); | 280 return list==null ? 0 : list.size(); |
325 } | 281 } |
326 | 282 |
327 public Iterable<Map.Entry> iterable(Luan luan) throws LuanException { | 283 public Iterable<Map.Entry> iterable(Luan luan) throws LuanException { |
328 final Iterator<Map.Entry> iter = iterator(luan); | 284 final Iterator<Map.Entry> iter = iterator(luan); |
341 } | 297 } |
342 }; | 298 }; |
343 } | 299 } |
344 | 300 |
345 public Iterator<Map.Entry> iterator(final Luan luan) throws LuanException { | 301 public Iterator<Map.Entry> iterator(final Luan luan) throws LuanException { |
346 if( getHandler("__pairs") == null ) | 302 if( getHandler(luan,"__pairs") == null ) |
347 return rawIterator(); | 303 return rawIterator(); |
348 final LuanFunction fn = pairs(luan); | 304 final LuanFunction fn = pairs(luan); |
349 return new Iterator<Map.Entry>() { | 305 return new Iterator<Map.Entry>() { |
350 private Map.Entry<Object,Object> next = getNext(); | 306 private Map.Entry<Object,Object> next = getNext(); |
351 | 307 |
378 } | 334 } |
379 }; | 335 }; |
380 } | 336 } |
381 | 337 |
382 public LuanFunction pairs(Luan luan) throws LuanException { | 338 public LuanFunction pairs(Luan luan) throws LuanException { |
383 Object h = getHandler("__pairs"); | 339 Object h = getHandler(luan,"__pairs"); |
384 if( h != null ) { | 340 if( h != null ) { |
385 if( h instanceof LuanFunction ) { | 341 if( h instanceof LuanFunction ) { |
386 LuanFunction fn = (LuanFunction)h; | 342 LuanFunction fn = (LuanFunction)h; |
387 Object obj = Luan.first(fn.call(luan,this)); | 343 Object obj = Luan.first(fn.call(luan,this)); |
388 if( !(obj instanceof LuanFunction) ) | 344 if( !(obj instanceof LuanFunction) ) |
406 } | 362 } |
407 }; | 363 }; |
408 } | 364 } |
409 | 365 |
410 public Iterator<Map.Entry> rawIterator() { | 366 public Iterator<Map.Entry> rawIterator() { |
411 check(); | |
412 if( list == null ) { | 367 if( list == null ) { |
413 if( map == null ) | 368 if( map == null ) |
414 return Collections.<Map.Entry>emptyList().iterator(); | 369 return Collections.<Map.Entry>emptyList().iterator(); |
415 return map.entrySet().iterator(); | 370 return map.entrySet().iterator(); |
416 } | 371 } |
460 } | 415 } |
461 }; | 416 }; |
462 } | 417 } |
463 | 418 |
464 public LuanTable rawSubList(int from,int to) { | 419 public LuanTable rawSubList(int from,int to) { |
465 check(); | |
466 LuanTable tbl = new LuanTable(); | 420 LuanTable tbl = new LuanTable(); |
467 tbl.list = new ArrayList<Object>(list().subList(from-1,to-1)); | 421 tbl.list = new ArrayList<Object>(list().subList(from-1,to-1)); |
468 return tbl; | 422 return tbl; |
469 } | 423 } |
470 | 424 |
471 public LuanTable getMetatable() { | 425 public LuanTable getMetatable() { |
472 check(); | |
473 return metatable; | 426 return metatable; |
474 } | 427 } |
475 | 428 |
476 public void setMetatable(LuanTable metatable) throws LuanException { | 429 public void setMetatable(LuanTable metatable) throws LuanException { |
477 check(); | 430 checkMutable(); |
478 this.metatable = metatable; | 431 this.metatable = metatable; |
479 } | 432 } |
480 | 433 |
481 public Object getHandler(String op) throws LuanException { | 434 public Object getHandler(Luan luan,String op) throws LuanException { |
482 check(); | 435 return metatable==null ? null : luan==null ? metatable.rawGet(op) : metatable.get(luan,op); |
483 return metatable==null ? null : metatable.rawGet(op); | |
484 } | 436 } |
485 | 437 |
486 private static Map<Object,Object> newMap() { | 438 private static Map<Object,Object> newMap() { |
487 return new LinkedHashMap<Object,Object>(); | 439 return new LinkedHashMap<Object,Object>(); |
488 } | 440 } |
509 map.put(entry.getKey(),entry.getValue()); | 461 map.put(entry.getKey(),entry.getValue()); |
510 } | 462 } |
511 return map; | 463 return map; |
512 } | 464 } |
513 | 465 |
514 public void rawClear() { | 466 public void rawClear() throws LuanException { |
515 check(); | 467 checkMutable(); |
516 map = null; | 468 map = null; |
517 list = null; | 469 list = null; |
518 } | 470 } |
519 | 471 |
520 public int hashValue() { | 472 public int hashValue() { |
538 n += list.size(); | 490 n += list.size(); |
539 return n; | 491 return n; |
540 } | 492 } |
541 | 493 |
542 public Object remove(Object key) throws LuanException { | 494 public Object remove(Object key) throws LuanException { |
543 if( immutable ) | 495 checkMutable(); |
544 throw new LuanException("table is immutable"); | |
545 Object old = rawGet(key); | 496 Object old = rawGet(key); |
546 rawPut(key,null); | 497 rawPut(key,null); |
547 return old; | 498 return old; |
548 } | 499 } |
549 | 500 |
550 protected void finalize() throws Throwable { | 501 protected void finalize() throws Throwable { |
551 Object h = getHandler("__gc"); | 502 Object h = getHandler(null,"__gc"); |
552 if( h != null ) { | 503 if( h != null ) { |
553 LuanFunction fn = Luan.checkFunction(h); | 504 LuanFunction fn = Luan.checkFunction(h); |
554 fn.call(new Luan(),this); // ??? should be immutable | 505 fn.call(new Luan(),this); // ??? should be immutable |
555 } | 506 } |
556 super.finalize(); | 507 super.finalize(); |