From: Robert Varga Date: Sat, 22 Aug 2015 22:36:51 +0000 (+0200) Subject: BUG-4158: optimize ImmutableOffsetMap X-Git-Tag: release/beryllium~357 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=ee655ecef110165baed51b8926dd7a55792350ca;p=yangtools.git BUG-4158: optimize ImmutableOffsetMap This patch providers optimized equals() for both version of OffsetMap. It also implements an optimized version of MutableOffsetMap.keySet(), which does not require SimpleEntry instantiation. Change-Id: I6a65680bbcc7ad37f251431e495cde48f23efb22 Signed-off-by: Robert Varga --- diff --git a/common/util/src/main/java/org/opendaylight/yangtools/util/ImmutableOffsetMap.java b/common/util/src/main/java/org/opendaylight/yangtools/util/ImmutableOffsetMap.java index 019722b509..5dcac60cc6 100644 --- a/common/util/src/main/java/org/opendaylight/yangtools/util/ImmutableOffsetMap.java +++ b/common/util/src/main/java/org/opendaylight/yangtools/util/ImmutableOffsetMap.java @@ -18,6 +18,7 @@ import java.io.Serializable; import java.lang.reflect.Field; import java.util.AbstractSet; import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -117,6 +118,50 @@ public class ImmutableOffsetMap extends AbstractLazyValueMap impleme return offsets.isEmpty(); } + @Override + public boolean equals(final Object o) { + if (o == this) { + return true; + } + if (o == null) { + return false; + } + + if (o instanceof ImmutableOffsetMap) { + final ImmutableOffsetMap om = (ImmutableOffsetMap) o; + if (offsets.equals(om.offsets) && Arrays.deepEquals(objects, om.objects)) { + return true; + } + } else if (o instanceof MutableOffsetMap) { + // Let MutableOffsetMap do the actual work. + return o.equals(this); + } else if (o instanceof Map) { + final Map om = (Map)o; + + // Size and key sets have to match + if (size() != om.size() || !keySet().equals(om.keySet())) { + return false; + } + + try { + // Ensure all objects are present + for (Entry e : offsets.entrySet()) { + final V v = objectToValue(e.getKey(), objects[e.getValue()]); + if (!v.equals(om.get(e.getKey()))) { + return false; + } + } + } catch (ClassCastException e) { + // Can be thrown by om.get() and indicate we have incompatible key types + return false; + } + + return true; + } + + return false; + } + @Override public final boolean containsKey(final Object key) { return offsets.containsKey(key); diff --git a/common/util/src/main/java/org/opendaylight/yangtools/util/MutableOffsetMap.java b/common/util/src/main/java/org/opendaylight/yangtools/util/MutableOffsetMap.java index a020c89d28..a08bd89257 100644 --- a/common/util/src/main/java/org/opendaylight/yangtools/util/MutableOffsetMap.java +++ b/common/util/src/main/java/org/opendaylight/yangtools/util/MutableOffsetMap.java @@ -127,7 +127,7 @@ public class MutableOffsetMap extends AbstractLazyValueMap implement @Override public final V put(final K key, final V value) { Preconditions.checkNotNull(value); - final Integer offset = offsets.get(key); + final Integer offset = offsets.get(Preconditions.checkNotNull(key)); if (offset == null) { final V ret = newKeys.put(key, value); if (ret == null) { @@ -253,6 +253,68 @@ public class MutableOffsetMap extends AbstractLazyValueMap implement return new MutableOffsetMap(this); } + @Override + public boolean equals(final Object o) { + if (o == this) { + return true; + } + if (o == null) { + return false; + } + + if (o instanceof ImmutableOffsetMap) { + final ImmutableOffsetMap om = (ImmutableOffsetMap) o; + if (newKeys.isEmpty() && offsets == om.offsets() && Arrays.deepEquals(objects, om.objects())) { + return true; + } + } else if (o instanceof MutableOffsetMap) { + final MutableOffsetMap om = (MutableOffsetMap) o; + if (offsets == om.offsets && Arrays.deepEquals(objects, om.objects) && newKeys.equals(om.newKeys)) { + return true; + } + } else if (o instanceof Map) { + final Map om = (Map)o; + + // Size and key sets have to match + if (size() != om.size() || !keySet().equals(om.keySet())) { + return false; + } + + try { + // Ensure all newKeys are present. Note newKeys is guaranteed to + // not contain null value. + for (Entry e : newKeys.entrySet()) { + if (!e.getValue().equals(om.get(e.getKey()))) { + return false; + } + } + + // Ensure all objects are present + for (Entry e : offsets.entrySet()) { + final Object obj = objects[e.getValue()]; + if (!NO_VALUE.equals(obj)) { + final V v = objectToValue(e.getKey(), obj); + if (!v.equals(om.get(e.getKey()))) { + return false; + } + } + } + } catch (ClassCastException e) { + // Can be thrown by om.get() and indicate we have incompatible key types + return false; + } + + return true; + } + + return false; + } + + @Override + public final Set keySet() { + return new KeySet(); + } + @VisibleForTesting boolean needClone() { return needClone; @@ -271,7 +333,13 @@ public class MutableOffsetMap extends AbstractLazyValueMap implement private final class EntrySet extends AbstractSet> { @Override public Iterator> iterator() { - return new EntrySetIterator(); + return new AbstractSetIterator>() { + @Override + public Entry next() { + final K key = nextKey(); + return new SimpleEntry<>(key, get(key)); + } + }; } @Override @@ -327,17 +395,34 @@ public class MutableOffsetMap extends AbstractLazyValueMap implement } } - private final class EntrySetIterator implements Iterator> { + private final class KeySet extends AbstractSet { + @Override + public Iterator iterator() { + return new AbstractSetIterator() { + @Override + public K next() { + return nextKey(); + } + }; + } + + @Override + public int size() { + return MutableOffsetMap.this.size(); + } + } + + private abstract class AbstractSetIterator implements Iterator { private final Iterator> oldIterator = offsets.entrySet().iterator(); - private final Iterator> newIterator = newKeys.entrySet().iterator(); + private final Iterator newIterator = newKeys.keySet().iterator(); private int expectedModCount = modCount; private K currentKey, nextKey; - EntrySetIterator() { - calculateNextKey(); + AbstractSetIterator() { + updateNextKey(); } - private void calculateNextKey() { + private void updateNextKey() { while (oldIterator.hasNext()) { final Entry e = oldIterator.next(); if (!NO_VALUE.equals(objects[e.getValue()])) { @@ -346,7 +431,7 @@ public class MutableOffsetMap extends AbstractLazyValueMap implement } } - nextKey = newIterator.hasNext() ? newIterator.next().getKey() : null; + nextKey = newIterator.hasNext() ? newIterator.next() : null; } private void checkModCount() { @@ -356,26 +441,13 @@ public class MutableOffsetMap extends AbstractLazyValueMap implement } @Override - public boolean hasNext() { + public final boolean hasNext() { checkModCount(); return nextKey != null; } @Override - public Entry next() { - if (nextKey == null) { - throw new NoSuchElementException(); - } - - checkModCount(); - currentKey = nextKey; - calculateNextKey(); - - return new SimpleEntry<>(currentKey, get(currentKey)); - } - - @Override - public void remove() { + public final void remove() { Preconditions.checkState(currentKey != null); checkModCount(); @@ -391,5 +463,17 @@ public class MutableOffsetMap extends AbstractLazyValueMap implement expectedModCount = ++modCount; currentKey = null; } + + protected final K nextKey() { + if (nextKey == null) { + throw new NoSuchElementException(); + } + + checkModCount(); + currentKey = nextKey; + updateNextKey(); + + return currentKey; + } } }