Search in sources :

Example 6 with AbstractBytes

use of jcog.data.byt.AbstractBytes in project narchy by automenta.

the class MyConcurrentRadixTree method removeHavingAcquiredWriteLock.

public boolean removeHavingAcquiredWriteLock(SearchResult searchResult, boolean recurse) {
    SearchResult.Classification classification = searchResult.classification;
    switch(classification) {
        case EXACT_MATCH:
            Node found = searchResult.found;
            Node parent = searchResult.parentNode;
            Object v = found.getValue();
            if (!recurse && ((v == null) || (v == VoidValue.SINGLETON))) {
                // No need to remove it...
                return false;
            }
            List<X> reinsertions = new FasterList<>(0);
            if (v != null && v != VoidValue.SINGLETON) {
                X xv = (X) v;
                boolean removed = tryRemove(xv);
                if (!recurse) {
                    if (!removed)
                        // remove was disabled for this entry
                        return false;
                } else {
                    if (!removed) {
                        // continue removing below then reinsert afterward
                        reinsertions.add(xv);
                    }
                }
            }
            // Proceed with deleting the node...
            FasterList<Node> childEdges = found.getOutgoingEdges();
            int numChildren = childEdges.size();
            if (numChildren > 0) {
                if (!recurse) {
                    if (numChildren > 1) {
                        // This node has more than one child, so if we delete the value from this node, we still need
                        // to leave a similar node in place to act as the split between the child edges.
                        // Just delete the value associated with this node.
                        // -> Clone this node without its value, preserving its child nodes...
                        @SuppressWarnings("NullableProblems") Node cloned = createNode(found.getIncomingEdge(), null, found.getOutgoingEdges(), false);
                        // Re-add the replacement node to the parent...
                        parent.updateOutgoingEdge(cloned);
                    } else if (numChildren == 1) {
                        // Node has one child edge.
                        // Create a new node which is the concatenation of the edges from this node and its child,
                        // and which has the outgoing edges of the child and the value from the child.
                        Node child = childEdges.get(0);
                        AbstractBytes concatenatedEdges = concatenate(found.getIncomingEdge(), child.getIncomingEdge());
                        Node mergedNode = createNode(concatenatedEdges, child.getValue(), child.getOutgoingEdges(), false);
                        // Re-add the merged node to the parent...
                        parent.updateOutgoingEdge(mergedNode);
                    }
                } else {
                    // collect all values from the subtree, call onRemove for them. then proceed below with removal of this node and its value
                    forEach(found, (k, f) -> {
                        boolean removed = tryRemove(f);
                        if (!removed) {
                            reinsertions.add(f);
                        }
                    });
                    numChildren = 0;
                }
            }
            if (numChildren == 0) {
                if (reinsertions.size() == 1) {
                    // in this case make no further changes
                    return false;
                }
                // Node has no children. Delete this node from its parent,
                // which involves re-creating the parent rather than simply updating its child edge
                // (this is why we need parentNodesParent).
                // However if this would leave the parent with only one remaining child edge,
                // and the parent itself has no value (is a split node), and the parent is not the root node
                // (a special case which we never merge), then we also need to merge the parent with its
                // remaining child.
                FasterList<Node> currentEdgesFromParent = parent.getOutgoingEdges();
                // Create a list of the outgoing edges of the parent which will remain
                // if we remove this child...
                int cen = currentEdgesFromParent.size();
                FasterList<Node> newEdgesOfParent = new FasterList<>(0, new Node[cen]);
                boolean differs = false;
                for (int i = 0; i < cen; i++) {
                    Node node = currentEdgesFromParent.get(i);
                    if (node != found) {
                        newEdgesOfParent.add(node);
                    } else {
                        differs = true;
                    }
                }
                if (!differs)
                    // re-use original
                    newEdgesOfParent = currentEdgesFromParent;
                // Note the parent might actually be the root node (which we should never merge)...
                boolean parentIsRoot = (parent == root);
                Node newParent;
                if (newEdgesOfParent.size() == 1 && parent.getValue() == null && !parentIsRoot) {
                    // Parent is a non-root split node with only one remaining child, which can now be merged.
                    Node parentsRemainingChild = newEdgesOfParent.get(0);
                    // Merge the parent with its only remaining child...
                    AbstractBytes concatenatedEdges = concatenate(parent.getIncomingEdge(), parentsRemainingChild.getIncomingEdge());
                    newParent = createNode(concatenatedEdges, parentsRemainingChild.getValue(), parentsRemainingChild.getOutgoingEdges(), parentIsRoot);
                } else {
                    // Parent is a node which either has a value of its own, has more than one remaining
                    // child, or is actually the root node (we never merge the root node).
                    // Create new parent node which is the same as is currently just without the edge to the
                    // node being deleted...
                    newParent = createNode(parent.getIncomingEdge(), parent.getValue(), newEdgesOfParent, parentIsRoot);
                }
                // Re-add the parent node to its parent...
                if (parentIsRoot) {
                    // Replace the root node...
                    this.root = newParent;
                } else {
                    // Re-add the parent node to its parent...
                    searchResult.parentNodesParent.updateOutgoingEdge(newParent);
                }
            }
            reinsertions.forEach(this::put);
            return true;
        default:
            return false;
    }
}
Also used : AbstractBytes(jcog.data.byt.AbstractBytes) FasterList(jcog.list.FasterList)

Example 7 with AbstractBytes

use of jcog.data.byt.AbstractBytes in project narchy by automenta.

the class MyConcurrentRadixTree method getValuesForClosestKeys.

/**
 * {@inheritDoc}
 */
public Iterable<X> getValuesForClosestKeys(AbstractBytes candidate) {
    acquireReadLockIfNecessary();
    try {
        SearchResult searchResult = searchTree(candidate);
        SearchResult.Classification classification = searchResult.classification;
        switch(classification) {
            case EXACT_MATCH:
                return getDescendantValues(candidate, searchResult.found);
            case KEY_ENDS_MID_EDGE:
                // Append the remaining characters of the edge to the key.
                // For example if we searched for CO, but first matching node was COFFEE,
                // the key associated with the first node should be COFFEE...
                AbstractBytes edgeSuffix = getSuffix(searchResult.found.getIncomingEdge(), searchResult.charsMatchedInNodeFound);
                candidate = concatenate(candidate, edgeSuffix);
                return getDescendantValues(candidate, searchResult.found);
            case INCOMPLETE_MATCH_TO_MIDDLE_OF_EDGE:
                {
                    // Example: if we searched for CX, but deepest matching node was CO,
                    // the results should include node CO and its descendants...
                    AbstractBytes keyOfParentNode = getPrefix(candidate, searchResult.charsMatched - searchResult.charsMatchedInNodeFound);
                    AbstractBytes keyOfNodeFound = concatenate(keyOfParentNode, searchResult.found.getIncomingEdge());
                    return getDescendantValues(keyOfNodeFound, searchResult.found);
                }
            case INCOMPLETE_MATCH_TO_END_OF_EDGE:
                if (searchResult.charsMatched == 0) {
                    // Closest match is the root node, we don't consider this a match for anything...
                    break;
                }
                // Example: if we searched for COFFEE, but deepest matching node was CO,
                // the results should include node CO and its descendants...
                AbstractBytes keyOfNodeFound = getPrefix(candidate, searchResult.charsMatched);
                return getDescendantValues(keyOfNodeFound, searchResult.found);
        }
        return Collections.emptySet();
    } finally {
        releaseReadLockIfNecessary();
    }
}
Also used : AbstractBytes(jcog.data.byt.AbstractBytes)

Example 8 with AbstractBytes

use of jcog.data.byt.AbstractBytes in project narchy by automenta.

the class MyConcurrentRadixTree method getKeyValuePairsForKeysStartingWith.

/**
 * {@inheritDoc}
 */
public Iterable<Pair<AbstractBytes, X>> getKeyValuePairsForKeysStartingWith(AbstractBytes prefix) {
    acquireReadLockIfNecessary();
    try {
        SearchResult searchResult = searchTree(prefix);
        SearchResult.Classification classification = searchResult.classification;
        Node f = searchResult.found;
        switch(classification) {
            case EXACT_MATCH:
                return getDescendantKeyValuePairs(prefix, f);
            case KEY_ENDS_MID_EDGE:
                // Append the remaining characters of the edge to the key.
                // For example if we searched for CO, but first matching node was COFFEE,
                // the key associated with the first node should be COFFEE...
                AbstractBytes edgeSuffix = getSuffix(f.getIncomingEdge(), searchResult.charsMatchedInNodeFound);
                prefix = concatenate(prefix, edgeSuffix);
                return getDescendantKeyValuePairs(prefix, f);
            default:
                // Incomplete match means key is not a prefix of any node...
                return Collections.emptySet();
        }
    } finally {
        releaseReadLockIfNecessary();
    }
}
Also used : AbstractBytes(jcog.data.byt.AbstractBytes)

Aggregations

AbstractBytes (jcog.data.byt.AbstractBytes)8 FasterList (jcog.list.FasterList)2