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();