Fixed Map & Set equals implementations in CollectionSupportImpl
[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                                                 return true;
296                                         } catch (ClassCastException unused) {
297                                                 return false;
298                                         } catch (NullPointerException unused) {
299                                                 return false;
300                                         }
301                                 }
302                                 return false;
303                         }
304                         ObjectResourceMap<?> other = (ObjectResourceMap<?>) obj;
305                         return session == other.session && backend.equals(other.backend);
306                 }
307
308         }
309
310         @SuppressWarnings("unchecked")
311         @Override
312         public <T, I> T createObjectResourceMap(Class<I> clazz) {
313                 return (T)new ObjectResourceMap<I>(session);
314         }
315
316         @SuppressWarnings("unchecked")
317         @Override
318         public <T, I> T createObjectResourceMap(Class<I> clazz, int capacity) {
319                 return (T)new ObjectResourceMap<I>(session, capacity);
320         }
321
322     static final class ResourceMap<T> implements org.simantics.db.ResourceMap<T> {
323
324         final private SessionImplSocket session;
325         final private TIntObjectHashMap<T> backend = new TIntObjectHashMap<T>();
326
327         ResourceMap(SessionImplSocket session) {
328                 this.session = session;
329         }
330
331                 @Override
332                 public void clear() {
333                         throw new UnsupportedOperationException("Not implemented");
334                 }
335
336                 @Override
337                 public boolean containsKey(Object resource) {
338                         ResourceImpl impl = (ResourceImpl)resource;
339                         return backend.containsKey(impl.id);
340                 }
341
342                 @SuppressWarnings("unchecked")
343                 @Override
344                 public boolean containsValue(Object value) {
345                         return backend.containsValue((T)value);
346                 }
347
348                 @Override
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>() {
352
353                                 @Override
354                                 public boolean execute(final int a, final T b) {
355                                         result.add(new Map.Entry<Resource, T>() {
356
357                                                 @Override
358                                                 public Resource getKey() {
359                                                         return new ResourceImpl(session.resourceSupport, a);
360                                                 }
361
362                                                 @Override
363                                                 public T getValue() {
364                                                         return b;
365                                                 }
366
367                                                 @Override
368                                                 public T setValue(T arg0) {
369                                                         throw new UnsupportedOperationException("Not supported");
370                                                 }
371
372                                         });
373                                         return true;
374                                 }
375
376                         });
377                         return result;
378                 }
379
380                 @Override
381                 public T get(Object resource) {
382                         ResourceImpl impl = (ResourceImpl)resource;
383                         return backend.get(impl.id);
384                 }
385
386                 @Override
387                 public boolean isEmpty() {
388                         return backend.isEmpty();
389                 }
390
391                 public class CallbackEntry<E> implements ResourceMapEntry<E> {
392
393                         int id;
394                         E value;
395
396                         @Override
397                         public Resource getKey() {
398                                 return new ResourceImpl(session.resourceSupport, id);
399                         }
400
401                         @Override
402                         public E getValue() {
403                                 return value;
404                         }
405
406                 }
407
408                 @Override
409                 public void iterateEntries(final Consumer<ResourceMapEntry<T>> callback) {
410                         final CallbackEntry<T> entry = new CallbackEntry<T>();
411                         backend.forEach(new TIntProcedure() {
412
413                                 @Override
414                                 public boolean execute(int value) {
415                                         entry.id = value;
416                                         entry.value = backend.get(value);
417                                         callback.accept(entry);
418                                         return true;
419                                 }
420                         });
421                 }
422
423                 @Override
424                 public Set<Resource> keySet() {
425                         final ResourceSet result = new ResourceSet(session);
426                         backend.forEach(new TIntProcedure() {
427
428                                 @Override
429                                 public boolean execute(int value) {
430                                         result.add(value);
431                                         return true;
432                                 }
433                         });
434                         return result;
435                 }
436
437                 @Override
438                 public T put(Resource resource, T value) {
439                         ResourceImpl impl = (ResourceImpl)resource;
440                         return backend.put(impl.id, value);
441                 }
442
443                 @Override
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>() {
448
449                                 @Override
450                                 public boolean execute(int a, T b) {
451                                         backend.put(a, b);
452                                         return true;
453                                 }
454
455                         });
456                 }
457
458                 @Override
459                 public T remove(Object key) {
460                         if (key instanceof ResourceImpl) {
461                                 ResourceImpl impl = (ResourceImpl)key;
462                                 return backend.remove(impl.id);
463                         }
464                         return null;
465                 }
466
467                 @Override
468                 public int size() {
469                         return backend.size();
470                 }
471
472                 @SuppressWarnings("unchecked")
473                 @Override
474                 public Collection<T> values() {
475                         ArrayList<T> result = new ArrayList<>();
476                         for(Object o : backend.values()) result.add((T)o);
477                         return result;
478                 }
479
480                 @Override
481                 public int hashCode() {
482                         return backend.hashCode();
483                 }
484
485                 @Override
486                 public boolean equals(Object obj) {
487                         if (this == obj)
488                                 return true;
489                         if (obj == null)
490                                 return false;
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())
496                                                 return false;
497                                         try {
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();
503                                                         if (value == null) {
504                                                                 if (!(m.get(key)==null && m.containsKey(key)))
505                                                                         return false;
506                                                         } else {
507                                                                 if (!value.equals(m.get(key)))
508                                                                         return false;
509                                                         }
510                                                 }
511                                                 return true;
512                                         } catch (ClassCastException unused) {
513                                                 return false;
514                                         } catch (NullPointerException unused) {
515                                                 return false;
516                                         }
517                                 }
518                                 return false;
519                         }
520                         ResourceMap<?> other = (ResourceMap<?>) obj;
521                         return session == other.session && backend.equals(other.backend);
522                 }
523
524     }
525
526         @SuppressWarnings("unchecked")
527         @Override
528         public <T, I> T createMap(Class<I> clazz) {
529                 return (T)new ResourceMap<I>(session);
530         }
531
532     static final class ResourceSet implements Set<Resource> {
533
534         final private SessionImplSocket session;
535         final private TIntHashSet backend;
536
537         ResourceSet(SessionImplSocket session) {
538                 this.session = session;
539                 backend = new TIntHashSet();
540         }
541
542         ResourceSet(SessionImplSocket session, int capacity) {
543                 this.session = session;
544                 backend = new TIntHashSet(capacity);
545         }
546
547         @Override
548                 public void clear() {
549                         backend.clear();
550                 }
551
552                 @Override
553                 public int size() {
554                         return backend.size();
555                 }
556
557                 @Override
558                 public boolean add(Resource resource) {
559                         ResourceImpl impl = (ResourceImpl)resource;
560                         return backend.add(impl.id);
561                 }
562
563                 boolean add(int id) {
564                         return backend.add(id);
565                 }
566
567                 @Override
568                 public boolean addAll(Collection<? extends Resource> rs) {
569                         boolean result = false;
570                         for(Resource r : rs) result |= add(r);
571                         return result;
572                 }
573
574                 @Override
575                 public boolean contains(Object resource) {
576                         ResourceImpl impl = (ResourceImpl)resource;
577                         return backend.contains(impl.id);
578                 }
579
580                 @Override
581                 public boolean containsAll(Collection<?> rs) {
582                         for (Object r : rs)
583                                 if (!contains(r))
584                                         return false;
585                         return true;
586                 }
587
588                 @Override
589                 public boolean isEmpty() {
590                         return backend.isEmpty();
591                 }
592
593                 @Override
594                 public Iterator<Resource> iterator() {
595                         return new Iterator<Resource>() {
596
597                                 TIntIterator it = backend.iterator();
598
599                                 @Override
600                                 public boolean hasNext() {
601                                         return it.hasNext();
602                                 }
603
604                                 @Override
605                                 public Resource next() {
606                                         return new ResourceImpl(session.resourceSupport, it.next());
607                                 }
608
609                                 @Override
610                                 public void remove() {
611                                         it.remove();
612                                 }
613
614                         };
615                 }
616
617                 @Override
618                 public boolean remove(Object resource) {
619                         ResourceImpl impl = (ResourceImpl)resource;
620                         return backend.remove(impl.id);
621                 }
622
623                 @Override
624                 public boolean removeAll(Collection<?> rs) {
625                         boolean result = false;
626                         for(Object r : rs) result |= remove(r);
627                         return result;
628                 }
629
630                 @Override
631                 public boolean retainAll(Collection<?> arg0) {
632                         throw new UnsupportedOperationException("Not implemented");
633                 }
634
635                 @Override
636                 public Object[] toArray() {
637                         return toArray(new Object[backend.size()]);
638                 }
639
640                 @SuppressWarnings("unchecked")
641                 @Override
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() {
647
648                                 int index = 0;
649
650                                 @Override
651                                 public boolean execute(int value) {
652                                         r[index++] = (T)new ResourceImpl(session.resourceSupport, value);
653                                         return true;
654                                 }
655                         });
656                         return r;
657                 }
658
659                 @Override
660                 public int hashCode() {
661                         return backend.hashCode();
662                 }
663
664                 @Override
665                 public boolean equals(Object obj) {
666                         if (this == obj)
667                                 return true;
668                         if (obj == null)
669                                 return false;
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())
675                                                 return false;
676                                         try {
677                                                 return containsAll(c);
678                                         } catch (ClassCastException unused) {
679                                                 return false;
680                                         } catch (NullPointerException unused) {
681                                                 return false;
682                                         }
683                                 }
684                                 return false;
685                         }
686                         ResourceSet other = (ResourceSet) obj;
687                         return session == other.session && backend.equals(other.backend);
688                 }
689
690     }
691
692         @Override
693         public Set<Resource> createSet() {
694                 return new ResourceSet(session);
695         }
696
697         @Override
698         public Set<Resource> createSet(int capacity) {
699                 return new ResourceSet(session, capacity);
700         }
701
702         static final class ResourceList implements List<Resource> {
703
704         final private SessionImplSocket session;
705         final private TIntArrayList backend;
706
707         ResourceList(SessionImplSocket session) {
708                 this.session = session;
709                 this.backend = new TIntArrayList();
710         }
711
712         ResourceList(SessionImplSocket session, int capacity) {
713                 this.session = session;
714                 this.backend = new TIntArrayList(capacity);
715         }
716
717         ResourceList(SessionImplSocket session, Collection<Resource> rs) {
718                 this.session = session;
719                 this.backend = new TIntArrayList(rs.size());
720                 addAll(rs);
721         }
722
723                 @Override
724                 public void clear() {
725                         throw new UnsupportedOperationException("Not implemented");
726                 }
727
728                 @Override
729                 public int size() {
730                         return backend.size();
731                 }
732
733                 @Override
734                 public boolean add(Resource resource) {
735                         if(resource == null) {
736                                 backend.add(0);
737                         } else {
738                                 ResourceImpl impl = (ResourceImpl)resource;
739                                 backend.add(impl.id);
740                         }
741                         return true;
742                 }
743
744                 @Override
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();
750                         }
751                         boolean result = true;
752                         for(Resource r : rs) result &= add(r);
753                         return result;
754                 }
755
756                 @Override
757                 public boolean contains(Object resource) {
758                         ResourceImpl impl = (ResourceImpl)resource;
759                         return backend.contains(impl.id);
760                 }
761
762                 @Override
763                 public boolean containsAll(Collection<?> rs) {
764                         boolean result = true;
765                         for(Object r : rs) result &= contains(r);
766                         return result;
767                 }
768
769                 @Override
770                 public boolean isEmpty() {
771                         return backend.isEmpty();
772                 }
773
774                 @Override
775                 public Iterator<Resource> iterator() {
776                         return new Iterator<Resource>() {
777
778                                 int index = 0;
779                                 int max = backend.size();
780
781                                 @Override
782                                 public boolean hasNext() {
783                                         return index < max;
784                                 }
785
786                                 @Override
787                                 public Resource next() {
788                                         int i = index;
789                                         if (i >= max)
790                                                 throw new NoSuchElementException();
791                                         int id = backend.getQuick(i);
792                                         index = i + 1;
793                                         return new ResourceImpl(session.resourceSupport, id);
794                                 }
795
796                                 @Override
797                                 public void remove() {
798                                         throw new UnsupportedOperationException("remove not supported");
799                                 }
800
801                         };
802                 }
803
804                 @Override
805                 public boolean remove(Object resource) {
806                         if(!(resource instanceof ResourceImpl)) return false;
807                         ResourceImpl impl = (ResourceImpl)resource;
808                         return backend.remove(impl.id);
809                 }
810
811                 @Override
812                 public boolean removeAll(Collection<?> rs) {
813                         boolean modified = false;
814                         for(Object o : rs)
815                                 modified |= remove(o);
816                         return modified;
817                 }
818
819                 @Override
820                 public boolean retainAll(Collection<?> arg0) {
821                         throw new UnsupportedOperationException("Not implemented");
822                 }
823
824                 @Override
825                 public Object[] toArray() {
826                         return toArray(new Object[backend.size()]);
827                 }
828
829                 @SuppressWarnings("unchecked")
830                 @Override
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() {
836
837                                 int index = 0;
838
839                                 @Override
840                                 public boolean execute(int value) {
841                                         r[index++] = (T)new ResourceImpl(session.resourceSupport, value);
842                                         return true;
843                                 }
844                         });
845                         return r;
846                 }
847
848                 void sort() {
849                         backend.sort();
850                 }
851
852                 @Override
853                 public boolean addAll(int index, Collection<? extends Resource> rs) {
854                         if(rs.isEmpty()) return false;
855                         int i = index;
856                         for(Resource r : rs) {
857                                 add(i++, r);
858                         }
859                         return true;
860                 }
861
862                 @Override
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);
867                 }
868
869                 @Override
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);
875                 }
876
877                 @Override
878                 public void add(int index, Resource resource) {
879                         ResourceImpl impl = (ResourceImpl)resource;
880                         backend.insert(index, impl.id);
881                 }
882
883                 @Override
884                 public Resource remove(int index) {
885                         int id = backend.removeAt(index);
886                         return new ResourceImpl(session.resourceSupport, id);
887                 }
888
889                 @Override
890                 public int indexOf(Object o) {
891                         if(!(o instanceof ResourceImpl)) return -1;
892                         ResourceImpl impl = (ResourceImpl)o;
893                         return backend.indexOf(impl.id);
894                 }
895
896                 @Override
897                 public int lastIndexOf(Object o) {
898                         if(!(o instanceof ResourceImpl)) return -1;
899                         ResourceImpl impl = (ResourceImpl)o;
900                         return backend.lastIndexOf(impl.id);
901                 }
902
903                 private class ListItr implements ListIterator<Resource> {
904
905                         int index;
906                         int max;
907
908                         public ListItr(int index) {
909                                 this.index = index;
910                                 this.max = size();
911                         }
912
913                         @Override
914                         public boolean hasNext() {
915                                 return index < max;
916                         }
917
918                         @Override
919                         public Resource next() {
920                                 int i = index;
921                                 if (i >= max)
922                                         throw new NoSuchElementException();
923                                 int id = backend.getQuick(index);
924                                 index = i + 1;
925                                 return new ResourceImpl(session.resourceSupport, id);
926                         }
927
928                         @Override
929                         public boolean hasPrevious() {
930                                 return index != 0;
931                         }
932
933                         @Override
934                         public Resource previous() {
935                                 int i = index - 1;
936                                 if (i < 0)
937                                         throw new NoSuchElementException();
938                                 int id = backend.getQuick(index);
939                                 index = i;
940                                 return new ResourceImpl(session.resourceSupport, id);
941                         }
942
943                         @Override
944                         public int nextIndex() {
945                                 return index;
946                         }
947
948                         @Override
949                         public int previousIndex() {
950                                 return index - 1;
951                         }
952
953                         @Override
954                         public void remove() {
955                                 throw new UnsupportedOperationException("remove not supported");
956                         }
957
958                         @Override
959                         public void set(Resource e) {
960                                 throw new UnsupportedOperationException("set not supported");
961                         }
962
963                         @Override
964                         public void add(Resource e) {
965                                 throw new UnsupportedOperationException("add not supported");
966                         }
967                 }
968
969                 @Override
970                 public ListIterator<Resource> listIterator() {
971                         return new ListItr(0);
972                 }
973
974                 @Override
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);
979                 }
980
981                 @Override
982                 public List<Resource> subList(int fromIndex, int toIndex) {
983                         ResourceList result = new ResourceList(session);
984                         for(int i=fromIndex;i<toIndex;i++)
985                                 result.add(get(i));
986                         return result;
987                 }
988
989                 @Override
990                 public int hashCode() {
991                         return backend.hashCode();
992                 }
993
994                 @Override
995                 public boolean equals(Object obj) {
996                         if (this == obj)
997                                 return true;
998                         if (obj == null)
999                                 return false;
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)))
1009                                                         return false;
1010                                         }
1011                                         return !(e1.hasNext() || e2.hasNext());
1012                                 }
1013                                 return false;
1014                         }
1015                         ResourceList other = (ResourceList) obj;
1016                         return session == other.session && backend.equals(other.backend);
1017                 }
1018
1019     }
1020
1021         @Override
1022         public List<Resource> createList() {
1023                 return new ResourceList(session);
1024         }
1025
1026         @Override
1027         public List<Resource> createList(int capacity) {
1028                 return new ResourceList(session, capacity);
1029         }
1030
1031     static final class StatementList implements Collection<Statement> {
1032
1033         final private SessionImplSocket session;
1034         final private TIntArrayList backend = new TIntArrayList();
1035
1036         StatementList(SessionImplSocket session) {
1037                 this.session = session;
1038         }
1039
1040                 @Override
1041                 public void clear() {
1042                         throw new UnsupportedOperationException("Not implemented");
1043                 }
1044
1045                 @Override
1046                 public int size() {
1047                         return backend.size() / 3;
1048                 }
1049
1050                 @Override
1051                 public boolean add(Statement stm) {
1052                         ResourceImpl s = (ResourceImpl)stm.getSubject();
1053                         ResourceImpl p = (ResourceImpl)stm.getPredicate();
1054                         ResourceImpl o = (ResourceImpl)stm.getObject();
1055                         backend.add(s.id);
1056                         backend.add(p.id);
1057                         backend.add(o.id);
1058                         return true;
1059                 }
1060
1061                 @Override
1062                 public boolean addAll(Collection<? extends Statement> rs) {
1063                         boolean result = false;
1064                         for(Statement r : rs) result |= add(r);
1065                         return result;
1066                 }
1067
1068                 @Override
1069                 public boolean contains(Object statement) {
1070                         throw new UnsupportedOperationException("Not implemented");
1071                 }
1072
1073                 @Override
1074                 public boolean containsAll(Collection<?> rs) {
1075                         throw new UnsupportedOperationException("Not implemented");
1076                 }
1077
1078                 @Override
1079                 public boolean isEmpty() {
1080                         return backend.isEmpty();
1081                 }
1082
1083                 @Override
1084                 public Iterator<Statement> iterator() {
1085                         return new Iterator<Statement>() {
1086
1087                                 int index = 0;
1088                                 int max = backend.size();
1089
1090                                 @Override
1091                                 public boolean hasNext() {
1092                                         return index < max;
1093                                 }
1094
1095                                 @Override
1096                                 public Statement next() {
1097                                         return new DirectStatementImpl(session.resourceSupport, backend.getQuick(index++), backend.getQuick(index++), backend.getQuick(index++));
1098                                 }
1099
1100                                 @Override
1101                                 public void remove() {
1102                                         throw new UnsupportedOperationException("Not supported");
1103                                 }
1104
1105                         };
1106                 }
1107
1108                 @Override
1109                 public boolean remove(Object resource) {
1110                         throw new UnsupportedOperationException("Not implemented");
1111                 }
1112
1113                 @Override
1114                 public boolean removeAll(Collection<?> rs) {
1115                         throw new UnsupportedOperationException("Not implemented");
1116                 }
1117
1118                 @Override
1119                 public boolean retainAll(Collection<?> arg0) {
1120                         throw new UnsupportedOperationException("Not implemented");
1121                 }
1122
1123                 @Override
1124                 public Object[] toArray() {
1125                         int stms = backend.size() / 3;
1126                         return toArray(new Object[stms]);
1127                 }
1128
1129                 @SuppressWarnings("unchecked")
1130                 @Override
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);
1136                         int index = 0;
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));
1139                         }
1140                         return r;
1141                 }
1142
1143                 @Override
1144                 public int hashCode() {
1145                         return backend.hashCode();
1146                 }
1147
1148                 @Override
1149                 public boolean equals(Object obj) {
1150                         if (this == obj)
1151                                 return true;
1152                         if (obj == null)
1153                                 return false;
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)))
1163                                                         return false;
1164                                         }
1165                                         return !(e1.hasNext() || e2.hasNext());
1166                                 }
1167                                 return false;
1168                         }
1169                         StatementList other = (StatementList) obj;
1170                         return session == other.session && backend.equals(other.backend);
1171                 }
1172
1173     }
1174
1175         @Override
1176         public Collection<Statement> createStatementList() {
1177                 return new StatementList(session);
1178         }
1179
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);
1184         };
1185
1186         @Override
1187         public void sort(List<Resource> list) {
1188                 if(list instanceof ResourceList) {
1189                         ((ResourceList) list).sort();
1190                 } else {
1191                         Collections.sort(list, RESOURCE_COMPARATOR);
1192                 }
1193         }
1194
1195         @Override
1196         public List<Resource> asSortedList(Collection<Resource> rs) {
1197                 ResourceList result = new ResourceList(session, rs);
1198                 result.sort();
1199                 return result;
1200         }
1201
1202         @Override
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);
1207             return result;
1208         }
1209
1210     @Override
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);
1214         return result;
1215     }
1216
1217 }