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;
+	}
+
+}