swim.collections.BTreeLeaf Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swim-collections Show documentation
Show all versions of swim-collections Show documentation
Immutable, structure sharing collections, including hash array mapped tries, finger tries, B-trees, and S-trees (sequence trees)
// Copyright 2015-2019 SWIM.AI inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package swim.collections;
import java.util.AbstractMap;
import java.util.Map;
import swim.util.CombinerFunction;
import swim.util.OrderedMapCursor;
class BTreeLeaf extends BTreePage {
final Map.Entry[] slots;
final U fold;
BTreeLeaf(Map.Entry[] slots, U fold) {
this.slots = slots;
this.fold = fold;
}
@Override
public final boolean isEmpty() {
return this.slots.length == 0;
}
@Override
public final int size() {
return this.slots.length;
}
@Override
public final int arity() {
return this.slots.length;
}
@Override
public final U fold() {
return this.fold;
}
@Override
public final K minKey() {
return this.slots[0].getKey();
}
@Override
public final K maxKey() {
return this.slots[this.slots.length - 1].getKey();
}
@Override
public final boolean containsKey(Object key, BTreeContext tree) {
return lookup(key, tree) >= 0;
}
@Override
public final boolean containsValue(Object value) {
final Map.Entry[] slots = this.slots;
for (int i = 0, n = slots.length; i < n; i += 1) {
if (value.equals(slots[i].getValue())) {
return true;
}
}
return false;
}
@Override
public final int indexOf(Object key, BTreeContext tree) {
return lookup(key, tree);
}
@Override
public final V get(Object key, BTreeContext tree) {
final int x = lookup(key, tree);
if (x >= 0) {
return this.slots[x].getValue();
} else {
return null;
}
}
@Override
public final Map.Entry getEntry(Object key, BTreeContext tree) {
final int x = lookup(key, tree);
if (x >= 0) {
return this.slots[x];
} else {
return null;
}
}
@Override
public final Map.Entry getIndex(int index) {
return this.slots[index];
}
@Override
public final Map.Entry firstEntry() {
if (this.slots.length != 0) {
return this.slots[0];
} else {
return null;
}
}
@Override
public final Map.Entry lastEntry() {
if (this.slots.length != 0) {
return this.slots[this.slots.length - 1];
} else {
return null;
}
}
@Override
public final Map.Entry nextEntry(K key, BTreeContext tree) {
int x = lookup(key, tree);
if (x >= 0) {
x += 1;
} else {
x = -(x + 1);
}
if (0 <= x && x < this.slots.length) {
return this.slots[x];
} else {
return null;
}
}
@Override
public final Map.Entry previousEntry(K key, BTreeContext tree) {
int x = lookup(key, tree);
if (x >= 0) {
x -= 1;
} else {
x = -(x + 2);
}
if (0 <= x && x < this.slots.length) {
return this.slots[x];
} else {
return null;
}
}
@Override
public final BTreeLeaf updated(K key, V newValue, BTreeContext tree) {
int x = lookup(key, tree);
if (x >= 0) {
return updatedSlot(x, key, newValue);
} else {
x = -(x + 1);
return insertedSlot(x, key, newValue);
}
}
@SuppressWarnings("unchecked")
private BTreeLeaf updatedSlot(int x, K key, V newValue) {
final Map.Entry[] oldSlots = this.slots;
if (newValue != oldSlots[x].getValue()) {
final Map.Entry[] newSlots = (Map.Entry[]) new Map.Entry, ?>[oldSlots.length];
System.arraycopy(oldSlots, 0, newSlots, 0, oldSlots.length);
newSlots[x] = new AbstractMap.SimpleImmutableEntry(key, newValue);
return newLeaf(newSlots, null);
} else {
return this;
}
}
@SuppressWarnings("unchecked")
private BTreeLeaf insertedSlot(int x, K key, V newValue) {
final Map.Entry[] oldSlots = this.slots;
final int n = oldSlots.length + 1;
final Map.Entry[] newSlots = (Map.Entry[]) new Map.Entry, ?>[n];
System.arraycopy(oldSlots, 0, newSlots, 0, x);
newSlots[x] = new AbstractMap.SimpleImmutableEntry(key, newValue);
System.arraycopy(oldSlots, x, newSlots, x + 1, n - (x + 1));
return newLeaf(newSlots, null);
}
@Override
public final BTreeLeaf removed(Object key, BTreeContext tree) {
final int x = lookup(key, tree);
if (x >= 0) {
if (this.slots.length > 1) {
return removedSlot(x);
} else {
return BTreeLeaf.empty();
}
} else {
return this;
}
}
@SuppressWarnings("unchecked")
private BTreeLeaf removedSlot(int x) {
final Map.Entry[] oldSlots = this.slots;
final int n = oldSlots.length - 1;
final Map.Entry[] newSlots = (Map.Entry[]) new Map.Entry, ?>[n];
System.arraycopy(oldSlots, 0, newSlots, 0, x);
System.arraycopy(oldSlots, x + 1, newSlots, x, n - x);
return newLeaf(newSlots, null);
}
@SuppressWarnings("unchecked")
@Override
public final BTreeLeaf drop(int lower, BTreeContext tree) {
if (lower > 0) {
final Map.Entry[] oldSlots = this.slots;
final int k = oldSlots.length;
if (lower < k) {
final int n = k - lower;
final Map.Entry[] newSlots = (Map.Entry[]) new Map.Entry, ?>[n];
System.arraycopy(oldSlots, lower, newSlots, 0, n);
return newLeaf(newSlots, null);
} else {
return BTreeLeaf.empty();
}
} else {
return this;
}
}
@SuppressWarnings("unchecked")
@Override
public final BTreeLeaf take(int upper, BTreeContext tree) {
final Map.Entry[] oldSlots = this.slots;
if (upper < oldSlots.length) {
if (upper > 0) {
final Map.Entry[] newSlots = (Map.Entry[]) new Map.Entry, ?>[upper];
System.arraycopy(oldSlots, 0, newSlots, 0, upper);
return newLeaf(newSlots, null);
} else {
return BTreeLeaf.empty();
}
} else {
return this;
}
}
@Override
public final BTreePage balanced(BTreeContext tree) {
final int n = this.slots.length;
if (n > 1 && tree.pageShouldSplit(this)) {
final int x = n >>> 1;
return split(x);
} else {
return this;
}
}
@SuppressWarnings("unchecked")
@Override
public final BTreeNode split(int x) {
final BTreePage[] newPages = (BTreePage[]) new BTreePage, ?, ?>[2];
final BTreeLeaf newLeftPage = splitLeft(x);
final BTreeLeaf newRightPage = splitRight(x);
newPages[0] = newLeftPage;
newPages[1] = newRightPage;
final K[] newKnots = (K[]) new Object[1];
newKnots[0] = newRightPage.minKey();
return newNode(newPages, newKnots, null, this.slots.length);
}
@SuppressWarnings("unchecked")
@Override
public final BTreeLeaf splitLeft(int x) {
final Map.Entry[] oldSlots = this.slots;
final Map.Entry[] newSlots = (Map.Entry[]) new Map.Entry, ?>[x];
System.arraycopy(oldSlots, 0, newSlots, 0, x);
return newLeaf(newSlots, null);
}
@SuppressWarnings("unchecked")
@Override
public final BTreeLeaf splitRight(int x) {
final Map.Entry[] oldSlots = this.slots;
final int y = oldSlots.length - x;
final Map.Entry[] newSlots = (Map.Entry[]) new Map.Entry, ?>[y];
System.arraycopy(oldSlots, x, newSlots, 0, y);
return newLeaf(newSlots, null);
}
@Override
public final BTreeLeaf reduced(U identity, CombinerFunction super V, U> accumulator,
CombinerFunction combiner) {
if (this.fold == null) {
final Map.Entry[] slots = this.slots;
U fold = identity;
for (int i = 0, n = slots.length; i < n; i += 1) {
fold = accumulator.combine(fold, slots[i].getValue());
}
return newLeaf(slots, fold);
} else {
return this;
}
}
@Override
public final OrderedMapCursor iterator() {
return new BTreeLeafCursor(this.slots, 0, this.slots.length);
}
@Override
public final OrderedMapCursor lastIterator() {
return new BTreeLeafCursor(this.slots, this.slots.length, this.slots.length);
}
protected final int lookup(Object key, BTreeContext tree) {
int lo = 0;
int hi = this.slots.length - 1;
while (lo <= hi) {
final int mid = (lo + hi) >>> 1;
final int order = tree.compareKey(key, this.slots[mid].getKey());
if (order > 0) {
lo = mid + 1;
} else if (order < 0) {
hi = mid - 1;
} else {
return mid;
}
}
return -(lo + 1);
}
protected BTreeLeaf newLeaf(Map.Entry[] slots, U fold) {
return new BTreeLeaf(slots, fold);
}
protected BTreeNode newNode(BTreePage[] pages, K[] knots, U fold, int size) {
return new BTreeNode(pages, knots, fold, size);
}
private static BTreeLeaf