/**
* Copyright (c) 2012-2016 André Bargull
* Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms.
*
* <https://github.com/anba/es6draft>
*/
package com.github.anba.es6draft.runtime.internal;
import java.util.*;
/**
*
*/
public final class IndexedMap<VALUE> implements Iterable<Map.Entry<Long, VALUE>> {
private static final long MAX_LENGTH = 0x1F_FFFF_FFFF_FFFFL;
private static final long MAX_DENSE_LENGTH = 0x7FFF_FFFF >> 4;
private static final int MIN_SPARSE_LENGTH = 32;
private static final int SPARSE_DENSE_RATIO = 8;
private static final Elements<?> EMPTY_ELEMENTS = new EmptyElements<>();
@SuppressWarnings("unchecked")
private static <VALUE> Elements<VALUE> emptyElements() {
return (Elements<VALUE>) EMPTY_ELEMENTS;
}
private long length;
private Elements<VALUE> elements;
public IndexedMap() {
this.length = 0;
this.elements = emptyElements();
}
public IndexedMap(long length) {
this.length = length;
this.elements = emptyElements();
}
public IndexedMap(long length, int capacity) {
this.length = length;
this.elements = new DenseElements<>(capacity);
}
private static abstract class Elements<VALUE> {
/**
* Returns the maximum property key index + 1.
*
* @return the maximum property key index + 1
*/
abstract long length();
/**
* Returns the underlying data structure's size or {@code 0} if unbound.
*
* @return the data structure's size or {@code 0}
*/
abstract int capacity();
/**
* Returns the total count of used entries in the underlying data structure.
*
* @return total count of used entries
*/
abstract int count();
/**
* Returns {@code true} if the property key was found.
*
* @param propertyKey
* the property key
* @return {@code true} if property key was found
*/
abstract boolean has(long propertyKey);
/**
* Returns the mapped value or {@code null} if not found.
*
* @param propertyKey
* the property key
* @return the mapped value or {@code null} if not found
*/
abstract VALUE get(long propertyKey);
/**
* Sets the property key to the new value.
*
* @param propertyKey
* the property key
* @param value
* the new property value
*/
abstract void put(long propertyKey, VALUE value);
/**
* Deletes the property key.
*
* @param propertyKey
* the property key
*/
abstract void delete(long propertyKey);
/**
* Returns a dense representation for this object.
*
* @return dense representation.
*/
abstract Elements<VALUE> toDense();
/**
* Returns a sparse representation for this object.
*
* @return sparse representation.
*/
abstract Elements<VALUE> toSparse();
/**
* Returns a sparse representation for this object.
*
* @return sparse representation.
*/
abstract Elements<VALUE> toSparseOrShrink();
/**
* Returns the indexed keys as strings.
*
* @return the indexed keys as strings
*/
abstract List<String> keys();
/**
* Returns the indexed keys as strings.
*
* @param from
* from index (inclusive)
* @param to
* to index (exclusive)
* @return the indexed keys as strings
*/
abstract List<String> keys(long from, long to);
/**
* Returns the indexed keys.
*
* @return the indexed keys
*/
abstract long[] indices();
/**
* Returns the indexed keys.
*
* @param from
* from index (inclusive)
* @param to
* to index (exclusive)
* @return the indexed keys
*/
abstract long[] indices(long from, long to);
@SuppressWarnings("unchecked")
static <T> T[] newArray(int length) {
return (T[]) new Object[length];
}
/**
* Returns an ascending iterator over the complete range.
*
* @return the range iterator
*/
abstract Iterator<Map.Entry<Long, VALUE>> iterator();
/**
* Returns an ascending iterator over the complete range.
*
* @return the range iterator
*/
abstract Iterator<Long> keysIterator();
/**
* Returns an ascending iterator over the complete range.
*
* @return the range iterator
*/
abstract Iterator<VALUE> valuesIterator();
/**
* Returns an ascending iterator over the requested range.
*
* @param from
* from index (inclusive)
* @param to
* to index (exclusive)
* @return the range iterator
*/
abstract Iterator<Map.Entry<Long, VALUE>> ascendingIterator(long from, long to);
/**
* Returns an descending iterator over the requested range.
*
* @param from
* from index (inclusive)
* @param to
* to index (exclusive)
* @return the range iterator
*/
abstract Iterator<Map.Entry<Long, VALUE>> descendingIterator(long from, long to);
}
private static final class EmptyElements<VALUE> extends Elements<VALUE> {
@Override
long length() {
return 0;
}
@Override
int capacity() {
return 0;
}
@Override
int count() {
return 0;
}
@Override
boolean has(long propertyKey) {
return false;
}
@Override
VALUE get(long propertyKey) {
return null;
}
@Override
void put(long propertyKey, VALUE value) {
throw new AssertionError();
}
@Override
void delete(long propertyKey) {
}
@Override
Elements<VALUE> toDense() {
return new DenseElements<>();
}
@Override
Elements<VALUE> toSparse() {
return new SparseElements<>();
}
@Override
Elements<VALUE> toSparseOrShrink() {
return new SparseElements<>();
}
@Override
List<String> keys() {
return Collections.emptyList();
}
@Override
List<String> keys(long from, long to) {
return Collections.emptyList();
}
@Override
long[] indices() {
return new long[0];
}
@Override
long[] indices(long from, long to) {
return new long[0];
}
@Override
Iterator<Long> keysIterator() {
return Collections.emptyIterator();
}
@Override
Iterator<VALUE> valuesIterator() {
return Collections.emptyIterator();
}
@Override
Iterator<Map.Entry<Long, VALUE>> iterator() {
return Collections.emptyIterator();
}
@Override
Iterator<Map.Entry<Long, VALUE>> ascendingIterator(long from, long to) {
return Collections.emptyIterator();
}
@Override
Iterator<Map.Entry<Long, VALUE>> descendingIterator(long from, long to) {
return Collections.emptyIterator();
}
@Override
public String toString() {
return "Empty=[]";
}
}
private static final class DenseElements<VALUE> extends Elements<VALUE> {
// Try to compact if 25% holes and capacity exceeds 32 elements
private static final int COMPACT_THRESHOLD = 32;
private static final int COMPACT_RATIO = 4;
private static final int MIN_CAPACITY = 8;
private static final Object[] EMPTY_ARRAY = {};
private VALUE[] array;
private int count;
DenseElements(VALUE[] array, int count) {
this.array = array;
this.count = count;
}
@SuppressWarnings("unchecked")
DenseElements() {
this((VALUE[]) EMPTY_ARRAY, 0);
}
DenseElements(int capacity) {
this(Elements.<VALUE> newArray(nextCapacity(capacity)), 0);
}
DenseElements(List<VALUE> c, int count) {
this(c.toArray(Elements.<VALUE> newArray(nextCapacity(c.size()))), count);
}
@Override
Elements<VALUE> toDense() {
return this;
}
@Override
Elements<VALUE> toSparse() {
VALUE[] arrayNoHoles = removeTrailingHoles(array);
return new SparseElements<>(new StubSortedMap<>(arrayNoHoles, count));
}
@Override
Elements<VALUE> toSparseOrShrink() {
VALUE[] arrayNoHoles = removeTrailingHoles(array);
if (arrayNoHoles != array) {
// shrunk array applicable for dense representation?
int capacity = arrayNoHoles.length;
if (!(capacity > MIN_SPARSE_LENGTH && count * SPARSE_DENSE_RATIO < capacity)) {
this.array = arrayNoHoles;
return this;
}
}
return new SparseElements<>(new StubSortedMap<>(arrayNoHoles, count));
}
@Override
long length() {
return getLastNonHoleIndex(array) + 1;
}
@Override
int capacity() {
return array.length;
}
@Override
int count() {
return count;
}
@Override
boolean has(long propertyKey) {
assert (int) propertyKey == propertyKey : "invalid dense index: " + propertyKey;
int index = (int) propertyKey;
VALUE[] array = this.array;
return index < array.length && array[index] != null;
}
@Override
VALUE get(long propertyKey) {
assert (int) propertyKey == propertyKey : "invalid dense index: " + propertyKey;
int index = (int) propertyKey;
VALUE[] array = this.array;
return index < array.length ? array[index] : null;
}
@Override
void put(long propertyKey, VALUE value) {
assert (int) propertyKey == propertyKey : "invalid dense index: " + propertyKey;
int index = (int) propertyKey;
VALUE[] array = this.array;
if (index < array.length) {
VALUE prev = array[index];
array[index] = value;
if (prev == null) {
count += 1;
}
} else {
add(index, value);
count += 1;
}
}
@Override
void delete(long propertyKey) {
assert (int) propertyKey == propertyKey : "invalid dense index: " + propertyKey;
int index = (int) propertyKey;
VALUE[] array = this.array;
if (index < array.length && array[index] != null) {
array[index] = null;
count -= 1;
}
}
@Override
List<String> keys() {
ArrayList<String> keys = new ArrayList<>(count());
Iterator<String> iter = new DenseStringKeyIterator<>(0, array.length, array);
while (iter.hasNext()) {
keys.add(iter.next());
}
return keys;
}
@Override
List<String> keys(long from, long to) {
assert from <= to;
int fromIndex = (int) Math.min(from, array.length);
int toIndex = (int) Math.min(to, array.length);
int size = Math.min(count(), toIndex - fromIndex);
ArrayList<String> keys = new ArrayList<>(size);
Iterator<String> iter = new DenseStringKeyIterator<>(fromIndex, toIndex, array);
while (iter.hasNext()) {
keys.add(iter.next());
}
return keys;
}
@Override
long[] indices() {
VALUE[] array = this.array;
long[] indices = new long[count()];
for (int i = 0, j = 0, len = array.length; i < len; ++i) {
if (array[i] != null) {
indices[j++] = i;
}
}
return indices;
}
@Override
long[] indices(long from, long to) {
VALUE[] array = this.array;
if (from >= array.length || from >= to) {
return new long[0];
}
int fromIndex = (int) Math.min(from, array.length);
int toIndex = (int) Math.min(to, array.length);
int range = (toIndex - fromIndex);
int j = 0;
long[] indices = new long[Math.min(range, count())];
for (int i = fromIndex; i < toIndex; ++i) {
if (array[i] != null) {
indices[j++] = i;
}
}
if (j != indices.length) {
indices = Arrays.copyOf(indices, j);
}
return indices;
}
@Override
Iterator<Map.Entry<Long, VALUE>> iterator() {
return new DenseEntryIterator<>(0, array.length, array);
}
@Override
Iterator<Long> keysIterator() {
return new DenseKeyIterator<>(0, array.length, array);
}
@Override
Iterator<VALUE> valuesIterator() {
return new DenseValueIterator<>(0, array.length, array);
}
@Override
Iterator<Map.Entry<Long, VALUE>> ascendingIterator(long from, long to) {
if (from >= array.length || from >= to) {
return Collections.emptyIterator();
}
int fromIndex = (int) Math.min(from, array.length);
int toIndex = (int) Math.min(to, array.length);
return new DenseEntryIterator<>(fromIndex, toIndex, array);
}
@Override
Iterator<Map.Entry<Long, VALUE>> descendingIterator(long from, long to) {
if (from >= array.length || from >= to) {
return Collections.emptyIterator();
}
int endIndex = (int) Math.min(from, array.length) - 1;
int startIndex = Math.max(0, (int) Math.min(to, array.length) - 1);
return new DenseEntryIterator<>(startIndex, endIndex, array);
}
@Override
public String toString() {
return "Dense=" + Arrays.toString(indices());
}
private void add(int index, VALUE value) {
VALUE[] array = this.array;
int newLength = nextCapacity(index);
VALUE[] newArray = newArray(newLength);
System.arraycopy(array, 0, newArray, 0, array.length);
newArray[index] = value;
this.array = newArray;
}
private static int nextCapacity(int v) {
// TODO: better capacity allocation
return Math.max(Integer.highestOneBit(v) << 1, MIN_CAPACITY);
}
private static <VALUE> VALUE[] removeTrailingHoles(VALUE[] array) {
int length = array.length;
if (length > COMPACT_THRESHOLD) {
// TODO: probably need to save a few holes as space
int trailingHoles = countTrailingHoles(array);
if (trailingHoles * COMPACT_RATIO > length) {
int newLength = array.length - trailingHoles;
VALUE[] newArray = newArray(newLength);
System.arraycopy(array, 0, newArray, 0, newLength);
return newArray;
}
}
return array;
}
private static <VALUE> int getLastNonHoleIndex(VALUE[] array) {
for (int i = array.length - 1; i >= 0; --i) {
if (array[i] != null) {
return i;
}
}
return -1;
}
private static <VALUE> int countTrailingHoles(VALUE[] array) {
int trailingHoles = 0;
for (int i = array.length - 1; i >= 0; --i) {
if (array[i] == null) {
trailingHoles += 1;
} else {
break;
}
}
return trailingHoles;
}
}
private static final class SparseElements<VALUE> extends Elements<VALUE> {
private final TreeMap<Long, VALUE> map;
SparseElements() {
map = new TreeMap<>();
}
SparseElements(SortedMap<Long, VALUE> sortedMap) {
map = new TreeMap<>(sortedMap);
}
private VALUE[] toArray() {
long length = length();
assert 0 <= length && length <= Integer.MAX_VALUE;
VALUE[] values = newArray((int) length);
for (Map.Entry<Long, VALUE> e : map.entrySet()) {
values[e.getKey().intValue()] = e.getValue();
}
return values;
}
@Override
Elements<VALUE> toDense() {
assert count() > 0;
return new DenseElements<>(Arrays.asList(toArray()), count());
}
@Override
Elements<VALUE> toSparse() {
return this;
}
@Override
Elements<VALUE> toSparseOrShrink() {
return this;
}
@Override
long length() {
return map.isEmpty() ? 0 : map.lastKey() + 1;
}
@Override
int capacity() {
return 0;
}
@Override
int count() {
return map.size();
}
@Override
boolean has(long propertyKey) {
return map.containsKey(propertyKey);
}
@Override
VALUE get(long propertyKey) {
return map.get(propertyKey);
}
@Override
void put(long propertyKey, VALUE value) {
map.put(propertyKey, value);
}
@Override
void delete(long propertyKey) {
map.remove(propertyKey);
}
@Override
List<String> keys() {
ArrayList<String> keys = new ArrayList<>(count());
for (Long k : map.keySet()) {
keys.add(k.toString());
}
return keys;
}
@Override
List<String> keys(long from, long to) {
assert from <= to;
int size = (int) Math.min(count(), to - from);
ArrayList<String> keys = new ArrayList<>(size);
for (Long k : map.subMap(from, true, to, false).keySet()) {
keys.add(k.toString());
}
return keys;
}
@Override
long[] indices() {
long[] indices = new long[count()];
int j = 0;
for (Long k : map.keySet()) {
indices[j++] = k;
}
return indices;
}
@Override
long[] indices(long from, long to) {
long length = length();
if (from >= length || from >= to) {
return new long[0];
}
long fromIndex = Math.min(from, length);
long toIndex = Math.min(to, length);
// Skip subMap() if whole range is requested.
if (fromIndex == 0 && toIndex == length) {
return indices();
}
long range = (toIndex - fromIndex);
int j = 0;
long[] indices = new long[(int) Math.min(range, count())];
for (Long k : map.subMap(from, true, to, false).keySet()) {
indices[j++] = k;
}
if (j != indices.length) {
indices = Arrays.copyOf(indices, j);
}
return indices;
}
@Override
Iterator<Map.Entry<Long, VALUE>> iterator() {
return map.entrySet().iterator();
}
@Override
Iterator<Long> keysIterator() {
return map.keySet().iterator();
}
@Override
Iterator<VALUE> valuesIterator() {
return map.values().iterator();
}
@Override
Iterator<Map.Entry<Long, VALUE>> ascendingIterator(long from, long to) {
return map.subMap(from, true, to, false).entrySet().iterator();
}
@Override
Iterator<Map.Entry<Long, VALUE>> descendingIterator(long from, long to) {
return map.descendingMap().subMap(to, false, from, true).entrySet().iterator();
}
@Override
public String toString() {
return "Sparse=" + Arrays.toString(indices());
}
}
private static abstract class DenseIterator<V, T> implements Iterator<T> {
private final V[] values;
private final int endIndex;
private final int step;
private int index;
DenseIterator(int startIndex, int endIndex, V[] values) {
assert 0 <= startIndex && startIndex <= values.length;
assert -1 <= endIndex && endIndex <= values.length;
this.index = startIndex;
this.step = startIndex <= endIndex ? 1 : -1;
this.endIndex = endIndex;
this.values = values;
}
private final int getNextIndex() {
V[] values = this.values;
for (int i = index; i != endIndex; i += step) {
if (values[i] != null) {
return i;
}
}
return -1;
}
protected final V value(int index) {
return values[index];
}
protected abstract T nextValue(int index);
@Override
public final T next() {
int nextIndex = getNextIndex();
if (nextIndex < 0) {
throw new NoSuchElementException();
}
index = nextIndex + step;
return nextValue(nextIndex);
}
@Override
public final boolean hasNext() {
return getNextIndex() >= 0;
}
@Override
public final void remove() {
throw new UnsupportedOperationException();
}
}
private static final class DenseKeyIterator<V> extends DenseIterator<V, Long> {
DenseKeyIterator(int startIndex, int endIndex, V[] values) {
super(startIndex, endIndex, values);
}
@Override
protected Long nextValue(int index) {
return (long) index;
}
}
private static final class DenseValueIterator<V> extends DenseIterator<V, V> {
DenseValueIterator(int startIndex, int endIndex, V[] values) {
super(startIndex, endIndex, values);
}
@Override
protected V nextValue(int index) {
return value(index);
}
}
private static final class DenseStringKeyIterator<V> extends DenseIterator<V, String> {
DenseStringKeyIterator(int startIndex, int endIndex, V[] values) {
super(startIndex, endIndex, values);
}
@Override
protected String nextValue(int index) {
return Integer.toString(index);
}
}
private static final class DenseEntryIterator<V> extends DenseIterator<V, Map.Entry<Long, V>> {
DenseEntryIterator(int startIndex, int endIndex, V[] values) {
super(startIndex, endIndex, values);
}
@Override
protected Map.Entry<Long, V> nextValue(int index) {
return new AbstractMap.SimpleImmutableEntry<>((long) index, value(index));
}
}
private static final class StubSortedMap<V> extends AbstractMap<Long, V> implements
SortedMap<Long, V> {
private final V[] values;
private final int size;
StubSortedMap(V[] values, int size) {
this.values = values;
this.size = size;
}
@Override
public int size() {
return size;
}
@Override
public Set<Map.Entry<Long, V>> entrySet() {
return new AbstractSet<Map.Entry<Long, V>>() {
@Override
public Iterator<java.util.Map.Entry<Long, V>> iterator() {
return new DenseEntryIterator<>(0, values.length, values);
}
@Override
public int size() {
return StubSortedMap.this.size();
}
};
}
@Override
public Comparator<? super Long> comparator() {
return null; // natural order
}
@Override
public SortedMap<Long, V> subMap(Long fromKey, Long toKey) {
throw new UnsupportedOperationException();
}
@Override
public SortedMap<Long, V> headMap(Long toKey) {
throw new UnsupportedOperationException();
}
@Override
public SortedMap<Long, V> tailMap(Long fromKey) {
throw new UnsupportedOperationException();
}
@Override
public Long firstKey() {
throw new UnsupportedOperationException();
}
@Override
public Long lastKey() {
throw new UnsupportedOperationException();
}
}
/**
* Returns {@code true} if the property key is a valid index.
*
* @param propertyKey
* the property key
* @return {@code true} if the property key is a valid index
*/
public static boolean isIndex(long propertyKey) {
return 0 <= propertyKey && propertyKey < MAX_LENGTH;
}
/**
* If {@code s} is an integer indexed property key less than {@code 2}<span><sup>{@code 53}
* </sup></span>{@code -1}, its integer value is returned. Otherwise {@code -1} is returned.
*
* @param propertyKey
* the property key
* @return the integer index or {@code -1}
*/
public static long toIndex(String propertyKey) {
return Strings.toIndex(propertyKey);
}
/**
* Returns the length.
*
* @return the length
*/
public long getLength() {
return length;
}
/**
* Returns {@code true} if the property key was found.
*
* @param propertyKey
* the property key
* @return {@code true} if property key was found
*/
public boolean containsKey(long propertyKey) {
assert isIndex(propertyKey) : "invalid index: " + propertyKey;
if (0 <= propertyKey && propertyKey < length) {
return elements.has(propertyKey);
}
return false;
}
/**
* Returns the mapped value or {@code null} if not found.
*
* @param propertyKey
* the property key
* @return the mapped value or {@code null} if not found
*/
public VALUE get(long propertyKey) {
assert isIndex(propertyKey) : "invalid index: " + propertyKey;
if (0 <= propertyKey && propertyKey < length) {
return elements.get(propertyKey);
}
return null;
}
/**
* Sets the property key to the new value.
*
* @param propertyKey
* the property key
* @param value
* the new property value
*/
public void put(long propertyKey, VALUE value) {
assert isIndex(propertyKey) : "invalid index: " + propertyKey;
if (propertyKey <= MAX_DENSE_LENGTH) {
smallPut((int) propertyKey, value);
} else {
largePut(propertyKey, value);
}
}
private static <VALUE> Elements<VALUE> createElements(int propertyKey) {
if (propertyKey < MIN_SPARSE_LENGTH) {
return new DenseElements<>(propertyKey);
} else {
return new SparseElements<>();
}
}
private void smallPut(int propertyKey, VALUE value) {
assert propertyKey <= (int) MAX_DENSE_LENGTH : "index too large: " + propertyKey;
Elements<VALUE> elements = this.elements;
if (elements == EMPTY_ELEMENTS) {
this.elements = elements = createElements(propertyKey);
}
if (propertyKey < length) {
// Switch to dense representation?
int count = elements.count(), capacity = elements.capacity();
if (capacity == 0 && count * 2 > length) {
this.elements = elements = elements.toDense();
}
} else {
// Switch to sparse representation?
int newLength = propertyKey + 1;
int count = elements.count(), capacity = newLength;
if (capacity > MIN_SPARSE_LENGTH && count * SPARSE_DENSE_RATIO < capacity) {
this.elements = elements = elements.toSparseOrShrink();
}
length = Math.max(length, newLength);
}
elements.put(propertyKey, value);
}
private void largePut(long propertyKey, VALUE value) {
assert propertyKey > MAX_DENSE_LENGTH : "index too small: " + propertyKey;
// Require sparse representation
Elements<VALUE> elements = this.elements = this.elements.toSparse();
elements.put(propertyKey, value);
length = Math.max(length, propertyKey + 1);
}
/**
* Deletes the property key.
*
* @param propertyKey
* the property key
*/
public void remove(long propertyKey) {
assert isIndex(propertyKey) : "invalid index: " + propertyKey;
if (0 <= propertyKey && propertyKey < length) {
elements.delete(propertyKey);
updateLength();
}
}
/**
* Deletes the property key. Does not perform any representation clean-up.
*
* @param propertyKey
* the property key
* @see #updateLength()
*/
public void removeUnchecked(long propertyKey) {
assert isIndex(propertyKey) : "invalid index: " + propertyKey;
if (0 <= propertyKey && propertyKey < length) {
elements.delete(propertyKey);
}
}
/**
* Updates the length and adjusts the internal representation.
*/
public void updateLength() {
// Switch to sparse representation?
Elements<VALUE> elements = this.elements;
int count = elements.count(), capacity = elements.capacity();
if (capacity > MIN_SPARSE_LENGTH && count * SPARSE_DENSE_RATIO < capacity) {
this.elements = elements = elements.toSparseOrShrink();
} else {
long length = elements.length();
if (capacity == 0 && count * 2 > length) {
this.elements = elements = elements.toDense();
}
}
// TODO: add explicit length logic
this.length = elements.length();
}
/**
* Returns {@code true} if the map uses the sparse elements representation.
*
* @return {@code true} if the map is sparse
*/
public boolean isSparse() {
return elements instanceof SparseElements;
}
/**
* Returns {@code true} if the map has holes.
*
* @return {@code true} if the map has holes
*/
public boolean hasHoles() {
return length != elements.count();
}
/**
* Returns {@code true} if the map is empty.
*
* @return {@code true} if the map is empty
*/
public boolean isEmpty() {
return elements.count() == 0;
}
/**
* Returns the number of mappings in this map.
*
* @return the number of mappings
*/
public int size() {
return elements.count();
}
/**
* Returns the indexed keys as strings.
*
* @return the indexed keys as strings
*/
public List<String> keys() {
return elements.keys();
}
/**
* Returns the indexed keys as strings.
*
* @param from
* from index (inclusive)
* @param to
* to index (exclusive)
* @return the indexed keys as strings
*/
public List<String> keys(long from, long to) {
if (from < 0 || to < 0 || from > to) {
throw new IndexOutOfBoundsException();
}
return elements.keys(from, to);
}
/**
* Returns the indexed keys.
*
* @return the indexed keys
*/
public long[] indices() {
return elements.indices();
}
/**
* Returns the indexed keys over the requested range.
*
* @param from
* from index (inclusive)
* @param to
* to index (exclusive)
* @return the indexed keys
*/
public long[] indices(long from, long to) {
return elements.indices(from, to);
}
/**
* Returns an ascending iterator over the complete range.
*
* @return the range iterator
*/
@Override
public Iterator<Map.Entry<Long, VALUE>> iterator() {
return elements.iterator();
}
/**
* Returns an ascending iterator over the complete range.
*
* @return the range iterator
*/
public Iterator<Long> keysIterator() {
return elements.keysIterator();
}
/**
* Returns an ascending iterator over the complete range.
*
* @return the range iterator
*/
public Iterator<VALUE> valuesIterator() {
return elements.valuesIterator();
}
/**
* Returns an ascending iterator over the requested range.
*
* @param from
* from index (inclusive)
* @param to
* to index (exclusive)
* @return the range iterator
*/
public Iterator<Map.Entry<Long, VALUE>> ascendingIterator(long from, long to) {
if (from < 0 || to < 0 || from > to) {
throw new IndexOutOfBoundsException();
}
return elements.ascendingIterator(from, to);
}
/**
* Returns a descending iterator over the requested range.
*
* @param from
* from index (inclusive)
* @param to
* to index (exclusive)
* @return the range iterator
*/
public Iterator<Map.Entry<Long, VALUE>> descendingIterator(long from, long to) {
if (from < 0 || to < 0 || from > to) {
throw new IndexOutOfBoundsException();
}
return elements.descendingIterator(from, to);
}
@Override
public String toString() {
return String.format("{length=%d, elements=%s}", length, elements);
}
}