BUG-7464: make LNodeEntry implement Map.Entry 44/49944/12
authorRobert Varga <rovarga@cisco.com>
Mon, 2 Jan 2017 13:29:57 +0000 (14:29 +0100)
committerRobert Varga <rovarga@cisco.com>
Tue, 10 Jan 2017 19:12:11 +0000 (20:12 +0100)
Since LNodeEntry already contains a key/value mapping, it is
advantageous to make it also implement Map.Entry, simply
because that allows us to skip temporary object instantiation
when iterating over entries.

This could be done via subclassing SimpleImmutableEntry, but
that forces us to implement Serializable, which is not what
we want.

Change-Id: I3b0a2384dfbb9c2ed14dd6c9d66dfe91e883f97a
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/INode.java
third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/LNode.java
third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/LNodeEntries.java
third-party/triemap/src/main/java/org/opendaylight/yangtools/triemap/LNodeEntry.java

index 74ef6236d05a6f106df619d7c96e104354defde1..af9a8a2bd62c4ba27f55d7f0987c9d3a793a7d08 100644 (file)
@@ -301,13 +301,13 @@ final class INode<K, V> extends BasicNode {
 
                 if (cond == null) {
                     if (entry != null) {
-                        return replaceln(ln, entry, v, ct) ? Optional.of(entry.value()) : null;
+                        return replaceln(ln, entry, v, ct) ? Optional.of(entry.getValue()) : null;
                     }
 
                     return insertln(ln, k, v, ct) ? Optional.empty() : null;
                 } else if (cond == ABSENT) {
                     if (entry != null) {
-                        return Optional.of(entry.value());
+                        return Optional.of(entry.getValue());
                     }
 
                     return insertln(ln, k, v, ct) ? Optional.empty() : null;
@@ -316,13 +316,13 @@ final class INode<K, V> extends BasicNode {
                         return Optional.empty();
                     }
 
-                    return replaceln(ln, entry, v, ct) ? Optional.of(entry.value()) : null;
+                    return replaceln(ln, entry, v, ct) ? Optional.of(entry.getValue()) : null;
                 } else {
-                    if (entry == null || !cond.equals(entry.value())) {
+                    if (entry == null || !cond.equals(entry.getValue())) {
                         return Optional.empty();
                     }
 
-                    return replaceln(ln, entry, v, ct) ? Optional.of(entry.value()) : null;
+                    return replaceln(ln, entry, v, ct) ? Optional.of(entry.getValue()) : null;
                 }
             } else {
                 throw new IllegalStateException("Unhandled node " + m);
@@ -397,7 +397,7 @@ final class INode<K, V> extends BasicNode {
             } else if (m instanceof LNode) {
                 // 5) an l-node
                 final LNodeEntry<K, V> entry = ((LNode<K, V>) m).get(ct.equiv(), k);
-                return entry != null ? entry.value() : null;
+                return entry != null ? entry.getValue() : null;
             } else {
                 throw new IllegalStateException("Unhandled node " + m);
             }
@@ -501,7 +501,7 @@ final class INode<K, V> extends BasicNode {
                 return Optional.empty();
             }
 
-            final V value = entry.value();
+            final V value = entry.getValue();
             if (cond != null && !cond.equals(value)) {
                 // Value does not match
                 return Optional.empty();
index 40d2b782b2c55dc19cacba3fe3f9d3f6190ac2d6..ca28a06216a9962971da57e3e77a35146e170ac1 100644 (file)
@@ -17,7 +17,6 @@ package org.opendaylight.yangtools.triemap;
 
 import java.util.Iterator;
 import java.util.Map.Entry;
-import java.util.Optional;
 
 final class LNode<K, V> extends MainNode<K, V> {
     private final LNodeEntries<K, V> listmap;
@@ -38,11 +37,9 @@ final class LNode<K, V> extends MainNode<K, V> {
         // We only ever create ListMaps with two or more entries,  and remove them as soon as they reach one element
         // (below), so we cannot observe a null return here.
         final LNodeEntries<K, V> map = listmap.remove(entry);
-        final Optional<Entry<K, V>> maybeKv = map.maybeSingleton();
-        if (maybeKv.isPresent()) {
-            final Entry<K, V> kv = maybeKv.get();
+        if (map.isSingle()) {
             // create it tombed so that it gets compressed on subsequent accesses
-            return new TNode<>(kv.getKey(), kv.getValue(), hc);
+            return new TNode<>(map.getKey(), map.getValue(), hc);
         }
 
         return new LNode<>(map);
@@ -70,6 +67,4 @@ final class LNode<K, V> extends MainNode<K, V> {
     Iterator<Entry<K, V>> iterator() {
         return listmap.iterator();
     }
-
-
 }
\ No newline at end of file
index 93382a9e6328ba1aaf43d6a64a23ae325c916f77..e1a859afc542516fb1ffbece24d707accc81e52f 100644 (file)
  */
 package org.opendaylight.yangtools.triemap;
 
-import java.util.AbstractMap.SimpleImmutableEntry;
 import java.util.Iterator;
 import java.util.Map.Entry;
 import java.util.NoSuchElementException;
-import java.util.Optional;
 
 /**
  * Similar to Scala's ListMap. Stores a linked set of entries, guaranteed to contain unique entry keys.
@@ -30,7 +28,7 @@ import java.util.Optional;
  * @param <V> the type of values
  */
 final class LNodeEntries<K, V> extends LNodeEntry<K, V> {
-    // Modified during remove0 only
+    // Modified during remove only
     private LNodeEntries<K, V> next;
 
     private LNodeEntries(final K k, final V v) {
@@ -46,8 +44,8 @@ final class LNodeEntries<K, V> extends LNodeEntry<K, V> {
         return new LNodeEntries<>(k1, v1, new LNodeEntries<>(k2, v2));
     }
 
-    Optional<Entry<K, V>> maybeSingleton() {
-        return next != null ? Optional.empty() : Optional.of(new SimpleImmutableEntry<>(key(), value()));
+    boolean isSingle() {
+        return next == null;
     }
 
     int size() {
@@ -60,14 +58,14 @@ final class LNodeEntries<K, V> extends LNodeEntry<K, V> {
 
     LNodeEntry<K, V> findEntry(final Equivalence<? super K> equiv, final K key) {
         // We do not perform recursion on purpose here, so we do not run out of stack if the key hashing fails.
-        LNodeEntries<K, V> head = this;
+        LNodeEntries<K, V> entry = this;
         do {
-            if (equiv.equivalent(head.key(), key)) {
-                return head;
+            if (equiv.equivalent(entry.getKey(), key)) {
+                return entry;
             }
 
-            head = head.next;
-        } while (head != null);
+            entry = entry.next;
+        } while (entry != null);
 
         return null;
     }
@@ -77,7 +75,7 @@ final class LNodeEntries<K, V> extends LNodeEntry<K, V> {
     }
 
     LNodeEntries<K, V> replace(final LNodeEntry<K, V> entry, final V v) {
-        return new LNodeEntries<>(entry.key(), v, remove(entry));
+        return new LNodeEntries<>(entry.getKey(), v, remove(entry));
     }
 
     LNodeEntries<K, V> remove(final LNodeEntry<K, V> entry) {
@@ -85,22 +83,24 @@ final class LNodeEntries<K, V> extends LNodeEntry<K, V> {
             return next;
         }
 
-        final LNodeEntries<K, V> ret = new LNodeEntries<>(key(), value());
+        final LNodeEntries<K, V> ret = new LNodeEntries<>(getKey(), getValue());
 
         LNodeEntries<K, V> last = ret;
         LNodeEntries<K, V> cur = next;
         while (cur != null) {
-            if (entry.equals(cur)) {
+            // We cannot use equals() here, as it is wired to key/value equality,
+            // which we really do not want.
+            if (entry == cur) {
                 last.next = cur.next;
                 return ret;
             }
 
-            last.next = new LNodeEntries<>(cur.key(), cur.value());
+            last.next = new LNodeEntries<>(cur.getKey(), cur.getValue());
             last = last.next;
             cur = cur.next;
         }
 
-        throw new IllegalStateException("Entry " + entry + " not found in entries " + this);
+        throw new IllegalStateException(String.format("Entry %s not found", entry));
     }
 
     Iterator<Entry<K, V>> iterator() {
@@ -125,7 +125,7 @@ final class LNodeEntries<K, V> extends LNodeEntry<K, V> {
                 throw new NoSuchElementException();
             }
 
-            final Entry<K, V> res = new SimpleImmutableEntry<>(n.key(), n.value());
+            final Entry<K, V> res = n;
             n = n.next;
             return res;
         }
index 66c11b721b6a3eef26c42af50969fb9eaef8e961..9005dc2ddd3ab3a69a207741f2b8fda474a431ea 100644 (file)
  */
 package org.opendaylight.yangtools.triemap;
 
+import java.util.Map.Entry;
+
 /**
- * A single entry in {@link LNodeEntries}.
+ * A single entry in {@link LNodeEntries}, implements {@link Entry} in order to prevent instantiation of objects for
+ * iteration.
  *
  * @author Robert Varga
  *
  * @param <K> the type of key
  * @param <V> the type of value
  */
-abstract class LNodeEntry<K, V> {
-    private final V value;
+abstract class LNodeEntry<K, V> implements Entry<K, V> {
     private final K key;
+    private final V value;
 
     LNodeEntry(final K key, final V value) {
-        this.value = value;
         this.key = key;
+        this.value = value;
     }
 
-    final K key() {
+    @Override
+    public final K getKey() {
         return key;
     }
 
-    final V value() {
+    @Override
+    public final V getValue() {
         return value;
     }
 
+    @Override
+    public final V setValue(final V value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public final int hashCode() {
+        return EntryUtil.hash(key, value);
+    }
+
+    @Override
+    public final boolean equals(final Object o) {
+        return EntryUtil.equal(o, key, value);
+    }
+
+    @Override
+    public final String toString() {
+        return EntryUtil.string(key, value);
+    }
 }