@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; }
@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; }