Remove the object cache
[yangtools.git] / third-party / triemap / src / main / java / org / opendaylight / yangtools / triemap / INode.java
index 2be06f0ad507f61a52860681e1652abba99c3da4..701d608f956f48de113632bb389c865f02bf0d65 100644 (file)
  */
 package org.opendaylight.yangtools.triemap;
 
+import static org.opendaylight.yangtools.triemap.Constants.LEVEL_BITS;
+import static org.opendaylight.yangtools.triemap.LookupResult.RESTART;
+import static org.opendaylight.yangtools.triemap.PresencePredicate.ABSENT;
+import static org.opendaylight.yangtools.triemap.PresencePredicate.PRESENT;
+
+import com.google.common.base.VerifyException;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.util.Optional;
 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
 
 final class INode<K, V> extends BasicNode {
-    static final Object KEY_PRESENT = new Object ();
-    static final Object KEY_ABSENT = new Object ();
-
-    /**
-     * Virtual result for lookup methods indicating that the lookup needs to be restarted. This is a faster version
-     * of throwing a checked exception to control the restart.
-     */
-    static final Object RESTART = new Object();
-
     @SuppressWarnings("rawtypes")
     private static final AtomicReferenceFieldUpdater<INode, MainNode> MAINNODE_UPDATER =
             AtomicReferenceFieldUpdater.newUpdater(INode.class, MainNode.class, "mainnode");
 
-    public final Gen gen;
+    private final Gen gen;
 
     private volatile MainNode<K, V> mainnode;
 
@@ -41,13 +39,13 @@ final class INode<K, V> extends BasicNode {
         this.mainnode = mainnode;
     }
 
-    MainNode<K, V> gcasRead(final TrieMap<K, V> ct) {
+    MainNode<K, V> gcasRead(final TrieMap<?, ?> ct) {
         return GCAS_READ(ct);
     }
 
-    MainNode<K, V> GCAS_READ(final TrieMap<K, V> ct) {
+    private MainNode<K, V> GCAS_READ(final TrieMap<?, ?> ct) {
         MainNode<K, V> m = /* READ */ mainnode;
-        MainNode<K, V> prevval = /* READ */ m.READ_PREV();
+        MainNode<K, V> prevval = /* READ */ m.readPrev();
         if (prevval == null) {
             return m;
         }
@@ -55,15 +53,12 @@ final class INode<K, V> extends BasicNode {
         return GCAS_Complete(m, ct);
     }
 
-    private MainNode<K, V> GCAS_Complete(MainNode<K, V> m, final TrieMap<K, V> ct) {
-        while (true) {
-            if (m == null) {
-                return null;
-            }
-
+    private MainNode<K, V> GCAS_Complete(final MainNode<K, V> oldmain, final TrieMap<?, ?> ct) {
+        MainNode<K, V> m = oldmain;
+        while (m != null) {
             // complete the GCAS
-            final MainNode<K, V> prev = /* READ */ m.READ_PREV();
-            final INode<K, V> ctr = ct.readRoot(true);
+            final MainNode<K, V> prev = /* READ */ m.readPrev();
+            final INode<?, ?> ctr = ct.readRoot(true);
             if (prev == null) {
                 return m;
             }
@@ -71,11 +66,11 @@ final class INode<K, V> extends BasicNode {
             if (prev instanceof FailedNode) {
                 // try to commit to previous value
                 FailedNode<K, V> fn = (FailedNode<K, V>) prev;
-                if (MAINNODE_UPDATER.compareAndSet(this, m, fn.READ_PREV())) {
-                    return fn.READ_PREV();
+                if (MAINNODE_UPDATER.compareAndSet(this, m, fn.readPrev())) {
+                    return fn.readPrev();
                 }
 
-                // Tail recursion: return GCAS_Complete (/* READ */ mainnode, ct);
+                // Tail recursion: return GCAS_Complete(/* READ */ mainnode, ct);
                 m = /* READ */ mainnode;
                 continue;
             }
@@ -90,27 +85,29 @@ final class INode<K, V> extends BasicNode {
             // or both
             if (ctr.gen == gen && !ct.isReadOnly()) {
                 // try to commit
-                if (m.CAS_PREV(prev, null)) {
+                if (m.casPrev(prev, null)) {
                     return m;
                 }
 
-                // Tail recursion: return GCAS_Complete (m, ct);
+                // Tail recursion: return GCAS_Complete(m, ct);
                 continue;
             }
 
             // try to abort
-            m.CAS_PREV(prev, new FailedNode<>(prev));
+            m.casPrev(prev, new FailedNode<>(prev));
 
             // Tail recursion: return GCAS_Complete(/* READ */ mainnode, ct);
             m = /* READ */ mainnode;
         }
+
+        return null;
     }
 
-    private boolean GCAS(final MainNode<K, V> old, final MainNode<K, V> n, final TrieMap<K, V> ct) {
-        n.WRITE_PREV(old);
+    private boolean GCAS(final MainNode<K, V> old, final MainNode<K, V> n, final TrieMap<?, ?> ct) {
+        n.writePrev(old);
         if (MAINNODE_UPDATER.compareAndSet(this, old, n)) {
             GCAS_Complete(n, ct);
-            return /* READ */ n.READ_PREV() == null;
+            return /* READ */ n.readPrev() == null;
         }
 
         return false;
@@ -120,7 +117,7 @@ final class INode<K, V> extends BasicNode {
         return new INode<>(gen, cn);
     }
 
-    INode<K, V> copyToGen(final Gen ngen, final TrieMap<K, V> ct) {
+    INode<K, V> copyToGen(final Gen ngen, final TrieMap<?, ?> ct) {
         return new INode<>(ngen, GCAS_READ(ct));
     }
 
@@ -129,10 +126,15 @@ final class INode<K, V> extends BasicNode {
      *
      * @return true if successful, false otherwise
      */
-    boolean rec_insert(final K k, final V v, final int hc, final int lev, final INode<K, V> parent, final Gen startgen,
+    boolean recInsert(final K key, final V value, final int hc, final int lev, final INode<K, V> parent,
             final TrieMap<K, V> ct) {
+        return recInsert(key, value, hc, lev, parent, gen, ct);
+    }
+
+    private boolean recInsert(final K k, final V v, final int hc, final int lev, final INode<K, V> parent,
+            final Gen startgen, final TrieMap<K, V> ct) {
         while (true) {
-            final MainNode<K, V> m = GCAS_READ (ct); // use -Yinline!
+            final MainNode<K, V> m = GCAS_READ(ct);
 
             if (m instanceof CNode) {
                 // 1) a multiway node
@@ -142,51 +144,65 @@ final class INode<K, V> extends BasicNode {
                 final int bmp = cn.bitmap;
                 final int mask = flag - 1;
                 final int pos = Integer.bitCount(bmp & mask);
+
                 if ((bmp & flag) != 0) {
                     // 1a) insert below
                     final BasicNode cnAtPos = cn.array[pos];
                     if (cnAtPos instanceof INode) {
                         final INode<K, V> in = (INode<K, V>) cnAtPos;
                         if (startgen == in.gen) {
-                            return in.rec_insert(k, v, hc, lev + 5, this, startgen, ct);
+                            return in.recInsert(k, v, hc, lev + LEVEL_BITS, this, startgen, ct);
                         }
                         if (GCAS(cn, cn.renewed(startgen, ct), ct)) {
-                            // Tail recursion: return rec_insert (k, v, hc, lev, parent, startgen, ct);
+                            // Tail recursion: return rec_insert(k, v, hc, lev, parent, startgen, ct);
                             continue;
                         }
 
                         return false;
                     } else if (cnAtPos instanceof SNode) {
                         final SNode<K, V> sn = (SNode<K, V>) cnAtPos;
-                        if (sn.hc == hc && ct.equal(sn.k, k)) {
+                        if (sn.hc == hc && ct.equal(sn.key, k)) {
                             return GCAS(cn, cn.updatedAt(pos, new SNode<>(k, v, hc), gen), ct);
                         }
 
                         final CNode<K, V> rn = (cn.gen == gen) ? cn : cn.renewed(gen, ct);
-                        final MainNode<K, V> nn = rn.updatedAt(pos, inode(CNode.dual(sn, sn.hc, new SNode<>(k, v, hc),
-                                hc, lev + 5, gen)), gen);
-                        return GCAS (cn, nn, ct);
+                        final MainNode<K, V> nn = rn.updatedAt(pos, inode(
+                            CNode.dual(sn, k, v, hc, lev + LEVEL_BITS, gen)), gen);
+                        return GCAS(cn, nn, ct);
+                    } else {
+                        throw CNode.invalidElement(cnAtPos);
                     }
-                } else {
-                    CNode<K, V> rn = (cn.gen == gen) ? cn : cn.renewed(gen, ct);
-                    MainNode<K, V> ncnode = rn.insertedAt(pos, flag, new SNode<> (k, v, hc), gen);
-                    return GCAS (cn, ncnode, ct);
                 }
+
+                final CNode<K, V> rn = (cn.gen == gen) ? cn : cn.renewed(gen, ct);
+                final MainNode<K, V> ncnode = rn.insertedAt(pos, flag, new SNode<>(k, v, hc), gen);
+                return GCAS(cn, ncnode, ct);
             } else if (m instanceof TNode) {
-                clean(parent, ct, lev - 5);
+                clean(parent, ct, lev - LEVEL_BITS);
                 return false;
             } else if (m instanceof LNode) {
-                LNode<K, V> ln = (LNode<K, V>) m;
-                MainNode<K, V> nn = ln.inserted(k, v);
-                return GCAS(ln, nn, ct);
+                final LNode<K, V> ln = (LNode<K, V>) m;
+                final LNodeEntry<K, V> entry = ln.get(ct.equiv(), k);
+                return entry != null ? replaceln(ln, entry, v, ct) : insertln(ln, k, v, ct);
             } else {
-                throw new IllegalStateException("Unhandled node " + m);
+                throw invalidElement(m);
             }
-
-            throw new RuntimeException ("Should not happen");
         }
     }
 
+    private static VerifyException invalidElement(final BasicNode elem) {
+        throw new VerifyException("An INode can host only a CNode, a TNode or an LNode, not " + elem);
+    }
+
+    @SuppressFBWarnings(value = "NP_OPTIONAL_RETURN_NULL",
+            justification = "Returning null Optional indicates the need to restart.")
+    private Optional<V> insertDual(final TrieMap<K, V> ct, final CNode<K, V> cn, final int pos, final SNode<K, V> sn,
+            final K k, final V v, final int hc, final int lev) {
+        final CNode<K, V> rn = (cn.gen == gen) ? cn : cn.renewed(gen, ct);
+        final MainNode<K, V> nn = rn.updatedAt(pos, inode(CNode.dual(sn, k, v, hc, lev + LEVEL_BITS, gen)), gen);
+        return GCAS(cn, nn, ct) ? Optional.empty() : null;
+    }
+
     /**
      * Inserts a new key value pair, given that a specific condition is met.
      *
@@ -198,10 +214,17 @@ final class INode<K, V> extends BasicNode {
      * @return null if unsuccessful, Option[V] otherwise (indicating
      *         previous value bound to the key)
      */
-    Optional<V> rec_insertif(final K k, final V v, final int hc, final Object cond, final int lev,
+    Optional<V> recInsertIf(final K k, final V v, final int hc, final Object cond, final int lev,
+            final INode<K, V> parent, final TrieMap<K, V> ct) {
+        return recInsertIf(k, v, hc, cond, lev, parent, gen, ct);
+    }
+
+    @SuppressFBWarnings(value = "NP_OPTIONAL_RETURN_NULL",
+            justification = "Returning null Optional indicates the need to restart.")
+    private Optional<V> recInsertIf(final K k, final V v, final int hc, final Object cond, final int lev,
             final INode<K, V> parent, final Gen startgen, final TrieMap<K, V> ct) {
         while (true) {
-            final MainNode<K, V> m = GCAS_READ(ct); // use -Yinline!
+            final MainNode<K, V> m = GCAS_READ(ct);
 
             if (m instanceof CNode) {
                 // 1) a multiway node
@@ -218,11 +241,11 @@ final class INode<K, V> extends BasicNode {
                     if (cnAtPos instanceof INode) {
                         final INode<K, V> in = (INode<K, V>) cnAtPos;
                         if (startgen == in.gen) {
-                            return in.rec_insertif(k, v, hc, cond, lev + 5, this, startgen, ct);
+                            return in.recInsertIf(k, v, hc, cond, lev + LEVEL_BITS, this, startgen, ct);
                         }
 
                         if (GCAS(cn, cn.renewed(startgen, ct), ct)) {
-                            // Tail recursion: return rec_insertif (k, v, hc, cond, lev, parent, startgen, ct);
+                            // Tail recursion: return rec_insertif(k, v, hc, cond, lev, parent, startgen, ct);
                             continue;
                         }
 
@@ -230,48 +253,34 @@ final class INode<K, V> extends BasicNode {
                     } else if (cnAtPos instanceof SNode) {
                         final SNode<K, V> sn = (SNode<K, V>) cnAtPos;
                         if (cond == null) {
-                            if (sn.hc == hc && ct.equal(sn.k, k)) {
+                            if (sn.hc == hc && ct.equal(sn.key, k)) {
                                 if (GCAS(cn, cn.updatedAt(pos, new SNode<>(k, v, hc), gen), ct)) {
-                                    return Optional.of(sn.v);
+                                    return Optional.of(sn.value);
                                 }
 
                                 return null;
                             }
 
-                            final CNode<K, V> rn = (cn.gen == gen) ? cn : cn.renewed(gen, ct);
-                            final MainNode<K, V> nn = rn.updatedAt(pos, inode (CNode.dual(sn, sn.hc,
-                                    new SNode<>(k, v, hc), hc, lev + 5, gen)), gen);
-                            if (GCAS(cn, nn, ct)) {
-                                return Optional.empty();
-                            }
-
-                            return null;
-                        } else if (cond == INode.KEY_ABSENT) {
-                            if (sn.hc == hc && ct.equal(sn.k, k)) {
-                                return Optional.of(sn.v);
-                            }
-
-                            final CNode<K, V> rn = (cn.gen == gen) ? cn : cn.renewed(gen, ct);
-                            final MainNode<K, V> nn = rn.updatedAt(pos, inode (CNode.dual(sn, sn.hc,
-                                new SNode<>(k, v, hc), hc, lev + 5, gen)), gen);
-                            if (GCAS(cn, nn, ct)) {
-                                return Optional.empty();
+                            return insertDual(ct, cn, pos, sn, k, v, hc, lev);
+                        } else if (cond == ABSENT) {
+                            if (sn.hc == hc && ct.equal(sn.key, k)) {
+                                return Optional.of(sn.value);
                             }
 
-                            return null;
-                        } else if (cond == INode.KEY_PRESENT) {
-                            if (sn.hc == hc && ct.equal(sn.k, k)) {
+                            return insertDual(ct, cn, pos, sn, k, v, hc, lev);
+                        } else if (cond == PRESENT) {
+                            if (sn.hc == hc && ct.equal(sn.key, k)) {
                                 if (GCAS(cn, cn.updatedAt(pos, new SNode<>(k, v, hc), gen), ct)) {
-                                    return Optional.of(sn.v);
+                                    return Optional.of(sn.value);
                                 }
                                 return null;
                             }
 
                             return Optional.empty();
                         } else {
-                            if (sn.hc == hc && ct.equal(sn.k, k) && cond.equals(sn.v)) {
+                            if (sn.hc == hc && ct.equal(sn.key, k) && cond.equals(sn.value)) {
                                 if (GCAS(cn, cn.updatedAt(pos, new SNode<>(k, v, hc), gen), ct)) {
-                                    return Optional.of(sn.v);
+                                    return Optional.of(sn.value);
                                 }
 
                                 return null;
@@ -279,77 +288,65 @@ final class INode<K, V> extends BasicNode {
 
                             return Optional.empty();
                         }
+                    } else {
+                        throw CNode.invalidElement(cnAtPos);
                     }
-                } else if (cond == null || cond == INode.KEY_ABSENT) {
+                } else if (cond == null || cond == ABSENT) {
                     final CNode<K, V> rn = (cn.gen == gen) ? cn : cn.renewed(gen, ct);
-                    final CNode<K, V> ncnode = rn.insertedAt (pos, flag, new SNode<>(k, v, hc), gen);
+                    final CNode<K, V> ncnode = rn.insertedAt(pos, flag, new SNode<>(k, v, hc), gen);
                     if (GCAS(cn, ncnode, ct)) {
                         return Optional.empty();
                     }
 
                     return null;
-                } else if (cond == INode.KEY_PRESENT) {
-                    return Optional.empty();
                 } else {
                     return Optional.empty();
                 }
             } else if (m instanceof TNode) {
-                clean(parent, ct, lev - 5);
+                clean(parent, ct, lev - LEVEL_BITS);
                 return null;
             } else if (m instanceof LNode) {
                 // 3) an l-node
                 final LNode<K, V> ln = (LNode<K, V>) m;
+                final LNodeEntry<K, V> entry = ln.get(ct.equiv(), k);
+
                 if (cond == null) {
-                    final Optional<V> optv = ln.get(k);
-                    if (insertln(ln, k, v, ct)) {
-                        return optv;
+                    if (entry != null) {
+                        return replaceln(ln, entry, v, ct) ? Optional.of(entry.getValue()) : null;
                     }
-                    return null;
-                } else if (cond == INode.KEY_ABSENT) {
-                    final Optional<V> t = ln.get(k);
-                    if (t.isPresent()) {
-                        return t;
+
+                    return insertln(ln, k, v, ct) ? Optional.empty() : null;
+                } else if (cond == ABSENT) {
+                    if (entry != null) {
+                        return Optional.of(entry.getValue());
                     }
-                    if (insertln(ln, k, v, ct)) {
+
+                    return insertln(ln, k, v, ct) ? Optional.empty() : null;
+                } else if (cond == PRESENT) {
+                    if (entry == null) {
                         return Optional.empty();
                     }
-                    return null;
-                } else if (cond == INode.KEY_PRESENT) {
-                    final Optional<V> t = ln.get(k);
-                    if (!t.isPresent()) {
-                        return t;
-                    }
-                    if (insertln(ln, k, v, ct)) {
-                        return t;
-                    }
-                    return null;
-                } else {
-                    final Optional<V> t = ln.get(k);
-                    if (t.isPresent()) {
-                        if (cond.equals(t.get())) {
-                            if (insertln(ln, k, v, ct)) {
-                                // Difference from Scala: we choose to reuse the object returned from LNode,
-                                // as the identity of the value does not matter in this call graph.
-                                return t;
-                            }
 
-                            return null;
-                        }
+                    return replaceln(ln, entry, v, ct) ? Optional.of(entry.getValue()) : null;
+                } else {
+                    if (entry == null || !cond.equals(entry.getValue())) {
+                        return Optional.empty();
                     }
 
-                    return Optional.empty();
+                    return replaceln(ln, entry, v, ct) ? Optional.of(entry.getValue()) : null;
                 }
             } else {
-                throw new IllegalStateException("Unhandled node " + m);
+                throw invalidElement(m);
             }
-
-            throw new RuntimeException("Should never happen");
         }
     }
 
-    boolean insertln(final LNode<K, V> ln, final K k, final V v, final TrieMap<K, V> ct) {
-        final LNode<K, V> nn = ln.inserted (k, v);
-        return GCAS(ln, nn, ct);
+    private boolean insertln(final LNode<K, V> ln, final K k, final V v, final TrieMap<K, V> ct) {
+        return GCAS(ln, ln.insertChild(k, v), ct);
+    }
+
+    private boolean replaceln(final LNode<K, V> ln, final LNodeEntry<K, V> entry, final V v, final TrieMap<K, V> ct) {
+        return GCAS(ln, ln.replaceChild(entry, v), ct);
     }
 
     /**
@@ -358,10 +355,14 @@ final class INode<K, V> extends BasicNode {
      * @return null if no value has been found, RESTART if the operation
      *         wasn't successful, or any other value otherwise
      */
-    Object rec_lookup(final K k, final int hc, final int lev, final INode<K, V> parent, final Gen startgen,
+    Object recLookup(final K k, final int hc, final int lev, final INode<K, V> parent, final TrieMap<K, V> ct) {
+        return recLookup(k, hc, lev, parent, gen, ct);
+    }
+
+    private Object recLookup(final K k, final int hc, final int lev, final INode<K, V> parent, final Gen startgen,
             final TrieMap<K, V> ct) {
         while (true) {
-            final MainNode<K, V> m = GCAS_READ(ct); // use -Yinline!
+            final MainNode<K, V> m = GCAS_READ(ct);
 
             if (m instanceof CNode) {
                 // 1) a multinode
@@ -369,6 +370,7 @@ final class INode<K, V> extends BasicNode {
                 final int idx = (hc >>> lev) & 0x1f;
                 final int flag = 1 << idx;
                 final int bmp = cn.bitmap;
+
                 if ((bmp & flag) == 0) {
                     // 1a) bitmap shows no binding
                     return null;
@@ -380,7 +382,7 @@ final class INode<K, V> extends BasicNode {
                 if (sub instanceof INode) {
                     final INode<K, V> in = (INode<K, V>) sub;
                     if (ct.isReadOnly() || (startgen == in.gen)) {
-                        return in.rec_lookup(k, hc, lev + 5, this, startgen, ct);
+                        return in.recLookup(k, hc, lev + LEVEL_BITS, this, startgen, ct);
                     }
 
                     if (GCAS(cn, cn.renewed(startgen, ct), ct)) {
@@ -388,59 +390,65 @@ final class INode<K, V> extends BasicNode {
                         continue;
                     }
 
-                    // used to be throw RestartException
                     return RESTART;
                 } else if (sub instanceof SNode) {
                     // 2) singleton node
                     final SNode<K, V> sn = (SNode<K, V>) sub;
-                    if (sn.hc == hc && ct.equal(sn.k, k)) {
-                        return sn.v;
+                    if (sn.hc == hc && ct.equal(sn.key, k)) {
+                        return sn.value;
                     }
 
                     return null;
+                } else {
+                    throw CNode.invalidElement(sub);
                 }
             } else if (m instanceof TNode) {
                 // 3) non-live node
                 return cleanReadOnly((TNode<K, V>) m, lev, parent, ct, k, hc);
             } else if (m instanceof LNode) {
                 // 5) an l-node
-                return ((LNode<K, V>) m).get(k).orElse(null);
+                final LNodeEntry<K, V> entry = ((LNode<K, V>) m).get(ct.equiv(), k);
+                return entry != null ? entry.getValue() : null;
             } else {
-                throw new IllegalStateException("Unhandled node " + m);
+                throw invalidElement(m);
             }
-
-            throw new RuntimeException ("Should not happen");
         }
     }
 
     private Object cleanReadOnly(final TNode<K, V> tn, final int lev, final INode<K, V> parent,
             final TrieMap<K, V> ct, final K k, final int hc) {
         if (ct.isReadOnly()) {
-            if (tn.hc == hc && ct.equal(tn.k, k)) {
-                return tn.v;
+            if (tn.hc == hc && ct.equal(tn.key, k)) {
+                return tn.value;
             }
 
             return null;
         }
 
-        // used to be throw RestartException
-        clean(parent, ct, lev - 5);
+        clean(parent, ct, lev - LEVEL_BITS);
         return RESTART;
     }
 
     /**
      * Removes the key associated with the given value.
      *
-     * @param v
+     * @param cond
      *            if null, will remove the key regardless of the value;
      *            otherwise removes only if binding contains that exact key
      *            and value
-     * @return null if not successful, an Option[V] indicating the previous
+     * @return null if not successful, an Optional indicating the previous
      *         value otherwise
      */
-    Optional<V> rec_remove(final K k, final V v, final int hc, final int lev, final INode<K, V> parent,
+    Optional<V> recRemove(final K k, final Object cond, final int hc, final int lev, final INode<K, V> parent,
+            final TrieMap<K, V> ct) {
+        return recRemove(k, cond, hc, lev, parent, gen, ct);
+    }
+
+    @SuppressFBWarnings(value = "NP_OPTIONAL_RETURN_NULL",
+            justification = "Returning null Optional indicates the need to restart.")
+    private Optional<V> recRemove(final K k, final Object cond, final int hc, final int lev, final INode<K, V> parent,
             final Gen startgen, final TrieMap<K, V> ct) {
-        final MainNode<K, V> m = GCAS_READ(ct); // use -Yinline!
+        final MainNode<K, V> m = GCAS_READ(ct);
 
         if (m instanceof CNode) {
             final CNode<K, V> cn = (CNode<K, V>) m;
@@ -453,31 +461,32 @@ final class INode<K, V> extends BasicNode {
 
             final int pos = Integer.bitCount(bmp & (flag - 1));
             final BasicNode sub = cn.array[pos];
-            Optional<V> res = null;
+            final Optional<V> res;
             if (sub instanceof INode) {
                 final INode<K, V> in = (INode<K, V>) sub;
                 if (startgen == in.gen) {
-                    res = in.rec_remove(k, v, hc, lev + 5, this, startgen, ct);
+                    res = in.recRemove(k, cond, hc, lev + LEVEL_BITS, this, startgen, ct);
                 } else {
-                    if (GCAS(cn, cn.renewed (startgen, ct), ct)) {
-                        res = rec_remove(k, v, hc, lev, parent, startgen, ct);
+                    if (GCAS(cn, cn.renewed(startgen, ct), ct)) {
+                        res = recRemove(k, cond, hc, lev, parent, startgen, ct);
                     } else {
                         res = null;
                     }
                 }
-
             } else if (sub instanceof SNode) {
                 final SNode<K, V> sn = (SNode<K, V>) sub;
-                if (sn.hc == hc && ct.equal(sn.k, k) && (v == null || v.equals(sn.v))) {
+                if (sn.hc == hc && ct.equal(sn.key, k) && (cond == null || cond.equals(sn.value))) {
                     final MainNode<K, V> ncn = cn.removedAt(pos, flag, gen).toContracted(lev);
                     if (GCAS(cn, ncn, ct)) {
-                        res = Optional.of(sn.v);
+                        res = Optional.of(sn.value);
                     } else {
                         res = null;
                     }
                 } else {
                     res = Optional.empty();
                 }
+            } else {
+                throw CNode.invalidElement(sub);
             }
 
             if (res == null || !res.isPresent()) {
@@ -494,34 +503,25 @@ final class INode<K, V> extends BasicNode {
 
             return res;
         } else if (m instanceof TNode) {
-            clean(parent, ct, lev - 5);
+            clean(parent, ct, lev - LEVEL_BITS);
             return null;
         } else if (m instanceof LNode) {
             final LNode<K, V> ln = (LNode<K, V>) m;
-            if (v == null) {
-                final Optional<V> optv = ln.get(k);
-                final MainNode<K, V> nn = ln.removed(k, ct);
-                if (GCAS(ln, nn, ct)) {
-                    return optv;
-                }
-
-                return null;
+            final LNodeEntry<K, V> entry = ln.get(ct.equiv(), k);
+            if (entry == null) {
+                // Key was not found, hence no modification is needed
+                return Optional.empty();
             }
 
-            final Optional<V> tmp = ln.get(k);
-            if (tmp.isPresent() && v.equals(tmp.get())) {
-                final MainNode<K, V> nn = ln.removed(k, ct);
-                if (GCAS(ln, nn, ct)) {
-                    return tmp;
-                }
-
-                return null;
+            final V value = entry.getValue();
+            if (cond != null && !cond.equals(value)) {
+                // Value does not match
+                return Optional.empty();
             }
 
-            // Key not found or value does not match: we have not removed anything
-            return Optional.empty();
+            return GCAS(ln, ln.removeChild(entry, hc), ct) ? Optional.of(value) : null;
         } else {
-            throw new IllegalStateException("Unhandled node " + m);
+            throw invalidElement(m);
         }
     }
 
@@ -535,7 +535,7 @@ final class INode<K, V> extends BasicNode {
             }
 
             final CNode<K, V> cn = (CNode<K, V>) pm;
-            final int idx = (hc >>> (lev - 5)) & 0x1f;
+            final int idx = (hc >>> (lev - LEVEL_BITS)) & 0x1f;
             final int bmp = cn.bitmap;
             final int flag = 1 << idx;
             if ((bmp & flag) == 0) {
@@ -545,15 +545,13 @@ final class INode<K, V> extends BasicNode {
 
             final int pos = Integer.bitCount(bmp & (flag - 1));
             final BasicNode sub = cn.array[pos];
-            if (sub == this) {
-                if (nonlive instanceof TNode) {
-                    final TNode<K, V> tn = (TNode<K, V>) nonlive;
-                    MainNode<K, V> ncn = cn.updatedAt(pos, tn.copyUntombed(), gen).toContracted(lev - 5);
-                    if (!parent.GCAS(cn, ncn, ct)) {
-                        if (ct.readRoot().gen == startgen) {
-                            // Tail recursion: cleanParent(nonlive, parent, ct, hc, lev, startgen);
-                            continue;
-                        }
+            if (sub == this && nonlive instanceof TNode) {
+                final TNode<?, ?> tn = (TNode<?, ?>) nonlive;
+                final MainNode<K, V> ncn = cn.updatedAt(pos, tn.copyUntombed(), gen).toContracted(lev - LEVEL_BITS);
+                if (!parent.GCAS(cn, ncn, ct)) {
+                    if (ct.readRoot().gen == startgen) {
+                        // Tail recursion: cleanParent(nonlive, parent, ct, hc, lev, startgen);
+                        continue;
                     }
                 }
             }
@@ -569,24 +567,7 @@ final class INode<K, V> extends BasicNode {
         }
     }
 
-    int cachedSize(final TrieMap<K, V> ct) {
-        MainNode<K, V> m = GCAS_READ(ct);
-        return m.cachedSize(ct);
-    }
-
-    // /* this is a quiescent method! */
-    // def string(lev: Int) = "%sINode -> %s".format("  " * lev, mainnode
-    // match {
-    // case null => "<null>"
-    // case tn: TNode[_, _] => "TNode(%s, %s, %d, !)".format(tn.k, tn.v,
-    // tn.hc)
-    // case cn: CNode[_, _] => cn.string(lev)
-    // case ln: LNode[_, _] => ln.string(lev)
-    // case x => "<elem: %s>".format(x)
-    // })
-
-    @Override
-    String string(final int lev) {
-        return "INode";
+    int size(final ImmutableTrieMap<?, ?> ct) {
+        return GCAS_READ(ct).size(ct);
     }
-}
\ No newline at end of file
+}