package org.osgl.util;
import org.osgl.$;
import org.osgl.exception.NotAppliedException;
import org.osgl.util.algo.Algorithms;
import java.io.Serializable;
import java.util.*;
/**
* An immutable list implementation. This class is guaranteed to be NOT empty
*/
class ImmutableList<T> extends ListBase<T>
implements C.List<T>, RandomAccess, Serializable {
private final T[] data_;
/**
* Construct the ImmutableList with an array. The array will be used
* directly as the backing data of this list. No data copy happen
*
* @param data an array of element backing this list
*/
protected ImmutableList(T[] data) {
E.NPE(data);
data_ = data;
}
@Override
protected EnumSet<C.Feature> initFeatures() {
return EnumSet.of(C.Feature.READONLY, C.Feature.LIMITED, C.Feature.ORDERED, C.Feature.IMMUTABLE, C.Feature.LAZY, C.Feature.PARALLEL, C.Feature.RANDOM_ACCESS);
}
@Override
public int size() throws UnsupportedOperationException {
return data_.length;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object o) {
return indexOf(o) > -1;
}
@Override
public Object[] toArray() {
T[] da = data_;
int sz = da.length;
Object[] ret = new Object[sz];
System.arraycopy(da, 0, ret, 0, sz);
return ret;
}
@Override
@SuppressWarnings("unchecked")
public <T1> T1[] toArray(T1[] a) {
int sza = a.length;
T[] da = data_;
int sz = da.length;
if (sza < sz) {
return (T1[]) Arrays.copyOf(da, sz, a.getClass());
}
System.arraycopy(da, 0, a, 0, sz);
if (sza > sz) {
a[sz] = null;
}
return a;
}
@Override
public boolean add(T t) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection<?> c) {
for (Object o : c) {
if (!contains(c)) {
return false;
}
}
return true;
}
@Override
public boolean addAll(Collection<? extends T> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(int index, Collection<? extends T> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public T get(int index) {
return data_[index];
}
@Override
public T set(int index, T element) {
throw new UnsupportedOperationException();
}
@Override
public void add(int index, T element) {
throw new UnsupportedOperationException();
}
@Override
public T remove(int index) {
throw new UnsupportedOperationException();
}
@Override
public int indexOf(Object o) {
T[] da = data_;
int sz = da.length;
if (o == null) {
for (int i = 0; i < sz; i++)
if (da[i] == null)
return i;
} else {
for (int i = 0; i < sz; i++)
if (o.equals(da[i]))
return i;
}
return -1;
}
@Override
public int lastIndexOf(Object o) {
T[] da = data_;
int sz = da.length;
if (o == null) {
for (int i = sz - 1; i >= 0; i--)
if (da[i] == null)
return i;
} else {
for (int i = sz - 1; i >= 0; i--)
if (o.equals(da[i]))
return i;
}
return -1;
}
private class Itr implements Iterator<T> {
protected int cursor = 0;
@Override
public boolean hasNext() {
return cursor != data_.length;
}
@Override
public T next() {
T[] da = data_;
if (cursor >= da.length) {
throw new NoSuchElementException();
}
int i = cursor++;
return da[i];
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
@Override
public Iterator<T> iterator() {
return new Itr();
}
private class LstItr extends Itr implements ListIterator<T> {
LstItr() {this(0);}
LstItr(int index) {
if (index < 0 || index > data_.length) {
throw new IndexOutOfBoundsException();
}
cursor = index;
}
@Override
public boolean hasPrevious() {
return cursor != 0;
}
@Override
public T previous() {
if (cursor < 0) {
throw new NoSuchElementException();
}
cursor--;
return data_[cursor];
}
@Override
public int nextIndex() {
return cursor;
}
@Override
public int previousIndex() {
return cursor - 1;
}
@Override
public void set(T t) {
throw new UnsupportedOperationException();
}
@Override
public void add(T t) {
throw new UnsupportedOperationException();
}
}
@Override
public ListIterator<T> listIterator() {
return new LstItr();
}
@Override
public ListIterator<T> listIterator(int index) {
return new LstItr(index);
}
@Override
public <R> C.List<R> map($.Function<? super T, ? extends R> mapper) {
if (isLazy()) {
return MappedList.of(this, mapper);
}
int sz = size();
ListBuilder<R> lb = new ListBuilder<R>(sz);
forEach($.f1(mapper).andThen(C.F.addTo(lb)));
return lb.toList();
}
@Override
public <R> C.List<R> flatMap($.Function<? super T, ? extends Iterable<? extends R>> mapper
) {
// TODO: handle lazy operation
int sz = size();
ListBuilder<R> lb = new ListBuilder<R>(sz * 3);
forEach($.f1(mapper).andThen(C.F.addAllTo(lb)));
return lb.toList();
}
@Override
public C.Sequence<T> append(Iterable<? extends T> iterable) {
return super.append(iterable);
}
private C.List<T> unLazyAppend(Collection<? extends T> collection) {
int szB = collection.size();
if (szB == 0) {
return this;
}
int szA = size();
T[] dataA = data_;
Object[] dataB = collection.toArray();
T[] data = $.newArray(dataA, szA + szB);
System.arraycopy(dataA, 0, data, 0, szA);
System.arraycopy(dataB, 0, data, szA, szB);
return of(data);
}
@Override
@SuppressWarnings("unchecked")
public C.List<T> append(Collection<? extends T> collection) {
if (collection instanceof C.List) {
return appendList((C.List<T>) collection);
} else {
return unLazyAppend(collection);
}
}
@Override
public C.ReversibleSequence<T> append(C.ReversibleSequence<T> seq) {
if (seq instanceof C.List) {
return appendList((C.List<T>) seq);
}
return super.appendReversibleSeq(seq);
}
@Override
public C.Sequence<T> append(C.Sequence<? extends T> seq) {
if (seq instanceof C.List) {
return appendList((C.List<T>) seq);
}
if (isLazy()) {
return CompositeSeq.of(this, seq);
}
ListBuilder<T> lb = new ListBuilder<T>(size() * 2);
lb.append(this).append(seq);
return lb.toList();
}
@Override
public C.Sequence<T> append(Iterator<? extends T> iterator) {
if (isLazy()) {
return CompositeSeq.of(this, C.seq(iterator));
}
ListBuilder<T> lb = new ListBuilder<T>(size() * 2);
lb.append(this).append(iterator);
return lb.toList();
}
@Override
public C.Sequence<T> append(Enumeration<? extends T> enumeration) {
if (isLazy()) {
return CompositeSeq.of(this, C.seq(enumeration));
}
ListBuilder<T> lb = new ListBuilder<T>(size() * 2);
lb.append(this).append(enumeration);
return lb.toList();
}
protected C.List<T> appendList(C.List<T> l) {
if (isLazy()) {
return CompositeList.of(this, l);
}
if (l instanceof ImmutableList) {
return appendImmutableList((ImmutableList<T>) l);
}
return unLazyAppend(l);
}
public C.List<T> append(C.List<T> l) {
return appendList(l);
}
private C.List<T> appendImmutableList(ImmutableList<T> l) {
int szA = size();
int szB = l.size();
T[] dataA = data_;
T[] data = $.newArray(dataA, szA + szB);
System.arraycopy(dataA, 0, data, 0, szA);
System.arraycopy(l.data_, 0, data, szA, szB);
return of(data);
}
public C.List<T> append(ImmutableList<T> l) {
return appendImmutableList(l);
}
private C.List<T> unLazyPrepend(Collection<? extends T> collection) {
int szB = collection.size();
if (szB == 0) {
return this;
}
int szA = size();
T[] dataA = data_;
Object[] dataB = collection.toArray();
T[] data = $.newArray(dataA, szA + szB);
System.arraycopy(dataB, 0, data, 0, szB);
System.arraycopy(dataA, 0, data, szB, szA);
return of(data);
}
@Override
@SuppressWarnings("unchecked")
public C.List<T> prepend(Collection<? extends T> collection) {
if (collection instanceof C.List) {
return prependList((C.List<T>) collection);
} else {
return unLazyPrepend(collection);
}
}
@Override
public C.ReversibleSequence<T> prepend(C.ReversibleSequence<T> seq) {
return super.prependReversibleSeq(seq);
}
@Override
public C.Sequence<T> prepend(C.Sequence<? extends T> seq) {
if (seq instanceof C.List) {
return prependList((C.List<T>) seq);
}
if (isLazy()) {
return CompositeSeq.of(seq, this);
}
ListBuilder<T> lb = new ListBuilder<T>(size() * 2);
lb.append(seq).append(this);
return lb.toList();
}
public C.List<T> prepend(C.List<T> l) {
if (isLazy()) {
return CompositeList.of(l, this);
}
if (l instanceof ImmutableList) {
return prependList((ImmutableList<T>) l);
}
return unLazyPrepend(l);
}
public C.List<T> prepend(ImmutableList<T> l) {
if (isLazy()) {
return CompositeList.of(l, this);
}
int szA = size();
int szB = l.size();
T[] myData = data_;
T[] data = $.newArray(myData, szA + szB);
System.arraycopy(l.data_, 0, data, 0, szB);
System.arraycopy(myData, 0, data, szB, szA);
return of(data);
}
private class ReverseItr implements Iterator<T> {
private LstItr itr;
ReverseItr() {
itr = new LstItr(size());
}
@Override
public boolean hasNext() {
return itr.hasPrevious();
}
@Override
public T next() {
return itr.previous();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
@Override
public Iterator<T> reverseIterator() {
return new ReverseItr();
}
@Override
public $.Option<T> findLast($.Function<? super T, Boolean> predicate) {
T[] ta = data_;
for (int i = ta.length - 1; i >= 0; --i) {
T t = ta[i];
if (predicate.apply(t)) {
return $.some(t);
}
}
return $.none();
}
@Override
public C.List<T> takeWhile($.Function<? super T, Boolean> predicate) {
int sz = size();
ListBuilder<T> lb = new ListBuilder<T>(sz);
for (T t : this) {
if (predicate.apply(t)) {
lb.add(t);
} else {
break;
}
}
return lb.toList();
}
@Override
public C.List<T> without(Collection<? super T> col) {
int sz = size();
T[] data = data_;
ListBuilder<T> lb = new ListBuilder<T>(sz);
for (int i = 0; i < sz; ++i) {
T t = data[i];
if (!col.contains(t)) {
lb.add(t);
}
}
return lb.toList();
}
@Override
public C.List<T> without(T element) {
int sz = size();
T[] data = data_;
ListBuilder<T> lb = new ListBuilder<T>(sz);
for (int i = 0; i < sz; ++i) {
T t = data[i];
if ($.ne(t, element)) {
lb.add(t);
}
}
return lb.toList();
}
@Override
public C.List<T> without(T element, T... elements) {
int len = elements.length;
if (len == 0) return without(element);
int sz = size();
T[] data = data_;
ListBuilder<T> lb = new ListBuilder<T>(sz);
T t0 = elements[0];
boolean c = false;
if (len < 8 && t0 instanceof Comparable) {
Arrays.sort(elements);
c = true;
}
if (c) {
for (int i = 0; i < sz; ++i) {
T t = data[i];
if ($.eq(t, element)) {
continue;
}
int id = Arrays.binarySearch(elements, t);
if (id > -1) continue;
lb.add(t);
}
} else {
for (int i = 0; i < sz; ++i) {
T t = data[i];
if ($.eq(t, element)) {
continue;
}
boolean found = false;
for (int j = 0; j < len; ++j) {
if ($.eq(elements[j], t)) {
found = true;
break;
};
}
if (!found) {
lb.add(t);
}
}
}
return lb.toList();
}
@Override
@SuppressWarnings("unchecked")
public C.List<T> reverse() {
if (isLazy()) {
return ReverseList.wrap(this);
}
T[] data = (T[]) Algorithms.ARRAY_REVERSE.apply(data_, 0, data_.length);
return of(data);
}
@Override
public C.List<T> prepend(T t) {
int sz = size();
T[] myData = data_;
T[] data = $.newArray(myData, sz + 1);
data[0] = t;
System.arraycopy(myData, 0, data, 1, sz);
return of(data);
}
@Override
public C.List<T> append(T t) {
int sz = size();
T[] myData = data_;
T[] data = $.newArray(myData, sz + 1);
data[sz] = t;
System.arraycopy(myData, 0, data, 0, sz);
return of(data);
}
@Override
public C.List<T> insert(int index, T t) throws IndexOutOfBoundsException {
T[] myData = data_;
int sz = data_.length;
if (sz < Math.abs(index)) {
throw new IndexOutOfBoundsException();
}
if (index < 0) {
index = sz + index;
}
T[] data = $.newArray(myData, sz + 1);
System.arraycopy(myData, 0, data, 0, index);
data[index] = t;
System.arraycopy(myData, index, data, index + 1, sz - index);
return of(data);
}
@Override
public C.List<T> insert(int index, T... ta) throws IndexOutOfBoundsException {
if (ta.length == 0) {
return this;
}
T[] myData = data_;
int sz = data_.length;
if (sz < Math.abs(index)) {
throw new IndexOutOfBoundsException();
}
if (index < 0) {
index = sz + index;
}
int delta = ta.length;
T[] data = $.newArray(myData, sz + delta);
if (index > 0) {
System.arraycopy(myData, 0, data, 0, index);
}
System.arraycopy(ta, 0, data, index, delta);
if (index < sz) {
System.arraycopy(myData, index, data, index + delta, sz - index);
}
return of(data);
}
@Override
public C.List<T> insert(int index, List<T> subList) throws IndexOutOfBoundsException {
if (subList.isEmpty()) {
return this;
}
T[] myData = data_;
int sz = data_.length;
if (sz < Math.abs(index)) {
throw new IndexOutOfBoundsException();
}
if (index < 0) {
index = sz + index;
}
int delta = subList.size();
T[] data = $.newArray(myData, sz + delta);
if (index > 0) {
System.arraycopy(myData, 0, data, 0, index);
}
for (int i = 0; i < delta; ++i) {
data[index + i] = subList.get(i);
}
if (index < sz) {
System.arraycopy(myData, index, data, index + delta, sz - index);
}
return of(data);
}
private class Csr implements Cursor<T> {
private int id_;
Csr() {this(-1);}
Csr(int index) {
if (index < -1) {
index = -1;
} else if (index > size()) {
index = size();
}
id_ = index;
}
@Override
public boolean isDefined() {
int id = id_;
return id > -1 && id < size();
}
@Override
public int index() {
return id_;
}
@Override
public T get() throws NoSuchElementException {
if (!isDefined()) {
throw new NoSuchElementException();
}
return data_[id_];
}
@Override
public boolean hasNext() {
return id_ < size() - 1;
}
@Override
public boolean hasPrevious() {
return id_ > 0;
}
@Override
public Cursor<T> parkLeft() {
id_ = -1;
return this;
}
@Override
public Cursor<T> parkRight() {
id_ = size();
return this;
}
@Override
public Cursor<T> forward() {
if (id_ >= size()) {
id_ = size();
throw new UnsupportedOperationException();
}
id_++;
return this;
}
@Override
public Cursor<T> backward() throws UnsupportedOperationException {
if (id_ <= -1) {
id_ = -1;
throw new UnsupportedOperationException();
}
id_--;
return this;
}
@Override
public Cursor<T> set(T t) throws IndexOutOfBoundsException, NullPointerException {
throw new UnsupportedOperationException();
}
@Override
public Cursor<T> drop() throws NoSuchElementException {
throw new UnsupportedOperationException();
}
@Override
public Cursor<T> prepend(T t) throws IndexOutOfBoundsException {
throw new UnsupportedOperationException();
}
@Override
public Cursor<T> append(T t) {
throw new UnsupportedOperationException();
}
}
@Override
public Cursor<T> locateLast($.Function<T, Boolean> predicate) {
int sz = size();
T[] data = data_;
for (int i = sz - 1; i >= 0; --i) {
T t = data[i];
if (predicate.apply(t)) {
return new Csr(i);
}
}
return new Csr(-1);
}
@Override
public Cursor<T> locate($.Function<T, Boolean> predicate) {
return locateFirst(predicate);
}
@Override
public Cursor<T> locateFirst($.Function<T, Boolean> predicate) {
int sz = size();
T[] data = data_;
for (int i = 0; i < sz; ++i) {
T t = data[i];
if (predicate.apply(t)) {
return new Csr(i);
}
}
return new Csr(sz);
}
@Override
public C.List<T> filter($.Function<? super T, Boolean> predicate) {
// TODO: handle lazy operation
int sz = size();
if (0 == sz) {
return Nil.list();
}
T[] data = $.newArray(data_);
int cursor = 0;
for (int i = 0; i < sz; ++i) {
T t = data_[i];
if (predicate.apply(t)) {
data[cursor++] = t;
}
}
if (0 == cursor) {
return Nil.list();
}
data = Arrays.copyOf(data, cursor);
return of(data);
}
@Override
public C.List<T> dropWhile($.Function<? super T, Boolean> predicate) {
//TODO: handle lazy operation
int sz = size();
$.Function<T, Boolean> f = $.F.negate(predicate);
Cursor<T> cursor = locateFirst(f);
if (!cursor.isDefined()) {
return Nil.list();
}
int id = cursor.index();
return subList(id, size());
}
@Override
public C.List<T> drop(int n) throws IndexOutOfBoundsException {
int size = size();
if (n < 0) {
n = -n;
if (n >= size) return C.list();
return take(size - n);
}
if (0 == n) {
return this;
}
if (n >= size) {
return Nil.list();
}
return subList(n, size());
}
@Override
public C.List<T> tail(int n) {
if (n < 0) {
return head(-n);
}
int sz = size();
if (n >= sz) {
return this;
}
return subList(sz - n, sz);
}
@Override
public C.List<T> tail() {
int sz = size();
if (sz == 0) {
throw new UnsupportedOperationException();
}
return subList(1, sz);
}
@Override
public C.List<T> take(int n) {
if (n < 0) {
return tail(-n);
}
int sz = size();
if (n >= sz) {
return this;
}
return subList(0, n);
}
@Override
protected void forEachLeft($.Function<? super T, ?> visitor) throws $.Break {
int sz = size();
T[] data = data_;
for (int i = 0; i < sz; ++i) {
T t = data[i];
try {
visitor.apply(t);
} catch (NotAppliedException e) {
// ignore
}
}
}
@Override
protected void forEachRight($.Function<? super T, ?> visitor) throws $.Break {
int sz = size();
T[] data = data_;
for (int i = sz - 1; i >= 0; --i) {
T t = data[i];
try {
visitor.apply(t);
} catch (NotAppliedException e) {
// ignore
}
}
}
@Override
public $.Option<T> findOne($.Function<? super T, Boolean> predicate) {
//todo parallel finding
int sz = size();
T[] data = data_;
for (int i = 0; i < sz; ++i) {
T t = data[i];
if (predicate.apply(t)) {
return $.some(t);
}
}
return $.none();
}
@Override
public T head() throws NoSuchElementException {
return data_[0];
}
@Override
public T last() throws NoSuchElementException {
return data_[size() - 1];
}
@Override
public <R> R reduce(R identity, $.Func2<R, T, R> accumulator) {
// TODO: parallel
return reduceLeft(identity, accumulator);
}
@Override
public <R> R reduceLeft(R identity, $.Func2<R, T, R> accumulator) {
int sz = size();
R ret = identity;
T[] data = data_;
for (int i = 0; i < sz; ++i) {
ret = accumulator.apply(ret, data[i]);
}
return ret;
}
@Override
public <R> R reduceRight(R identity, $.Func2<R, T, R> accumulator) {
int sz = size();
R ret = identity;
T[] data = data_;
for (int i = sz - 1; i >= 0; --i) {
ret = accumulator.apply(ret, data[i]);
}
return ret;
}
@Override
public $.Option<T> reduce($.Func2<T, T, T> accumulator) {
// TODO parallel
return reduceLeft(accumulator);
}
@Override
public $.Option<T> reduceLeft($.Func2<T, T, T> accumulator) {
int sz = size();
T[] data = data_;
T ret = data[0];
for (int i = 1; i < sz; ++i) {
ret = accumulator.apply(ret, data[i]);
}
return $.some(ret);
}
@Override
public $.Option<T> reduceRight($.Func2<T, T, T> accumulator) {
int sz = size();
T[] data = data_;
T ret = data[sz - 1];
for (int i = sz - 2; i >= 0; --i) {
ret = accumulator.apply(ret, data[i]);
}
return $.some(ret);
}
@Override
int modCount() {
return 0;
}
@Override
void removeRange2(int fromIndex, int toIndex) {
throw new UnsupportedOperationException();
}
static <T> C.List<T> of(T[] data) {
E.NPE(data);
int len = data.length;
if (len == 0) {
return Nil.list();
} else if (len == 1) {
return $.val(data[0]);
} else {
return new ImmutableList<T>(data);
}
}
static <T> C.List<T> copyOf(T[] data) {
int sz = data.length;
if (sz == 0) {
return Nil.list();
}
T[] a = Arrays.copyOf(data, sz);
return new ImmutableList<T>(a);
}
}
class ImmutableSubList<T> extends RandomAccessSubList<T> {
ImmutableSubList(ListBase<T> list, int fromIndex, int toIndex) {
super(list, fromIndex, toIndex);
}
@Override
public C.List<T> subList(int fromIndex, int toIndex) {
return new ImmutableSubList<T>(this, fromIndex, toIndex);
}
@Override
protected void checkForComodification() {
return;
}
@Override
public T set(int index, T element) {
throw new UnsupportedOperationException();
}
@Override
public void add(int index, T element) {
throw new UnsupportedOperationException();
}
@Override
public T remove(int index) {
throw new UnsupportedOperationException();
}
@Override
protected void removeRange(int fromIndex, int toIndex) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection<? extends T> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(int index, Collection<? extends T> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Iterable<? extends T> iterable) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public boolean add(T t) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
}