Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package io.sirix.index.art;
import java.util.*;
import java.util.function.Consumer;
// A NavigableMap that adds range checking (if passed in key is within lower and upper bound)
// for all the map methods and then relays the call
// into the backing map
abstract class NavigableSubMap extends AbstractMap
implements NavigableMap {
final AdaptiveRadixTree tree;
/**
* Endpoints are represented as triples (fromStart, lo,
* loInclusive) and (toEnd, hi, hiInclusive). If fromStart is
* true, then the low (absolute) bound is the start of the
* backing map, and the other values are ignored. Otherwise,
* if loInclusive is true, lo is the inclusive bound, else lo
* is the exclusive bound. Similarly for the upper bound.
*/
final K lo, hi;
final byte[] loBytes, hiBytes;
final boolean fromStart, toEnd;
final boolean loInclusive, hiInclusive;
NavigableSubMap(AdaptiveRadixTree m,
boolean fromStart, K lo, boolean loInclusive,
boolean toEnd, K hi, boolean hiInclusive) {
// equivalent to type check in TreeMap
this.loBytes = fromStart ? null : m.binaryComparable().get(lo);
this.hiBytes = toEnd ? null : m.binaryComparable().get(hi);
if (!fromStart && !toEnd) {
if (m.compare(loBytes, 0, loBytes.length, hiBytes, 0, hiBytes.length) > 0)
throw new IllegalArgumentException("fromKey > toKey");
}
this.tree = m;
this.fromStart = fromStart;
this.lo = lo;
this.loInclusive = loInclusive;
this.toEnd = toEnd;
this.hi = hi;
this.hiInclusive = hiInclusive;
}
// internal utilities
final boolean tooLow(K key) {
if (!fromStart) {
int c = tree.compare(key, loBytes);
// if c == 0 and if lower bound is exclusive
// then this key is too low
// else it is not, since it is as low as our lower bound
if (c < 0 || (c == 0 && !loInclusive))
return true;
}
// we don't have a lower bound
return false;
}
final boolean tooHigh(K key) {
if (!toEnd) {
int c = tree.compare(key, hiBytes);
// if c == 0 and if upper bound is exclusive
// then this key is too higher
// else it is not, since it is as greater as our upper bound
if (c > 0 || (c == 0 && !hiInclusive))
return true;
}
// we don't have an upper bound
return false;
}
final boolean inRange(K key) {
return !tooLow(key) && !tooHigh(key);
}
final boolean inClosedRange(K key) {
// if we don't have any upper nor lower bounds, then all keys are always in range.
// if we have a lower bound, then this key ought to be higher than our lower bound (closed, hence including).
// if we have an upper bound, then this key ought to be lower than our upper bound (closed, hence including).
return (fromStart || tree.compare(key, loBytes) >= 0)
&& (toEnd || tree.compare(key, hiBytes) <= 0);
}
final boolean inRange(K key, boolean inclusive) {
return inclusive ? inRange(key) : inClosedRange(key);
}
/*
* Absolute versions of relation operations.
* Subclasses map to these using like-named "sub"
* versions that invert senses for descending maps
*/
final LeafNode absLowest() {
LeafNode e =
(fromStart ? tree.getFirstEntry() :
(loInclusive ? tree.getCeilingEntry(loBytes) :
tree.getHigherEntry(loBytes)));
return (e == null || tooHigh(e.getKey())) ? null : e;
}
final LeafNode absHighest() {
LeafNode e =
(toEnd ? tree.getLastEntry() :
(hiInclusive ? tree.getFloorEntry(hiBytes) :
tree.getLowerEntry(hiBytes)));
return (e == null || tooLow(e.getKey())) ? null : e;
}
final LeafNode absCeiling(K key) {
if (tooLow(key))
return absLowest();
LeafNode e = tree.getCeilingEntry(key);
return (e == null || tooHigh(e.getKey())) ? null : e;
}
final LeafNode absHigher(K key) {
if (tooLow(key))
return absLowest();
LeafNode e = tree.getHigherEntry(key);
return (e == null || tooHigh(e.getKey())) ? null : e;
}
final LeafNode absFloor(K key) {
if (tooHigh(key))
return absHighest();
LeafNode e = tree.getFloorEntry(key);
return (e == null || tooLow(e.getKey())) ? null : e;
}
final LeafNode absLower(K key) {
if (tooHigh(key))
return absHighest();
LeafNode e = tree.getLowerEntry(key);
return (e == null || tooLow(e.getKey())) ? null : e;
}
/** Returns the absolute high fence for ascending traversal */
final LeafNode absHighFence() {
return (toEnd ? null : (hiInclusive ?
tree.getHigherEntry(hiBytes) :
tree.getCeilingEntry(hiBytes))); // then hi itself (but we want the entry, hence traversal is required)
}
/** Return the absolute low fence for descending traversal */
final LeafNode absLowFence() {
return (fromStart ? null : (loInclusive ?
tree.getLowerEntry(loBytes) :
tree.getFloorEntry(loBytes))); // then lo itself (but we want the entry, hence traversal is required)
}
// Abstract methods defined in ascending vs descending classes
// These relay to the appropriate absolute versions
abstract LeafNode subLowest();
abstract LeafNode subHighest();
abstract LeafNode subCeiling(K key);
abstract LeafNode subHigher(K key);
abstract LeafNode subFloor(K key);
abstract LeafNode subLower(K key);
/* Returns ascending iterator from the perspective of this submap */
abstract Iterator keyIterator();
abstract Spliterator keySpliterator();
/* Returns descending iterator from the perspective of this submap*/
abstract Iterator descendingKeyIterator();
// public methods
@Override
public boolean isEmpty() {
return (fromStart && toEnd) ? tree.isEmpty() : entrySet().isEmpty();
}
@Override
public int size() {
return (fromStart && toEnd) ? tree.size() : entrySet().size();
}
@Override
public final boolean containsKey(Object key) {
return inRange((K) key) && tree.containsKey(key);
}
@Override
public final V put(K key, V value) {
if (!inRange(key))
throw new IllegalArgumentException("key out of range");
return tree.put(key, value);
}
@Override
public final V get(Object key) {
return !inRange((K) key) ? null : tree.get(key);
}
@Override
public final V remove(Object key) {
return !inRange((K) key) ? null : tree.remove(key);
}
@Override
public final Entry ceilingEntry(K key) {
return AdaptiveRadixTree.exportEntry(subCeiling(key));
}
@Override
public final K ceilingKey(K key) {
return AdaptiveRadixTree.keyOrNull(subCeiling(key));
}
@Override
public final Entry higherEntry(K key) {
return AdaptiveRadixTree.exportEntry(subHigher(key));
}
@Override
public final K higherKey(K key) {
return AdaptiveRadixTree.keyOrNull(subHigher(key));
}
@Override
public final Entry floorEntry(K key) {
return AdaptiveRadixTree.exportEntry(subFloor(key));
}
@Override
public final K floorKey(K key) {
return AdaptiveRadixTree.keyOrNull(subFloor(key));
}
@Override
public final Entry lowerEntry(K key) {
return AdaptiveRadixTree.exportEntry(subLower(key));
}
@Override
public final K lowerKey(K key) {
return AdaptiveRadixTree.keyOrNull(subLower(key));
}
@Override
public final K firstKey() {
return AdaptiveRadixTree.key(subLowest());
}
@Override
public final K lastKey() {
return AdaptiveRadixTree.key(subHighest());
}
@Override
public final Entry firstEntry() {
return AdaptiveRadixTree.exportEntry(subLowest());
}
@Override
public final Entry lastEntry() {
return AdaptiveRadixTree.exportEntry(subHighest());
}
@Override
public final Entry pollFirstEntry() {
LeafNode e = subLowest();
Entry result = AdaptiveRadixTree.exportEntry(e);
if (e != null)
tree.deleteEntry(e);
return result;
}
@Override
public final Entry pollLastEntry() {
LeafNode e = subHighest();
Entry result = AdaptiveRadixTree.exportEntry(e);
if (e != null)
tree.deleteEntry(e);
return result;
}
// Views
transient NavigableMap descendingMapView;
transient EntrySetView entrySetView;
transient KeySet navigableKeySetView;
@Override
public final NavigableSet navigableKeySet() {
KeySet nksv = navigableKeySetView;
return (nksv != null) ? nksv :
(navigableKeySetView = new KeySet<>(this));
}
@Override
public final Set keySet() {
return navigableKeySet();
}
@Override
public NavigableSet descendingKeySet() {
return descendingMap().navigableKeySet();
}
@Override
public final SortedMap subMap(K fromKey, K toKey) {
return subMap(fromKey, true, toKey, false);
}
@Override
public final SortedMap headMap(K toKey) {
return headMap(toKey, false);
}
@Override
public final SortedMap tailMap(K fromKey) {
return tailMap(fromKey, true);
}
// View classes
// entry set views for submaps
abstract class EntrySetView extends AbstractSet> {
private transient int size = -1, sizeModCount;
// if the submap does not define any upper and lower bounds
// i.e. it is the same view as the original map (very unlikely)
// then no need to explicitly calculate the size.
@Override
public int size() {
if (fromStart && toEnd)
return tree.size();
// if size == -1, it is the first time we're calculating the size
// if sizeModCount != m.getModCount(), the map has had modification operations
// so it's size must've changed, recalculate.
if (size == -1 || sizeModCount != tree.getModCount()) {
sizeModCount = tree.getModCount();
size = 0;
Iterator> i = iterator();
while (i.hasNext()) {
size++;
i.next();
}
}
return size;
}
@Override
public boolean isEmpty() {
LeafNode n = absLowest();
return n == null || tooHigh(n.getKey());
}
// efficient impl of contains than the default in AbstractSet
@Override
public boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Entry, ?> entry = (Entry, ?>) o;
Object key = entry.getKey();
if (!inRange((K) key))
return false;
LeafNode, ?> node = tree.getEntry(key);
return node != null &&
AdaptiveRadixTree.valEquals(node.getValue(), entry.getValue());
}
// efficient impl of remove than the default in AbstractSet
@Override
public boolean remove(Object o) {
if (!(o instanceof Map.Entry))
return false;
Entry, ?> entry = (Entry, ?>) o;
Object key = entry.getKey();
if (!inRange((K) key))
return false;
LeafNode node = tree.getEntry(key);
if (node != null && AdaptiveRadixTree.valEquals(node.getValue(),
entry.getValue())) {
tree.deleteEntry(node);
return true;
}
return false;
}
}
/* Dummy value serving as unmatchable fence key for unbounded SubMapIterators */
private static final Object UNBOUNDED = new Object();
/*
* Iterators for SubMaps
* that understand the submap's upper and lower bound while iterating.
* Fence is one of the bounds depending on the kind of iterator (ascending, descending)
* and first becomes the other one to start from.
*/
abstract class SubMapIterator implements Iterator {
LeafNode lastReturned;
LeafNode next;
final Object fenceKey;
int expectedModCount;
SubMapIterator(LeafNode first,
LeafNode fence) {
expectedModCount = tree.getModCount();
lastReturned = null;
next = first;
fenceKey = fence == null ? UNBOUNDED : fence.getKey();
}
@Override
public final boolean hasNext() {
return next != null && next.getKey() != fenceKey;
}
final LeafNode nextEntry() {
LeafNode e = next;
if (e == null || e.getKey() == fenceKey)
throw new NoSuchElementException();
if (tree.getModCount() != expectedModCount)
throw new ConcurrentModificationException();
next = AdaptiveRadixTree.successor(e);
lastReturned = e;
return e;
}
final LeafNode prevEntry() {
LeafNode e = next;
if (e == null || e.getKey() == fenceKey)
throw new NoSuchElementException();
if (tree.getModCount() != expectedModCount)
throw new ConcurrentModificationException();
next = AdaptiveRadixTree.predecessor(e);
lastReturned = e;
return e;
}
@Override
public void remove() {
if (lastReturned == null)
throw new IllegalStateException();
if (tree.getModCount() != expectedModCount)
throw new ConcurrentModificationException();
// deleted entries are replaced by their successors
// if (lastReturned.left != null && lastReturned.right != null)
// next = lastReturned;
tree.deleteEntry(lastReturned);
lastReturned = null;
expectedModCount = tree.getModCount();
}
}
final class SubMapEntryIterator extends SubMapIterator> {
SubMapEntryIterator(LeafNode first,
LeafNode fence) {
super(first, fence);
}
@Override
public Entry next() {
return nextEntry();
}
}
final class DescendingSubMapEntryIterator extends SubMapIterator> {
DescendingSubMapEntryIterator(LeafNode last,
LeafNode fence) {
super(last, fence);
}
@Override
public Entry next() {
return prevEntry();
}
}
// Implement minimal Spliterator as KeySpliterator backup
final class SubMapKeyIterator extends SubMapIterator
implements Spliterator {
SubMapKeyIterator(LeafNode first,
LeafNode fence) {
super(first, fence);
}
@Override
public K next() {
return nextEntry().getKey();
}
@Override
public Spliterator trySplit() {
return null;
}
@Override
public void forEachRemaining(Consumer super K> action) {
while (hasNext())
action.accept(next());
}
@Override
public boolean tryAdvance(Consumer super K> action) {
if (hasNext()) {
action.accept(next());
return true;
}
return false;
}
// estimating size of submap would be expensive
// since we'd have to traverse from lower bound to upper bound
// for this submap
@Override
public long estimateSize() {
return Long.MAX_VALUE;
}
@Override
public int characteristics() {
return Spliterator.DISTINCT | Spliterator.ORDERED |
Spliterator.SORTED;
}
@Override
public final Comparator super K> getComparator() {
return NavigableSubMap.this.comparator();
}
}
final class DescendingSubMapKeyIterator extends SubMapIterator
implements Spliterator {
DescendingSubMapKeyIterator(LeafNode last,
LeafNode fence) {
super(last, fence);
}
@Override
public K next() {
return prevEntry().getKey();
}
@Override
public Spliterator trySplit() {
return null;
}
@Override
public void forEachRemaining(Consumer super K> action) {
while (hasNext())
action.accept(next());
}
@Override
public boolean tryAdvance(Consumer super K> action) {
if (hasNext()) {
action.accept(next());
return true;
}
return false;
}
@Override
public long estimateSize() {
return Long.MAX_VALUE;
}
@Override
public int characteristics() {
return Spliterator.DISTINCT | Spliterator.ORDERED;
}
}
}