From: Tuukka Lehtonen Date: Thu, 30 Nov 2017 17:48:29 +0000 (+0200) Subject: Fixed CollectionSupportImpl.ResourceList iteration order X-Git-Tag: v1.31.0~5 X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=commitdiff_plain;h=ee53d30622180b7d36010b518ff032f340c70fdb Fixed CollectionSupportImpl.ResourceList iteration order Implemented CollectionSupportImpl.ResourceList#listIterator methods. Removed use of the deprecated Callback interface in org.simantics.db.ResourceMap. refs #7654 Change-Id: I22ee6da55326bf884b24e63eb2d9ed30fc242771 --- diff --git a/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/CollectionSupportImpl.java b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/CollectionSupportImpl.java index 37c89ff5f..15bbffad8 100644 --- a/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/CollectionSupportImpl.java +++ b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/CollectionSupportImpl.java @@ -10,7 +10,9 @@ import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Set; +import java.util.function.Consumer; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; @@ -20,7 +22,6 @@ import org.simantics.db.impl.ResourceImpl; import org.simantics.db.impl.graph.ReadGraphImpl; import org.simantics.db.impl.query.IntSet; import org.simantics.db.service.CollectionSupport; -import org.simantics.utils.datastructures.Callback; import gnu.trove.impl.Constants; import gnu.trove.iterator.TIntIterator; @@ -35,38 +36,38 @@ import gnu.trove.procedure.TObjectProcedure; import gnu.trove.set.hash.TIntHashSet; public class CollectionSupportImpl implements CollectionSupport { - + final private SessionImplSocket session; - + CollectionSupportImpl(SessionImplSocket session) { this.session = session; } - + static final class IntResourceMap { - + final private SessionImplSocket session; final private TIntIntHashMap backend = new TIntIntHashMap(Constants.DEFAULT_CAPACITY, Constants.DEFAULT_LOAD_FACTOR, -1, 0); - + IntResourceMap(SessionImplSocket session) { this.session = session; } - + public int size() { return backend.size(); } - + public boolean isEmpty() { return backend.isEmpty(); } - + public boolean containsKey(int key) { return backend.containsKey(key); } - + public boolean containsValue(int value) { return backend.containsValue(value); } - + public Resource get(int key) { try { return session.getResourceByKey(backend.get(key)); @@ -75,7 +76,7 @@ public class CollectionSupportImpl implements CollectionSupport { } return null; } - + public Resource put(int key, Resource value) { ResourceImpl impl = (ResourceImpl) value; int i = backend.put(key, impl.id); @@ -89,7 +90,7 @@ public class CollectionSupportImpl implements CollectionSupport { } return null; } - + public Resource remove(int key) { throw new UnsupportedOperationException("remove not supported"); } @@ -111,16 +112,16 @@ public class CollectionSupportImpl implements CollectionSupport { return session == other.session && backend.equals(other.backend); } } - + public IntResourceMap createIntResourceMap() { return new IntResourceMap(session); } static final class ObjectResourceMap implements Map { - + final private SessionImplSocket session; final private TObjectIntHashMap backend; - + ObjectResourceMap(SessionImplSocket session) { this.session = session; backend = new TObjectIntHashMap(Constants.DEFAULT_CAPACITY, Constants.DEFAULT_LOAD_FACTOR, 0); @@ -130,7 +131,7 @@ public class CollectionSupportImpl implements CollectionSupport { this.session = session; backend = new TObjectIntHashMap(capacity, Constants.DEFAULT_LOAD_FACTOR, 0); } - + @Override public int size() { return backend.size(); @@ -139,18 +140,18 @@ public class CollectionSupportImpl implements CollectionSupport { public boolean isEmpty() { return backend.isEmpty(); } - + @Override public boolean containsKey(Object key) { return backend.contains(key); } - + @Override public boolean containsValue(Object value) { ResourceImpl impl = (ResourceImpl) value; return backend.containsValue(impl.id); } - + @Override public Resource get(Object key) { try { @@ -163,7 +164,7 @@ public class CollectionSupportImpl implements CollectionSupport { } return null; } - + @Override public Resource put(T key, Resource value) { ResourceImpl impl = (ResourceImpl) value; @@ -178,12 +179,12 @@ public class CollectionSupportImpl implements CollectionSupport { } return null; } - + @Override public Resource remove(Object key) { throw new UnsupportedOperationException("remove not supported, structure is immutable"); } - + @Override public void putAll(Map map) { @SuppressWarnings("unchecked") @@ -197,12 +198,12 @@ public class CollectionSupportImpl implements CollectionSupport { } }); } - + @Override public void clear() { throw new UnsupportedOperationException("clear not supported, structure is immutable"); } - + @Override public Set keySet() { final Set result = new HashSet(); @@ -216,7 +217,7 @@ public class CollectionSupportImpl implements CollectionSupport { }); return result; } - + @Override public Collection values() { ArrayList result = new ArrayList(); @@ -229,7 +230,7 @@ public class CollectionSupportImpl implements CollectionSupport { } return result; } - + @Override public Set> entrySet() { final HashSet> result = new HashSet>(); @@ -253,7 +254,7 @@ public class CollectionSupportImpl implements CollectionSupport { public Resource setValue(Resource value) { throw new UnsupportedOperationException("Map.Entry.setValue not supported, structure is immutable"); } - + }); } }); @@ -271,14 +272,40 @@ public class CollectionSupportImpl implements CollectionSupport { return true; if (obj == null) return false; - if (getClass() != obj.getClass()) + if (getClass() != obj.getClass()) { + if (obj instanceof Map) { + // Nonoptimal fallback for comparing against generic Map + Map m = (Map) obj; + if (m.size() != size()) + return false; + try { + Iterator> i = entrySet().iterator(); + while (i.hasNext()) { + Entry e = i.next(); + T key = e.getKey(); + Resource value = e.getValue(); + if (value == null) { + if (!(m.get(key)==null && m.containsKey(key))) + return false; + } else { + if (!value.equals(m.get(key))) + return false; + } + } + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } return false; + } ObjectResourceMap other = (ObjectResourceMap) obj; return session == other.session && backend.equals(other.backend); } } - + @SuppressWarnings("unchecked") @Override public T createObjectResourceMap(Class clazz) { @@ -292,14 +319,14 @@ public class CollectionSupportImpl implements CollectionSupport { } static final class ResourceMap implements org.simantics.db.ResourceMap { - + final private SessionImplSocket session; final private TIntObjectHashMap backend = new TIntObjectHashMap(); ResourceMap(SessionImplSocket session) { this.session = session; } - + @Override public void clear() { throw new UnsupportedOperationException("Not implemented"); @@ -340,11 +367,11 @@ public class CollectionSupportImpl implements CollectionSupport { public T setValue(T arg0) { throw new UnsupportedOperationException("Not supported"); } - + }); return true; } - + }); return result; } @@ -361,10 +388,10 @@ public class CollectionSupportImpl implements CollectionSupport { } public class CallbackEntry implements ResourceMapEntry { - + int id; E value; - + @Override public Resource getKey() { return new ResourceImpl(session.resourceSupport, id); @@ -374,29 +401,29 @@ public class CollectionSupportImpl implements CollectionSupport { public E getValue() { return value; } - + } - + @Override - public void iterateEntries(final Callback> callback) { + public void iterateEntries(final Consumer> callback) { final CallbackEntry entry = new CallbackEntry(); backend.forEach(new TIntProcedure() { - + @Override public boolean execute(int value) { entry.id = value; entry.value = backend.get(value); - callback.run(entry); + callback.accept(entry); return true; } }); } - + @Override public Set keySet() { final ResourceSet result = new ResourceSet(session); backend.forEach(new TIntProcedure() { - + @Override public boolean execute(int value) { result.add(value); @@ -423,13 +450,17 @@ public class CollectionSupportImpl implements CollectionSupport { backend.put(a, b); return true; } - + }); } @Override - public T remove(Object arg0) { - throw new UnsupportedOperationException("Not implemented"); + public T remove(Object key) { + if (key instanceof ResourceImpl) { + ResourceImpl impl = (ResourceImpl)key; + return backend.remove(impl.id); + } + return null; } @Override @@ -440,7 +471,7 @@ public class CollectionSupportImpl implements CollectionSupport { @SuppressWarnings("unchecked") @Override public Collection values() { - ArrayList result = new ArrayList(); + ArrayList result = new ArrayList<>(); for(Object o : backend.values()) result.add((T)o); return result; } @@ -456,14 +487,40 @@ public class CollectionSupportImpl implements CollectionSupport { return true; if (obj == null) return false; - if (getClass() != obj.getClass()) + if (getClass() != obj.getClass()) { + if (obj instanceof Map) { + // Nonoptimal fallback for comparing against generic Map + Map m = (Map) obj; + if (m.size() != size()) + return false; + try { + Iterator> i = entrySet().iterator(); + while (i.hasNext()) { + Entry e = i.next(); + Resource key = e.getKey(); + T value = e.getValue(); + if (value == null) { + if (!(m.get(key)==null && m.containsKey(key))) + return false; + } else { + if (!value.equals(m.get(key))) + return false; + } + } + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } return false; + } ResourceMap other = (ResourceMap) obj; return session == other.session && backend.equals(other.backend); } - + } - + @SuppressWarnings("unchecked") @Override public T createMap(Class clazz) { @@ -471,7 +528,7 @@ public class CollectionSupportImpl implements CollectionSupport { } static final class ResourceSet implements Set { - + final private SessionImplSocket session; final private TIntHashSet backend; @@ -479,7 +536,7 @@ public class CollectionSupportImpl implements CollectionSupport { this.session = session; backend = new TIntHashSet(); } - + ResourceSet(SessionImplSocket session, int capacity) { this.session = session; backend = new TIntHashSet(capacity); @@ -500,15 +557,15 @@ public class CollectionSupportImpl implements CollectionSupport { ResourceImpl impl = (ResourceImpl)resource; return backend.add(impl.id); } - + boolean add(int id) { return backend.add(id); } @Override public boolean addAll(Collection rs) { - boolean result = true; - for(Resource r : rs) result &= add(r); + boolean result = false; + for(Resource r : rs) result |= add(r); return result; } @@ -520,9 +577,10 @@ public class CollectionSupportImpl implements CollectionSupport { @Override public boolean containsAll(Collection rs) { - boolean result = true; - for(Object r : rs) result &= contains(r); - return result; + for (Object r : rs) + if (!contains(r)) + return false; + return true; } @Override @@ -535,7 +593,7 @@ public class CollectionSupportImpl implements CollectionSupport { return new Iterator() { TIntIterator it = backend.iterator(); - + @Override public boolean hasNext() { return it.hasNext(); @@ -550,7 +608,7 @@ public class CollectionSupportImpl implements CollectionSupport { public void remove() { it.remove(); } - + }; } @@ -562,8 +620,8 @@ public class CollectionSupportImpl implements CollectionSupport { @Override public boolean removeAll(Collection rs) { - boolean result = true; - for(Object r : rs) result &= remove(r); + boolean result = false; + for(Object r : rs) result |= remove(r); return result; } @@ -574,24 +632,26 @@ public class CollectionSupportImpl implements CollectionSupport { @Override public Object[] toArray() { - throw new UnsupportedOperationException("Not implemented"); + return toArray(new Object[backend.size()]); } @SuppressWarnings("unchecked") @Override - public T[] toArray(T[] arg0) { - final T[] result = (T[])Array.newInstance(arg0.getClass().getComponentType(), backend.size()); + public T[] toArray(T[] a) { + int size = backend.size(); + T[] r = a.length >= size ? a : + (T[])Array.newInstance(a.getClass().getComponentType(), size); backend.forEach(new TIntProcedure() { - + int index = 0; - + @Override public boolean execute(int value) { - result[index++] = (T)new ResourceImpl(session.resourceSupport, value); + r[index++] = (T)new ResourceImpl(session.resourceSupport, value); return true; } }); - return result; + return r; } @Override @@ -605,26 +665,40 @@ public class CollectionSupportImpl implements CollectionSupport { return true; if (obj == null) return false; - if (getClass() != obj.getClass()) + if (getClass() != obj.getClass()) { + if (obj instanceof Set) { + // Nonoptimal fallback for comparing against generic Set + Collection c = (Collection) obj; + if (c.size() != size()) + return false; + try { + return containsAll(c); + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } return false; + } ResourceSet other = (ResourceSet) obj; return session == other.session && backend.equals(other.backend); } - + } - + @Override public Set createSet() { return new ResourceSet(session); } - + @Override public Set createSet(int capacity) { return new ResourceSet(session, capacity); } static final class ResourceList implements List { - + final private SessionImplSocket session; final private TIntArrayList backend; @@ -698,24 +772,30 @@ public class CollectionSupportImpl implements CollectionSupport { @Override public Iterator iterator() { return new Iterator() { - - int index = backend.size(); - + + int index = 0; + int max = backend.size(); + @Override public boolean hasNext() { - return index > 0; + return index < max; } @Override public Resource next() { - return new ResourceImpl(session.resourceSupport, backend.getQuick(--index)); + int i = index; + if (i >= max) + throw new NoSuchElementException(); + int id = backend.getQuick(i); + index = i + 1; + return new ResourceImpl(session.resourceSupport, id); } @Override public void remove() { - throw new UnsupportedOperationException("Not supported"); + throw new UnsupportedOperationException("remove not supported"); } - + }; } @@ -746,21 +826,23 @@ public class CollectionSupportImpl implements CollectionSupport { @SuppressWarnings("unchecked") @Override - public T[] toArray(T[] arg0) { - final T[] result = (T[])Array.newInstance(arg0.getClass().getComponentType(), backend.size()); + public T[] toArray(T[] a) { + int size = backend.size(); + T[] r = a.length >= size ? a : + (T[])Array.newInstance(a.getClass().getComponentType(), size); backend.forEach(new TIntProcedure() { - + int index = 0; - + @Override public boolean execute(int value) { - result[index++] = (T)new ResourceImpl(session.resourceSupport, value); + r[index++] = (T)new ResourceImpl(session.resourceSupport, value); return true; } }); - return result; + return r; } - + void sort() { backend.sort(); } @@ -816,14 +898,82 @@ public class CollectionSupportImpl implements CollectionSupport { return backend.lastIndexOf(impl.id); } + private class ListItr implements ListIterator { + + int index; + int max; + + public ListItr(int index) { + this.index = index; + this.max = size(); + } + + @Override + public boolean hasNext() { + return index < max; + } + + @Override + public Resource next() { + int i = index; + if (i >= max) + throw new NoSuchElementException(); + int id = backend.getQuick(index); + index = i + 1; + return new ResourceImpl(session.resourceSupport, id); + } + + @Override + public boolean hasPrevious() { + return index != 0; + } + + @Override + public Resource previous() { + int i = index - 1; + if (i < 0) + throw new NoSuchElementException(); + int id = backend.getQuick(index); + index = i; + return new ResourceImpl(session.resourceSupport, id); + } + + @Override + public int nextIndex() { + return index; + } + + @Override + public int previousIndex() { + return index - 1; + } + + @Override + public void remove() { + throw new UnsupportedOperationException("remove not supported"); + } + + @Override + public void set(Resource e) { + throw new UnsupportedOperationException("set not supported"); + } + + @Override + public void add(Resource e) { + throw new UnsupportedOperationException("add not supported"); + } + } + @Override public ListIterator listIterator() { - throw new UnsupportedOperationException("Not implemented"); + return new ListItr(0); } @Override public ListIterator listIterator(int index) { - throw new UnsupportedOperationException("Not implemented"); + if (index < 0 || index > backend.size()) + throw new IndexOutOfBoundsException("Index: "+index); + return new ListItr(index); } @Override @@ -845,8 +995,21 @@ public class CollectionSupportImpl implements CollectionSupport { return true; if (obj == null) return false; - if (getClass() != obj.getClass()) + if (getClass() != obj.getClass()) { + if (obj instanceof List) { + // Nonoptimal fallback for comparing against generic List + ListIterator e1 = listIterator(); + ListIterator e2 = ((List) obj).listIterator(); + while (e1.hasNext() && e2.hasNext()) { + Object o1 = e1.next(); + Object o2 = e2.next(); + if (!(o1==null ? o2==null : o1.equals(o2))) + return false; + } + return !(e1.hasNext() || e2.hasNext()); + } return false; + } ResourceList other = (ResourceList) obj; return session == other.session && backend.equals(other.backend); } @@ -864,14 +1027,14 @@ public class CollectionSupportImpl implements CollectionSupport { } static final class StatementList implements Collection { - + final private SessionImplSocket session; final private TIntArrayList backend = new TIntArrayList(); StatementList(SessionImplSocket session) { this.session = session; } - + @Override public void clear() { throw new UnsupportedOperationException("Not implemented"); @@ -895,8 +1058,8 @@ public class CollectionSupportImpl implements CollectionSupport { @Override public boolean addAll(Collection rs) { - boolean result = true; - for(Statement r : rs) result &= add(r); + boolean result = false; + for(Statement r : rs) result |= add(r); return result; } @@ -921,10 +1084,10 @@ public class CollectionSupportImpl implements CollectionSupport { int index = 0; int max = backend.size(); - + @Override public boolean hasNext() { - return index < max; + return index < max; } @Override @@ -936,7 +1099,7 @@ public class CollectionSupportImpl implements CollectionSupport { public void remove() { throw new UnsupportedOperationException("Not supported"); } - + }; } @@ -957,24 +1120,22 @@ public class CollectionSupportImpl implements CollectionSupport { @Override public Object[] toArray() { - throw new UnsupportedOperationException("Not implemented"); + int stms = backend.size() / 3; + return toArray(new Object[stms]); } @SuppressWarnings("unchecked") @Override - public T[] toArray(T[] arg0) { - final T[] result = (T[])Array.newInstance(arg0.getClass().getComponentType(), backend.size()); - backend.forEach(new TIntProcedure() { - - int index = 0; - - @Override - public boolean execute(int value) { - result[index++] = (T)new ResourceImpl(session.resourceSupport, value); - return true; - } - }); - return result; + public T[] toArray(T[] a) { + int size = backend.size(); + int stms = size / 3; + T[] r = a.length >= size ? a : + (T[])Array.newInstance(a.getClass().getComponentType(), stms); + int index = 0; + for (int i = 0; i < size; i += 3) { + r[index++] = (T) new DirectStatementImpl(session.resourceSupport, backend.getQuick(i), backend.getQuick(i+1), backend.getQuick(i+2)); + } + return r; } @Override @@ -988,12 +1149,25 @@ public class CollectionSupportImpl implements CollectionSupport { return true; if (obj == null) return false; - if (getClass() != obj.getClass()) + if (getClass() != obj.getClass()) { + if (obj instanceof Collection) { + // Nonoptimal fallback for comparing against generic Collection + Iterator e1 = iterator(); + Iterator e2 = ((Collection) obj).iterator(); + while (e1.hasNext() && e2.hasNext()) { + Object o1 = e1.next(); + Object o2 = e2.next(); + if (!(o1==null ? o2==null : o1.equals(o2))) + return false; + } + return !(e1.hasNext() || e2.hasNext()); + } return false; + } StatementList other = (StatementList) obj; return session == other.session && backend.equals(other.backend); } - + } @Override @@ -1001,17 +1175,10 @@ public class CollectionSupportImpl implements CollectionSupport { return new StatementList(session); } - private static Comparator RESOURCE_COMPARATOR = new Comparator() { - @Override - public int compare(Resource o1, Resource o2) { - ResourceImpl r1 = (ResourceImpl)o1; - ResourceImpl r2 = (ResourceImpl)o2; - return compare(r1.id, r2.id); - } - - private int compare(int x, int y) { - return (x < y) ? -1 : ((x == y) ? 0 : 1); - } + private static Comparator RESOURCE_COMPARATOR = (o1, o2) -> { + ResourceImpl r1 = (ResourceImpl)o1; + ResourceImpl r2 = (ResourceImpl)o2; + return Integer.compare(r1.id, r2.id); }; @Override @@ -1022,14 +1189,14 @@ public class CollectionSupportImpl implements CollectionSupport { Collections.sort(list, RESOURCE_COMPARATOR); } } - + @Override public List asSortedList(Collection rs) { ResourceList result = new ResourceList(session, rs); result.sort(); return result; } - + @Override public org.simantics.db.ResourceSet getResourceSet(ReadGraph graph, Collection resources) { if(resources instanceof ResourceSet) return (org.simantics.db.ResourceSet)resources; @@ -1044,5 +1211,5 @@ public class CollectionSupportImpl implements CollectionSupport { for(Resource r : rs) result.add(r); return result; } - + } diff --git a/bundles/org.simantics.db/src/org/simantics/db/ResourceMap.java b/bundles/org.simantics.db/src/org/simantics/db/ResourceMap.java index 4201d30ec..6baef4783 100644 --- a/bundles/org.simantics.db/src/org/simantics/db/ResourceMap.java +++ b/bundles/org.simantics.db/src/org/simantics/db/ResourceMap.java @@ -1,8 +1,7 @@ package org.simantics.db; import java.util.Map; - -import org.simantics.utils.datastructures.Callback; +import java.util.function.Consumer; public interface ResourceMap extends Map { @@ -11,6 +10,6 @@ public interface ResourceMap extends Map { public T getValue(); } - public void iterateEntries(final Callback> callback); + public void iterateEntries(final Consumer> callback); }