Please wait. This can take some minutes ...
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.
swim.collections.FingerTrieSeq Maven / Gradle / Ivy
Go to download
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.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import swim.codec.Debug;
import swim.codec.Format;
import swim.codec.Output;
import swim.util.Builder;
import swim.util.Murmur3;
public final class FingerTrieSeq implements List, Debug {
final Object[] prefix;
final FingerTrieSeq branch;
final Object[] suffix;
final int length;
FingerTrieSeq(Object[] prefix, FingerTrieSeq branch, Object[] suffix, int length) {
this.prefix = prefix;
this.branch = branch;
this.suffix = suffix;
this.length = length;
}
@SuppressWarnings("unchecked")
FingerTrieSeq() {
this.prefix = EMPTY_LEAF;
this.branch = (FingerTrieSeq) this;
this.suffix = EMPTY_LEAF;
this.length = 0;
}
@Override
public boolean isEmpty() {
return this.length == 0;
}
@Override
public int size() {
return this.length;
}
@Override
public boolean contains(Object elem) {
final Iterator iter = iterator();
while (iter.hasNext()) {
final T next = iter.next();
if (elem == null ? next == null : elem.equals(next)) {
return true;
}
}
return false;
}
@Override
public boolean containsAll(Collection> elems) {
for (Object elem : elems) {
if (!contains(elem)) {
return false;
}
}
return true;
}
@SuppressWarnings("unchecked")
@Override
public T get(int index) {
final Object[] prefix = this.prefix;
final int n = index - prefix.length;
if (n < 0) {
return (T) prefix[index];
} else {
final FingerTrieSeq branch = this.branch;
final int j = n - (branch.length << 5);
if (j < 0) {
return (T) branch.get(n >> 5)[n & 0x1F];
} else {
return (T) this.suffix[j];
}
}
}
@Override
public T set(int index, T nwElem) {
throw new UnsupportedOperationException();
}
@Override
public boolean add(T newElem) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection extends T> newElems) {
throw new UnsupportedOperationException();
}
@Override
public void add(int index, T newElem) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(int index, Collection extends T> newElems) {
throw new UnsupportedOperationException();
}
@Override
public T remove(int index) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object elem) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection> elems) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection> elems) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public int indexOf(Object elem) {
for (int i = 0, n = length; i < n; i += 1) {
if (elem == null ? get(i) == null : elem.equals(get(i))) {
return i;
}
}
return -1;
}
@Override
public int lastIndexOf(Object elem) {
for (int i = length - 1; i >= 0; i -= 1) {
if (elem == null ? get(i) == null : elem.equals(get(i))) {
return i;
}
}
return -1;
}
public FingerTrieSeq updated(int index, T elem) {
final Object[] oldPrefix = this.prefix;
final int a = oldPrefix.length;
final int n = index - a;
if (n < 0) {
final Object[] newPrefix = new Object[a];
System.arraycopy(oldPrefix, 0, newPrefix, 0, a);
newPrefix[index] = elem;
return new FingerTrieSeq(newPrefix, this.branch, this.suffix, this.length);
} else {
final FingerTrieSeq oldBranch = this.branch;
final int j = n - (oldBranch.length << 5);
if (j < 0) {
final Object[] oldInfix = oldBranch.get(n >> 5);
final Object[] newInfix = new Object[32];
System.arraycopy(oldInfix, 0, newInfix, 0, 32);
newInfix[n & 0x1F] = elem;
final FingerTrieSeq newBranch = oldBranch.updated(n >> 5, newInfix);
return new FingerTrieSeq(oldPrefix, newBranch, this.suffix, this.length);
} else {
final Object[] oldSuffix = this.suffix;
final int b = oldSuffix.length;
final Object[] newSuffix = new Object[b];
System.arraycopy(oldSuffix, 0, newSuffix, 0, b);
newSuffix[j] = elem;
return new FingerTrieSeq(oldPrefix, oldBranch, newSuffix, this.length);
}
}
}
@SuppressWarnings("unchecked")
public T head() {
if (this.length == 0) {
throw new NoSuchElementException();
}
return (T) this.prefix[0];
}
public FingerTrieSeq tail() {
if (this.length == 0) {
throw new UnsupportedOperationException();
}
return drop(1);
}
public FingerTrieSeq body() {
if (this.length == 0) {
throw new UnsupportedOperationException();
}
return take(this.length - 1);
}
@SuppressWarnings("unchecked")
public T foot() {
if (this.length == 0) {
throw new NoSuchElementException();
}
if (this.length <= 32) {
return (T) this.prefix[this.prefix.length - 1];
} else {
return (T) this.suffix[this.suffix.length - 1];
}
}
@SuppressWarnings("unchecked")
public FingerTrieSeq drop(int lower) {
if (lower <= 0) {
return this;
} else if (lower >= this.length) {
return (FingerTrieSeq) EMPTY;
} else {
final int n = lower - this.prefix.length;
final int k = this.length - lower;
final FingerTrieSeq oldBranch = this.branch;
if (n == 0) {
if (oldBranch.length > 0) {
return new FingerTrieSeq(oldBranch.head(), oldBranch.tail(), this.suffix, k);
} else {
return new FingerTrieSeq(this.suffix, EMPTY_NODE, EMPTY_LEAF, k);
}
} else if (n < 0) {
final Object[] newPrefix = new Object[-n];
System.arraycopy(this.prefix, lower, newPrefix, 0, -n);
return new FingerTrieSeq(newPrefix, oldBranch, this.suffix, k);
} else {
final int j = n - (oldBranch.length << 5);
if (j < 0) {
final FingerTrieSeq split = oldBranch.drop(n >> 5);
final Object[] oldPrefix = split.head();
final Object[] newPrefix = new Object[oldPrefix.length - (n & 0x1F)];
System.arraycopy(oldPrefix, n & 0x1F, newPrefix, 0, newPrefix.length);
return new FingerTrieSeq(newPrefix, split.tail(), this.suffix, k);
} else {
final Object[] newPrefix = new Object[k];
System.arraycopy(this.suffix, j, newPrefix, 0, k);
return new FingerTrieSeq(newPrefix, EMPTY_NODE, EMPTY_LEAF, k);
}
}
}
}
@SuppressWarnings("unchecked")
public FingerTrieSeq take(int upper) {
if (upper <= 0) {
return (FingerTrieSeq) EMPTY;
} else if (upper >= this.length) {
return this;
} else {
final int n = upper - this.prefix.length;
if (n == 0) {
return new FingerTrieSeq(this.prefix, EMPTY_NODE, EMPTY_LEAF, upper);
} else if (n < 0) {
final Object[] newPrefix = new Object[upper];
System.arraycopy(this.prefix, 0, newPrefix, 0, upper);
return new FingerTrieSeq(newPrefix, EMPTY_NODE, EMPTY_LEAF, upper);
} else {
final FingerTrieSeq oldBranch = this.branch;
final int j = n - (oldBranch.length << 5);
if (j == 0) {
if (oldBranch.length > 0) {
return new FingerTrieSeq(this.prefix, oldBranch.body(), oldBranch.foot(), upper);
} else {
return new FingerTrieSeq(this.suffix, EMPTY_NODE, EMPTY_LEAF, upper);
}
} else if (j < 0) {
final FingerTrieSeq split = oldBranch.take(((n + 0x1F) & 0xFFFFFFE0) >> 5);
final Object[] oldSuffix = split.foot();
final Object[] newSuffix = new Object[((((n & 0x1F) ^ 0x1F) + 1) & 0x20) | (n & 0x1F)];
System.arraycopy(oldSuffix, 0, newSuffix, 0, newSuffix.length);
return new FingerTrieSeq(this.prefix, split.body(), newSuffix, upper);
} else {
final Object[] newSuffix = new Object[j];
System.arraycopy(this.suffix, 0, newSuffix, 0, j);
return new FingerTrieSeq(this.prefix, oldBranch, newSuffix, upper);
}
}
}
}
@SuppressWarnings("unchecked")
public FingerTrieSeq slice(int lower, int upper) {
if (lower >= upper) {
return (FingerTrieSeq) EMPTY;
} else {
return drop(lower).take(upper - Math.max(0, lower));
}
}
public FingerTrieSeq appended(T elem) {
final int i = this.prefix.length;
final int j = this.suffix.length;
final int n = this.branch.length;
if (n == 0 && j == 0 && i < 32) {
final Object[] newPrefix = new Object[i + 1];
System.arraycopy(this.prefix, 0, newPrefix, 0, i);
newPrefix[i] = elem;
return new FingerTrieSeq(newPrefix, EMPTY_NODE, EMPTY_LEAF, this.length + 1);
} else if (n == 0 && i + j < 32) {
final Object[] newPrefix = new Object[i + j + 1];
System.arraycopy(this.prefix, 0, newPrefix, 0, i);
System.arraycopy(this.suffix, 0, newPrefix, i, j);
newPrefix[i + j] = elem;
return new FingerTrieSeq(newPrefix, EMPTY_NODE, EMPTY_LEAF, this.length + 1);
} else if (n == 0 && i + j < 64) {
final Object[] newPrefix = new Object[32];
System.arraycopy(this.prefix, 0, newPrefix, 0, i);
System.arraycopy(this.suffix, 0, newPrefix, i, 32 - i);
final Object[] newSuffix = new Object[i + j - 32 + 1];
System.arraycopy(this.suffix, 32 - i, newSuffix, 0, i + j - 32);
newSuffix[i + j - 32] = elem;
return new FingerTrieSeq(newPrefix, EMPTY_NODE, newSuffix, this.length + 1);
} else if (j < 32) {
final Object[] newSuffix = new Object[j + 1];
System.arraycopy(this.suffix, 0, newSuffix, 0, j);
newSuffix[j] = elem;
return new FingerTrieSeq(this.prefix, this.branch, newSuffix, this.length + 1);
} else {
final Object[] newSuffix = new Object[1];
newSuffix[0] = elem;
final FingerTrieSeq newBranch = this.branch.appended(this.suffix);
return new FingerTrieSeq(this.prefix, newBranch, newSuffix, this.length + 1);
}
}
public FingerTrieSeq appended(Collection extends T> elems) {
final FingerTrieSeqBuilder builder = new FingerTrieSeqBuilder(this);
builder.addAll(elems);
return builder.bind();
}
public FingerTrieSeq prepended(T elem) {
final int i = this.prefix.length;
final int j = this.suffix.length;
final int n = this.branch.length;
if (n == 0 && j == 0 && i < 32) {
final Object[] newPrefix = new Object[1 + i];
newPrefix[0] = elem;
System.arraycopy(this.prefix, 0, newPrefix, 1, i);
return new FingerTrieSeq(newPrefix, EMPTY_NODE, EMPTY_LEAF, 1 + this.length);
} else if (n == 0 && i + j < 32) {
final Object[] newPrefix = new Object[1 + i + j];
newPrefix[0] = elem;
System.arraycopy(this.prefix, 0, newPrefix, 1, i);
System.arraycopy(this.suffix, 0, newPrefix, 1 + i, j);
return new FingerTrieSeq(newPrefix, EMPTY_NODE, EMPTY_LEAF, 1 + this.length);
} else if (n == 0 && i + j < 64) {
final Object[] newPrefix = new Object[1 + i + j - 32];
newPrefix[0] = elem;
System.arraycopy(this.prefix, 0, newPrefix, 1, i + j - 32);
final Object[] newSuffix = new Object[32];
System.arraycopy(this.prefix, i + j - 32, newSuffix, 0, 32 - j);
System.arraycopy(this.suffix, 0, newSuffix, 32 - j, j);
return new FingerTrieSeq(newPrefix, EMPTY_NODE, newSuffix, 1 + this.length);
} else if (i < 32) {
final Object[] newPrefix = new Object[1 + i];
newPrefix[0] = elem;
System.arraycopy(this.prefix, 0, newPrefix, 1, i);
return new FingerTrieSeq(newPrefix, this.branch, this.suffix, 1 + this.length);
} else {
final Object[] newPrefix = new Object[1];
newPrefix[0] = elem;
final FingerTrieSeq newBranch = this.branch.prepended(this.prefix);
return new FingerTrieSeq(newPrefix, newBranch, this.suffix, 1 + this.length);
}
}
public FingerTrieSeq prepended(Collection extends T> elems) {
final FingerTrieSeqBuilder builder = new FingerTrieSeqBuilder();
builder.addAll(elems);
builder.addAll(this);
return builder.bind();
}
public FingerTrieSeq removed(int index) {
if (index < 0 || index >= length) {
throw new IndexOutOfBoundsException(String.valueOf(index));
}
if (index == 0) {
return drop(1);
} else {
final int newLength = length - 1;
if (index == newLength) {
return take(index);
} else if (index > 0) {
final FingerTrieSeqBuilder builder = new FingerTrieSeqBuilder(take(index));
do {
index += 1;
builder.add(get(index));
} while (index < newLength);
return builder.bind();
} else {
return this;
}
}
}
public FingerTrieSeq removed(Object elem) {
final int index = indexOf(elem);
if (index >= 0) {
return removed(index);
} else {
return this;
}
}
@Override
public FingerTrieSeq subList(int fromIndex, int toIndex) {
if (fromIndex < 0 || toIndex > length || fromIndex > toIndex) {
throw new IndexOutOfBoundsException(fromIndex + ", " + toIndex);
}
return drop(fromIndex).take(toIndex - fromIndex);
}
@Override
public Object[] toArray() {
final int n = length;
final Object[] array = new Object[n];
for (int i = 0; i < n; i += 1) {
array[i] = get(i);
}
return array;
}
@SuppressWarnings("unchecked")
@Override
public T[] toArray(T[] array) {
final int n = length;
if (array.length < n) {
array = (T[]) Array.newInstance(array.getClass().getComponentType(), n);
}
for (int i = 0; i < n; i += 1) {
array[i] = (T) get(i);
}
if (array.length > n) {
array[n] = null;
}
return array;
}
@Override
public Iterator iterator() {
return new FingerTrieSeqIterator(this);
}
@Override
public ListIterator listIterator() {
return new FingerTrieSeqIterator(this);
}
@Override
public ListIterator listIterator(int index) {
return new FingerTrieSeqIterator(this, index);
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (other instanceof FingerTrieSeq>) {
final FingerTrieSeq that = (FingerTrieSeq) other;
if (this.length == that.length) {
final Iterator these = iterator();
final Iterator those = that.iterator();
while (these.hasNext() && those.hasNext()) {
final T x = these.next();
final T y = those.next();
if (x == null ? y != null : !x.equals(y)) {
return false;
}
}
return true;
}
}
return false;
}
@Override
public int hashCode() {
if (hashSeed == 0) {
hashSeed = Murmur3.seed(FingerTrieSeq.class);
}
int h = hashSeed;
final Iterator these = iterator();
while (these.hasNext()) {
h = Murmur3.mix(h, Murmur3.hash(these.next()));
}
return Murmur3.mash(h);
}
@Override
public void debug(Output> output) {
output = output.write("FingerTrieSeq").write('.');
final Iterator these = iterator();
if (these.hasNext()) {
output = output.write("of").write('(').debug(these.next());
while (these.hasNext()) {
output = output.write(", ").debug(these.next());
}
} else {
output = output.write("empty").write('(');
}
output = output.write(')');
}
@Override
public String toString() {
return Format.debug(this);
}
private static int hashSeed;
static final Object[] EMPTY_LEAF = new Object[0];
static final FingerTrieSeq> EMPTY = new FingerTrieSeq();
@SuppressWarnings("unchecked")
static final FingerTrieSeq EMPTY_NODE = (FingerTrieSeq) EMPTY;
@SuppressWarnings("unchecked")
public static FingerTrieSeq empty() {
return (FingerTrieSeq) EMPTY;
}
public static FingerTrieSeq of(T elem0, T elem1) {
final FingerTrieSeqBuilder builder = new FingerTrieSeqBuilder();
builder.add(elem0);
builder.add(elem1);
return builder.bind();
}
@SuppressWarnings("unchecked")
public static FingerTrieSeq of(T... elems) {
final FingerTrieSeqBuilder builder = new FingerTrieSeqBuilder();
for (T elem : elems) {
builder.add(elem);
}
return builder.bind();
}
public static FingerTrieSeq from(Iterable extends T> elems) {
final FingerTrieSeqBuilder builder = new FingerTrieSeqBuilder();
for (T elem : elems) {
builder.add(elem);
}
return builder.bind();
}
public static Builder> builder(FingerTrieSeq extends T> trie) {
return new FingerTrieSeqBuilder(trie);
}
public static Builder> builder() {
return new FingerTrieSeqBuilder();
}
}
final class FingerTrieSeqBuilder implements Builder> {
Object[] prefix;
FingerTrieSeqBuilder branch;
Object[] buffer;
int length;
FingerTrieSeqBuilder(FingerTrieSeq extends T> trie) {
if (trie.length > 32) {
this.prefix = trie.prefix;
if (trie.length > 64) {
this.branch = new FingerTrieSeqBuilder(trie.branch);
}
this.buffer = trie.suffix;
} else if (trie.length > 0) {
this.buffer = trie.prefix;
}
this.length = trie.length;
}
FingerTrieSeqBuilder() {
this.prefix = null;
this.branch = null;
this.buffer = null;
this.length = 0;
}
private int getSkew() {
return (this.prefix != null ? this.length - this.prefix.length : this.length) & 0x1F;
}
@Override
public boolean add(T elem) {
final int offset = getSkew();
if (offset == 0) {
if (this.buffer != null) {
if (this.prefix == null) {
this.prefix = this.buffer;
} else {
if (this.branch == null) {
this.branch = new FingerTrieSeqBuilder();
}
this.branch.add(this.buffer);
}
}
this.buffer = new Object[32];
} else if (this.buffer.length < 32) {
final Object[] newBuffer = new Object[32];
System.arraycopy(this.buffer, 0, newBuffer, 0, offset);
this.buffer = newBuffer;
}
this.buffer[offset] = elem;
this.length += 1;
return true;
}
@Override
public boolean addAll(Collection extends T> elems) {
if (elems instanceof FingerTrieSeq>) {
return addAll((FingerTrieSeq extends T>) elems);
} else {
for (T elem : elems) {
add(elem);
}
return true;
}
}
boolean addAll(FingerTrieSeq extends T> that) {
if (this.length == 0 && that.length != 0) {
if (that.length > 32) {
this.prefix = that.prefix;
if (that.length > 64) {
this.branch = new FingerTrieSeqBuilder(that.branch);
}
this.buffer = that.suffix;
} else {
this.buffer = that.prefix;
}
this.length = that.length;
} else if (that.length != 0) {
final int offset = getSkew();
if (((offset + that.prefix.length) & 0x1F) == 0) {
if (buffer.length < 32) {
final Object[] newBuffer = new Object[32];
System.arraycopy(this.buffer, 0, newBuffer, 0, offset);
this.buffer = newBuffer;
}
if (offset > 0) {
System.arraycopy(that.prefix, 0, this.buffer, offset, 32 - offset);
} else {
if (this.prefix == null) {
this.prefix = this.buffer;
} else {
if (this.branch == null) {
this.branch = new FingerTrieSeqBuilder();
}
this.branch.add(this.buffer);
}
this.buffer = that.prefix;
}
if (that.suffix.length > 0) {
if (this.branch == null) {
this.branch = new FingerTrieSeqBuilder();
}
this.branch.add(this.buffer);
this.branch.addAll(that.branch);
this.buffer = that.suffix;
}
this.length += that.length;
} else {
for (T elem : that) {
add(elem);
}
}
}
return true;
}
public void clear() {
this.prefix = null;
this.branch = null;
this.buffer = null;
this.length = 0;
}
@SuppressWarnings("unchecked")
@Override
public FingerTrieSeq bind() {
if (this.length == 0) {
return (FingerTrieSeq) FingerTrieSeq.EMPTY;
} else {
final int offset = getSkew();
if (offset != 0 && offset != this.buffer.length) {
final Object[] suffix = new Object[offset];
System.arraycopy(this.buffer, 0, suffix, 0, offset);
this.buffer = suffix;
}
if (prefix == null) {
return new FingerTrieSeq(this.buffer, FingerTrieSeq.EMPTY_NODE,
FingerTrieSeq.EMPTY_LEAF, this.length);
} else if (branch == null) {
return new FingerTrieSeq(this.prefix, FingerTrieSeq.EMPTY_NODE, this.buffer, this.length);
} else {
return new FingerTrieSeq(this.prefix, this.branch.bind(), this.buffer, this.length);
}
}
}
}
final class FingerTrieSeqSegmenter implements ListIterator {
final Object[] prefix;
final FingerTrieSeq branch;
final Object[] suffix;
FingerTrieSeqSegmenter inner;
Object[] infix;
int infixIndex;
int index;
int phase;
FingerTrieSeqSegmenter(FingerTrieSeq> trie) {
this.prefix = trie.prefix;
this.branch = trie.branch;
this.suffix = trie.suffix;
this.phase = trie.length > 0 ? 0 : 3;
}
FingerTrieSeqSegmenter(FingerTrieSeq> trie, int index) {
this.prefix = trie.prefix;
this.branch = trie.branch;
this.suffix = trie.suffix;
this.index = index;
if (index == 0) {
this.phase = 0;
} else if (index - 1 < this.branch.length) {
this.inner = new FingerTrieSeqSegmenter(this.branch, (index - 1) >> 5);
this.infix = this.inner.next();
this.infixIndex = (index - 1) & 0x1F;
this.phase = 1;
} else if (index == 1 + this.branch.length && this.suffix.length > 0) {
this.phase = 2;
} else {
this.phase = 3;
}
}
@Override
public boolean hasNext() {
return this.phase < 3;
}
@Override
public int nextIndex() {
return this.index;
}
@Override
public Object[] next() {
switch (this.phase) {
case 0:
this.index += 1;
if (this.branch.length > 0) {
this.inner = new FingerTrieSeqSegmenter(this.branch);
this.infix = this.inner.next();
this.infixIndex = 0;
this.phase = 1;
} else if (this.suffix.length > 0) {
this.phase = 2;
} else {
this.phase = 3;
}
return this.prefix;
case 1:
final Object[] head = (Object[]) this.infix[this.infixIndex];
this.infixIndex += 1;
this.index += 1;
if (this.infixIndex >= this.infix.length) {
if (this.inner.hasNext()) {
this.infix = this.inner.next();
this.infixIndex = 0;
} else {
this.inner = null;
this.phase = 2;
}
}
return head;
case 2:
this.index += 1;
this.phase = 3;
return this.suffix;
default:
throw new NoSuchElementException();
}
}
@Override
public boolean hasPrevious() {
return this.phase > 0;
}
@Override
public int previousIndex() {
return this.index - 1;
}
@Override
public Object[] previous() {
switch (this.phase) {
case 1:
this.index -= 1;
if (this.infixIndex > 0) {
this.infixIndex -= 1;
return (Object[]) this.infix[this.infixIndex];
} else {
this.inner.previous();
if (this.inner.hasPrevious()) {
this.infix = this.inner.previous();
this.infixIndex = this.infix.length - 1;
this.inner.next();
return (Object[]) this.infix[this.infixIndex];
} else {
this.inner = null;
this.phase = 0;
return this.prefix;
}
}
case 2:
this.index -= 1;
if (this.branch.length > 0) {
if (this.inner == null) {
this.inner = new FingerTrieSeqSegmenter(this.branch, this.branch.length);
}
this.infix = this.inner.previous();
this.infixIndex = this.infix.length - 1;
this.inner.next();
this.phase = 1;
return (Object[]) this.infix[this.infixIndex];
} else {
this.phase = 0;
return this.prefix;
}
case 3:
this.index -= 1;
if (this.suffix.length > 0) {
this.phase = 2;
return this.suffix;
} else if (this.branch.length > 0) {
if (this.inner == null) {
this.inner = new FingerTrieSeqSegmenter(this.branch, this.branch.length);
}
this.infix = this.inner.previous();
this.infixIndex = this.infix.length - 1;
this.inner.next();
this.phase = 1;
return (Object[]) this.infix[this.infixIndex];
} else {
this.phase = 0;
return this.prefix;
}
default:
throw new NoSuchElementException();
}
}
@Override
public void add(Object[] segment) {
throw new UnsupportedOperationException();
}
@Override
public void set(Object[] segment) {
throw new UnsupportedOperationException();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
final class FingerTrieSeqIterator implements ListIterator {
final FingerTrieSeqSegmenter segmenter;
Object[] page;
int pageIndex;
int index;
FingerTrieSeqIterator(FingerTrieSeq trie) {
this.segmenter = new FingerTrieSeqSegmenter(trie);
if (this.segmenter.hasNext()) {
this.page = this.segmenter.next();
} else {
this.page = FingerTrieSeq.EMPTY_LEAF;
}
}
FingerTrieSeqIterator(FingerTrieSeq trie, int index) {
final int n = index - trie.prefix.length;
if (n < 0) {
this.segmenter = new FingerTrieSeqSegmenter(trie, 1);
this.page = trie.prefix;
this.pageIndex = index;
} else if (index < trie.length) {
final int j = n - (trie.branch.length << 5);
if (j < 0) {
this.segmenter = new FingerTrieSeqSegmenter(trie, 1 + (n >> 5));
this.page = this.segmenter.next();
this.pageIndex = n & 0x1F;
} else {
this.segmenter = new FingerTrieSeqSegmenter(trie, 1 + trie.branch.length);
this.page = this.segmenter.next();
this.pageIndex = j;
}
} else {
this.segmenter = new FingerTrieSeqSegmenter(trie, trie.length);
this.page = FingerTrieSeq.EMPTY_LEAF;
this.pageIndex = 0;
}
this.index = index;
}
@Override
public boolean hasNext() {
return this.pageIndex < this.page.length;
}
@Override
public int nextIndex() {
return this.index;
}
@SuppressWarnings("unchecked")
@Override
public T next() {
if (this.pageIndex < this.page.length) {
final T head = (T) this.page[this.pageIndex];
this.pageIndex += 1;
this.index += 1;
if (this.pageIndex >= this.page.length) {
if (this.segmenter.hasNext()) {
this.page = this.segmenter.next();
} else {
this.page = FingerTrieSeq.EMPTY_LEAF;
}
this.pageIndex = 0;
}
return head;
} else {
throw new NoSuchElementException();
}
}
@Override
public boolean hasPrevious() {
return this.index > 0;
}
@Override
public int previousIndex() {
return this.index - 1;
}
@SuppressWarnings("unchecked")
@Override
public T previous() {
if (this.pageIndex > 0) {
this.index -= 1;
this.pageIndex -= 1;
return (T) this.page[this.pageIndex];
} else {
this.segmenter.previous();
if (this.segmenter.hasPrevious()) {
this.index -= 1;
this.page = this.segmenter.previous();
this.pageIndex = this.page.length - 1;
this.segmenter.next();
return (T) this.page[this.pageIndex];
} else {
throw new NoSuchElementException();
}
}
}
@Override
public void add(T elem) {
throw new UnsupportedOperationException();
}
@Override
public void set(T elem) {
throw new UnsupportedOperationException();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}