All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jamieswhiteshirt.rtree3i.Branch Maven / Gradle / Ivy

The newest version!
package com.jamieswhiteshirt.rtree3i;

import com.google.common.base.Preconditions;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;

final class Branch implements Node {
    private final List> children;
    private final Box box;
    private final int size;

    static  Branch containing(List> children) {
        return new Branch<>(children, Util.mbb(children.stream().map(Node::getBox).collect(Collectors.toList())));
    }

    Branch(List> children, Box box) {
        Preconditions.checkArgument(!children.isEmpty());
        this.children = children;
        this.box = box;
        int size = 0;
        for (Node child : children) {
            size += child.size();
        }
        this.size = size;
    }

    private List> makeNonLeaves(Groups> pair) {
        List> list = new ArrayList<>();
        list.add(containing(pair.getGroup1().getEntries()));
        list.add(containing(pair.getGroup2().getEntries()));
        return list;
    }

    private Node selectChildForPut(Box box, Configuration configuration) {
        for (final Node child : children) {
            if (child.containsBucket(box)) {
                return child;
            }
        }
        return configuration.getSelector().select(box, children);
    }

    @Override
    public List> put(Box box, Entry entry, Configuration configuration) {
        final Node child = selectChildForPut(box, configuration);
        List> list = child.put(box, entry, configuration);
        List> children2 = Util.replace(children, child, list);
        if (children2.size() <= configuration.getMaxChildren()) {
            return Collections.singletonList(containing(children2));
        } else {
            Groups> pair = configuration.getSplitter().split(children2,
                configuration.getMinChildren(), Node::getBox);
            return makeNonLeaves(pair);
        }
    }

    @Override
    public List> putBucket(Bucket bucket, Configuration configuration) {
        final Node child = selectChildForPut(bucket.getBox(), configuration);
        List> list = child.putBucket(bucket, configuration);
        List> children2 = Util.replace(children, child, list);
        if (children2.size() <= configuration.getMaxChildren()) {
            return Collections.singletonList(containing(children2));
        } else {
            Groups> pair = configuration.getSplitter().split(children2,
                configuration.getMinChildren(), Node::getBox);
            return makeNonLeaves(pair);
        }
    }

    @Override
    public NodeAndEntries remove(Box box, Entry entry, Configuration configuration) {
        // the result of performing a remove of the given entry from this node
        // will be that zero or more entries will be needed to be added back to
        // the root of the tree (because num entries of their node fell below
        // minChildren),
        // zero or more children will need to be removed from this node,
        // zero or more nodes to be added as children to this node(because
        // entries have been deleted from them and they still have enough
        // members to be active)
        List> addTheseEntries = new ArrayList<>();
        List> removeTheseNodes = new ArrayList<>();
        List> addTheseNodes = new ArrayList<>();
        int countDeleted = 0;

        for (final Node child : children) {
            if (child.getBox().contains(box)) {
                final NodeAndEntries result = child.remove(box, entry, configuration);
                if (result.getNode() != null) {
                    if (result.getNode() != child) {
                        // deletion occurred and child is above minChildren so
                        // we update it
                        addTheseNodes.add(result.getNode());
                        removeTheseNodes.add(child);
                        addTheseEntries.addAll(result.getEntriesToAdd());
                        countDeleted += result.countDeleted();
                    }
                    // else nothing was deleted from that child
                } else {
                    // deletion occurred and brought child below minChildren
                    // so we redistribute its entries
                    removeTheseNodes.add(child);
                    addTheseEntries.addAll(result.getEntriesToAdd());
                    countDeleted += result.countDeleted();
                }
            }
        }
        if (removeTheseNodes.isEmpty()) {
            return new NodeAndEntries<>(this, Collections.emptyList(), 0);
        } else {
            List> nodes = Util.remove(children, removeTheseNodes);
            nodes.addAll(addTheseNodes);
            if (nodes.size() == 0) {
                return new NodeAndEntries<>(null, addTheseEntries, countDeleted);
            } else {
                Branch node = containing(nodes);
                return new NodeAndEntries<>(node, addTheseEntries, countDeleted);
            }
        }
    }

    @Override
    public NodeAndEntries remove(Box box, K key, Configuration configuration) {
        // the result of performing a remove of the given entry from this node
        // will be that zero or more entries will be needed to be added back to
        // the root of the tree (because num entries of their node fell below
        // minChildren),
        // zero or more children will need to be removed from this node,
        // zero or more nodes to be added as children to this node(because
        // entries have been deleted from them and they still have enough
        // members to be active)
        List> addTheseEntries = new ArrayList<>();
        List> removeTheseNodes = new ArrayList<>();
        List> addTheseNodes = new ArrayList<>();
        int countDeleted = 0;

        for (final Node child : children) {
            if (child.getBox().contains(box)) {
                final NodeAndEntries result = child.remove(box, key, configuration);
                if (result.getNode() != null) {
                    if (result.getNode() != child) {
                        // deletion occurred and child is above minChildren so
                        // we update it
                        addTheseNodes.add(result.getNode());
                        removeTheseNodes.add(child);
                        addTheseEntries.addAll(result.getEntriesToAdd());
                        countDeleted += result.countDeleted();
                    }
                    // else nothing was deleted from that child
                } else {
                    // deletion occurred and brought child below minChildren
                    // so we redistribute its entries
                    removeTheseNodes.add(child);
                    addTheseEntries.addAll(result.getEntriesToAdd());
                    countDeleted += result.countDeleted();
                }
            }
        }
        if (removeTheseNodes.isEmpty()) {
            return new NodeAndEntries<>(this, Collections.emptyList(), 0);
        } else {
            List> nodes = Util.remove(children, removeTheseNodes);
            nodes.addAll(addTheseNodes);
            if (nodes.size() == 0) {
                return new NodeAndEntries<>(null, addTheseEntries, countDeleted);
            } else {
                Branch node = containing(nodes);
                return new NodeAndEntries<>(node, addTheseEntries, countDeleted);
            }
        }
    }

    @Override
    public Entry get(Box box, K key) {
        for (final Node child : children) {
            if (child.getBox().contains(box)) {
                Entry entry = child.get(box, key);
                if (entry != null) return entry;
            }
        }
        return null;
    }

    @Override
    public void forEach(Predicate boxPredicate, Consumer> action) {
        if (boxPredicate.test(box)) {
            for (final Node child : children) {
                child.forEach(boxPredicate, action);
            }
        }
    }

    @Override
    public boolean anyMatch(Predicate boxPredicate, Predicate> entryPredicate) {
        if (boxPredicate.test(box)) {
            for (final Node child : children) {
                if (child.anyMatch(boxPredicate, entryPredicate)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public boolean allMatch(Predicate boxPredicate, Predicate> entryPredicate) {
        if (boxPredicate.test(box)) {
            for (final Node child : children) {
                if (!child.allMatch(boxPredicate, entryPredicate)) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    @Override
    public  T reduce(Predicate boxPredicate, T identity, BiFunction, T> operator) {
        if (boxPredicate.test(box)) {
            T acc = identity;
            for (final Node child : children) {
                acc = child.reduce(boxPredicate, acc, operator);
            }
            return acc;
        }
        return identity;
    }

    @Override
    public int count(Predicate boxPredicate, Predicate> entryPredicate) {
        if (boxPredicate.test(box)) {
            int count = 0;
            for (final Node child : children) {
                count += child.count(boxPredicate, entryPredicate);
            }
            return count;
        }
        return 0;
    }

    @Override
    public boolean contains(Box box, Entry entry) {
        if (this.box.contains(box)) {
            for (final Node child : children) {
                if (child.contains(box, entry)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public boolean containsBucket(Box box) {
        if (this.box.contains(box)) {
            for (final Node child : children) {
                if (child.containsBucket(box)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public int calculateDepth() {
        return children.get(0).calculateDepth() + 1;
    }

    @Override
    public Box getBox() {
        return box;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isLeaf() {
        return false;
    }

    @Override
    public String asString(String margin) {
        StringBuilder s = new StringBuilder();
        s.append(margin);
        s.append("mbb=");
        s.append(getBox());
        s.append('\n');
        for (Node child : children) {
            s.append(child.asString("  " + margin));
        }
        return s.toString();
    }

    @Override
    public String toString() {
        return asString("");
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy