comparison core/src/luan/LuanTable.java @ 408:1b38de2b1845

merge LuanTableImpl into LuanTable
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 29 Apr 2015 13:15:17 -0600
parents core/src/luan/LuanTableImpl.java@9321a33b9b1c
children 23b99a5039b5
comparison
equal deleted inserted replaced
407:7fd9f1b7b878 408:1b38de2b1845
1 package luan; 1 package luan;
2 2
3 import java.util.Iterator;
4 import java.util.ListIterator;
3 import java.util.Map; 5 import java.util.Map;
6 import java.util.AbstractMap;
7 import java.util.LinkedHashMap;
4 import java.util.List; 8 import java.util.List;
9 import java.util.ArrayList;
10 import java.util.Collections;
11 import java.util.Comparator;
5 import java.util.Set; 12 import java.util.Set;
6 import java.util.Comparator; 13 import java.util.HashSet;
7 14 import java.util.IdentityHashMap;
8 15 import java.util.regex.Pattern;
9 public interface LuanTable extends Iterable<Map.Entry<Object,Object>> { 16
10 public boolean isEmpty(); 17
11 public boolean isList(); 18 public final class LuanTable implements Iterable<Map.Entry<Object,Object>>, LuanRepr, DeepCloneable<LuanTable> {
12 public boolean isSet(); 19 private Map<Object,Object> map = null;
13 public Set<Object> asSet(); 20 private List<Object> list = null;
14 public List<Object> asList(); 21 private LuanTable metatable = null;
15 public Map<Object,Object> asMap(); 22 private boolean hasJava = false;
16 public Object get(Object key); 23
17 public void put(Object key,Object val); 24 public LuanTable() {}
18 public void insert(int pos,Object value); 25
19 public void add(Object value); 26 LuanTable(List<Object> list) {
20 public Object remove(int pos); 27 this.list = list;
21 public void sort(Comparator<Object> cmp); 28 this.map = newMap();
22 public int length(); 29 map.put("n",list.size());
23 public LuanTable subList(int from,int to); 30 for( int i=0; i<list.size(); i++ ) {
24 public LuanTable getMetatable(); 31 if( list.get(i) == null ) {
25 public void setMetatable(LuanTable metatable); 32 listToMap(i);
26 public LuanTable cloneTable(); 33 break;
27 public boolean hasJava(); 34 }
28 public void setJava(); 35 }
36 }
37
38 LuanTable(Map<Object,Object> map) {
39 map.remove(null);
40 for( Iterator<Object> i=map.values().iterator(); i.hasNext(); ) {
41 if( i.next() == null )
42 i.remove();
43 }
44 this.map = map;
45 }
46
47 LuanTable(Set<Object> set) {
48 map = newMap();
49 for( Object obj : set ) {
50 if( obj != null )
51 map.put(obj,Boolean.TRUE);
52 }
53 }
54
55 @Override public LuanTable shallowClone() {
56 return new LuanTable();
57 }
58
59 @Override public void deepenClone(LuanTable clone,DeepCloner cloner) {
60 if( map != null ) {
61 clone.map = newMap();
62 for( Map.Entry<Object,Object> entry : map.entrySet() ) {
63 clone.map.put( cloner.get(entry.getKey()), cloner.get(entry.getValue()) );
64 }
65 }
66 if( list != null ) {
67 clone.list = new ArrayList<Object>();
68 for( Object obj : list ) {
69 clone.list.add( cloner.get(obj) );
70 }
71 }
72 if( metatable != null )
73 clone.metatable = cloner.get(metatable);
74 clone.hasJava = hasJava;
75 }
76
77 public boolean isList() {
78 return map==null || map.isEmpty();
79 }
80
81 public List<Object> asList() {
82 return list!=null ? list : Collections.emptyList();
83 }
84
85 private Map<Object,Object> map() {
86 return map!=null ? map : Collections.emptyMap();
87 }
88 /*
89 @Override public boolean isSet() {
90 if( list != null ) {
91 for( Object obj : list ) {
92 if( obj!=null && !obj.equals(Boolean.TRUE) )
93 return false;
94 }
95 }
96 if( map != null ) {
97 for( Object obj : map.values() ) {
98 if( !obj.equals(Boolean.TRUE) )
99 return false;
100 }
101 }
102 return true;
103 }
104
105 @Override public Set<Object> asSet() {
106 if( list == null || list.isEmpty() )
107 return map!=null ? map.keySet() : Collections.emptySet();
108 Set<Object> rtn = map!=null ? new HashSet<Object>(map.keySet()) : new HashSet<Object>();
109 for( int i=1; i<=list.size(); i++ ) {
110 rtn.add(i);
111 }
112 return rtn;
113 }
114 */
115 protected String type() {
116 return "table";
117 }
118
119 public Object get(Object key) {
120 if( list != null ) {
121 Integer iT = Luan.asInteger(key);
122 if( iT != null ) {
123 int i = iT - 1;
124 if( i>=0 && i<list.size() )
125 return list.get(i);
126 }
127 }
128 if( map==null )
129 return null;
130 return map.get(key);
131 }
132
133 public void put(Object key,Object val) {
134 Integer iT = Luan.asInteger(key);
135 if( iT != null ) {
136 int i = iT - 1;
137 if( list != null || i == 0 ) {
138 if( i == list().size() ) {
139 if( val != null ) {
140 list.add(val);
141 mapToList();
142 }
143 return;
144 } else if( i>=0 && i<list.size() ) {
145 list.set(i,val);
146 if( val == null ) {
147 listToMap(i);
148 }
149 return;
150 }
151 }
152 }
153 if( map==null ) {
154 map = newMap();
155 }
156 if( key instanceof Number && !(key instanceof Double) ) {
157 Number n = (Number)key;
158 key = Double.valueOf(n.doubleValue());
159 }
160 if( val == null ) {
161 map.remove(key);
162 } else {
163 map.put(key,val);
164 }
165 }
166
167 private void mapToList() {
168 if( map != null ) {
169 while(true) {
170 Object v = map.remove(Double.valueOf(list.size()+1));
171 if( v == null )
172 break;
173 list.add(v);
174 }
175 }
176 }
177
178 private void listToMap(int from) {
179 if( list != null ) {
180 while( list.size() > from ) {
181 int i = list.size() - 1;
182 Object v = list.remove(i);
183 if( v != null ) {
184 if( map==null )
185 map = newMap();
186 map.put(i+1,v);
187 }
188 }
189 }
190 }
191
192 private List<Object> list() {
193 if( list == null ) {
194 list = new ArrayList<Object>();
195 mapToList();
196 }
197 return list;
198 }
199
200 public void insert(int pos,Object value) {
201 if( value==null )
202 throw new IllegalArgumentException("can't insert a nil value");
203 list().add(pos-1,value);
204 mapToList();
205 }
206
207 public void add(Object value) {
208 if( value==null )
209 throw new IllegalArgumentException("can't add a nil value");
210 list().add(value);
211 mapToList();
212 }
213
214 public Object remove(int pos) {
215 return list().remove(pos-1);
216 }
217
218 public void sort(Comparator<Object> cmp) {
219 Collections.sort(list(),cmp);
220 }
221
222 public int length() {
223 return list==null ? 0 : list.size();
224 }
225
226 @Override public Iterator<Map.Entry<Object,Object>> iterator() {
227 if( list == null ) {
228 if( map == null )
229 return Collections.<Map.Entry<Object,Object>>emptyList().iterator();
230 return map.entrySet().iterator();
231 }
232 if( map == null )
233 return listIterator();
234 return new Iterator<Map.Entry<Object,Object>>() {
235 Iterator<Map.Entry<Object,Object>> iter = listIterator();
236 boolean isList = true;
237 public boolean hasNext() {
238 boolean b = iter.hasNext();
239 if( !b && isList ) {
240 iter = map.entrySet().iterator();
241 isList = false;
242 b = iter.hasNext();
243 }
244 return b;
245 }
246 public Map.Entry<Object,Object> next() {
247 return iter.next();
248 }
249 public void remove() {
250 throw new UnsupportedOperationException();
251 }
252 };
253 }
254
255 private Iterator<Map.Entry<Object,Object>> listIterator() {
256 if( list == null )
257 return Collections.<Map.Entry<Object,Object>>emptyList().iterator();
258 final ListIterator iter = list.listIterator();
259 return new Iterator<Map.Entry<Object,Object>>() {
260 public boolean hasNext() {
261 return iter.hasNext();
262 }
263 public Map.Entry<Object,Object> next() {
264 Double key = Double.valueOf(iter.nextIndex()+1);
265 return new AbstractMap.SimpleEntry<Object,Object>(key,iter.next());
266 }
267 public void remove() {
268 throw new UnsupportedOperationException();
269 }
270 };
271 }
272
273 public LuanTable subList(int from,int to) {
274 LuanTable tbl = shallowClone();
275 tbl.list = new ArrayList<Object>(list().subList(from-1,to-1));
276 return tbl;
277 }
278
279 public LuanTable getMetatable() {
280 return metatable;
281 }
282
283 public void setMetatable(LuanTable metatable) {
284 this.metatable = metatable;
285 }
286
287 public boolean hasJava() {
288 return hasJava;
289 }
290
291 public void setJava() {
292 hasJava = true;
293 }
294
295
296 // from AbstractLuanTable
297
298 protected final Map<Object,Object> newMap() {
299 return new LinkedHashMap<Object,Object>();
300 }
301
302 public boolean isEmpty() {
303 return isList() && length()==0;
304 }
305
306 public boolean isSet() {
307 for( Map.Entry<Object,Object> entry : this ) {
308 if( !entry.getValue().equals(Boolean.TRUE) )
309 return false;
310 }
311 return true;
312 }
313
314 public Set<Object> asSet() {
315 Set<Object> set = new HashSet<Object>();
316 for( Map.Entry<Object,Object> entry : this ) {
317 set.add(entry.getKey());
318 }
319 return set;
320 }
321
322 public Map<Object,Object> asMap() {
323 Map<Object,Object> map = newMap();
324 for( Map.Entry<Object,Object> entry : this ) {
325 map.put(entry.getKey(),entry.getValue());
326 }
327 return map;
328 }
329
330 public LuanTable cloneTable() {
331 return isList() ? new LuanTable(new ArrayList<Object>(asList())) : new LuanTable(asMap());
332 }
333
334 @Override public String repr() {
335 return repr( Collections.newSetFromMap(new IdentityHashMap<LuanTable,Boolean>()) );
336 }
337
338 private String repr(Set<LuanTable> set) {
339 if( !set.add(this) ) {
340 return "\"<circular reference>\"";
341 }
342 StringBuilder sb = new StringBuilder();
343 sb.append('{');
344 boolean isFirst = true;
345 for( Object obj : asList() ) {
346 if( isFirst ) {
347 isFirst = false;
348 } else {
349 sb.append(", ");
350 }
351 sb.append(repr(set,obj));
352 }
353 for( Map.Entry<Object,Object> entry : map().entrySet() ) {
354 if( isFirst ) {
355 isFirst = false;
356 } else {
357 sb.append(", ");
358 }
359 sb.append(reprKey(set,entry.getKey())).append('=').append(repr(set,entry.getValue()));
360 }
361 sb.append('}');
362 return sb.toString();
363 }
364
365 private static final Pattern namePtn = Pattern.compile("[a-zA-Z_][a-zA-Z_0-9]*");
366
367 private String reprKey(Set<LuanTable> set,Object obj) {
368 if( obj instanceof String ) {
369 String s = (String)obj;
370 if( namePtn.matcher(s).matches() )
371 return s;
372 }
373 return "[" + repr(set,obj) + "]";
374 }
375
376 String repr(Set<LuanTable> set,Object obj) {
377 if( obj instanceof LuanTable ) {
378 LuanTable t = (LuanTable)obj;
379 return t.repr(set);
380 } else {
381 String s = Luan.repr(obj);
382 if( s == null )
383 s = "<couldn't repr: " + Luan.stringEncode(Luan.toString(obj)) + ">";
384 return s;
385 }
386 }
387
29 } 388 }