Mercurial Hosting > luan
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/LuanTable.java Fri Aug 26 14:36:40 2016 -0600 @@ -0,0 +1,451 @@ +package luan; + +import java.util.Iterator; +import java.util.ListIterator; +import java.util.Map; +import java.util.AbstractMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Set; +import java.util.HashSet; + + +public final class LuanTable implements DeepCloneable { + private Map map = null; + private List list = null; + private LuanTable metatable = null; + public LuanJava java; + + public LuanTable() {} + + public LuanTable(List list) { + int n = list.size(); + for( int i=0; i<n; i++ ) { + Object val = list.get(i); + if( val != null ) + rawPut(i+1,val); + } + } + + public LuanTable(Map map) { + for( Object stupid : map.entrySet() ) { + Map.Entry entry = (Map.Entry)stupid; + Object key = entry.getKey(); + Object value = entry.getValue(); + if( key != null && value != null ) + rawPut(key,value); + } + } + + public LuanTable(Set set) { + for( Object el : set ) { + if( el != null ) + rawPut(el,Boolean.TRUE); + } + } + + public LuanTable(LuanTable tbl) { + if( tbl.map != null && !tbl.map.isEmpty() ) + this.map = new LinkedHashMap<Object,Object>(tbl.map); + if( tbl.rawLength() > 0 ) + this.list = new ArrayList<Object>(tbl.list); + this.metatable = tbl.metatable; + } + + @Override public LuanTable shallowClone() { + return new LuanTable(); + } + + @Override public void deepenClone(DeepCloneable dc,DeepCloner cloner) { + LuanTable clone = (LuanTable)dc; + if( map != null ) { + clone.map = newMap(); + for( Object stupid : map.entrySet() ) { + Map.Entry entry = (Map.Entry)stupid; + clone.map.put( cloner.get(entry.getKey()), cloner.get(entry.getValue()) ); + } + } + if( list != null ) { + clone.list = new ArrayList<Object>(); + for( Object obj : list ) { + clone.list.add( cloner.get(obj) ); + } + } + if( metatable != null ) + clone.metatable = (LuanTable)cloner.get(metatable); + clone.java = (LuanJava)cloner.deepClone(java); + } + + public boolean isList() { + return map==null || map.isEmpty(); + } + + public List<Object> asList() { + return list!=null ? list : Collections.emptyList(); + } + + public String toString(LuanState luan) throws LuanException { + Object h = getHandler("__to_string"); + if( h == null ) + return rawToString(); + if( h instanceof LuanMeta ) { + LuanMeta meta = (LuanMeta)h; + return meta.__to_string(luan,this); + } + LuanFunction fn = Luan.checkFunction(h); + return Luan.checkString( Luan.first( fn.call(luan,new Object[]{this}) ) ); + } + + public String rawToString() { + return "table: " + Integer.toHexString(hashCode()); + } + + public Object get(LuanState luan,Object key) throws LuanException { + Object value = rawGet(key); + if( value != null ) + return value; + Object h = getHandler("__index"); + if( h==null ) + return null; + if( h instanceof LuanFunction ) { + LuanFunction fn = (LuanFunction)h; + return Luan.first(fn.call(luan,new Object[]{this,key})); + } + if( h instanceof LuanMeta ) { + LuanMeta meta = (LuanMeta)h; + return meta.__index(luan,this,key); + } + return luan.index(h,key); + } + + public Object rawGet(Object key) { + if( list != null ) { + Integer iT = Luan.asInteger(key); + if( iT != null ) { + int i = iT - 1; + if( i>=0 && i<list.size() ) + return list.get(i); + } + } + if( map==null ) + return null; + if( key instanceof Number && !(key instanceof Double) ) { + Number n = (Number)key; + key = Double.valueOf(n.doubleValue()); + } + return map.get(key); + } + + public void put(LuanState luan,Object key,Object value) throws LuanException { + Object h = getHandler("__new_index"); + if( h==null || rawGet(key)!=null ) { + rawPut(key,value); + return; + } + if( h instanceof LuanFunction ) { + LuanFunction fn = (LuanFunction)h; + fn.call(luan,new Object[]{this,key,value}); + return; + } + if( h instanceof LuanMeta ) { + LuanMeta meta = (LuanMeta)h; + meta.__new_index(luan,this,key,value); + return; + } + if( h instanceof LuanTable ) { + LuanTable tbl = (LuanTable)h; + tbl.put(luan,key,value); + return; + } + throw new LuanException("invalid type "+Luan.type(h)+" for metamethod __new_index"); + } + + public void rawPut(Object key,Object val) { + Integer iT = Luan.asInteger(key); + if( iT != null ) { + int i = iT - 1; + if( list != null || i == 0 ) { + if( i == list().size() ) { + if( val != null ) { + list.add(val); + mapToList(); + } + return; + } else if( i>=0 && i<list.size() ) { + list.set(i,val); + if( val == null ) { + listToMap(i); + } + return; + } + } + } + if( map==null ) + map = newMap(); + if( key instanceof Number && !(key instanceof Double) ) { + Number n = (Number)key; + key = Double.valueOf(n.doubleValue()); + } + if( val == null ) { + map.remove(key); + } else { + map.put(key,val); + } + } + + private void mapToList() { + if( map != null ) { + while(true) { + Object v = map.remove(Double.valueOf(list.size()+1)); + if( v == null ) + break; + list.add(v); + } + } + } + + private void listToMap(int from) { + if( list != null ) { + while( list.size() > from ) { + int i = list.size() - 1; + Object v = list.remove(i); + if( v != null ) { + if( map==null ) + map = newMap(); + map.put(i+1,v); + } + } + } + } + + private List<Object> list() { + if( list == null ) { + list = new ArrayList<Object>(); + mapToList(); + } + return list; + } + + public void rawInsert(int pos,Object value) { + if( value==null ) + throw new IllegalArgumentException("can't insert a nil value"); + list().add(pos-1,value); + mapToList(); + } + + public Object rawRemove(int pos) { + return list().remove(pos-1); + } + + public void rawSort(Comparator<Object> cmp) { + Collections.sort(list(),cmp); + } + + public int length(LuanState luan) throws LuanException { + Object h = getHandler("__len"); + if( h != null ) { + LuanFunction fn = Luan.checkFunction(h); + return (Integer)Luan.first(fn.call(luan,new Object[]{this})); + } + return rawLength(); + } + + public int rawLength() { + return list==null ? 0 : list.size(); + } + + public Iterable<Map.Entry<Object,Object>> iterable(LuanState luan) throws LuanException { + final Iterator<Map.Entry<Object,Object>> iter = iterator(luan); + return new Iterable<Map.Entry<Object,Object>>() { + public Iterator<Map.Entry<Object,Object>> iterator() { + return iter; + } + }; + } + + public Iterable<Map.Entry<Object,Object>> rawIterable() throws LuanException { + final Iterator<Map.Entry<Object,Object>> iter = rawIterator(); + return new Iterable<Map.Entry<Object,Object>>() { + public Iterator<Map.Entry<Object,Object>> iterator() { + return iter; + } + }; + } + + public Iterator<Map.Entry<Object,Object>> iterator(final LuanState luan) throws LuanException { + if( getHandler("__pairs") == null ) + return rawIterator(); + final LuanFunction fn = pairs(luan); + return new Iterator<Map.Entry<Object,Object>>() { + private Map.Entry<Object,Object> next = getNext(); + + private Map.Entry<Object,Object> getNext() { + try { + Object obj = fn.call(luan); + if( obj==null ) + return null; + Object[] a = (Object[])obj; + if( a.length == 0 || a[0]==null ) + return null; + return new AbstractMap.SimpleEntry<Object,Object>(a[0],a[1]); + } catch(LuanException e) { + throw new LuanRuntimeException(e); + } + } + + public boolean hasNext() { + return next != null; + } + + public Map.Entry<Object,Object> next() { + Map.Entry<Object,Object> rtn = next; + next = getNext(); + return rtn; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + public LuanFunction pairs(LuanState luan) throws LuanException { + Object h = getHandler("__pairs"); + if( h != null ) { + if( h instanceof LuanFunction ) { + LuanFunction fn = (LuanFunction)h; + Object obj = Luan.first(fn.call(luan,new Object[]{this})); + if( !(obj instanceof LuanFunction) ) + throw new LuanException( "metamethod __pairs should return function but returned " + Luan.type(obj) ); + return (LuanFunction)obj; + } + if( h instanceof LuanMeta ) { + LuanMeta meta = (LuanMeta)h; + return meta.__pairs(luan,this); + } + throw new LuanException( "invalid type of metamethod __pairs: " + Luan.type(h) ); + } + return rawPairs(); + } + + private LuanFunction rawPairs() { + return new LuanFunction() { + final Iterator<Map.Entry<Object,Object>> iter = rawIterator(); + + @Override public Object[] call(LuanState luan,Object[] args) { + if( !iter.hasNext() ) + return LuanFunction.NOTHING; + Map.Entry<Object,Object> entry = iter.next(); + return new Object[]{entry.getKey(),entry.getValue()}; + } + }; + } + + public Iterator<Map.Entry<Object,Object>> rawIterator() { + if( list == null ) { + if( map == null ) + return Collections.<Map.Entry<Object,Object>>emptyList().iterator(); + return map.entrySet().iterator(); + } + if( map == null ) + return listIterator(); + return new Iterator<Map.Entry<Object,Object>>() { + Iterator<Map.Entry<Object,Object>> iter = listIterator(); + boolean isList = true; + + public boolean hasNext() { + boolean b = iter.hasNext(); + if( !b && isList ) { + iter = map.entrySet().iterator(); + isList = false; + b = iter.hasNext(); + } + return b; + } + + public Map.Entry<Object,Object> next() { + return iter.next(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + private Iterator<Map.Entry<Object,Object>> listIterator() { + if( list == null ) + return Collections.<Map.Entry<Object,Object>>emptyList().iterator(); + final ListIterator iter = list.listIterator(); + return new Iterator<Map.Entry<Object,Object>>() { + + public boolean hasNext() { + return iter.hasNext(); + } + + public Map.Entry<Object,Object> next() { + Integer key = iter.nextIndex()+1; + return new AbstractMap.SimpleEntry<Object,Object>(key,iter.next()); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + public LuanTable rawSubList(int from,int to) { + LuanTable tbl = shallowClone(); + tbl.list = new ArrayList<Object>(list().subList(from-1,to-1)); + return tbl; + } + + public LuanTable getMetatable() { + return metatable; + } + + public void setMetatable(LuanTable metatable) { + this.metatable = metatable; + } + + public Object getHandler(String op) { + return metatable==null ? null : metatable.rawGet(op); + } + + private Map<Object,Object> newMap() { + return new LinkedHashMap<Object,Object>(); + } + + public boolean isSet(LuanState luan) throws LuanException { + for( Map.Entry<Object,Object> entry : iterable(luan) ) { + if( !entry.getValue().equals(Boolean.TRUE) ) + return false; + } + return true; + } + + public Set<Object> asSet(LuanState luan) throws LuanException { + Set<Object> set = new HashSet<Object>(); + for( Map.Entry<Object,Object> entry : iterable(luan) ) { + set.add(entry.getKey()); + } + return set; + } + + public Map<Object,Object> asMap(LuanState luan) throws LuanException { + Map<Object,Object> map = newMap(); + for( Map.Entry<Object,Object> entry : iterable(luan) ) { + map.put(entry.getKey(),entry.getValue()); + } + return map; + } + + public void rawClear() { + map = null; + list = null; + } + +}