package fi.vtt.simantics.procore.internal; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Set; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Statement; import org.simantics.db.exception.ResourceNotFoundException; import org.simantics.db.impl.ResourceImpl; import org.simantics.db.impl.graph.ReadGraphImpl; import org.simantics.db.impl.query.IntSet; import org.simantics.db.service.CollectionSupport; import org.simantics.utils.datastructures.Callback; import gnu.trove.impl.Constants; import gnu.trove.iterator.TIntIterator; import gnu.trove.list.array.TIntArrayList; import gnu.trove.map.hash.TIntIntHashMap; import gnu.trove.map.hash.TIntObjectHashMap; import gnu.trove.map.hash.TObjectIntHashMap; import gnu.trove.procedure.TIntObjectProcedure; import gnu.trove.procedure.TIntProcedure; import gnu.trove.procedure.TObjectIntProcedure; import gnu.trove.procedure.TObjectProcedure; import gnu.trove.set.hash.TIntHashSet; public class CollectionSupportImpl implements CollectionSupport { final private SessionImplSocket session; CollectionSupportImpl(SessionImplSocket session) { this.session = session; } static final class IntResourceMap { final private SessionImplSocket session; final private TIntIntHashMap backend = new TIntIntHashMap(Constants.DEFAULT_CAPACITY, Constants.DEFAULT_LOAD_FACTOR, -1, 0); IntResourceMap(SessionImplSocket session) { this.session = session; } public int size() { return backend.size(); } public boolean isEmpty() { return backend.isEmpty(); } public boolean containsKey(int key) { return backend.containsKey(key); } public boolean containsValue(int value) { return backend.containsValue(value); } public Resource get(int key) { try { return session.getResourceByKey(backend.get(key)); } catch (ResourceNotFoundException e) { e.printStackTrace(); } return null; } public Resource put(int key, Resource value) { ResourceImpl impl = (ResourceImpl) value; int i = backend.put(key, impl.id); if (i == 0) return null; else try { return session.getResourceByKey(i); } catch (ResourceNotFoundException e) { e.printStackTrace(); } return null; } public Resource remove(int key) { throw new UnsupportedOperationException("remove not supported"); } @Override public int hashCode() { return backend.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; IntResourceMap other = (IntResourceMap) obj; return session == other.session && backend.equals(other.backend); } } public IntResourceMap createIntResourceMap() { return new IntResourceMap(session); } static final class ObjectResourceMap implements Map { final private SessionImplSocket session; final private TObjectIntHashMap backend; ObjectResourceMap(SessionImplSocket session) { this.session = session; backend = new TObjectIntHashMap(Constants.DEFAULT_CAPACITY, Constants.DEFAULT_LOAD_FACTOR, 0); } ObjectResourceMap(SessionImplSocket session, int capacity) { this.session = session; backend = new TObjectIntHashMap(capacity, Constants.DEFAULT_LOAD_FACTOR, 0); } @Override public int size() { return backend.size(); } @Override public boolean isEmpty() { return backend.isEmpty(); } @Override public boolean containsKey(Object key) { return backend.contains(key); } @Override public boolean containsValue(Object value) { ResourceImpl impl = (ResourceImpl) value; return backend.containsValue(impl.id); } @Override public Resource get(Object key) { try { int result = backend.get(key); if (result == 0) return null; return session.getResourceByKey(result); } catch (ResourceNotFoundException e) { e.printStackTrace(); } return null; } @Override public Resource put(T key, Resource value) { ResourceImpl impl = (ResourceImpl) value; int i = backend.put(key, impl.id); if (i == 0) return null; else try { return session.getResourceByKey(i); } catch (ResourceNotFoundException e) { e.printStackTrace(); } return null; } @Override public Resource remove(Object key) { throw new UnsupportedOperationException("remove not supported, structure is immutable"); } @Override public void putAll(Map map) { @SuppressWarnings("unchecked") ObjectResourceMap other = (ObjectResourceMap) map; other.backend.forEachEntry(new TObjectIntProcedure() { @Override public boolean execute(T a, int b) { backend.put(a, b); return true; } }); } @Override public void clear() { throw new UnsupportedOperationException("clear not supported, structure is immutable"); } @Override public Set keySet() { final Set result = new HashSet(); backend.forEach(new TObjectProcedure() { @Override public boolean execute(T object) { result.add(object); return true; } }); return result; } @Override public Collection values() { ArrayList result = new ArrayList(); for (int key : backend.values()) { try { result.add(session.getResourceByKey(key)); } catch (ResourceNotFoundException e) { e.printStackTrace(); } } return result; } @Override public Set> entrySet() { final HashSet> result = new HashSet>(); backend.forEachEntry(new TObjectIntProcedure() { @Override public boolean execute(final T a, final int b) { return result.add(new Map.Entry() { @Override public T getKey() { return a; } @Override public Resource getValue() { return new ResourceImpl(session.resourceSupport, b); } @Override public Resource setValue(Resource value) { throw new UnsupportedOperationException("Map.Entry.setValue not supported, structure is immutable"); } }); } }); return result; } @Override public int hashCode() { return backend.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ObjectResourceMap other = (ObjectResourceMap) obj; return session == other.session && backend.equals(other.backend); } } @SuppressWarnings("unchecked") @Override public T createObjectResourceMap(Class clazz) { return (T)new ObjectResourceMap(session); } @SuppressWarnings("unchecked") @Override public T createObjectResourceMap(Class clazz, int capacity) { return (T)new ObjectResourceMap(session, capacity); } static final class ResourceMap implements org.simantics.db.ResourceMap { final private SessionImplSocket session; final private TIntObjectHashMap backend = new TIntObjectHashMap(); ResourceMap(SessionImplSocket session) { this.session = session; } @Override public void clear() { throw new UnsupportedOperationException("Not implemented"); } @Override public boolean containsKey(Object resource) { ResourceImpl impl = (ResourceImpl)resource; return backend.containsKey(impl.id); } @SuppressWarnings("unchecked") @Override public boolean containsValue(Object value) { return backend.containsValue((T)value); } @Override public Set> entrySet() { final HashSet> result = new HashSet>(); backend.forEachEntry(new TIntObjectProcedure() { @Override public boolean execute(final int a, final T b) { result.add(new Map.Entry() { @Override public Resource getKey() { return new ResourceImpl(session.resourceSupport, a); } @Override public T getValue() { return b; } @Override public T setValue(T arg0) { throw new UnsupportedOperationException("Not supported"); } }); return true; } }); return result; } @Override public T get(Object resource) { ResourceImpl impl = (ResourceImpl)resource; return backend.get(impl.id); } @Override public boolean isEmpty() { return backend.isEmpty(); } public class CallbackEntry implements ResourceMapEntry { int id; E value; @Override public Resource getKey() { return new ResourceImpl(session.resourceSupport, id); } @Override public E getValue() { return value; } } @Override public void iterateEntries(final Callback> callback) { final CallbackEntry entry = new CallbackEntry(); backend.forEach(new TIntProcedure() { @Override public boolean execute(int value) { entry.id = value; entry.value = backend.get(value); callback.run(entry); return true; } }); } @Override public Set keySet() { final ResourceSet result = new ResourceSet(session); backend.forEach(new TIntProcedure() { @Override public boolean execute(int value) { result.add(value); return true; } }); return result; } @Override public T put(Resource resource, T value) { ResourceImpl impl = (ResourceImpl)resource; return backend.put(impl.id, value); } @Override public void putAll(Map map) { @SuppressWarnings("unchecked") ResourceMap other = (ResourceMap)map; other.backend.forEachEntry(new TIntObjectProcedure() { @Override public boolean execute(int a, T b) { backend.put(a, b); return true; } }); } @Override public T remove(Object arg0) { throw new UnsupportedOperationException("Not implemented"); } @Override public int size() { return backend.size(); } @SuppressWarnings("unchecked") @Override public Collection values() { ArrayList result = new ArrayList(); for(Object o : backend.values()) result.add((T)o); return result; } @Override public int hashCode() { return backend.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ResourceMap other = (ResourceMap) obj; return session == other.session && backend.equals(other.backend); } } @SuppressWarnings("unchecked") @Override public T createMap(Class clazz) { return (T)new ResourceMap(session); } static final class ResourceSet implements Set { final private SessionImplSocket session; final private TIntHashSet backend; ResourceSet(SessionImplSocket session) { this.session = session; backend = new TIntHashSet(); } ResourceSet(SessionImplSocket session, int capacity) { this.session = session; backend = new TIntHashSet(capacity); } @Override public void clear() { backend.clear(); } @Override public int size() { return backend.size(); } @Override public boolean add(Resource resource) { ResourceImpl impl = (ResourceImpl)resource; return backend.add(impl.id); } boolean add(int id) { return backend.add(id); } @Override public boolean addAll(Collection rs) { boolean result = true; for(Resource r : rs) result &= add(r); return result; } @Override public boolean contains(Object resource) { ResourceImpl impl = (ResourceImpl)resource; return backend.contains(impl.id); } @Override public boolean containsAll(Collection rs) { boolean result = true; for(Object r : rs) result &= contains(r); return result; } @Override public boolean isEmpty() { return backend.isEmpty(); } @Override public Iterator iterator() { return new Iterator() { TIntIterator it = backend.iterator(); @Override public boolean hasNext() { return it.hasNext(); } @Override public Resource next() { return new ResourceImpl(session.resourceSupport, it.next()); } @Override public void remove() { it.remove(); } }; } @Override public boolean remove(Object resource) { ResourceImpl impl = (ResourceImpl)resource; return backend.remove(impl.id); } @Override public boolean removeAll(Collection rs) { boolean result = true; for(Object r : rs) result &= remove(r); return result; } @Override public boolean retainAll(Collection arg0) { throw new UnsupportedOperationException("Not implemented"); } @Override public Object[] toArray() { throw new UnsupportedOperationException("Not implemented"); } @SuppressWarnings("unchecked") @Override public T[] toArray(T[] arg0) { final T[] result = (T[])Array.newInstance(arg0.getClass().getComponentType(), backend.size()); backend.forEach(new TIntProcedure() { int index = 0; @Override public boolean execute(int value) { result[index++] = (T)new ResourceImpl(session.resourceSupport, value); return true; } }); return result; } @Override public int hashCode() { return backend.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ResourceSet other = (ResourceSet) obj; return session == other.session && backend.equals(other.backend); } } @Override public Set createSet() { return new ResourceSet(session); } @Override public Set createSet(int capacity) { return new ResourceSet(session, capacity); } static final class ResourceList implements List { final private SessionImplSocket session; final private TIntArrayList backend; ResourceList(SessionImplSocket session) { this.session = session; this.backend = new TIntArrayList(); } ResourceList(SessionImplSocket session, Collection rs) { this.session = session; this.backend = new TIntArrayList(rs.size()); addAll(rs); } @Override public void clear() { throw new UnsupportedOperationException("Not implemented"); } @Override public int size() { return backend.size(); } @Override public boolean add(Resource resource) { if(resource == null) { backend.add(0); } else { ResourceImpl impl = (ResourceImpl)resource; backend.add(impl.id); } return true; } @Override public boolean addAll(Collection rs) { if(rs instanceof ResourceList) { ResourceList rl = (ResourceList)rs; backend.addAll(rl.backend); return !rl.isEmpty(); } boolean result = true; for(Resource r : rs) result &= add(r); return result; } @Override public boolean contains(Object resource) { ResourceImpl impl = (ResourceImpl)resource; return backend.contains(impl.id); } @Override public boolean containsAll(Collection rs) { boolean result = true; for(Object r : rs) result &= contains(r); return result; } @Override public boolean isEmpty() { return backend.isEmpty(); } @Override public Iterator iterator() { return new Iterator() { int index = backend.size(); @Override public boolean hasNext() { return index > 0; } @Override public Resource next() { return new ResourceImpl(session.resourceSupport, backend.getQuick(--index)); } @Override public void remove() { throw new UnsupportedOperationException("Not supported"); } }; } @Override public boolean remove(Object resource) { if(!(resource instanceof ResourceImpl)) return false; ResourceImpl impl = (ResourceImpl)resource; return backend.remove(impl.id); } @Override public boolean removeAll(Collection rs) { boolean modified = false; for(Object o : rs) modified |= remove(o); return modified; } @Override public boolean retainAll(Collection arg0) { throw new UnsupportedOperationException("Not implemented"); } @Override public Object[] toArray() { return toArray(new Object[backend.size()]); } @SuppressWarnings("unchecked") @Override public T[] toArray(T[] arg0) { final T[] result = (T[])Array.newInstance(arg0.getClass().getComponentType(), backend.size()); backend.forEach(new TIntProcedure() { int index = 0; @Override public boolean execute(int value) { result[index++] = (T)new ResourceImpl(session.resourceSupport, value); return true; } }); return result; } void sort() { backend.sort(); } @Override public boolean addAll(int index, Collection rs) { if(rs.isEmpty()) return false; int i = index; for(Resource r : rs) { add(i++, r); } return true; } @Override public Resource get(int index) { int id = backend.get(index); if(id == 0) return null; return new ResourceImpl(session.resourceSupport, id); } @Override public Resource set(int index, Resource resource) { ResourceImpl impl = (ResourceImpl)resource; int old = backend.set(index, impl.id); if(old == 0) return null; return new ResourceImpl(session.resourceSupport, old); } @Override public void add(int index, Resource resource) { ResourceImpl impl = (ResourceImpl)resource; backend.insert(index, impl.id); } @Override public Resource remove(int index) { int id = backend.removeAt(index); return new ResourceImpl(session.resourceSupport, id); } @Override public int indexOf(Object o) { if(!(o instanceof ResourceImpl)) return -1; ResourceImpl impl = (ResourceImpl)o; return backend.indexOf(impl.id); } @Override public int lastIndexOf(Object o) { if(!(o instanceof ResourceImpl)) return -1; ResourceImpl impl = (ResourceImpl)o; return backend.lastIndexOf(impl.id); } @Override public ListIterator listIterator() { throw new UnsupportedOperationException("Not implemented"); } @Override public ListIterator listIterator(int index) { throw new UnsupportedOperationException("Not implemented"); } @Override public List subList(int fromIndex, int toIndex) { ResourceList result = new ResourceList(session); for(int i=fromIndex;i createList() { return new ResourceList(session); } static final class StatementList implements Collection { final private SessionImplSocket session; final private TIntArrayList backend = new TIntArrayList(); StatementList(SessionImplSocket session) { this.session = session; } @Override public void clear() { throw new UnsupportedOperationException("Not implemented"); } @Override public int size() { return backend.size() / 3; } @Override public boolean add(Statement stm) { ResourceImpl s = (ResourceImpl)stm.getSubject(); ResourceImpl p = (ResourceImpl)stm.getPredicate(); ResourceImpl o = (ResourceImpl)stm.getObject(); backend.add(s.id); backend.add(p.id); backend.add(o.id); return true; } @Override public boolean addAll(Collection rs) { boolean result = true; for(Statement r : rs) result &= add(r); return result; } @Override public boolean contains(Object statement) { throw new UnsupportedOperationException("Not implemented"); } @Override public boolean containsAll(Collection rs) { throw new UnsupportedOperationException("Not implemented"); } @Override public boolean isEmpty() { return backend.isEmpty(); } @Override public Iterator iterator() { return new Iterator() { int index = 0; int max = backend.size(); @Override public boolean hasNext() { return index < max; } @Override public Statement next() { return new DirectStatementImpl(session.resourceSupport, backend.getQuick(index++), backend.getQuick(index++), backend.getQuick(index++)); } @Override public void remove() { throw new UnsupportedOperationException("Not supported"); } }; } @Override public boolean remove(Object resource) { throw new UnsupportedOperationException("Not implemented"); } @Override public boolean removeAll(Collection rs) { throw new UnsupportedOperationException("Not implemented"); } @Override public boolean retainAll(Collection arg0) { throw new UnsupportedOperationException("Not implemented"); } @Override public Object[] toArray() { throw new UnsupportedOperationException("Not implemented"); } @SuppressWarnings("unchecked") @Override public T[] toArray(T[] arg0) { final T[] result = (T[])Array.newInstance(arg0.getClass().getComponentType(), backend.size()); backend.forEach(new TIntProcedure() { int index = 0; @Override public boolean execute(int value) { result[index++] = (T)new ResourceImpl(session.resourceSupport, value); return true; } }); return result; } @Override public int hashCode() { return backend.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; StatementList other = (StatementList) obj; return session == other.session && backend.equals(other.backend); } } @Override public Collection createStatementList() { return new StatementList(session); } private static Comparator RESOURCE_COMPARATOR = new Comparator() { @Override public int compare(Resource o1, Resource o2) { ResourceImpl r1 = (ResourceImpl)o1; ResourceImpl r2 = (ResourceImpl)o2; return compare(r1.id, r2.id); } private int compare(int x, int y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); } }; @Override public void sort(List list) { if(list instanceof ResourceList) { ((ResourceList) list).sort(); } else { Collections.sort(list, RESOURCE_COMPARATOR); } } @Override public List asSortedList(Collection rs) { ResourceList result = new ResourceList(session, rs); result.sort(); return result; } @Override public org.simantics.db.ResourceSet getResourceSet(ReadGraph graph, Collection resources) { if(resources instanceof ResourceSet) return (org.simantics.db.ResourceSet)resources; org.simantics.db.ResourceSet result = new IntSet(((ReadGraphImpl)graph).processor.querySupport); for(Resource r : resources) result.add(r); return result; } @Override public org.simantics.db.ResourceSet getResourceSet(ReadGraph graph, Resource ... rs) { org.simantics.db.ResourceSet result = new IntSet(((ReadGraphImpl)graph).processor.querySupport); for(Resource r : rs) result.add(r); return result; } }