1 package fi.vtt.simantics.procore.internal;
3 import java.lang.reflect.Array;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.Collections;
7 import java.util.Comparator;
8 import java.util.HashSet;
9 import java.util.Iterator;
10 import java.util.List;
11 import java.util.ListIterator;
13 import java.util.NoSuchElementException;
15 import java.util.function.Consumer;
17 import org.simantics.db.ReadGraph;
18 import org.simantics.db.Resource;
19 import org.simantics.db.Statement;
20 import org.simantics.db.exception.ResourceNotFoundException;
21 import org.simantics.db.impl.ResourceImpl;
22 import org.simantics.db.impl.graph.ReadGraphImpl;
23 import org.simantics.db.impl.query.IntSet;
24 import org.simantics.db.service.CollectionSupport;
26 import gnu.trove.impl.Constants;
27 import gnu.trove.iterator.TIntIterator;
28 import gnu.trove.list.array.TIntArrayList;
29 import gnu.trove.map.hash.TIntIntHashMap;
30 import gnu.trove.map.hash.TIntObjectHashMap;
31 import gnu.trove.map.hash.TObjectIntHashMap;
32 import gnu.trove.procedure.TIntObjectProcedure;
33 import gnu.trove.procedure.TIntProcedure;
34 import gnu.trove.procedure.TObjectIntProcedure;
35 import gnu.trove.procedure.TObjectProcedure;
36 import gnu.trove.set.hash.TIntHashSet;
38 public class CollectionSupportImpl implements CollectionSupport {
40 final private SessionImplSocket session;
42 CollectionSupportImpl(SessionImplSocket session) {
43 this.session = session;
46 static final class IntResourceMap {
48 final private SessionImplSocket session;
49 final private TIntIntHashMap backend = new TIntIntHashMap(Constants.DEFAULT_CAPACITY, Constants.DEFAULT_LOAD_FACTOR, -1, 0);
51 IntResourceMap(SessionImplSocket session) {
52 this.session = session;
56 return backend.size();
59 public boolean isEmpty() {
60 return backend.isEmpty();
63 public boolean containsKey(int key) {
64 return backend.containsKey(key);
67 public boolean containsValue(int value) {
68 return backend.containsValue(value);
71 public Resource get(int key) {
73 return session.getResourceByKey(backend.get(key));
74 } catch (ResourceNotFoundException e) {
80 public Resource put(int key, Resource value) {
81 ResourceImpl impl = (ResourceImpl) value;
82 int i = backend.put(key, impl.id);
87 return session.getResourceByKey(i);
88 } catch (ResourceNotFoundException e) {
94 public Resource remove(int key) {
95 throw new UnsupportedOperationException("remove not supported");
99 public int hashCode() {
100 return backend.hashCode();
104 public boolean equals(Object obj) {
109 if (getClass() != obj.getClass())
111 IntResourceMap other = (IntResourceMap) obj;
112 return session == other.session && backend.equals(other.backend);
116 public IntResourceMap createIntResourceMap() {
117 return new IntResourceMap(session);
120 static final class ObjectResourceMap<T> implements Map<T, Resource> {
122 final private SessionImplSocket session;
123 final private TObjectIntHashMap<T> backend;
125 ObjectResourceMap(SessionImplSocket session) {
126 this.session = session;
127 backend = new TObjectIntHashMap<T>(Constants.DEFAULT_CAPACITY, Constants.DEFAULT_LOAD_FACTOR, 0);
130 ObjectResourceMap(SessionImplSocket session, int capacity) {
131 this.session = session;
132 backend = new TObjectIntHashMap<T>(capacity, Constants.DEFAULT_LOAD_FACTOR, 0);
137 return backend.size();
140 public boolean isEmpty() {
141 return backend.isEmpty();
145 public boolean containsKey(Object key) {
146 return backend.contains(key);
150 public boolean containsValue(Object value) {
151 ResourceImpl impl = (ResourceImpl) value;
152 return backend.containsValue(impl.id);
156 public Resource get(Object key) {
158 int result = backend.get(key);
161 return session.getResourceByKey(result);
162 } catch (ResourceNotFoundException e) {
169 public Resource put(T key, Resource value) {
170 ResourceImpl impl = (ResourceImpl) value;
171 int i = backend.put(key, impl.id);
176 return session.getResourceByKey(i);
177 } catch (ResourceNotFoundException e) {
184 public Resource remove(Object key) {
185 throw new UnsupportedOperationException("remove not supported, structure is immutable");
189 public void putAll(Map<? extends T, ? extends Resource> map) {
190 @SuppressWarnings("unchecked")
191 ObjectResourceMap<T> other = (ObjectResourceMap<T>) map;
192 other.backend.forEachEntry(new TObjectIntProcedure<T>() {
195 public boolean execute(T a, int b) {
203 public void clear() {
204 throw new UnsupportedOperationException("clear not supported, structure is immutable");
208 public Set<T> keySet() {
209 final Set<T> result = new HashSet<T>();
210 backend.forEach(new TObjectProcedure<T>() {
213 public boolean execute(T object) {
222 public Collection<Resource> values() {
223 ArrayList<Resource> result = new ArrayList<Resource>();
224 for (int key : backend.values()) {
226 result.add(session.getResourceByKey(key));
227 } catch (ResourceNotFoundException e) {
235 public Set<java.util.Map.Entry<T, Resource>> entrySet() {
236 final HashSet<java.util.Map.Entry<T, Resource>> result = new HashSet<java.util.Map.Entry<T, Resource>>();
237 backend.forEachEntry(new TObjectIntProcedure<T>() {
240 public boolean execute(final T a, final int b) {
241 return result.add(new Map.Entry<T, Resource>() {
249 public Resource getValue() {
250 return new ResourceImpl(session.resourceSupport, b);
254 public Resource setValue(Resource value) {
255 throw new UnsupportedOperationException("Map.Entry.setValue not supported, structure is immutable");
265 public int hashCode() {
266 return backend.hashCode();
270 public boolean equals(Object obj) {
275 if (getClass() != obj.getClass()) {
276 if (obj instanceof Map) {
277 // Nonoptimal fallback for comparing against generic Map
278 Map<?,?> m = (Map<?,?>) obj;
279 if (m.size() != size())
282 Iterator<Entry<T,Resource>> i = entrySet().iterator();
283 while (i.hasNext()) {
284 Entry<T,Resource> e = i.next();
286 Resource value = e.getValue();
288 if (!(m.get(key)==null && m.containsKey(key)))
291 if (!value.equals(m.get(key)))
296 } catch (ClassCastException unused) {
298 } catch (NullPointerException unused) {
304 ObjectResourceMap<?> other = (ObjectResourceMap<?>) obj;
305 return session == other.session && backend.equals(other.backend);
310 @SuppressWarnings("unchecked")
312 public <T, I> T createObjectResourceMap(Class<I> clazz) {
313 return (T)new ObjectResourceMap<I>(session);
316 @SuppressWarnings("unchecked")
318 public <T, I> T createObjectResourceMap(Class<I> clazz, int capacity) {
319 return (T)new ObjectResourceMap<I>(session, capacity);
322 static final class ResourceMap<T> implements org.simantics.db.ResourceMap<T> {
324 final private SessionImplSocket session;
325 final private TIntObjectHashMap<T> backend = new TIntObjectHashMap<T>();
327 ResourceMap(SessionImplSocket session) {
328 this.session = session;
332 public void clear() {
333 throw new UnsupportedOperationException("Not implemented");
337 public boolean containsKey(Object resource) {
338 ResourceImpl impl = (ResourceImpl)resource;
339 return backend.containsKey(impl.id);
342 @SuppressWarnings("unchecked")
344 public boolean containsValue(Object value) {
345 return backend.containsValue((T)value);
349 public Set<java.util.Map.Entry<Resource, T>> entrySet() {
350 final HashSet<java.util.Map.Entry<Resource, T>> result = new HashSet<java.util.Map.Entry<Resource, T>>();
351 backend.forEachEntry(new TIntObjectProcedure<T>() {
354 public boolean execute(final int a, final T b) {
355 result.add(new Map.Entry<Resource, T>() {
358 public Resource getKey() {
359 return new ResourceImpl(session.resourceSupport, a);
363 public T getValue() {
368 public T setValue(T arg0) {
369 throw new UnsupportedOperationException("Not supported");
381 public T get(Object resource) {
382 ResourceImpl impl = (ResourceImpl)resource;
383 return backend.get(impl.id);
387 public boolean isEmpty() {
388 return backend.isEmpty();
391 public class CallbackEntry<E> implements ResourceMapEntry<E> {
397 public Resource getKey() {
398 return new ResourceImpl(session.resourceSupport, id);
402 public E getValue() {
409 public void iterateEntries(final Consumer<ResourceMapEntry<T>> callback) {
410 final CallbackEntry<T> entry = new CallbackEntry<T>();
411 backend.forEach(new TIntProcedure() {
414 public boolean execute(int value) {
416 entry.value = backend.get(value);
417 callback.accept(entry);
424 public Set<Resource> keySet() {
425 final ResourceSet result = new ResourceSet(session);
426 backend.forEach(new TIntProcedure() {
429 public boolean execute(int value) {
438 public T put(Resource resource, T value) {
439 ResourceImpl impl = (ResourceImpl)resource;
440 return backend.put(impl.id, value);
444 public void putAll(Map<? extends Resource, ? extends T> map) {
445 @SuppressWarnings("unchecked")
446 ResourceMap<T> other = (ResourceMap<T>)map;
447 other.backend.forEachEntry(new TIntObjectProcedure<T>() {
450 public boolean execute(int a, T b) {
459 public T remove(Object key) {
460 if (key instanceof ResourceImpl) {
461 ResourceImpl impl = (ResourceImpl)key;
462 return backend.remove(impl.id);
469 return backend.size();
472 @SuppressWarnings("unchecked")
474 public Collection<T> values() {
475 ArrayList<T> result = new ArrayList<>();
476 for(Object o : backend.values()) result.add((T)o);
481 public int hashCode() {
482 return backend.hashCode();
486 public boolean equals(Object obj) {
491 if (getClass() != obj.getClass()) {
492 if (obj instanceof Map) {
493 // Nonoptimal fallback for comparing against generic Map
494 Map<?,?> m = (Map<?,?>) obj;
495 if (m.size() != size())
498 Iterator<Entry<Resource,T>> i = entrySet().iterator();
499 while (i.hasNext()) {
500 Entry<Resource,T> e = i.next();
501 Resource key = e.getKey();
502 T value = e.getValue();
504 if (!(m.get(key)==null && m.containsKey(key)))
507 if (!value.equals(m.get(key)))
512 } catch (ClassCastException unused) {
514 } catch (NullPointerException unused) {
520 ResourceMap<?> other = (ResourceMap<?>) obj;
521 return session == other.session && backend.equals(other.backend);
526 @SuppressWarnings("unchecked")
528 public <T, I> T createMap(Class<I> clazz) {
529 return (T)new ResourceMap<I>(session);
532 static final class ResourceSet implements Set<Resource> {
534 final private SessionImplSocket session;
535 final private TIntHashSet backend;
537 ResourceSet(SessionImplSocket session) {
538 this.session = session;
539 backend = new TIntHashSet();
542 ResourceSet(SessionImplSocket session, int capacity) {
543 this.session = session;
544 backend = new TIntHashSet(capacity);
548 public void clear() {
554 return backend.size();
558 public boolean add(Resource resource) {
559 ResourceImpl impl = (ResourceImpl)resource;
560 return backend.add(impl.id);
563 boolean add(int id) {
564 return backend.add(id);
568 public boolean addAll(Collection<? extends Resource> rs) {
569 boolean result = false;
570 for(Resource r : rs) result |= add(r);
575 public boolean contains(Object resource) {
576 ResourceImpl impl = (ResourceImpl)resource;
577 return backend.contains(impl.id);
581 public boolean containsAll(Collection<?> rs) {
589 public boolean isEmpty() {
590 return backend.isEmpty();
594 public Iterator<Resource> iterator() {
595 return new Iterator<Resource>() {
597 TIntIterator it = backend.iterator();
600 public boolean hasNext() {
605 public Resource next() {
606 return new ResourceImpl(session.resourceSupport, it.next());
610 public void remove() {
618 public boolean remove(Object resource) {
619 ResourceImpl impl = (ResourceImpl)resource;
620 return backend.remove(impl.id);
624 public boolean removeAll(Collection<?> rs) {
625 boolean result = false;
626 for(Object r : rs) result |= remove(r);
631 public boolean retainAll(Collection<?> arg0) {
632 throw new UnsupportedOperationException("Not implemented");
636 public Object[] toArray() {
637 return toArray(new Object[backend.size()]);
640 @SuppressWarnings("unchecked")
642 public <T> T[] toArray(T[] a) {
643 int size = backend.size();
644 T[] r = a.length >= size ? a :
645 (T[])Array.newInstance(a.getClass().getComponentType(), size);
646 backend.forEach(new TIntProcedure() {
651 public boolean execute(int value) {
652 r[index++] = (T)new ResourceImpl(session.resourceSupport, value);
660 public int hashCode() {
661 return backend.hashCode();
665 public boolean equals(Object obj) {
670 if (getClass() != obj.getClass()) {
671 if (obj instanceof Set) {
672 // Nonoptimal fallback for comparing against generic Set
673 Collection<?> c = (Collection<?>) obj;
674 if (c.size() != size())
677 return containsAll(c);
678 } catch (ClassCastException unused) {
680 } catch (NullPointerException unused) {
686 ResourceSet other = (ResourceSet) obj;
687 return session == other.session && backend.equals(other.backend);
693 public Set<Resource> createSet() {
694 return new ResourceSet(session);
698 public Set<Resource> createSet(int capacity) {
699 return new ResourceSet(session, capacity);
702 static final class ResourceList implements List<Resource> {
704 final private SessionImplSocket session;
705 final private TIntArrayList backend;
707 ResourceList(SessionImplSocket session) {
708 this.session = session;
709 this.backend = new TIntArrayList();
712 ResourceList(SessionImplSocket session, int capacity) {
713 this.session = session;
714 this.backend = new TIntArrayList(capacity);
717 ResourceList(SessionImplSocket session, Collection<Resource> rs) {
718 this.session = session;
719 this.backend = new TIntArrayList(rs.size());
724 public void clear() {
725 throw new UnsupportedOperationException("Not implemented");
730 return backend.size();
734 public boolean add(Resource resource) {
735 if(resource == null) {
738 ResourceImpl impl = (ResourceImpl)resource;
739 backend.add(impl.id);
745 public boolean addAll(Collection<? extends Resource> rs) {
746 if(rs instanceof ResourceList) {
747 ResourceList rl = (ResourceList)rs;
748 backend.addAll(rl.backend);
749 return !rl.isEmpty();
751 boolean result = true;
752 for(Resource r : rs) result &= add(r);
757 public boolean contains(Object resource) {
758 ResourceImpl impl = (ResourceImpl)resource;
759 return backend.contains(impl.id);
763 public boolean containsAll(Collection<?> rs) {
764 boolean result = true;
765 for(Object r : rs) result &= contains(r);
770 public boolean isEmpty() {
771 return backend.isEmpty();
775 public Iterator<Resource> iterator() {
776 return new Iterator<Resource>() {
779 int max = backend.size();
782 public boolean hasNext() {
787 public Resource next() {
790 throw new NoSuchElementException();
791 int id = backend.getQuick(i);
793 return new ResourceImpl(session.resourceSupport, id);
797 public void remove() {
798 throw new UnsupportedOperationException("remove not supported");
805 public boolean remove(Object resource) {
806 if(!(resource instanceof ResourceImpl)) return false;
807 ResourceImpl impl = (ResourceImpl)resource;
808 return backend.remove(impl.id);
812 public boolean removeAll(Collection<?> rs) {
813 boolean modified = false;
815 modified |= remove(o);
820 public boolean retainAll(Collection<?> arg0) {
821 throw new UnsupportedOperationException("Not implemented");
825 public Object[] toArray() {
826 return toArray(new Object[backend.size()]);
829 @SuppressWarnings("unchecked")
831 public <T> T[] toArray(T[] a) {
832 int size = backend.size();
833 T[] r = a.length >= size ? a :
834 (T[])Array.newInstance(a.getClass().getComponentType(), size);
835 backend.forEach(new TIntProcedure() {
840 public boolean execute(int value) {
841 r[index++] = (T)new ResourceImpl(session.resourceSupport, value);
853 public boolean addAll(int index, Collection<? extends Resource> rs) {
854 if(rs.isEmpty()) return false;
856 for(Resource r : rs) {
863 public Resource get(int index) {
864 int id = backend.get(index);
865 if(id == 0) return null;
866 return new ResourceImpl(session.resourceSupport, id);
870 public Resource set(int index, Resource resource) {
871 ResourceImpl impl = (ResourceImpl)resource;
872 int old = backend.set(index, impl.id);
873 if(old == 0) return null;
874 return new ResourceImpl(session.resourceSupport, old);
878 public void add(int index, Resource resource) {
879 ResourceImpl impl = (ResourceImpl)resource;
880 backend.insert(index, impl.id);
884 public Resource remove(int index) {
885 int id = backend.removeAt(index);
886 return new ResourceImpl(session.resourceSupport, id);
890 public int indexOf(Object o) {
891 if(!(o instanceof ResourceImpl)) return -1;
892 ResourceImpl impl = (ResourceImpl)o;
893 return backend.indexOf(impl.id);
897 public int lastIndexOf(Object o) {
898 if(!(o instanceof ResourceImpl)) return -1;
899 ResourceImpl impl = (ResourceImpl)o;
900 return backend.lastIndexOf(impl.id);
903 private class ListItr implements ListIterator<Resource> {
908 public ListItr(int index) {
914 public boolean hasNext() {
919 public Resource next() {
922 throw new NoSuchElementException();
923 int id = backend.getQuick(index);
925 return new ResourceImpl(session.resourceSupport, id);
929 public boolean hasPrevious() {
934 public Resource previous() {
937 throw new NoSuchElementException();
938 int id = backend.getQuick(index);
940 return new ResourceImpl(session.resourceSupport, id);
944 public int nextIndex() {
949 public int previousIndex() {
954 public void remove() {
955 throw new UnsupportedOperationException("remove not supported");
959 public void set(Resource e) {
960 throw new UnsupportedOperationException("set not supported");
964 public void add(Resource e) {
965 throw new UnsupportedOperationException("add not supported");
970 public ListIterator<Resource> listIterator() {
971 return new ListItr(0);
975 public ListIterator<Resource> listIterator(int index) {
976 if (index < 0 || index > backend.size())
977 throw new IndexOutOfBoundsException("Index: "+index);
978 return new ListItr(index);
982 public List<Resource> subList(int fromIndex, int toIndex) {
983 ResourceList result = new ResourceList(session);
984 for(int i=fromIndex;i<toIndex;i++)
990 public int hashCode() {
991 return backend.hashCode();
995 public boolean equals(Object obj) {
1000 if (getClass() != obj.getClass()) {
1001 if (obj instanceof List) {
1002 // Nonoptimal fallback for comparing against generic List
1003 ListIterator<?> e1 = listIterator();
1004 ListIterator<?> e2 = ((List<?>) obj).listIterator();
1005 while (e1.hasNext() && e2.hasNext()) {
1006 Object o1 = e1.next();
1007 Object o2 = e2.next();
1008 if (!(o1==null ? o2==null : o1.equals(o2)))
1011 return !(e1.hasNext() || e2.hasNext());
1015 ResourceList other = (ResourceList) obj;
1016 return session == other.session && backend.equals(other.backend);
1022 public List<Resource> createList() {
1023 return new ResourceList(session);
1027 public List<Resource> createList(int capacity) {
1028 return new ResourceList(session, capacity);
1031 static final class StatementList implements Collection<Statement> {
1033 final private SessionImplSocket session;
1034 final private TIntArrayList backend = new TIntArrayList();
1036 StatementList(SessionImplSocket session) {
1037 this.session = session;
1041 public void clear() {
1042 throw new UnsupportedOperationException("Not implemented");
1047 return backend.size() / 3;
1051 public boolean add(Statement stm) {
1052 ResourceImpl s = (ResourceImpl)stm.getSubject();
1053 ResourceImpl p = (ResourceImpl)stm.getPredicate();
1054 ResourceImpl o = (ResourceImpl)stm.getObject();
1062 public boolean addAll(Collection<? extends Statement> rs) {
1063 boolean result = false;
1064 for(Statement r : rs) result |= add(r);
1069 public boolean contains(Object statement) {
1070 throw new UnsupportedOperationException("Not implemented");
1074 public boolean containsAll(Collection<?> rs) {
1075 throw new UnsupportedOperationException("Not implemented");
1079 public boolean isEmpty() {
1080 return backend.isEmpty();
1084 public Iterator<Statement> iterator() {
1085 return new Iterator<Statement>() {
1088 int max = backend.size();
1091 public boolean hasNext() {
1096 public Statement next() {
1097 return new DirectStatementImpl(session.resourceSupport, backend.getQuick(index++), backend.getQuick(index++), backend.getQuick(index++));
1101 public void remove() {
1102 throw new UnsupportedOperationException("Not supported");
1109 public boolean remove(Object resource) {
1110 throw new UnsupportedOperationException("Not implemented");
1114 public boolean removeAll(Collection<?> rs) {
1115 throw new UnsupportedOperationException("Not implemented");
1119 public boolean retainAll(Collection<?> arg0) {
1120 throw new UnsupportedOperationException("Not implemented");
1124 public Object[] toArray() {
1125 int stms = backend.size() / 3;
1126 return toArray(new Object[stms]);
1129 @SuppressWarnings("unchecked")
1131 public <T> T[] toArray(T[] a) {
1132 int size = backend.size();
1133 int stms = size / 3;
1134 T[] r = a.length >= size ? a :
1135 (T[])Array.newInstance(a.getClass().getComponentType(), stms);
1137 for (int i = 0; i < size; i += 3) {
1138 r[index++] = (T) new DirectStatementImpl(session.resourceSupport, backend.getQuick(i), backend.getQuick(i+1), backend.getQuick(i+2));
1144 public int hashCode() {
1145 return backend.hashCode();
1149 public boolean equals(Object obj) {
1154 if (getClass() != obj.getClass()) {
1155 if (obj instanceof Collection) {
1156 // Nonoptimal fallback for comparing against generic Collection
1157 Iterator<?> e1 = iterator();
1158 Iterator<?> e2 = ((Collection<?>) obj).iterator();
1159 while (e1.hasNext() && e2.hasNext()) {
1160 Object o1 = e1.next();
1161 Object o2 = e2.next();
1162 if (!(o1==null ? o2==null : o1.equals(o2)))
1165 return !(e1.hasNext() || e2.hasNext());
1169 StatementList other = (StatementList) obj;
1170 return session == other.session && backend.equals(other.backend);
1176 public Collection<Statement> createStatementList() {
1177 return new StatementList(session);
1180 private static Comparator<Resource> RESOURCE_COMPARATOR = (o1, o2) -> {
1181 ResourceImpl r1 = (ResourceImpl)o1;
1182 ResourceImpl r2 = (ResourceImpl)o2;
1183 return Integer.compare(r1.id, r2.id);
1187 public void sort(List<Resource> list) {
1188 if(list instanceof ResourceList) {
1189 ((ResourceList) list).sort();
1191 Collections.sort(list, RESOURCE_COMPARATOR);
1196 public List<Resource> asSortedList(Collection<Resource> rs) {
1197 ResourceList result = new ResourceList(session, rs);
1203 public org.simantics.db.ResourceSet getResourceSet(ReadGraph graph, Collection<Resource> resources) {
1204 if(resources instanceof ResourceSet) return (org.simantics.db.ResourceSet)resources;
1205 org.simantics.db.ResourceSet result = new IntSet(((ReadGraphImpl)graph).processor.querySupport);
1206 for(Resource r : resources) result.add(r);
1211 public org.simantics.db.ResourceSet getResourceSet(ReadGraph graph, Resource ... rs) {
1212 org.simantics.db.ResourceSet result = new IntSet(((ReadGraphImpl)graph).processor.querySupport);
1213 for(Resource r : rs) result.add(r);