@Override
 public boolean put(@NotNull final ByteIterable key, @NotNull final ByteIterable value) {
   final ByteIterator it = key.iterator();
   MutableNode node = root;
   MutableNode prev = null;
   byte prevFirstByte = (byte) 0;
   boolean result = false;
   while (true) {
     final NodeBase.MatchResult matchResult = node.matchesKeySequence(it);
     final int matchingLength = matchResult.matchingLength;
     if (matchingLength < 0) {
       final MutableNode prefix = node.splitKey(-matchingLength - 1, matchResult.keyByte);
       if (matchResult.hasNext) {
         prefix.hang(matchResult.nextByte, it).setValue(value);
       } else {
         prefix.setValue(value);
       }
       if (prev == null) {
         root = new MutableRoot(prefix, root.sourceAddress);
       } else {
         prev.setChild(prevFirstByte, prefix);
       }
       ++size;
       result = true;
       break;
     }
     if (!it.hasNext()) {
       final ByteIterable oldValue = node.getValue();
       node.setValue(value);
       if (oldValue == null) {
         ++size;
         result = true;
       }
       break;
     }
     final byte nextByte = it.next();
     final NodeBase child = node.getChild(this, nextByte);
     if (child == null) {
       if (node.hasChildren() || node.hasKey() || node.hasValue()) {
         node.hang(nextByte, it).setValue(value);
       } else {
         node.setKeySequence(new ArrayByteIterable(nextByte, it));
         node.setValue(value);
       }
       ++size;
       result = true;
       break;
     }
     prev = node;
     prevFirstByte = nextByte;
     final MutableNode mutableChild = child.getMutableCopy(this);
     if (!child.isMutable()) {
       node.setChild(nextByte, mutableChild);
     }
     node = mutableChild;
   }
   TreeCursorMutable.notifyCursors(this);
   return result;
 }
 private static void reclaim(
     @NotNull final PatriciaReclaimSourceTraverser source,
     @NotNull final PatriciaReclaimActualTraverser actual) {
   final NodeBase actualNode = actual.currentNode;
   final NodeBase sourceNode = source.currentNode;
   if (actualNode.getAddress() == sourceNode.getAddress()) {
     actual.currentNode = actualNode.getMutableCopy(actual.mainTree);
     actual.getItr();
     actual.wasReclaim = true;
     reclaimActualChildren(source, actual);
   } else {
     @NotNull ByteIterator srcItr = sourceNode.keySequence.iterator();
     @NotNull ByteIterator actItr = actualNode.keySequence.iterator();
     int srcPushes = 0;
     int actPushes = 0;
     while (true) {
       if (srcItr.hasNext()) {
         if (actItr.hasNext()) {
           if (srcItr.next() != actItr.next()) { // key is not matching
             break;
           }
         } else {
           final NodeChildrenIterator children = actual.currentNode.getChildren(srcItr.next());
           final ChildReference child = children.getNode();
           if (child == null) {
             break;
           }
           actual.currentChild = child;
           actual.currentIterator = children;
           actual.moveDown();
           ++actPushes;
           actItr = actual.currentNode.keySequence.iterator();
         }
       } else if (actItr.hasNext()) {
         final NodeChildrenIterator children = source.currentNode.getChildren(actItr.next());
         final ChildReference child = children.getNode();
         if (child == null || !source.isAddressReclaimable(child.suffixAddress)) {
           break; // child can be expired if source parent was already not-current
         }
         source.currentChild = child;
         source.currentIterator = children;
         source.moveDown();
         ++srcPushes;
         srcItr = source.currentNode.keySequence.iterator();
       } else { // both iterators matched, here comes the branching
         reclaimChildren(source, actual);
         break;
       }
     }
     for (int i = 0; i < srcPushes; ++i) {
       source.moveUp();
     }
     for (int i = 0; i < actPushes; ++i) {
       actual.popAndMutate();
     }
   }
 }
 private boolean deleteImpl(@NotNull final ByteIterable key) {
   final ByteIterator it = key.iterator();
   NodeBase node = root;
   final Deque<ChildReferenceTransient> stack = new ArrayDeque<>();
   for (; ; ) {
     if (node == null || node.matchesKeySequence(it).matchingLength < 0) {
       return false;
     }
     if (!it.hasNext()) {
       break;
     }
     final byte nextByte = it.next();
     stack.push(new ChildReferenceTransient(nextByte, node));
     node = node.getChild(this, nextByte);
   }
   if (!node.hasValue()) {
     return false;
   }
   --size;
   MutableNode mutableNode = node.getMutableCopy(this);
   ChildReferenceTransient parent = stack.peek();
   final boolean hasChildren = mutableNode.hasChildren();
   if (!hasChildren && parent != null) {
     stack.pop();
     mutableNode = parent.mutate(this);
     mutableNode.removeChild(parent.firstByte);
     if (!mutableNode.hasValue() && mutableNode.getChildrenCount() == 1) {
       mutableNode.mergeWithSingleChild(this);
     }
   } else {
     mutableNode.setValue(null);
     if (!hasChildren) {
       mutableNode.setKeySequence(ByteIterable.EMPTY);
     } else if (mutableNode.getChildrenCount() == 1) {
       mutableNode.mergeWithSingleChild(this);
     }
   }
   mutateUp(stack, mutableNode);
   return true;
 }
 @Override
 public boolean add(@NotNull final ByteIterable key, @NotNull final ByteIterable value) {
   final ByteIterator it = key.iterator();
   NodeBase node = root;
   MutableNode mutableNode = null;
   final Deque<ChildReferenceTransient> stack = new ArrayDeque<>();
   while (true) {
     final NodeBase.MatchResult matchResult = node.matchesKeySequence(it);
     final int matchingLength = matchResult.matchingLength;
     if (matchingLength < 0) {
       final MutableNode prefix =
           node.getMutableCopy(this).splitKey(-matchingLength - 1, matchResult.keyByte);
       if (matchResult.hasNext) {
         prefix.hang(matchResult.nextByte, it).setValue(value);
       } else {
         prefix.setValue(value);
       }
       if (stack.isEmpty()) {
         root = new MutableRoot(prefix, root.sourceAddress);
       } else {
         final ChildReferenceTransient parent = stack.pop();
         mutableNode = parent.mutate(this);
         mutableNode.setChild(parent.firstByte, prefix);
       }
       break;
     }
     if (!it.hasNext()) {
       if (node.hasValue()) {
         return false;
       }
       mutableNode = node.getMutableCopy(this);
       mutableNode.setValue(value);
       break;
     }
     final byte nextByte = it.next();
     final NodeBase child = node.getChild(this, nextByte);
     if (child == null) {
       mutableNode = node.getMutableCopy(this);
       if (mutableNode.hasChildren() || mutableNode.hasKey() || mutableNode.hasValue()) {
         mutableNode.hang(nextByte, it).setValue(value);
       } else {
         mutableNode.setKeySequence(new ArrayByteIterable(nextByte, it));
         mutableNode.setValue(value);
       }
       break;
     }
     stack.push(new ChildReferenceTransient(nextByte, node));
     node = child;
   }
   ++size;
   mutateUp(stack, mutableNode);
   TreeCursorMutable.notifyCursors(this);
   return true;
 }