15bbffad859b880f19d545cfa8a9a2207ee605de
[simantics/platform.git] / bundles / org.simantics.db.procore / src / fi / vtt / simantics / procore / internal / CollectionSupportImpl.java
1 package fi.vtt.simantics.procore.internal;
2
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;
12 import java.util.Map;
13 import java.util.NoSuchElementException;
14 import java.util.Set;
15 import java.util.function.Consumer;
16
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;
25
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;
37
38 public class CollectionSupportImpl implements CollectionSupport {
39
40         final private SessionImplSocket session;
41
42         CollectionSupportImpl(SessionImplSocket session) {
43                 this.session = session;
44         }
45
46         static final class IntResourceMap {
47
48                 final private SessionImplSocket session;
49                 final private TIntIntHashMap backend = new TIntIntHashMap(Constants.DEFAULT_CAPACITY, Constants.DEFAULT_LOAD_FACTOR, -1, 0);
50
51                 IntResourceMap(SessionImplSocket session) {
52                         this.session = session;
53                 }
54
55                 public int size() {
56                         return backend.size();
57                 }
58
59                 public boolean isEmpty() {
60                         return backend.isEmpty();
61                 }
62
63                 public boolean containsKey(int key) {
64                         return backend.containsKey(key);
65                 }
66
67                 public boolean containsValue(int value) {
68                         return backend.containsValue(value);
69                 }
70
71                 public Resource get(int key) {
72                         try {
73                                 return session.getResourceByKey(backend.get(key));
74                         } catch (ResourceNotFoundException e) {
75                                 e.printStackTrace();
76                         }
77                         return null;
78                 }
79
80                 public Resource put(int key, Resource value) {
81                         ResourceImpl impl = (ResourceImpl) value;
82                         int i = backend.put(key, impl.id);
83                         if (i == 0)
84                                 return null;
85                         else
86                                 try {
87                                         return session.getResourceByKey(i);
88                                 } catch (ResourceNotFoundException e) {
89                                         e.printStackTrace();
90                                 }
91                         return null;
92                 }
93
94                 public Resource remove(int key) {
95                         throw new UnsupportedOperationException("remove not supported");
96                 }
97
98                 @Override
99                 public int hashCode() {
100                         return backend.hashCode();
101                 }
102
103                 @Override
104                 public boolean equals(Object obj) {
105                         if (this == obj)
106                                 return true;
107                         if (obj == null)
108                                 return false;
109                         if (getClass() != obj.getClass())
110                                 return false;
111                         IntResourceMap other = (IntResourceMap) obj;
112                         return session == other.session && backend.equals(other.backend);
113                 }
114         }
115
116         public IntResourceMap createIntResourceMap() {
117                 return new IntResourceMap(session);
118         }
119
120         static final class ObjectResourceMap<T> implements Map<T, Resource> {
121
122                 final private SessionImplSocket session;
123                 final private TObjectIntHashMap<T> backend;
124
125                 ObjectResourceMap(SessionImplSocket session) {
126                         this.session = session;
127                         backend = new TObjectIntHashMap<T>(Constants.DEFAULT_CAPACITY, Constants.DEFAULT_LOAD_FACTOR, 0);
128                 }
129
130                 ObjectResourceMap(SessionImplSocket session, int capacity) {
131                         this.session = session;
132                         backend = new TObjectIntHashMap<T>(capacity, Constants.DEFAULT_LOAD_FACTOR, 0);
133                 }
134
135                 @Override
136                 public int size() {
137                         return backend.size();
138                 }
139                 @Override
140                 public boolean isEmpty() {
141                         return backend.isEmpty();
142                 }
143
144                 @Override
145                 public boolean containsKey(Object key) {
146                         return backend.contains(key);
147                 }
148
149                 @Override
150                 public boolean containsValue(Object value) {
151                         ResourceImpl impl = (ResourceImpl) value;
152                         return backend.containsValue(impl.id);
153                 }
154
155                 @Override
156                 public Resource get(Object key) {
157                         try {
158                                 int result = backend.get(key);
159                                 if (result == 0)
160                                         return null;
161                                 return session.getResourceByKey(result);
162                         } catch (ResourceNotFoundException e) {
163                                 e.printStackTrace();
164                         }
165                         return null;
166                 }
167
168                 @Override
169                 public Resource put(T key, Resource value) {
170                         ResourceImpl impl = (ResourceImpl) value;
171                         int i = backend.put(key, impl.id);
172                         if (i == 0)
173                                 return null;
174                         else
175                                 try {
176                                         return session.getResourceByKey(i);
177                                 } catch (ResourceNotFoundException e) {
178                                         e.printStackTrace();
179                                 }
180                         return null;
181                 }
182
183                 @Override
184                 public Resource remove(Object key) {
185                         throw new UnsupportedOperationException("remove not supported, structure is immutable");
186                 }
187
188                 @Override
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>() {
193
194                                 @Override
195                                 public boolean execute(T a, int b) {
196                                         backend.put(a, b);
197                                         return true;
198                                 }
199                         });
200                 }
201
202                 @Override
203                 public void clear() {
204                         throw new UnsupportedOperationException("clear not supported, structure is immutable");
205                 }
206
207                 @Override
208                 public Set<T> keySet() {
209                         final Set<T> result = new HashSet<T>();
210                         backend.forEach(new TObjectProcedure<T>() {
211
212                                 @Override
213                                 public boolean execute(T object) {
214                                         result.add(object);
215                                         return true;
216                                 }
217                         });
218                         return result;
219                 }
220
221                 @Override
222                 public Collection<Resource> values() {
223                         ArrayList<Resource> result = new ArrayList<Resource>();
224                         for (int key : backend.values()) {
225                                 try {
226                                         result.add(session.getResourceByKey(key));
227                                 } catch (ResourceNotFoundException e) {
228                                         e.printStackTrace();
229                                 }
230                         }
231                         return result;
232                 }
233
234                 @Override
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>() {
238
239                                 @Override
240                                 public boolean execute(final T a, final int b) {
241                                         return result.add(new Map.Entry<T, Resource>() {
242
243                                                 @Override
244                                                 public T getKey() {
245                                                         return a;
246                                                 }
247
248                                                 @Override
249                                                 public Resource getValue() {
250                                                         return new ResourceImpl(session.resourceSupport, b);
251                                                 }
252
253                                                 @Override
254                                                 public Resource setValue(Resource value) {
255                                                         throw new UnsupportedOperationException("Map.Entry.setValue not supported, structure is immutable");
256                                                 }
257
258                                         });
259                                 }
260                         });
261                         return result;
262                 }
263
264                 @Override
265                 public int hashCode() {
266                         return backend.hashCode();
267                 }
268
269                 @Override
270                 public boolean equals(Object obj) {
271                         if (this == obj)
272                                 return true;
273                         if (obj == null)
274                                 return false;
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())
280                                                 return false;
281                                         try {
282                                                 Iterator<Entry<T,Resource>> i = entrySet().iterator();
283                                                 while (i.hasNext()) {
284                                                         Entry<T,Resource> e = i.next();
285                                                         T key = e.getKey();
286                                                         Resource value = e.getValue();
287                                                         if (value == null) {
288                                                                 if (!(m.get(key)==null && m.containsKey(key)))
289                                                                         return false;
290                                                         } else {
291                                                                 if (!value.equals(m.get(key)))
292                                                                         return false;
293                                                         }
294                                                 }
295                                         } catch (ClassCastException unused) {
296                                                 return false;
297                                         } catch (NullPointerException unused) {
298                                                 return false;
299                                         }
300                                 }
301                                 return false;
302                         }
303                         ObjectResourceMap<?> other = (ObjectResourceMap<?>) obj;
304                         return session == other.session && backend.equals(other.backend);
305                 }
306
307         }
308
309         @SuppressWarnings("unchecked")
310         @Override
311         public <T, I> T createObjectResourceMap(Class<I> clazz) {
312                 return (T)new ObjectResourceMap<I>(session);
313         }
314
315         @SuppressWarnings("unchecked")
316         @Override
317         public <T, I> T createObjectResourceMap(Class<I> clazz, int capacity) {
318                 return (T)new ObjectResourceMap<I>(session, capacity);
319         }
320
321     static final class ResourceMap<T> implements org.simantics.db.ResourceMap<T> {
322
323         final private SessionImplSocket session;
324         final private TIntObjectHashMap<T> backend = new TIntObjectHashMap<T>();
325
326         ResourceMap(SessionImplSocket session) {
327                 this.session = session;
328         }
329
330                 @Override
331                 public void clear() {
332                         throw new UnsupportedOperationException("Not implemented");
333                 }
334
335                 @Override
336                 public boolean containsKey(Object resource) {
337                         ResourceImpl impl = (ResourceImpl)resource;
338                         return backend.containsKey(impl.id);
339                 }
340
341                 @SuppressWarnings("unchecked")
342                 @Override
343                 public boolean containsValue(Object value) {
344                         return backend.containsValue((T)value);
345                 }
346
347                 @Override
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>() {
351
352                                 @Override
353                                 public boolean execute(final int a, final T b) {
354                                         result.add(new Map.Entry<Resource, T>() {
355
356                                                 @Override
357                                                 public Resource getKey() {
358                                                         return new ResourceImpl(session.resourceSupport, a);
359                                                 }
360
361                                                 @Override
362                                                 public T getValue() {
363                                                         return b;
364                                                 }
365
366                                                 @Override
367                                                 public T setValue(T arg0) {
368                                                         throw new UnsupportedOperationException("Not supported");
369                                                 }
370
371                                         });
372                                         return true;
373                                 }
374
375                         });
376                         return result;
377                 }
378
379                 @Override
380                 public T get(Object resource) {
381                         ResourceImpl impl = (ResourceImpl)resource;
382                         return backend.get(impl.id);
383                 }
384
385                 @Override
386                 public boolean isEmpty() {
387                         return backend.isEmpty();
388                 }
389
390                 public class CallbackEntry<E> implements ResourceMapEntry<E> {
391
392                         int id;
393                         E value;
394
395                         @Override
396                         public Resource getKey() {
397                                 return new ResourceImpl(session.resourceSupport, id);
398                         }
399
400                         @Override
401                         public E getValue() {
402                                 return value;
403                         }
404
405                 }
406
407                 @Override
408                 public void iterateEntries(final Consumer<ResourceMapEntry<T>> callback) {
409                         final CallbackEntry<T> entry = new CallbackEntry<T>();
410                         backend.forEach(new TIntProcedure() {
411
412                                 @Override
413                                 public boolean execute(int value) {
414                                         entry.id = value;
415                                         entry.value = backend.get(value);
416                                         callback.accept(entry);
417                                         return true;
418                                 }
419                         });
420                 }
421
422                 @Override
423                 public Set<Resource> keySet() {
424                         final ResourceSet result = new ResourceSet(session);
425                         backend.forEach(new TIntProcedure() {
426
427                                 @Override
428                                 public boolean execute(int value) {
429                                         result.add(value);
430                                         return true;
431                                 }
432                         });
433                         return result;
434                 }
435
436                 @Override
437                 public T put(Resource resource, T value) {
438                         ResourceImpl impl = (ResourceImpl)resource;
439                         return backend.put(impl.id, value);
440                 }
441
442                 @Override
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>() {
447
448                                 @Override
449                                 public boolean execute(int a, T b) {
450                                         backend.put(a, b);
451                                         return true;
452                                 }
453
454                         });
455                 }
456
457                 @Override
458                 public T remove(Object key) {
459                         if (key instanceof ResourceImpl) {
460                                 ResourceImpl impl = (ResourceImpl)key;
461                                 return backend.remove(impl.id);
462                         }
463                         return null;
464                 }
465
466                 @Override
467                 public int size() {
468                         return backend.size();
469                 }
470
471                 @SuppressWarnings("unchecked")
472                 @Override
473                 public Collection<T> values() {
474                         ArrayList<T> result = new ArrayList<>();
475                         for(Object o : backend.values()) result.add((T)o);
476                         return result;
477                 }
478
479                 @Override
480                 public int hashCode() {
481                         return backend.hashCode();
482                 }
483
484                 @Override
485                 public boolean equals(Object obj) {
486                         if (this == obj)
487                                 return true;
488                         if (obj == null)
489                                 return false;
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())
495                                                 return false;
496                                         try {
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();
502                                                         if (value == null) {
503                                                                 if (!(m.get(key)==null && m.containsKey(key)))
504                                                                         return false;
505                                                         } else {
506                                                                 if (!value.equals(m.get(key)))
507                                                                         return false;
508                                                         }
509                                                 }
510                                         } catch (ClassCastException unused) {
511                                                 return false;
512                                         } catch (NullPointerException unused) {
513                                                 return false;
514                                         }
515                                 }
516                                 return false;
517                         }
518                         ResourceMap<?> other = (ResourceMap<?>) obj;
519                         return session == other.session && backend.equals(other.backend);
520                 }
521
522     }
523
524         @SuppressWarnings("unchecked")
525         @Override
526         public <T, I> T createMap(Class<I> clazz) {
527                 return (T)new ResourceMap<I>(session);
528         }
529
530     static final class ResourceSet implements Set<Resource> {
531
532         final private SessionImplSocket session;
533         final private TIntHashSet backend;
534
535         ResourceSet(SessionImplSocket session) {
536                 this.session = session;
537                 backend = new TIntHashSet();
538         }
539
540         ResourceSet(SessionImplSocket session, int capacity) {
541                 this.session = session;
542                 backend = new TIntHashSet(capacity);
543         }
544
545         @Override
546                 public void clear() {
547                         backend.clear();
548                 }
549
550                 @Override
551                 public int size() {
552                         return backend.size();
553                 }
554
555                 @Override
556                 public boolean add(Resource resource) {
557                         ResourceImpl impl = (ResourceImpl)resource;
558                         return backend.add(impl.id);
559                 }
560
561                 boolean add(int id) {
562                         return backend.add(id);
563                 }
564
565                 @Override
566                 public boolean addAll(Collection<? extends Resource> rs) {
567                         boolean result = false;
568                         for(Resource r : rs) result |= add(r);
569                         return result;
570                 }
571
572                 @Override
573                 public boolean contains(Object resource) {
574                         ResourceImpl impl = (ResourceImpl)resource;
575                         return backend.contains(impl.id);
576                 }
577
578                 @Override
579                 public boolean containsAll(Collection<?> rs) {
580                         for (Object r : rs)
581                                 if (!contains(r))
582                                         return false;
583                         return true;
584                 }
585
586                 @Override
587                 public boolean isEmpty() {
588                         return backend.isEmpty();
589                 }
590
591                 @Override
592                 public Iterator<Resource> iterator() {
593                         return new Iterator<Resource>() {
594
595                                 TIntIterator it = backend.iterator();
596
597                                 @Override
598                                 public boolean hasNext() {
599                                         return it.hasNext();
600                                 }
601
602                                 @Override
603                                 public Resource next() {
604                                         return new ResourceImpl(session.resourceSupport, it.next());
605                                 }
606
607                                 @Override
608                                 public void remove() {
609                                         it.remove();
610                                 }
611
612                         };
613                 }
614
615                 @Override
616                 public boolean remove(Object resource) {
617                         ResourceImpl impl = (ResourceImpl)resource;
618                         return backend.remove(impl.id);
619                 }
620
621                 @Override
622                 public boolean removeAll(Collection<?> rs) {
623                         boolean result = false;
624                         for(Object r : rs) result |= remove(r);
625                         return result;
626                 }
627
628                 @Override
629                 public boolean retainAll(Collection<?> arg0) {
630                         throw new UnsupportedOperationException("Not implemented");
631                 }
632
633                 @Override
634                 public Object[] toArray() {
635                         return toArray(new Object[backend.size()]);
636                 }
637
638                 @SuppressWarnings("unchecked")
639                 @Override
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() {
645
646                                 int index = 0;
647
648                                 @Override
649                                 public boolean execute(int value) {
650                                         r[index++] = (T)new ResourceImpl(session.resourceSupport, value);
651                                         return true;
652                                 }
653                         });
654                         return r;
655                 }
656
657                 @Override
658                 public int hashCode() {
659                         return backend.hashCode();
660                 }
661
662                 @Override
663                 public boolean equals(Object obj) {
664                         if (this == obj)
665                                 return true;
666                         if (obj == null)
667                                 return false;
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())
673                                                 return false;
674                                         try {
675                                                 return containsAll(c);
676                                         } catch (ClassCastException unused) {
677                                                 return false;
678                                         } catch (NullPointerException unused) {
679                                                 return false;
680                                         }
681                                 }
682                                 return false;
683                         }
684                         ResourceSet other = (ResourceSet) obj;
685                         return session == other.session && backend.equals(other.backend);
686                 }
687
688     }
689
690         @Override
691         public Set<Resource> createSet() {
692                 return new ResourceSet(session);
693         }
694
695         @Override
696         public Set<Resource> createSet(int capacity) {
697                 return new ResourceSet(session, capacity);
698         }
699
700         static final class ResourceList implements List<Resource> {
701
702         final private SessionImplSocket session;
703         final private TIntArrayList backend;
704
705         ResourceList(SessionImplSocket session) {
706                 this.session = session;
707                 this.backend = new TIntArrayList();
708         }
709
710         ResourceList(SessionImplSocket session, int capacity) {
711                 this.session = session;
712                 this.backend = new TIntArrayList(capacity);
713         }
714
715         ResourceList(SessionImplSocket session, Collection<Resource> rs) {
716                 this.session = session;
717                 this.backend = new TIntArrayList(rs.size());
718                 addAll(rs);
719         }
720
721                 @Override
722                 public void clear() {
723                         throw new UnsupportedOperationException("Not implemented");
724                 }
725
726                 @Override
727                 public int size() {
728                         return backend.size();
729                 }
730
731                 @Override
732                 public boolean add(Resource resource) {
733                         if(resource == null) {
734                                 backend.add(0);
735                         } else {
736                                 ResourceImpl impl = (ResourceImpl)resource;
737                                 backend.add(impl.id);
738                         }
739                         return true;
740                 }
741
742                 @Override
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();
748                         }
749                         boolean result = true;
750                         for(Resource r : rs) result &= add(r);
751                         return result;
752                 }
753
754                 @Override
755                 public boolean contains(Object resource) {
756                         ResourceImpl impl = (ResourceImpl)resource;
757                         return backend.contains(impl.id);
758                 }
759
760                 @Override
761                 public boolean containsAll(Collection<?> rs) {
762                         boolean result = true;
763                         for(Object r : rs) result &= contains(r);
764                         return result;
765                 }
766
767                 @Override
768                 public boolean isEmpty() {
769                         return backend.isEmpty();
770                 }
771
772                 @Override
773                 public Iterator<Resource> iterator() {
774                         return new Iterator<Resource>() {
775
776                                 int index = 0;
777                                 int max = backend.size();
778
779                                 @Override
780                                 public boolean hasNext() {
781                                         return index < max;
782                                 }
783
784                                 @Override
785                                 public Resource next() {
786                                         int i = index;
787                                         if (i >= max)
788                                                 throw new NoSuchElementException();
789                                         int id = backend.getQuick(i);
790                                         index = i + 1;
791                                         return new ResourceImpl(session.resourceSupport, id);
792                                 }
793
794                                 @Override
795                                 public void remove() {
796                                         throw new UnsupportedOperationException("remove not supported");
797                                 }
798
799                         };
800                 }
801
802                 @Override
803                 public boolean remove(Object resource) {
804                         if(!(resource instanceof ResourceImpl)) return false;
805                         ResourceImpl impl = (ResourceImpl)resource;
806                         return backend.remove(impl.id);
807                 }
808
809                 @Override
810                 public boolean removeAll(Collection<?> rs) {
811                         boolean modified = false;
812                         for(Object o : rs)
813                                 modified |= remove(o);
814                         return modified;
815                 }
816
817                 @Override
818                 public boolean retainAll(Collection<?> arg0) {
819                         throw new UnsupportedOperationException("Not implemented");
820                 }
821
822                 @Override
823                 public Object[] toArray() {
824                         return toArray(new Object[backend.size()]);
825                 }
826
827                 @SuppressWarnings("unchecked")
828                 @Override
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() {
834
835                                 int index = 0;
836
837                                 @Override
838                                 public boolean execute(int value) {
839                                         r[index++] = (T)new ResourceImpl(session.resourceSupport, value);
840                                         return true;
841                                 }
842                         });
843                         return r;
844                 }
845
846                 void sort() {
847                         backend.sort();
848                 }
849
850                 @Override
851                 public boolean addAll(int index, Collection<? extends Resource> rs) {
852                         if(rs.isEmpty()) return false;
853                         int i = index;
854                         for(Resource r : rs) {
855                                 add(i++, r);
856                         }
857                         return true;
858                 }
859
860                 @Override
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);
865                 }
866
867                 @Override
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);
873                 }
874
875                 @Override
876                 public void add(int index, Resource resource) {
877                         ResourceImpl impl = (ResourceImpl)resource;
878                         backend.insert(index, impl.id);
879                 }
880
881                 @Override
882                 public Resource remove(int index) {
883                         int id = backend.removeAt(index);
884                         return new ResourceImpl(session.resourceSupport, id);
885                 }
886
887                 @Override
888                 public int indexOf(Object o) {
889                         if(!(o instanceof ResourceImpl)) return -1;
890                         ResourceImpl impl = (ResourceImpl)o;
891                         return backend.indexOf(impl.id);
892                 }
893
894                 @Override
895                 public int lastIndexOf(Object o) {
896                         if(!(o instanceof ResourceImpl)) return -1;
897                         ResourceImpl impl = (ResourceImpl)o;
898                         return backend.lastIndexOf(impl.id);
899                 }
900
901                 private class ListItr implements ListIterator<Resource> {
902
903                         int index;
904                         int max;
905
906                         public ListItr(int index) {
907                                 this.index = index;
908                                 this.max = size();
909                         }
910
911                         @Override
912                         public boolean hasNext() {
913                                 return index < max;
914                         }
915
916                         @Override
917                         public Resource next() {
918                                 int i = index;
919                                 if (i >= max)
920                                         throw new NoSuchElementException();
921                                 int id = backend.getQuick(index);
922                                 index = i + 1;
923                                 return new ResourceImpl(session.resourceSupport, id);
924                         }
925
926                         @Override
927                         public boolean hasPrevious() {
928                                 return index != 0;
929                         }
930
931                         @Override
932                         public Resource previous() {
933                                 int i = index - 1;
934                                 if (i < 0)
935                                         throw new NoSuchElementException();
936                                 int id = backend.getQuick(index);
937                                 index = i;
938                                 return new ResourceImpl(session.resourceSupport, id);
939                         }
940
941                         @Override
942                         public int nextIndex() {
943                                 return index;
944                         }
945
946                         @Override
947                         public int previousIndex() {
948                                 return index - 1;
949                         }
950
951                         @Override
952                         public void remove() {
953                                 throw new UnsupportedOperationException("remove not supported");
954                         }
955
956                         @Override
957                         public void set(Resource e) {
958                                 throw new UnsupportedOperationException("set not supported");
959                         }
960
961                         @Override
962                         public void add(Resource e) {
963                                 throw new UnsupportedOperationException("add not supported");
964                         }
965                 }
966
967                 @Override
968                 public ListIterator<Resource> listIterator() {
969                         return new ListItr(0);
970                 }
971
972                 @Override
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);
977                 }
978
979                 @Override
980                 public List<Resource> subList(int fromIndex, int toIndex) {
981                         ResourceList result = new ResourceList(session);
982                         for(int i=fromIndex;i<toIndex;i++)
983                                 result.add(get(i));
984                         return result;
985                 }
986
987                 @Override
988                 public int hashCode() {
989                         return backend.hashCode();
990                 }
991
992                 @Override
993                 public boolean equals(Object obj) {
994                         if (this == obj)
995                                 return true;
996                         if (obj == null)
997                                 return false;
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)))
1007                                                         return false;
1008                                         }
1009                                         return !(e1.hasNext() || e2.hasNext());
1010                                 }
1011                                 return false;
1012                         }
1013                         ResourceList other = (ResourceList) obj;
1014                         return session == other.session && backend.equals(other.backend);
1015                 }
1016
1017     }
1018
1019         @Override
1020         public List<Resource> createList() {
1021                 return new ResourceList(session);
1022         }
1023
1024         @Override
1025         public List<Resource> createList(int capacity) {
1026                 return new ResourceList(session, capacity);
1027         }
1028
1029     static final class StatementList implements Collection<Statement> {
1030
1031         final private SessionImplSocket session;
1032         final private TIntArrayList backend = new TIntArrayList();
1033
1034         StatementList(SessionImplSocket session) {
1035                 this.session = session;
1036         }
1037
1038                 @Override
1039                 public void clear() {
1040                         throw new UnsupportedOperationException("Not implemented");
1041                 }
1042
1043                 @Override
1044                 public int size() {
1045                         return backend.size() / 3;
1046                 }
1047
1048                 @Override
1049                 public boolean add(Statement stm) {
1050                         ResourceImpl s = (ResourceImpl)stm.getSubject();
1051                         ResourceImpl p = (ResourceImpl)stm.getPredicate();
1052                         ResourceImpl o = (ResourceImpl)stm.getObject();
1053                         backend.add(s.id);
1054                         backend.add(p.id);
1055                         backend.add(o.id);
1056                         return true;
1057                 }
1058
1059                 @Override
1060                 public boolean addAll(Collection<? extends Statement> rs) {
1061                         boolean result = false;
1062                         for(Statement r : rs) result |= add(r);
1063                         return result;
1064                 }
1065
1066                 @Override
1067                 public boolean contains(Object statement) {
1068                         throw new UnsupportedOperationException("Not implemented");
1069                 }
1070
1071                 @Override
1072                 public boolean containsAll(Collection<?> rs) {
1073                         throw new UnsupportedOperationException("Not implemented");
1074                 }
1075
1076                 @Override
1077                 public boolean isEmpty() {
1078                         return backend.isEmpty();
1079                 }
1080
1081                 @Override
1082                 public Iterator<Statement> iterator() {
1083                         return new Iterator<Statement>() {
1084
1085                                 int index = 0;
1086                                 int max = backend.size();
1087
1088                                 @Override
1089                                 public boolean hasNext() {
1090                                         return index < max;
1091                                 }
1092
1093                                 @Override
1094                                 public Statement next() {
1095                                         return new DirectStatementImpl(session.resourceSupport, backend.getQuick(index++), backend.getQuick(index++), backend.getQuick(index++));
1096                                 }
1097
1098                                 @Override
1099                                 public void remove() {
1100                                         throw new UnsupportedOperationException("Not supported");
1101                                 }
1102
1103                         };
1104                 }
1105
1106                 @Override
1107                 public boolean remove(Object resource) {
1108                         throw new UnsupportedOperationException("Not implemented");
1109                 }
1110
1111                 @Override
1112                 public boolean removeAll(Collection<?> rs) {
1113                         throw new UnsupportedOperationException("Not implemented");
1114                 }
1115
1116                 @Override
1117                 public boolean retainAll(Collection<?> arg0) {
1118                         throw new UnsupportedOperationException("Not implemented");
1119                 }
1120
1121                 @Override
1122                 public Object[] toArray() {
1123                         int stms = backend.size() / 3;
1124                         return toArray(new Object[stms]);
1125                 }
1126
1127                 @SuppressWarnings("unchecked")
1128                 @Override
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);
1134                         int index = 0;
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));
1137                         }
1138                         return r;
1139                 }
1140
1141                 @Override
1142                 public int hashCode() {
1143                         return backend.hashCode();
1144                 }
1145
1146                 @Override
1147                 public boolean equals(Object obj) {
1148                         if (this == obj)
1149                                 return true;
1150                         if (obj == null)
1151                                 return false;
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)))
1161                                                         return false;
1162                                         }
1163                                         return !(e1.hasNext() || e2.hasNext());
1164                                 }
1165                                 return false;
1166                         }
1167                         StatementList other = (StatementList) obj;
1168                         return session == other.session && backend.equals(other.backend);
1169                 }
1170
1171     }
1172
1173         @Override
1174         public Collection<Statement> createStatementList() {
1175                 return new StatementList(session);
1176         }
1177
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);
1182         };
1183
1184         @Override
1185         public void sort(List<Resource> list) {
1186                 if(list instanceof ResourceList) {
1187                         ((ResourceList) list).sort();
1188                 } else {
1189                         Collections.sort(list, RESOURCE_COMPARATOR);
1190                 }
1191         }
1192
1193         @Override
1194         public List<Resource> asSortedList(Collection<Resource> rs) {
1195                 ResourceList result = new ResourceList(session, rs);
1196                 result.sort();
1197                 return result;
1198         }
1199
1200         @Override
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);
1205             return result;
1206         }
1207
1208     @Override
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);
1212         return result;
1213     }
1214
1215 }