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)))
295 } catch (ClassCastException unused) {
297 } catch (NullPointerException unused) {
303 ObjectResourceMap<?> other = (ObjectResourceMap<?>) obj;
304 return session == other.session && backend.equals(other.backend);
309 @SuppressWarnings("unchecked")
311 public <T, I> T createObjectResourceMap(Class<I> clazz) {
312 return (T)new ObjectResourceMap<I>(session);
315 @SuppressWarnings("unchecked")
317 public <T, I> T createObjectResourceMap(Class<I> clazz, int capacity) {
318 return (T)new ObjectResourceMap<I>(session, capacity);
321 static final class ResourceMap<T> implements org.simantics.db.ResourceMap<T> {
323 final private SessionImplSocket session;
324 final private TIntObjectHashMap<T> backend = new TIntObjectHashMap<T>();
326 ResourceMap(SessionImplSocket session) {
327 this.session = session;
331 public void clear() {
332 throw new UnsupportedOperationException("Not implemented");
336 public boolean containsKey(Object resource) {
337 ResourceImpl impl = (ResourceImpl)resource;
338 return backend.containsKey(impl.id);
341 @SuppressWarnings("unchecked")
343 public boolean containsValue(Object value) {
344 return backend.containsValue((T)value);
348 public Set<java.util.Map.Entry<Resource, T>> entrySet() {
349 final HashSet<java.util.Map.Entry<Resource, T>> result = new HashSet<java.util.Map.Entry<Resource, T>>();
350 backend.forEachEntry(new TIntObjectProcedure<T>() {
353 public boolean execute(final int a, final T b) {
354 result.add(new Map.Entry<Resource, T>() {
357 public Resource getKey() {
358 return new ResourceImpl(session.resourceSupport, a);
362 public T getValue() {
367 public T setValue(T arg0) {
368 throw new UnsupportedOperationException("Not supported");
380 public T get(Object resource) {
381 ResourceImpl impl = (ResourceImpl)resource;
382 return backend.get(impl.id);
386 public boolean isEmpty() {
387 return backend.isEmpty();
390 public class CallbackEntry<E> implements ResourceMapEntry<E> {
396 public Resource getKey() {
397 return new ResourceImpl(session.resourceSupport, id);
401 public E getValue() {
408 public void iterateEntries(final Consumer<ResourceMapEntry<T>> callback) {
409 final CallbackEntry<T> entry = new CallbackEntry<T>();
410 backend.forEach(new TIntProcedure() {
413 public boolean execute(int value) {
415 entry.value = backend.get(value);
416 callback.accept(entry);
423 public Set<Resource> keySet() {
424 final ResourceSet result = new ResourceSet(session);
425 backend.forEach(new TIntProcedure() {
428 public boolean execute(int value) {
437 public T put(Resource resource, T value) {
438 ResourceImpl impl = (ResourceImpl)resource;
439 return backend.put(impl.id, value);
443 public void putAll(Map<? extends Resource, ? extends T> map) {
444 @SuppressWarnings("unchecked")
445 ResourceMap<T> other = (ResourceMap<T>)map;
446 other.backend.forEachEntry(new TIntObjectProcedure<T>() {
449 public boolean execute(int a, T b) {
458 public T remove(Object key) {
459 if (key instanceof ResourceImpl) {
460 ResourceImpl impl = (ResourceImpl)key;
461 return backend.remove(impl.id);
468 return backend.size();
471 @SuppressWarnings("unchecked")
473 public Collection<T> values() {
474 ArrayList<T> result = new ArrayList<>();
475 for(Object o : backend.values()) result.add((T)o);
480 public int hashCode() {
481 return backend.hashCode();
485 public boolean equals(Object obj) {
490 if (getClass() != obj.getClass()) {
491 if (obj instanceof Map) {
492 // Nonoptimal fallback for comparing against generic Map
493 Map<?,?> m = (Map<?,?>) obj;
494 if (m.size() != size())
497 Iterator<Entry<Resource,T>> i = entrySet().iterator();
498 while (i.hasNext()) {
499 Entry<Resource,T> e = i.next();
500 Resource key = e.getKey();
501 T value = e.getValue();
503 if (!(m.get(key)==null && m.containsKey(key)))
506 if (!value.equals(m.get(key)))
510 } catch (ClassCastException unused) {
512 } catch (NullPointerException unused) {
518 ResourceMap<?> other = (ResourceMap<?>) obj;
519 return session == other.session && backend.equals(other.backend);
524 @SuppressWarnings("unchecked")
526 public <T, I> T createMap(Class<I> clazz) {
527 return (T)new ResourceMap<I>(session);
530 static final class ResourceSet implements Set<Resource> {
532 final private SessionImplSocket session;
533 final private TIntHashSet backend;
535 ResourceSet(SessionImplSocket session) {
536 this.session = session;
537 backend = new TIntHashSet();
540 ResourceSet(SessionImplSocket session, int capacity) {
541 this.session = session;
542 backend = new TIntHashSet(capacity);
546 public void clear() {
552 return backend.size();
556 public boolean add(Resource resource) {
557 ResourceImpl impl = (ResourceImpl)resource;
558 return backend.add(impl.id);
561 boolean add(int id) {
562 return backend.add(id);
566 public boolean addAll(Collection<? extends Resource> rs) {
567 boolean result = false;
568 for(Resource r : rs) result |= add(r);
573 public boolean contains(Object resource) {
574 ResourceImpl impl = (ResourceImpl)resource;
575 return backend.contains(impl.id);
579 public boolean containsAll(Collection<?> rs) {
587 public boolean isEmpty() {
588 return backend.isEmpty();
592 public Iterator<Resource> iterator() {
593 return new Iterator<Resource>() {
595 TIntIterator it = backend.iterator();
598 public boolean hasNext() {
603 public Resource next() {
604 return new ResourceImpl(session.resourceSupport, it.next());
608 public void remove() {
616 public boolean remove(Object resource) {
617 ResourceImpl impl = (ResourceImpl)resource;
618 return backend.remove(impl.id);
622 public boolean removeAll(Collection<?> rs) {
623 boolean result = false;
624 for(Object r : rs) result |= remove(r);
629 public boolean retainAll(Collection<?> arg0) {
630 throw new UnsupportedOperationException("Not implemented");
634 public Object[] toArray() {
635 return toArray(new Object[backend.size()]);
638 @SuppressWarnings("unchecked")
640 public <T> T[] toArray(T[] a) {
641 int size = backend.size();
642 T[] r = a.length >= size ? a :
643 (T[])Array.newInstance(a.getClass().getComponentType(), size);
644 backend.forEach(new TIntProcedure() {
649 public boolean execute(int value) {
650 r[index++] = (T)new ResourceImpl(session.resourceSupport, value);
658 public int hashCode() {
659 return backend.hashCode();
663 public boolean equals(Object obj) {
668 if (getClass() != obj.getClass()) {
669 if (obj instanceof Set) {
670 // Nonoptimal fallback for comparing against generic Set
671 Collection<?> c = (Collection<?>) obj;
672 if (c.size() != size())
675 return containsAll(c);
676 } catch (ClassCastException unused) {
678 } catch (NullPointerException unused) {
684 ResourceSet other = (ResourceSet) obj;
685 return session == other.session && backend.equals(other.backend);
691 public Set<Resource> createSet() {
692 return new ResourceSet(session);
696 public Set<Resource> createSet(int capacity) {
697 return new ResourceSet(session, capacity);
700 static final class ResourceList implements List<Resource> {
702 final private SessionImplSocket session;
703 final private TIntArrayList backend;
705 ResourceList(SessionImplSocket session) {
706 this.session = session;
707 this.backend = new TIntArrayList();
710 ResourceList(SessionImplSocket session, int capacity) {
711 this.session = session;
712 this.backend = new TIntArrayList(capacity);
715 ResourceList(SessionImplSocket session, Collection<Resource> rs) {
716 this.session = session;
717 this.backend = new TIntArrayList(rs.size());
722 public void clear() {
723 throw new UnsupportedOperationException("Not implemented");
728 return backend.size();
732 public boolean add(Resource resource) {
733 if(resource == null) {
736 ResourceImpl impl = (ResourceImpl)resource;
737 backend.add(impl.id);
743 public boolean addAll(Collection<? extends Resource> rs) {
744 if(rs instanceof ResourceList) {
745 ResourceList rl = (ResourceList)rs;
746 backend.addAll(rl.backend);
747 return !rl.isEmpty();
749 boolean result = true;
750 for(Resource r : rs) result &= add(r);
755 public boolean contains(Object resource) {
756 ResourceImpl impl = (ResourceImpl)resource;
757 return backend.contains(impl.id);
761 public boolean containsAll(Collection<?> rs) {
762 boolean result = true;
763 for(Object r : rs) result &= contains(r);
768 public boolean isEmpty() {
769 return backend.isEmpty();
773 public Iterator<Resource> iterator() {
774 return new Iterator<Resource>() {
777 int max = backend.size();
780 public boolean hasNext() {
785 public Resource next() {
788 throw new NoSuchElementException();
789 int id = backend.getQuick(i);
791 return new ResourceImpl(session.resourceSupport, id);
795 public void remove() {
796 throw new UnsupportedOperationException("remove not supported");
803 public boolean remove(Object resource) {
804 if(!(resource instanceof ResourceImpl)) return false;
805 ResourceImpl impl = (ResourceImpl)resource;
806 return backend.remove(impl.id);
810 public boolean removeAll(Collection<?> rs) {
811 boolean modified = false;
813 modified |= remove(o);
818 public boolean retainAll(Collection<?> arg0) {
819 throw new UnsupportedOperationException("Not implemented");
823 public Object[] toArray() {
824 return toArray(new Object[backend.size()]);
827 @SuppressWarnings("unchecked")
829 public <T> T[] toArray(T[] a) {
830 int size = backend.size();
831 T[] r = a.length >= size ? a :
832 (T[])Array.newInstance(a.getClass().getComponentType(), size);
833 backend.forEach(new TIntProcedure() {
838 public boolean execute(int value) {
839 r[index++] = (T)new ResourceImpl(session.resourceSupport, value);
851 public boolean addAll(int index, Collection<? extends Resource> rs) {
852 if(rs.isEmpty()) return false;
854 for(Resource r : rs) {
861 public Resource get(int index) {
862 int id = backend.get(index);
863 if(id == 0) return null;
864 return new ResourceImpl(session.resourceSupport, id);
868 public Resource set(int index, Resource resource) {
869 ResourceImpl impl = (ResourceImpl)resource;
870 int old = backend.set(index, impl.id);
871 if(old == 0) return null;
872 return new ResourceImpl(session.resourceSupport, old);
876 public void add(int index, Resource resource) {
877 ResourceImpl impl = (ResourceImpl)resource;
878 backend.insert(index, impl.id);
882 public Resource remove(int index) {
883 int id = backend.removeAt(index);
884 return new ResourceImpl(session.resourceSupport, id);
888 public int indexOf(Object o) {
889 if(!(o instanceof ResourceImpl)) return -1;
890 ResourceImpl impl = (ResourceImpl)o;
891 return backend.indexOf(impl.id);
895 public int lastIndexOf(Object o) {
896 if(!(o instanceof ResourceImpl)) return -1;
897 ResourceImpl impl = (ResourceImpl)o;
898 return backend.lastIndexOf(impl.id);
901 private class ListItr implements ListIterator<Resource> {
906 public ListItr(int index) {
912 public boolean hasNext() {
917 public Resource next() {
920 throw new NoSuchElementException();
921 int id = backend.getQuick(index);
923 return new ResourceImpl(session.resourceSupport, id);
927 public boolean hasPrevious() {
932 public Resource previous() {
935 throw new NoSuchElementException();
936 int id = backend.getQuick(index);
938 return new ResourceImpl(session.resourceSupport, id);
942 public int nextIndex() {
947 public int previousIndex() {
952 public void remove() {
953 throw new UnsupportedOperationException("remove not supported");
957 public void set(Resource e) {
958 throw new UnsupportedOperationException("set not supported");
962 public void add(Resource e) {
963 throw new UnsupportedOperationException("add not supported");
968 public ListIterator<Resource> listIterator() {
969 return new ListItr(0);
973 public ListIterator<Resource> listIterator(int index) {
974 if (index < 0 || index > backend.size())
975 throw new IndexOutOfBoundsException("Index: "+index);
976 return new ListItr(index);
980 public List<Resource> subList(int fromIndex, int toIndex) {
981 ResourceList result = new ResourceList(session);
982 for(int i=fromIndex;i<toIndex;i++)
988 public int hashCode() {
989 return backend.hashCode();
993 public boolean equals(Object obj) {
998 if (getClass() != obj.getClass()) {
999 if (obj instanceof List) {
1000 // Nonoptimal fallback for comparing against generic List
1001 ListIterator<?> e1 = listIterator();
1002 ListIterator<?> e2 = ((List<?>) obj).listIterator();
1003 while (e1.hasNext() && e2.hasNext()) {
1004 Object o1 = e1.next();
1005 Object o2 = e2.next();
1006 if (!(o1==null ? o2==null : o1.equals(o2)))
1009 return !(e1.hasNext() || e2.hasNext());
1013 ResourceList other = (ResourceList) obj;
1014 return session == other.session && backend.equals(other.backend);
1020 public List<Resource> createList() {
1021 return new ResourceList(session);
1025 public List<Resource> createList(int capacity) {
1026 return new ResourceList(session, capacity);
1029 static final class StatementList implements Collection<Statement> {
1031 final private SessionImplSocket session;
1032 final private TIntArrayList backend = new TIntArrayList();
1034 StatementList(SessionImplSocket session) {
1035 this.session = session;
1039 public void clear() {
1040 throw new UnsupportedOperationException("Not implemented");
1045 return backend.size() / 3;
1049 public boolean add(Statement stm) {
1050 ResourceImpl s = (ResourceImpl)stm.getSubject();
1051 ResourceImpl p = (ResourceImpl)stm.getPredicate();
1052 ResourceImpl o = (ResourceImpl)stm.getObject();
1060 public boolean addAll(Collection<? extends Statement> rs) {
1061 boolean result = false;
1062 for(Statement r : rs) result |= add(r);
1067 public boolean contains(Object statement) {
1068 throw new UnsupportedOperationException("Not implemented");
1072 public boolean containsAll(Collection<?> rs) {
1073 throw new UnsupportedOperationException("Not implemented");
1077 public boolean isEmpty() {
1078 return backend.isEmpty();
1082 public Iterator<Statement> iterator() {
1083 return new Iterator<Statement>() {
1086 int max = backend.size();
1089 public boolean hasNext() {
1094 public Statement next() {
1095 return new DirectStatementImpl(session.resourceSupport, backend.getQuick(index++), backend.getQuick(index++), backend.getQuick(index++));
1099 public void remove() {
1100 throw new UnsupportedOperationException("Not supported");
1107 public boolean remove(Object resource) {
1108 throw new UnsupportedOperationException("Not implemented");
1112 public boolean removeAll(Collection<?> rs) {
1113 throw new UnsupportedOperationException("Not implemented");
1117 public boolean retainAll(Collection<?> arg0) {
1118 throw new UnsupportedOperationException("Not implemented");
1122 public Object[] toArray() {
1123 int stms = backend.size() / 3;
1124 return toArray(new Object[stms]);
1127 @SuppressWarnings("unchecked")
1129 public <T> T[] toArray(T[] a) {
1130 int size = backend.size();
1131 int stms = size / 3;
1132 T[] r = a.length >= size ? a :
1133 (T[])Array.newInstance(a.getClass().getComponentType(), stms);
1135 for (int i = 0; i < size; i += 3) {
1136 r[index++] = (T) new DirectStatementImpl(session.resourceSupport, backend.getQuick(i), backend.getQuick(i+1), backend.getQuick(i+2));
1142 public int hashCode() {
1143 return backend.hashCode();
1147 public boolean equals(Object obj) {
1152 if (getClass() != obj.getClass()) {
1153 if (obj instanceof Collection) {
1154 // Nonoptimal fallback for comparing against generic Collection
1155 Iterator<?> e1 = iterator();
1156 Iterator<?> e2 = ((Collection<?>) obj).iterator();
1157 while (e1.hasNext() && e2.hasNext()) {
1158 Object o1 = e1.next();
1159 Object o2 = e2.next();
1160 if (!(o1==null ? o2==null : o1.equals(o2)))
1163 return !(e1.hasNext() || e2.hasNext());
1167 StatementList other = (StatementList) obj;
1168 return session == other.session && backend.equals(other.backend);
1174 public Collection<Statement> createStatementList() {
1175 return new StatementList(session);
1178 private static Comparator<Resource> RESOURCE_COMPARATOR = (o1, o2) -> {
1179 ResourceImpl r1 = (ResourceImpl)o1;
1180 ResourceImpl r2 = (ResourceImpl)o2;
1181 return Integer.compare(r1.id, r2.id);
1185 public void sort(List<Resource> list) {
1186 if(list instanceof ResourceList) {
1187 ((ResourceList) list).sort();
1189 Collections.sort(list, RESOURCE_COMPARATOR);
1194 public List<Resource> asSortedList(Collection<Resource> rs) {
1195 ResourceList result = new ResourceList(session, rs);
1201 public org.simantics.db.ResourceSet getResourceSet(ReadGraph graph, Collection<Resource> resources) {
1202 if(resources instanceof ResourceSet) return (org.simantics.db.ResourceSet)resources;
1203 org.simantics.db.ResourceSet result = new IntSet(((ReadGraphImpl)graph).processor.querySupport);
1204 for(Resource r : resources) result.add(r);
1209 public org.simantics.db.ResourceSet getResourceSet(ReadGraph graph, Resource ... rs) {
1210 org.simantics.db.ResourceSet result = new IntSet(((ReadGraphImpl)graph).processor.querySupport);
1211 for(Resource r : rs) result.add(r);