Mercurial Hosting > luan
comparison src/luan/LuanTable.java @ 775:1a68fc55a80c
simplify dir structure
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Fri, 26 Aug 2016 14:36:40 -0600 |
parents | core/src/luan/LuanTable.java@d3e5414bdf4c |
children | fbbdd369a13a |
comparison
equal
deleted
inserted
replaced
774:3e30cf310e56 | 775:1a68fc55a80c |
---|---|
1 package luan; | |
2 | |
3 import java.util.Iterator; | |
4 import java.util.ListIterator; | |
5 import java.util.Map; | |
6 import java.util.AbstractMap; | |
7 import java.util.LinkedHashMap; | |
8 import java.util.List; | |
9 import java.util.ArrayList; | |
10 import java.util.Collections; | |
11 import java.util.Comparator; | |
12 import java.util.Set; | |
13 import java.util.HashSet; | |
14 | |
15 | |
16 public final class LuanTable implements DeepCloneable { | |
17 private Map map = null; | |
18 private List list = null; | |
19 private LuanTable metatable = null; | |
20 public LuanJava java; | |
21 | |
22 public LuanTable() {} | |
23 | |
24 public LuanTable(List list) { | |
25 int n = list.size(); | |
26 for( int i=0; i<n; i++ ) { | |
27 Object val = list.get(i); | |
28 if( val != null ) | |
29 rawPut(i+1,val); | |
30 } | |
31 } | |
32 | |
33 public LuanTable(Map map) { | |
34 for( Object stupid : map.entrySet() ) { | |
35 Map.Entry entry = (Map.Entry)stupid; | |
36 Object key = entry.getKey(); | |
37 Object value = entry.getValue(); | |
38 if( key != null && value != null ) | |
39 rawPut(key,value); | |
40 } | |
41 } | |
42 | |
43 public LuanTable(Set set) { | |
44 for( Object el : set ) { | |
45 if( el != null ) | |
46 rawPut(el,Boolean.TRUE); | |
47 } | |
48 } | |
49 | |
50 public LuanTable(LuanTable tbl) { | |
51 if( tbl.map != null && !tbl.map.isEmpty() ) | |
52 this.map = new LinkedHashMap<Object,Object>(tbl.map); | |
53 if( tbl.rawLength() > 0 ) | |
54 this.list = new ArrayList<Object>(tbl.list); | |
55 this.metatable = tbl.metatable; | |
56 } | |
57 | |
58 @Override public LuanTable shallowClone() { | |
59 return new LuanTable(); | |
60 } | |
61 | |
62 @Override public void deepenClone(DeepCloneable dc,DeepCloner cloner) { | |
63 LuanTable clone = (LuanTable)dc; | |
64 if( map != null ) { | |
65 clone.map = newMap(); | |
66 for( Object stupid : map.entrySet() ) { | |
67 Map.Entry entry = (Map.Entry)stupid; | |
68 clone.map.put( cloner.get(entry.getKey()), cloner.get(entry.getValue()) ); | |
69 } | |
70 } | |
71 if( list != null ) { | |
72 clone.list = new ArrayList<Object>(); | |
73 for( Object obj : list ) { | |
74 clone.list.add( cloner.get(obj) ); | |
75 } | |
76 } | |
77 if( metatable != null ) | |
78 clone.metatable = (LuanTable)cloner.get(metatable); | |
79 clone.java = (LuanJava)cloner.deepClone(java); | |
80 } | |
81 | |
82 public boolean isList() { | |
83 return map==null || map.isEmpty(); | |
84 } | |
85 | |
86 public List<Object> asList() { | |
87 return list!=null ? list : Collections.emptyList(); | |
88 } | |
89 | |
90 public String toString(LuanState luan) throws LuanException { | |
91 Object h = getHandler("__to_string"); | |
92 if( h == null ) | |
93 return rawToString(); | |
94 if( h instanceof LuanMeta ) { | |
95 LuanMeta meta = (LuanMeta)h; | |
96 return meta.__to_string(luan,this); | |
97 } | |
98 LuanFunction fn = Luan.checkFunction(h); | |
99 return Luan.checkString( Luan.first( fn.call(luan,new Object[]{this}) ) ); | |
100 } | |
101 | |
102 public String rawToString() { | |
103 return "table: " + Integer.toHexString(hashCode()); | |
104 } | |
105 | |
106 public Object get(LuanState luan,Object key) throws LuanException { | |
107 Object value = rawGet(key); | |
108 if( value != null ) | |
109 return value; | |
110 Object h = getHandler("__index"); | |
111 if( h==null ) | |
112 return null; | |
113 if( h instanceof LuanFunction ) { | |
114 LuanFunction fn = (LuanFunction)h; | |
115 return Luan.first(fn.call(luan,new Object[]{this,key})); | |
116 } | |
117 if( h instanceof LuanMeta ) { | |
118 LuanMeta meta = (LuanMeta)h; | |
119 return meta.__index(luan,this,key); | |
120 } | |
121 return luan.index(h,key); | |
122 } | |
123 | |
124 public Object rawGet(Object key) { | |
125 if( list != null ) { | |
126 Integer iT = Luan.asInteger(key); | |
127 if( iT != null ) { | |
128 int i = iT - 1; | |
129 if( i>=0 && i<list.size() ) | |
130 return list.get(i); | |
131 } | |
132 } | |
133 if( map==null ) | |
134 return null; | |
135 if( key instanceof Number && !(key instanceof Double) ) { | |
136 Number n = (Number)key; | |
137 key = Double.valueOf(n.doubleValue()); | |
138 } | |
139 return map.get(key); | |
140 } | |
141 | |
142 public void put(LuanState luan,Object key,Object value) throws LuanException { | |
143 Object h = getHandler("__new_index"); | |
144 if( h==null || rawGet(key)!=null ) { | |
145 rawPut(key,value); | |
146 return; | |
147 } | |
148 if( h instanceof LuanFunction ) { | |
149 LuanFunction fn = (LuanFunction)h; | |
150 fn.call(luan,new Object[]{this,key,value}); | |
151 return; | |
152 } | |
153 if( h instanceof LuanMeta ) { | |
154 LuanMeta meta = (LuanMeta)h; | |
155 meta.__new_index(luan,this,key,value); | |
156 return; | |
157 } | |
158 if( h instanceof LuanTable ) { | |
159 LuanTable tbl = (LuanTable)h; | |
160 tbl.put(luan,key,value); | |
161 return; | |
162 } | |
163 throw new LuanException("invalid type "+Luan.type(h)+" for metamethod __new_index"); | |
164 } | |
165 | |
166 public void rawPut(Object key,Object val) { | |
167 Integer iT = Luan.asInteger(key); | |
168 if( iT != null ) { | |
169 int i = iT - 1; | |
170 if( list != null || i == 0 ) { | |
171 if( i == list().size() ) { | |
172 if( val != null ) { | |
173 list.add(val); | |
174 mapToList(); | |
175 } | |
176 return; | |
177 } else if( i>=0 && i<list.size() ) { | |
178 list.set(i,val); | |
179 if( val == null ) { | |
180 listToMap(i); | |
181 } | |
182 return; | |
183 } | |
184 } | |
185 } | |
186 if( map==null ) | |
187 map = newMap(); | |
188 if( key instanceof Number && !(key instanceof Double) ) { | |
189 Number n = (Number)key; | |
190 key = Double.valueOf(n.doubleValue()); | |
191 } | |
192 if( val == null ) { | |
193 map.remove(key); | |
194 } else { | |
195 map.put(key,val); | |
196 } | |
197 } | |
198 | |
199 private void mapToList() { | |
200 if( map != null ) { | |
201 while(true) { | |
202 Object v = map.remove(Double.valueOf(list.size()+1)); | |
203 if( v == null ) | |
204 break; | |
205 list.add(v); | |
206 } | |
207 } | |
208 } | |
209 | |
210 private void listToMap(int from) { | |
211 if( list != null ) { | |
212 while( list.size() > from ) { | |
213 int i = list.size() - 1; | |
214 Object v = list.remove(i); | |
215 if( v != null ) { | |
216 if( map==null ) | |
217 map = newMap(); | |
218 map.put(i+1,v); | |
219 } | |
220 } | |
221 } | |
222 } | |
223 | |
224 private List<Object> list() { | |
225 if( list == null ) { | |
226 list = new ArrayList<Object>(); | |
227 mapToList(); | |
228 } | |
229 return list; | |
230 } | |
231 | |
232 public void rawInsert(int pos,Object value) { | |
233 if( value==null ) | |
234 throw new IllegalArgumentException("can't insert a nil value"); | |
235 list().add(pos-1,value); | |
236 mapToList(); | |
237 } | |
238 | |
239 public Object rawRemove(int pos) { | |
240 return list().remove(pos-1); | |
241 } | |
242 | |
243 public void rawSort(Comparator<Object> cmp) { | |
244 Collections.sort(list(),cmp); | |
245 } | |
246 | |
247 public int length(LuanState luan) throws LuanException { | |
248 Object h = getHandler("__len"); | |
249 if( h != null ) { | |
250 LuanFunction fn = Luan.checkFunction(h); | |
251 return (Integer)Luan.first(fn.call(luan,new Object[]{this})); | |
252 } | |
253 return rawLength(); | |
254 } | |
255 | |
256 public int rawLength() { | |
257 return list==null ? 0 : list.size(); | |
258 } | |
259 | |
260 public Iterable<Map.Entry<Object,Object>> iterable(LuanState luan) throws LuanException { | |
261 final Iterator<Map.Entry<Object,Object>> iter = iterator(luan); | |
262 return new Iterable<Map.Entry<Object,Object>>() { | |
263 public Iterator<Map.Entry<Object,Object>> iterator() { | |
264 return iter; | |
265 } | |
266 }; | |
267 } | |
268 | |
269 public Iterable<Map.Entry<Object,Object>> rawIterable() throws LuanException { | |
270 final Iterator<Map.Entry<Object,Object>> iter = rawIterator(); | |
271 return new Iterable<Map.Entry<Object,Object>>() { | |
272 public Iterator<Map.Entry<Object,Object>> iterator() { | |
273 return iter; | |
274 } | |
275 }; | |
276 } | |
277 | |
278 public Iterator<Map.Entry<Object,Object>> iterator(final LuanState luan) throws LuanException { | |
279 if( getHandler("__pairs") == null ) | |
280 return rawIterator(); | |
281 final LuanFunction fn = pairs(luan); | |
282 return new Iterator<Map.Entry<Object,Object>>() { | |
283 private Map.Entry<Object,Object> next = getNext(); | |
284 | |
285 private Map.Entry<Object,Object> getNext() { | |
286 try { | |
287 Object obj = fn.call(luan); | |
288 if( obj==null ) | |
289 return null; | |
290 Object[] a = (Object[])obj; | |
291 if( a.length == 0 || a[0]==null ) | |
292 return null; | |
293 return new AbstractMap.SimpleEntry<Object,Object>(a[0],a[1]); | |
294 } catch(LuanException e) { | |
295 throw new LuanRuntimeException(e); | |
296 } | |
297 } | |
298 | |
299 public boolean hasNext() { | |
300 return next != null; | |
301 } | |
302 | |
303 public Map.Entry<Object,Object> next() { | |
304 Map.Entry<Object,Object> rtn = next; | |
305 next = getNext(); | |
306 return rtn; | |
307 } | |
308 | |
309 public void remove() { | |
310 throw new UnsupportedOperationException(); | |
311 } | |
312 }; | |
313 } | |
314 | |
315 public LuanFunction pairs(LuanState luan) throws LuanException { | |
316 Object h = getHandler("__pairs"); | |
317 if( h != null ) { | |
318 if( h instanceof LuanFunction ) { | |
319 LuanFunction fn = (LuanFunction)h; | |
320 Object obj = Luan.first(fn.call(luan,new Object[]{this})); | |
321 if( !(obj instanceof LuanFunction) ) | |
322 throw new LuanException( "metamethod __pairs should return function but returned " + Luan.type(obj) ); | |
323 return (LuanFunction)obj; | |
324 } | |
325 if( h instanceof LuanMeta ) { | |
326 LuanMeta meta = (LuanMeta)h; | |
327 return meta.__pairs(luan,this); | |
328 } | |
329 throw new LuanException( "invalid type of metamethod __pairs: " + Luan.type(h) ); | |
330 } | |
331 return rawPairs(); | |
332 } | |
333 | |
334 private LuanFunction rawPairs() { | |
335 return new LuanFunction() { | |
336 final Iterator<Map.Entry<Object,Object>> iter = rawIterator(); | |
337 | |
338 @Override public Object[] call(LuanState luan,Object[] args) { | |
339 if( !iter.hasNext() ) | |
340 return LuanFunction.NOTHING; | |
341 Map.Entry<Object,Object> entry = iter.next(); | |
342 return new Object[]{entry.getKey(),entry.getValue()}; | |
343 } | |
344 }; | |
345 } | |
346 | |
347 public Iterator<Map.Entry<Object,Object>> rawIterator() { | |
348 if( list == null ) { | |
349 if( map == null ) | |
350 return Collections.<Map.Entry<Object,Object>>emptyList().iterator(); | |
351 return map.entrySet().iterator(); | |
352 } | |
353 if( map == null ) | |
354 return listIterator(); | |
355 return new Iterator<Map.Entry<Object,Object>>() { | |
356 Iterator<Map.Entry<Object,Object>> iter = listIterator(); | |
357 boolean isList = true; | |
358 | |
359 public boolean hasNext() { | |
360 boolean b = iter.hasNext(); | |
361 if( !b && isList ) { | |
362 iter = map.entrySet().iterator(); | |
363 isList = false; | |
364 b = iter.hasNext(); | |
365 } | |
366 return b; | |
367 } | |
368 | |
369 public Map.Entry<Object,Object> next() { | |
370 return iter.next(); | |
371 } | |
372 | |
373 public void remove() { | |
374 throw new UnsupportedOperationException(); | |
375 } | |
376 }; | |
377 } | |
378 | |
379 private Iterator<Map.Entry<Object,Object>> listIterator() { | |
380 if( list == null ) | |
381 return Collections.<Map.Entry<Object,Object>>emptyList().iterator(); | |
382 final ListIterator iter = list.listIterator(); | |
383 return new Iterator<Map.Entry<Object,Object>>() { | |
384 | |
385 public boolean hasNext() { | |
386 return iter.hasNext(); | |
387 } | |
388 | |
389 public Map.Entry<Object,Object> next() { | |
390 Integer key = iter.nextIndex()+1; | |
391 return new AbstractMap.SimpleEntry<Object,Object>(key,iter.next()); | |
392 } | |
393 | |
394 public void remove() { | |
395 throw new UnsupportedOperationException(); | |
396 } | |
397 }; | |
398 } | |
399 | |
400 public LuanTable rawSubList(int from,int to) { | |
401 LuanTable tbl = shallowClone(); | |
402 tbl.list = new ArrayList<Object>(list().subList(from-1,to-1)); | |
403 return tbl; | |
404 } | |
405 | |
406 public LuanTable getMetatable() { | |
407 return metatable; | |
408 } | |
409 | |
410 public void setMetatable(LuanTable metatable) { | |
411 this.metatable = metatable; | |
412 } | |
413 | |
414 public Object getHandler(String op) { | |
415 return metatable==null ? null : metatable.rawGet(op); | |
416 } | |
417 | |
418 private Map<Object,Object> newMap() { | |
419 return new LinkedHashMap<Object,Object>(); | |
420 } | |
421 | |
422 public boolean isSet(LuanState luan) throws LuanException { | |
423 for( Map.Entry<Object,Object> entry : iterable(luan) ) { | |
424 if( !entry.getValue().equals(Boolean.TRUE) ) | |
425 return false; | |
426 } | |
427 return true; | |
428 } | |
429 | |
430 public Set<Object> asSet(LuanState luan) throws LuanException { | |
431 Set<Object> set = new HashSet<Object>(); | |
432 for( Map.Entry<Object,Object> entry : iterable(luan) ) { | |
433 set.add(entry.getKey()); | |
434 } | |
435 return set; | |
436 } | |
437 | |
438 public Map<Object,Object> asMap(LuanState luan) throws LuanException { | |
439 Map<Object,Object> map = newMap(); | |
440 for( Map.Entry<Object,Object> entry : iterable(luan) ) { | |
441 map.put(entry.getKey(),entry.getValue()); | |
442 } | |
443 return map; | |
444 } | |
445 | |
446 public void rawClear() { | |
447 map = null; | |
448 list = null; | |
449 } | |
450 | |
451 } |