BUG-7464: fix checkstyle warnings
[yangtools.git] / third-party / triemap / src / main / java / org / opendaylight / yangtools / triemap / LNodeEntries.java
index e1a859afc542516fb1ffbece24d707accc81e52f..570205e7a9f1b7d756834ce126c783d04095742c 100644 (file)
  */
 package org.opendaylight.yangtools.triemap;
 
-import java.util.Iterator;
-import java.util.Map.Entry;
-import java.util.NoSuchElementException;
+import com.google.common.base.VerifyException;
 
 /**
- * Similar to Scala's ListMap. Stores a linked set of entries, guaranteed to contain unique entry keys.
+ * Similar to Scala's ListMap, this is a single-linked list of set of map entries. Aside from the java.util.Set
+ * contract, this class fulfills the requirements for an immutable map entryset.
  *
  * @author Robert Varga
  *
  * @param <K> the type of keys
  * @param <V> the type of values
  */
-final class LNodeEntries<K, V> extends LNodeEntry<K, V> {
-    // Modified during remove only
-    private LNodeEntries<K, V> next;
+abstract class LNodeEntries<K, V> extends LNodeEntry<K, V> {
+    private static final class Single<K, V> extends LNodeEntries<K, V> {
+        Single(final K key, final V value) {
+            super(key, value);
+        }
 
-    private LNodeEntries(final K k, final V v) {
-        this(k, v, null);
+        @Override
+        LNodeEntries<K, V> next() {
+            return null;
+        }
     }
 
-    private LNodeEntries(final K k, final V v, final LNodeEntries<K, V> next) {
-        super(k, v);
-        this.next = next;
-    }
+    private static final class Multiple<K, V> extends LNodeEntries<K, V> {
+        // Modified during remove only, otherwise final
+        LNodeEntries<K, V> next;
 
-    static <K,V> LNodeEntries<K, V> map(final K k1, final V v1, final K k2, final V v2) {
-        return new LNodeEntries<>(k1, v1, new LNodeEntries<>(k2, v2));
+        // Used in remove() only
+        Multiple(final LNodeEntries<K, V> entry) {
+            this(entry.getKey(), entry.getValue(), null);
+        }
+
+        Multiple(final K key, final V value, final LNodeEntries<K, V> next) {
+            super(key, value);
+            this.next = next;
+        }
+
+        @Override
+        LNodeEntries<K, V> next() {
+            return next;
+        }
     }
 
-    boolean isSingle() {
-        return next == null;
+    LNodeEntries(final K key, final V value) {
+        super(key, value);
     }
 
-    int size() {
-        int sz = 1;
-        for (LNodeEntries<?, ?> wlk = next; wlk != null; wlk = wlk.next) {
-            sz++;
-        }
-        return sz;
+    static <K,V> LNodeEntries<K, V> map(final K k1, final V v1, final K k2, final V v2) {
+        return new Multiple<>(k1, v1, new Single<>(k2, v2));
     }
 
-    LNodeEntry<K, V> findEntry(final Equivalence<? super K> equiv, final K key) {
+    /**
+     * Return the remainder of this list. Useful for implementing Iterator-like contract. Null indicates there are no
+     * more entries.
+     *
+     * @return Remainder of this list, or null if nothing remains
+     */
+    abstract LNodeEntries<K, V> next();
+
+    final 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> entry = this;
         do {
@@ -64,70 +82,48 @@ final class LNodeEntries<K, V> extends LNodeEntry<K, V> {
                 return entry;
             }
 
-            entry = entry.next;
+            entry = entry.next();
         } while (entry != null);
 
         return null;
     }
 
-    LNodeEntries<K,V> insert(final K key, final V value) {
-        return new LNodeEntries<>(key, value, this);
+    final LNodeEntries<K,V> insert(final K key, final V value) {
+        return new Multiple<>(key, value, this);
     }
 
-    LNodeEntries<K, V> replace(final LNodeEntry<K, V> entry, final V v) {
-        return new LNodeEntries<>(entry.getKey(), v, remove(entry));
+    final LNodeEntries<K, V> replace(final LNodeEntry<K, V> entry, final V value) {
+        final LNodeEntries<K, V> removed;
+        return (removed = remove(entry)) == null ? new Single<>(entry.getKey(), value)
+                : new Multiple<>(entry.getKey(), value, removed);
     }
 
-    LNodeEntries<K, V> remove(final LNodeEntry<K, V> entry) {
+    final LNodeEntries<K, V> remove(final LNodeEntry<K, V> entry) {
         if (entry == this) {
-            return next;
+            return next();
         }
 
-        final LNodeEntries<K, V> ret = new LNodeEntries<>(getKey(), getValue());
+        // This will result in a list with a long tail, i.e last entry storing explicit null. Overhead is amortized
+        // against the number of entries. We do not retain chains shorter than two, so the worst-case overhead is
+        // half-a-reference for an entry.
+        final Multiple<K, V> ret = new Multiple<>(this);
 
-        LNodeEntries<K, V> last = ret;
-        LNodeEntries<K, V> cur = next;
+        Multiple<K, V> last = ret;
+        LNodeEntries<K, V> cur = next();
         while (cur != null) {
-            // We cannot use equals() here, as it is wired to key/value equality,
-            // which we really do not want.
+            // We cannot use equals() here, as it is wired to key equality and we must never compare entries based on
+            // that property. This method is intended to remove a known reference, so identity is what we want.
             if (entry == cur) {
-                last.next = cur.next;
+                last.next = cur.next();
                 return ret;
             }
 
-            last.next = new LNodeEntries<>(cur.getKey(), cur.getValue());
-            last = last.next;
-            cur = cur.next;
-        }
-
-        throw new IllegalStateException(String.format("Entry %s not found", entry));
-    }
-
-    Iterator<Entry<K, V>> iterator() {
-        return new NodeIterator<>(this);
-    }
-
-    static final class NodeIterator<K,V> implements Iterator<Entry<K, V>> {
-        private LNodeEntries<K, V> n;
-
-        NodeIterator(final LNodeEntries<K, V> n) {
-            this.n = n;
+            final Multiple<K, V> tmp = new Multiple<>(cur);
+            last.next = tmp;
+            last = tmp;
+            cur = cur.next();
         }
 
-        @Override
-        public boolean hasNext() {
-            return n != null;
-        }
-
-        @Override
-        public Entry<K, V> next() {
-            if (n == null) {
-                throw new NoSuchElementException();
-            }
-
-            final Entry<K, V> res = n;
-            n = n.next;
-            return res;
-        }
+        throw new VerifyException(String.format("Failed to find entry %s", entry));
     }
 }