org.javimmutable.collections.tree.ThreeNode Maven / Gradle / Ivy
///###////////////////////////////////////////////////////////////////////////
//
// Burton Computer Corporation
// http://www.burton-computer.com
//
// Copyright (c) 2014, Burton Computer Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the
// distribution.
//
// Neither the name of the Burton Computer Corporation nor the names
// of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package org.javimmutable.collections.tree;
import org.javimmutable.collections.Cursor;
import org.javimmutable.collections.Holder;
import org.javimmutable.collections.JImmutableMap;
import org.javimmutable.collections.cursors.LazyCursor;
import org.javimmutable.collections.cursors.MultiCursor;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import java.util.Collection;
import java.util.Comparator;
@Immutable
public class ThreeNode
extends TreeNode
{
private final TreeNode left;
private final TreeNode middle;
private final TreeNode right;
private final K leftMaxKey;
private final K middleMaxKey;
private final K rightMaxKey;
public ThreeNode(TreeNode left,
TreeNode middle,
TreeNode right,
K leftMaxKey,
K middleMaxKey,
K rightMaxKey)
{
this.left = left;
this.middle = middle;
this.right = right;
this.leftMaxKey = leftMaxKey;
this.middleMaxKey = middleMaxKey;
this.rightMaxKey = rightMaxKey;
}
@Override
public V getValueOr(Comparator comparator,
K key,
V defaultValue)
{
if (comparator.compare(key, leftMaxKey) <= 0) {
return left.getValueOr(comparator, key, defaultValue);
}
if (comparator.compare(key, middleMaxKey) <= 0) {
return middle.getValueOr(comparator, key, defaultValue);
} else {
return right.getValueOr(comparator, key, defaultValue);
}
}
@Override
public Holder find(Comparator comparator,
K key)
{
if (comparator.compare(key, leftMaxKey) <= 0) {
return left.find(comparator, key);
}
if (comparator.compare(key, middleMaxKey) <= 0) {
return middle.find(comparator, key);
} else {
return right.find(comparator, key);
}
}
@Override
public Holder> findEntry(Comparator comparator,
K key)
{
if (comparator.compare(key, leftMaxKey) <= 0) {
return left.findEntry(comparator, key);
}
if (comparator.compare(key, middleMaxKey) <= 0) {
return middle.findEntry(comparator, key);
} else {
return right.findEntry(comparator, key);
}
}
@Override
K getMaxKey()
{
return rightMaxKey;
}
@Override
UpdateResult assignImpl(Comparator comparator,
K key,
V value)
{
if (comparator.compare(key, leftMaxKey) <= 0) {
UpdateResult result = left.assignImpl(comparator, key, value);
switch (result.type) {
case UNCHANGED:
return result;
case INPLACE:
return UpdateResult.createInPlace(new ThreeNode(result.newNode,
middle,
right,
result.newNode.getMaxKey(),
middleMaxKey,
rightMaxKey),
result.sizeDelta
);
case SPLIT:
return UpdateResult.createSplit(result.createTwoNode(),
new TwoNode(middle,
right,
middleMaxKey,
rightMaxKey),
result.sizeDelta
);
}
} else if (comparator.compare(key, middleMaxKey) <= 0) {
UpdateResult result = middle.assignImpl(comparator, key, value);
switch (result.type) {
case UNCHANGED:
return result;
case INPLACE:
return UpdateResult.createInPlace(new ThreeNode(left,
result.newNode,
right,
leftMaxKey,
result.newNode.getMaxKey(),
rightMaxKey),
result.sizeDelta
);
case SPLIT:
return UpdateResult.createSplit(new TwoNode(left,
result.newNode,
leftMaxKey,
result.newNode.getMaxKey()),
new TwoNode(result.extraNode,
right,
result.extraNode.getMaxKey(),
rightMaxKey),
result.sizeDelta
);
}
} else {
UpdateResult result = right.assignImpl(comparator, key, value);
switch (result.type) {
case UNCHANGED:
return result;
case INPLACE:
return UpdateResult.createInPlace(new ThreeNode(left,
middle,
result.newNode,
leftMaxKey,
middleMaxKey,
result.newNode.getMaxKey()),
result.sizeDelta
);
case SPLIT:
return UpdateResult.createSplit(new TwoNode(left,
middle,
leftMaxKey,
middleMaxKey),
result.createTwoNode(),
result.sizeDelta
);
}
}
throw new RuntimeException();
}
@Override
public void addEntriesTo(Collection> collection)
{
left.addEntriesTo(collection);
middle.addEntriesTo(collection);
right.addEntriesTo(collection);
}
@Override
public int verifyDepthsMatch()
{
final int leftDepth = left.verifyDepthsMatch();
final int middleDepth = middle.verifyDepthsMatch();
final int rightDepth = right.verifyDepthsMatch();
if (leftDepth != middleDepth || leftDepth != rightDepth) {
throw new RuntimeException(String.format("depth mismatch %d %d %d", leftDepth, middleDepth, rightDepth));
}
return leftDepth + 1;
}
@Override
DeleteResult deleteImpl(Comparator comparator,
K key)
{
if (comparator.compare(key, leftMaxKey) <= 0) {
DeleteResult result = left.deleteImpl(comparator, key);
switch (result.type) {
case UNCHANGED:
return result;
case INPLACE:
return DeleteResult.createInPlace(new ThreeNode(result.node,
middle,
right,
result.node.getMaxKey(),
middleMaxKey,
rightMaxKey));
case ELIMINATED:
return DeleteResult.createInPlace(new TwoNode(middle,
right,
middleMaxKey,
rightMaxKey));
case REMNANT:
DeleteMergeResult mergeResult = middle.leftDeleteMerge(result.node);
if (mergeResult.right == null) {
return DeleteResult.createInPlace(mergeResult.createLeftTwoNode(right, rightMaxKey));
} else {
return DeleteResult.createInPlace(mergeResult.createLeftThreeNode(right, rightMaxKey));
}
}
} else if (comparator.compare(key, middleMaxKey) <= 0) {
DeleteResult result = middle.deleteImpl(comparator, key);
switch (result.type) {
case UNCHANGED:
return result;
case INPLACE:
return DeleteResult.createInPlace(new ThreeNode(left,
result.node,
right,
leftMaxKey,
result.node.getMaxKey(),
rightMaxKey));
case ELIMINATED:
return DeleteResult.createInPlace(new TwoNode(left,
right,
leftMaxKey,
rightMaxKey));
case REMNANT:
DeleteMergeResult mergeResult = right.leftDeleteMerge(result.node);
if (mergeResult.right == null) {
return DeleteResult.createInPlace(mergeResult.createRightTwoNode(left, leftMaxKey));
} else {
return DeleteResult.createInPlace(mergeResult.createRightThreeNode(left, leftMaxKey));
}
}
} else {
DeleteResult result = right.deleteImpl(comparator, key);
switch (result.type) {
case UNCHANGED:
return DeleteResult.createUnchanged();
case INPLACE:
return DeleteResult.createInPlace(new ThreeNode(left,
middle,
result.node,
leftMaxKey,
middleMaxKey,
result.node.getMaxKey()));
case ELIMINATED:
return DeleteResult.createInPlace(new TwoNode(left,
middle,
leftMaxKey,
middleMaxKey));
case REMNANT:
DeleteMergeResult mergeResult = middle.rightDeleteMerge(result.node);
if (mergeResult.right == null) {
return DeleteResult.createInPlace(mergeResult.createRightTwoNode(left, leftMaxKey));
} else {
return DeleteResult.createInPlace(mergeResult.createRightThreeNode(left, leftMaxKey));
}
}
}
throw new RuntimeException();
}
@Override
DeleteMergeResult leftDeleteMerge(TreeNode node)
{
return new DeleteMergeResult(new TwoNode(node,
left,
node.getMaxKey(),
leftMaxKey),
new TwoNode(middle,
right,
middleMaxKey,
rightMaxKey)
);
}
@Override
DeleteMergeResult rightDeleteMerge(TreeNode node)
{
return new DeleteMergeResult(new TwoNode(left,
middle,
leftMaxKey,
middleMaxKey),
new TwoNode(right,
node,
rightMaxKey,
node.getMaxKey())
);
}
public TreeNode getLeft()
{
return left;
}
public TreeNode getMiddle()
{
return middle;
}
public TreeNode getRight()
{
return right;
}
public K getLeftMaxKey()
{
return leftMaxKey;
}
public K getMiddleMaxKey()
{
return middleMaxKey;
}
public K getRightMaxKey()
{
return rightMaxKey;
}
@Override
public String toString()
{
return String.format("(%s,%s,%s)", left, middle, right);
}
@Override
@Nonnull
public Cursor> cursor()
{
return MultiCursor.of(LazyCursor.of(left), LazyCursor.of(middle), LazyCursor.of(right));
}
@SuppressWarnings("RedundantIfStatement")
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ThreeNode threeNode = (ThreeNode)o;
if (left != null ? !left.equals(threeNode.left) : threeNode.left != null) {
return false;
}
if (leftMaxKey != null ? !leftMaxKey.equals(threeNode.leftMaxKey) : threeNode.leftMaxKey != null) {
return false;
}
if (middle != null ? !middle.equals(threeNode.middle) : threeNode.middle != null) {
return false;
}
if (middleMaxKey != null ? !middleMaxKey.equals(threeNode.middleMaxKey) : threeNode.middleMaxKey != null) {
return false;
}
if (right != null ? !right.equals(threeNode.right) : threeNode.right != null) {
return false;
}
if (rightMaxKey != null ? !rightMaxKey.equals(threeNode.rightMaxKey) : threeNode.rightMaxKey != null) {
return false;
}
return true;
}
@Override
public int hashCode()
{
int result = left != null ? left.hashCode() : 0;
result = 31 * result + (middle != null ? middle.hashCode() : 0);
result = 31 * result + (right != null ? right.hashCode() : 0);
result = 31 * result + (leftMaxKey != null ? leftMaxKey.hashCode() : 0);
result = 31 * result + (middleMaxKey != null ? middleMaxKey.hashCode() : 0);
result = 31 * result + (rightMaxKey != null ? rightMaxKey.hashCode() : 0);
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy