All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.osgl.util.ListBase Maven / Gradle / Ivy

The newest version!
package org.osgl.util;

/*-
 * #%L
 * Java Tool
 * %%
 * Copyright (C) 2014 - 2017 OSGL (Open Source General Library)
 * %%
 * 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.
 * #L%
 */

import static org.osgl.util.C.Feature.SORTED;

import org.osgl.$;
import org.osgl.Lang;
import org.osgl.exception.NotAppliedException;

import java.util.*;

public abstract class ListBase extends AbstractList implements C.List {

    private boolean sorted = false;

    // utilities
    protected final boolean isLazy() {
        return is(C.Feature.LAZY);
    }

    protected final boolean isImmutable() {
        return is(C.Feature.IMMUTABLE);
    }

    protected final boolean isReadOnly() {
        return is(C.Feature.READONLY);
    }

    protected final boolean isMutable() {
        return !isImmutable() && !isReadOnly();
    }

    protected void forEachLeft($.Visitor visitor) throws $.Break {
        for (T t : this) {
            try {
                visitor.apply(t);
            } catch (NotAppliedException e) {
                // ignore
            }
        }
    }

    protected void forEachLeft($.IndexedVisitor indexedVisitor) throws $.Break {
        for (int i = 0, j = size(); i < j; ++i) {
            try {
                indexedVisitor.apply(i, get(i));
            } catch (NotAppliedException e) {
                // ignore
            }
        }
    }

    protected void forEachRight($.Visitor visitor) throws $.Break {
        Iterator itr = reverseIterator();
        while (itr.hasNext()) {
            try {
                visitor.apply(itr.next());
            } catch (NotAppliedException e) {
                // ignore
            }
        }
    }

    protected void forEachRight($.IndexedVisitor indexedVisitor) throws $.Break {
        for (int i = size() - 1; i >= 0; --i) {
            try {
                indexedVisitor.apply(i, get(i));
            } catch (NotAppliedException e) {
                // ignore
            }
        }
    }

    @Override
    public C.List parallel() {
        setFeature(C.Feature.PARALLEL);
        return this;
    }

    @Override
    public C.List sequential() {
        unsetFeature(C.Feature.PARALLEL);
        return this;
    }

    @Override
    public C.List lazy() {
        setFeature(C.Feature.LAZY);
        return this;
    }

    @Override
    public C.List eager() {
        unsetFeature(C.Feature.LAZY);
        return this;
    }

    @Override
    public C.List snapshot() {
        if (isImmutable()) {
            return this;
        }
        return ListBuilder.toList(this);
    }

    @Override
    public C.List readOnly() {
        if (isMutable()) {
            return new ReadOnlyDelegatingList(this);
        }
        return this;
    }

    @Override
    public C.List copy() {
        return C.newList(this);
    }

    @Override
    public C.List sorted() {
        if (size() == 0) return C.newList();
        T t = get(0);
        C.List l = copy();
        if (!(t instanceof Comparable)) {
            return l;
        }
        Object[] a = l.toArray();
       	Arrays.sort(a);
       	ListIterator i = l.listIterator();
       	for (int j=0; j sorted(Comparator comparator) {
        C.List l = copy();
        Collections.sort(l, comparator);
        ((ListBase)l).setFeature(SORTED);
        return l;
    }

    @Override
    public C.List unique() {
        Set set = C.newSet();
        C.List retList = null;
        int i = 0;
        for (T t: this) {
            i++;
            if (set.contains(t)) {
                if (null == retList) {
                    retList = C.newSizedList(size());
                    retList.addAll(subList(0, i - 1));
                }
            } else if (null != retList) {
                retList.add(t);
            }
            set.add(t);
        }
        return null == retList ? this : retList;
    }

    public C.List unique(Comparator comp) {
        Set set = new TreeSet(comp);
        C.List retList = null;
        int i = 0;
        for (T t: this) {
            i++;
            if (set.contains(t)) {
                if (null == retList) {
                    retList = C.newSizedList(size());
                    retList.addAll(subList(0, i - 1));
                }
            } else if (null != retList) {
                retList.add(t);
            }
            set.add(t);
        }
        return null == retList ? this : retList;
    }

    @Override
    public C.List subList(int fromIndex, int toIndex) {
        if (fromIndex == toIndex) {
            return Nil.list();
        }
        if (is(C.Feature.RANDOM_ACCESS)) {
            return new RandomAccessSubList(this, fromIndex, toIndex);
        } else {
            return new SubList(this, fromIndex, toIndex);
        }
    }

    @Override
    public boolean add(T t) {
        boolean b = super.add(t);
        if (b) {
            sorted = false;
        }
        return b;
    }

    @Override
    public void add(int index, T element) {
        super.add(index, element);
        sorted = false;
        unsetFeature(SORTED);
    }

    public boolean addAll(Iterable iterable) {
        boolean modified = false;
        Iterator e = iterable.iterator();
        while (e.hasNext()) {
            if (add(e.next())) {
                modified = true;
            }
        }
        sorted = !modified;
        if (!sorted) {
            unsetFeature(SORTED);
        }
        return modified;
    }

    @Override
    public int hashCode() {
        return 31 * super.hashCode() + $.hc(features_);
    }

    // --- Featured methods

    volatile private EnumSet features_;

    protected final EnumSet features_() {
        if (null == features_) {
            synchronized (this) {
                if (null == features_) {
                    features_ = initFeatures();
                    assert (null != features_);
                }
            }
        }
        return features_;
    }

    /**
     * Sub class should override this method to provide initial feature
     * set for the feature based instance
     *
     * @return the initial feature set configuration
     */
    abstract protected EnumSet initFeatures();

    @Override
    public final EnumSet features() {
        return EnumSet.copyOf(features_());
    }

    @Override
    public final boolean is(C.Feature feature) {
        return features_().contains(feature);
    }

    protected ListBase setFeature(C.Feature feature) {
        features_().add(feature);
        return this;
    }

    protected ListBase unsetFeature(C.Feature feature) {
        features_().remove(feature);
        return this;
    }

    // --- eof Featured methods

    // --- Traversal methods

    @Override
    public boolean allMatch($.Function predicate) {
        return !anyMatch($.F.negate(predicate));
    }

    @Override
    public boolean anyMatch($.Function predicate) {
        return findOne(predicate).isDefined();
    }

    @Override
    public boolean noneMatch($.Function predicate) {
        return !anyMatch(predicate);
    }

    @Override
    public $.Option findOne(final $.Function predicate) {
        try {
            forEach(new $.Visitor() {
                @Override
                public void visit(T t) throws $.Break {
                    if (predicate.apply(t)) {
                        throw new $.Break(t);
                    }
                }
            });
            return $.none();
        } catch ($.Break b) {
            T t = b.get();
            return $.some(t);
        }
    }

    // --- eof Traversal methods


    @Override
    public C.List asList() {
        return this;
    }

    @Override
    public Iterator iterator() {
        return listIterator();
    }

    public abstract ListIterator listIterator(int index);

    @Override
    public Iterator reverseIterator() {
        final ListIterator li = listIterator(size());

        return new Iterator() {
            @Override
            public boolean hasNext() {
                return li.hasPrevious();
            }

            @Override
            public T next() {
                return li.previous();
            }

            @Override
            public void remove() {
                li.remove();
            }
        };
    }

    @Override
    public final T first() throws NoSuchElementException {
        return head();
    }

    @Override
    public T head() throws NoSuchElementException {
        return iterator().next();
    }

    @Override
    public T last() throws NoSuchElementException {
        return reverseIterator().next();
    }

    @Override
    public C.List take(int n) {
        boolean immutable = isImmutable();
        if (n == 0) {
            if (immutable) {
                return Nil.list();
            } else {
                return C.newList();
            }
        } else if (n < 0) {
            return drop(size() + n);
        } else if (n >= size()) {
            return this;
        }
        if (immutable) {
            return subList(0, n);
        }
        C.List l = C.newSizedList(n);
        l.addAll(subList(0, n));
        return l;
    }

    @Override
    public C.List takeWhile($.Function predicate) {
        boolean immutable = isImmutable();
        int sz = size();
        if (immutable) {
            if (0 == sz) {
                return Nil.list();
            }
            ListBuilder lb = new ListBuilder(sz);
            for (T t : this) {
                if (predicate.apply(t)) {
                    lb.add(t);
                } else {
                    break;
                }
            }
            return lb.toList();
        } else {
            if (0 == sz) {
                return C.newList();
            }
            C.List l = C.newSizedList(sz);
            for (T t : this) {
                if (predicate.apply(t)) {
                    l.add(t);
                } else {
                    break;
                }
            }
            return l;
        }
    }

    @Override
    public C.List drop(int n) throws IndexOutOfBoundsException {
        int sz = size();
        boolean immutable = isImmutable();
        if (n < 0) {
            n = -n;
            if (n >= sz) {
                if (immutable) return C.newList();
                else return C.list();
            } else {
                return take(sz - n);
            }
        }
        if (0 == n) {
            return this;
        }
        // TODO handle lazy drop
        if (immutable) {
            return subList(n, size());
        }
        if (n >= sz) {
            return C.newList();
        }
        C.List l = C.newSizedList(sz - n);
        l.addAll(subList(n, sz));
        return l;
    }

    @Override
    public C.List dropWhile($.Function predicate) {
        boolean immutable = isImmutable();
        int sz = size();
        if (immutable) {
            if (0 == sz) {
                return Nil.list();
            }
            ListBuilder lb = new ListBuilder(sz);
            boolean found = false;
            for (T t : this) {
                if (!found && predicate.apply(t)) {
                    continue;
                } else {
                    found = true;
                    lb.add(t);
                }
            }
            return lb.toList();
        } else {
            if (0 == sz) {
                return C.newList();
            }
            C.List l = C.newSizedList(sz);
            boolean found = false;
            for (T t : this) {
                if (!found && predicate.apply(t)) {
                    continue;
                } else {
                    found = true;
                    l.add(t);
                }
            }
            return l;
        }
    }

    @Override
    public C.List remove($.Function predicate) {
        boolean immutable = isImmutable();
        int sz = size();
        // TODO: handle lazy remove
        if (immutable) {
            if (0 == sz) {
                return Nil.list();
            }
            ListBuilder lb = new ListBuilder(sz);
            forEach($.visitor($.predicate(predicate).elseThen(C.F.addTo(lb))));
            return lb.toList();
        } else {
            if (0 == sz) {
                return C.newList();
            }
            C.List l = C.newSizedList(sz);
            forEach($.visitor($.predicate(predicate).elseThen(C.F.addTo(l))));
            return l;
        }
    }

    @Override
    public  C.List map($.Function mapper) {
        boolean immutable = isImmutable();
        int sz = size();
        if (isLazy()) {
            return MappedList.of(this, mapper);
        }
        if (immutable) {
            if (0 == sz) {
                return Nil.list();
            }
            ListBuilder lb = new ListBuilder(sz);
            forEach($.visitor($.f1(mapper).andThen(C.F.addTo(lb))));
            return lb.toList();
        } else {
            if (0 == sz) {
                return C.newList();
            }
            C.List l = C.newSizedList(sz);
            forEach($.visitor($.f1(mapper).andThen(C.F.addTo(l))));
            return l;
        }
    }

    @Override
    public  C.List flatMap($.Function> mapper
    ) {
        boolean immutable = isImmutable();
        int sz = size();
        // TODO: handle lazy flatmap
        if (immutable) {
            if (0 == sz) {
                return Nil.list();
            }
            ListBuilder lb = new ListBuilder<>(sz * 3);
            forEach($.visitor($.f1(mapper).andThen(C.F.addAllTo(lb))));
            return lb.toList();
        } else {
            if (0 == sz) {
                return C.newList();
            }
            C.List l = C.newSizedList(sz * 3);
            forEach($.visitor($.f1(mapper).andThen(C.F.addAllTo(l))));
            return l;
        }
    }

    @Override
    public  C.List collect(String path) {
        boolean immutable = isImmutable();
        int sz = size();
        if (0 == sz) {
            return immutable ? Nil.list() : C.newList();
        }
        if (immutable) {
            ListBuilder lb = new ListBuilder<>(sz);
            for (T t : this) {
                lb.add((R) $.getProperty(t, path));
            }
            return lb.toList();
        } else {
            C.List list = C.newSizedList(sz);
            for (T t : this) {
                list.add((R) $.getProperty(t, path));
            }
            return list;
        }
    }

    @Override
    public C.List filter($.Function predicate) {
        boolean immutable = isImmutable();
        int sz = size();
        // TODO: handle lazy filter
        if (immutable) {
            if (0 == sz) {
                return Nil.list();
            }
            ListBuilder lb = new ListBuilder(sz);
            forEach($.visitor($.predicate(predicate).ifThen(C.F.addTo(lb))));
            return lb.toList();
        } else {
            if (0 == sz) {
                return C.newList();
            }
            C.List l = C.newSizedList(sz);
            forEach($.visitor($.predicate(predicate).ifThen(C.F.addTo(l))));
            return l;
        }
    }

    @Override
    public Lang.T2, C.List> split(final Lang.Function predicate) {
        final C.List left = C.newList();
        final C.List right = C.newList();
        accept(new $.Visitor() {
            @Override
            public void visit(T t) throws Lang.Break {
                if (predicate.apply(t)) {
                    left.add(t);
                } else {
                    right.add(t);
                }
            }
        });
        if (isImmutable() || isReadOnly()) {
            return $.T2(C.list(left), C.list(right));
        }
        return $.T2(left, right);
    }

    private Cursor fromLeft() {
        return new ListIteratorCursor(listIterator(0));
    }

    private Cursor fromRight() {
        return new ListIteratorCursor(listIterator(size()));
    }

    @Override
    public Cursor locateFirst($.Function predicate) {
        Cursor c = fromLeft();
        while (c.hasNext()) {
            T t = c.forward().get();
            if (predicate.apply(t)) {
                return c;
            }
        }
        return c;
    }

    @Override
    public Cursor locate($.Function predicate) {
        return locateFirst(predicate);
    }

    @Override
    public Cursor locateLast($.Function predicate) {
        Cursor c = fromRight();
        while (c.hasPrevious()) {
            T t = c.backward().get();
            if (predicate.apply(t)) {
                return c;
            }
        }
        return c;
    }

    @Override
    public C.List insert(int index, T t) throws IndexOutOfBoundsException {
        int sz = size();
        if (sz < Math.abs(index)) {
            throw new IndexOutOfBoundsException();
        }
        if (index < 0) {
            index = sz + index;
        }
        if (isMutable()) {
            add(index, t);
            return this;
        }
        if (isImmutable()) {
            ListBuilder lb = new ListBuilder(sz + 1);
            if (index > 0) {
                lb.addAll(subList(0, index));
            }
            lb.add(t);
            if (index < sz) {
                lb.addAll(subList(index, sz));
            }
            return lb.toList();
        } else {
            C.List l = C.newSizedList(sz + 1);
            if (index > 0) {
                l.addAll(subList(0, index));
            }
            l.add(t);
            if (index < sz) {
                l.addAll(subList(index, sz));
            }
            return l;
        }
    }

    @Override
    public C.List insert(int index, T... ta) throws IndexOutOfBoundsException {
        if (ta.length == 0) {
            return this;
        }
        return insert(index, C.listOf(ta));
    }

    @Override
    public C.List insert(int index, List subList) throws IndexOutOfBoundsException {
        if (subList.isEmpty()) {
            return this;
        }
        int sz = size();
        if (sz < Math.abs(index)) {
            throw new IndexOutOfBoundsException();
        }
        if (index < 0) {
            index = sz + index;
        }
        if (isMutable()) {
            addAll(index, subList);
            return this;
        }
        if (isImmutable()) {
            int delta = subList.size();
            ListBuilder lb = new ListBuilder(sz + delta);
            if (index > 0) {
                lb.addAll(subList(0, index));
            }
            lb.addAll(subList);
            if (index < sz) {
                lb.addAll(subList(index, sz));
            }
            return lb.toList();
        } else {
            C.List l = C.newSizedList(sz + 1);
            if (index > 0) {
                l.addAll(subList(0, index));
            }
            l.addAll(subList);
            if (index < sz) {
                l.addAll(subList(index, sz));
            }
            return l;
        }
    }

    @Override
    public C.List reverse() {
        if (isLazy()) {
            return ReverseList.wrap(this);
        }
        boolean immutable = isImmutable();
        int sz = size();
        if (immutable) {
            if (0 == sz) {
                return Nil.list();
            }
            ListBuilder lb = new ListBuilder(sz);
            Iterator itr = reverseIterator();
            while (itr.hasNext()) {
                lb.add(itr.next());
            }
            return lb.toList();
        } else {
            if (0 == sz) {
                return C.newList();
            }
            C.List l = C.newSizedList(sz);
            Iterator itr = reverseIterator();
            while (itr.hasNext()) {
                l.add(itr.next());
            }
            return l;
        }
    }

    @Override
    public C.List without(Collection col) {
        return filter($.F.negate(C.F.containsIn(col)));
    }

    @Override
    public C.List without(T element) {
        return filter(($.F.ne().curry(element)));
    }

    @Override
    public C.List without(T element, T... elements) {
        elements = $.concat(elements, element);
        C.List l = without(element);
        int len = elements.length;
        if (0 == len) {
            return l;
        }
        boolean c = false;
        if (8 < len) {
            T t0 = elements[0];
            if (t0 instanceof Comparable) {
                c = true;
                Arrays.sort(elements);
            }
        }
        C.List lr = C.newSizedList(l.size());
        if (c) {
            for (T t : l) {
                int id = Arrays.binarySearch(elements, t);
                if (id == -1) continue;
                lr.add(t);
            }
        } else {
            for (T t : l) {
                boolean found = false;
                for (int i = 0; i < len; ++i) {
                    if ($.eq(elements[i], t)) {
                        found = true;
                        break;
                    }
                }
                if (!found) lr.add(t);
            }
        }
        return lr;
    }

    @Override
    public C.List accept($.Visitor visitor) {
        forEachLeft(visitor);
        return this;
    }

    @Override
    public C.List each($.Visitor visitor) {
        return accept(visitor);
    }

    @Override
    public C.List forEach($.Visitor visitor) {
        return accept(visitor);
    }

    @Override
    public C.List acceptLeft($.Visitor visitor) {
        forEachLeft(visitor);
        return this;
    }

    @Override
    public C.List acceptRight($.Visitor visitor) {
        forEachRight(visitor);
        return this;
    }

    @Override
    public C.List accept($.IndexedVisitor indexedVisitor) {
        forEachLeft(indexedVisitor);
        return this;
    }

    @Override
    public C.List each($.IndexedVisitor indexedVisitor) {
        return accept(indexedVisitor);
    }

    @Override
    public C.List forEach($.IndexedVisitor indexedVisitor) {
        return accept(indexedVisitor);
    }

    @Override
    public C.List acceptLeft($.IndexedVisitor indexedVisitor) {
        forEachLeft(indexedVisitor);
        return this;
    }

    @Override
    public C.List acceptRight($.IndexedVisitor indexedVisitor) {
        forEachRight(indexedVisitor);
        return this;
    }

    @Override
    public C.List head(int n) {
        return take(n);
    }

    @Override
    public C.List tail() {
        int sz = size();
        if (0 == sz) {
            throw new UnsupportedOperationException();
        }
        if (isImmutable()) {
            return subList(1, sz);
        }
        C.List l = C.newSizedList(sz - 1);
        l.addAll(subList(1, sz));
        return l;
    }

    @Override
    public C.List tail(int n) {
        boolean immutable = isImmutable();
        int sz = size();
        if (n < 0) {
            return head(-n);
        } else if (n == 0) {
            if (immutable) {
                return Nil.list();
            } else {
                return C.newList();
            }
        } else if (n >= sz) {
            return this;
        }
        C.List sl = subList(sz - n, sz);
        if (immutable) {
            return sl;
        }
        C.List l = C.newSizedList(n);
        l.addAll(sl);
        return l;
    }

    @SuppressWarnings("unchecked")
    private C.List unLazyAppend(Iterable iterable) {
        if (isMutable()) {
            if (iterable instanceof Collection) {
                addAll((Collection) iterable);
            } else {
                C.forEach(iterable, $.visitor(C.F.addTo(this)));
            }
            return this;
        }
        // immutable
        if (isImmutable()) {
            ListBuilder lb = new ListBuilder(size() * 2);
            lb.append(this).append(iterable);
            return lb.toList();
        }
        // mutable but read only
        C.List l = C.newSizedList(size() * 2);
        l.addAll(this);
        l.addAll(iterable);
        return l;
    }

    private C.List unLazyAppend(Iterator iterator) {
        if (isMutable()) {
            C.forEach(iterator, $.visitor(C.F.addTo(this)));
            return this;
        }
        ListBuilder lb = new ListBuilder(size() * 2);
        lb.append(this).append(iterator);
        return lb.toList();
    }

    private C.List unLazyAppend(Enumeration enumeration) {
        if (isMutable()) {
            C.forEach(new EnumerationIterator(enumeration), $.visitor(C.F.addTo(this)));
            return this;
        }
        ListBuilder lb = new ListBuilder(size() * 2);
        lb.append(this).append(enumeration);
        return lb.toList();
    }

    @Override
    @SuppressWarnings("unchecked")
    public C.Sequence append(Iterable iterable) {
        if (iterable instanceof C.List) {
            return appendList((C.List) iterable);
        } else if (iterable instanceof C.Sequence) {
            return append((C.Sequence) iterable);
        } else if (iterable instanceof Collection) {
            return append((Collection) iterable);
        } else if (isLazy()) {
            return CompositeSeq.of(this, IterableSeq.of(iterable));
        } else {
            return unLazyAppend(iterable);
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public C.List append(Collection collection) {
        if (collection instanceof C.List) {
            return appendList((C.List) collection);
        } else {
            return unLazyAppend(collection);
        }
    }

    @Override
    public C.Sequence append(C.Sequence seq) {
        if (seq instanceof C.List) {
            return appendList((C.List) seq);
        }
        if (isLazy()) {
            return CompositeSeq.of(this, seq);
        }
        return unLazyAppend(seq);
    }

    @Override
    public C.Sequence append(Iterator iterator) {
        if (isLazy()) {
            return CompositeSeq.of(this, C.seq(iterator));
        }
        return unLazyAppend(iterator);
    }

    @Override
    public C.Sequence append(Enumeration enumeration) {
        return append(new EnumerationIterator(enumeration));
    }

    protected C.ReversibleSequence appendReversibleSeq(C.ReversibleSequence seq) {
        if (seq instanceof C.List) {
            return appendList((C.List) seq);
        }
        // TODO support lazy append reversible sequence
        return unLazyAppend(seq);
    }

    public C.ReversibleSequence append(C.ReversibleSequence seq) {
        return appendReversibleSeq(seq);
    }

    protected C.List appendList(C.List list) {
        if (isLazy()) {
            return CompositeList.of(this, list);
        }
        return unLazyAppend(list);
    }

    @Override
    public C.List append(C.List list) {
        return appendList(list);
    }

    @Override
    public C.List append(T t) {
        if (isMutable()) {
            add(t);
            return this;
        }
        // Immutable
        if (isImmutable()) {
            ListBuilder lb = new ListBuilder(size() + 1);
            lb.addAll(this);
            lb.add(t);
            return lb.toList();
        }
        // mutable but readonly
        C.List l = C.newSizedList(size() + 1);
        l.addAll(this);
        l.add(t);
        return l;
    }

    private C.List unLazyPrepend(Iterable iterable) {
        if (isMutable()) {
            int pos = 0;
            for (T t : iterable) {
                add(pos++, t);
            }
            return this;
        }
        // immutable
        if (isImmutable()) {
            ListBuilder lb = new ListBuilder(size() * 2);
            lb.append(iterable).append(this);
            return lb.toList();
        }
        // mutable but read only
        C.List l = C.newSizedList(size() * 2);
        l.addAll(iterable);
        l.addAll(this);
        return l;
    }

    private C.List unLazyPrepend(Iterator iterator) {
        if (isMutable()) {
            int pos = 0;
            while (iterator.hasNext()) {
                add(pos++, iterator.next());
            }
            return this;
        }
        ListBuilder lb = new ListBuilder(size() * 2);
        lb.append(iterator).append(this);
        return lb.toList();
    }

    private C.List unLazyPrepend(Enumeration enumeration) {
        if (isMutable()) {
            int pos = 0;
            while (enumeration.hasMoreElements()) {
                add(pos++, enumeration.nextElement());
            }
            return this;
        }
        ListBuilder lb = new ListBuilder(size() * 2);
        lb.append(enumeration).append(this);
        return lb.toList();
    }


    @Override
    @SuppressWarnings("unchecked")
    public C.List prepend(Collection collection) {
        if (collection instanceof C.List) {
            return prependList((C.List) collection);
        }
        return unLazyPrepend(collection);
    }

    @Override
    @SuppressWarnings("unchecked")
    public C.Sequence prepend(Iterable iterable) {
        if (iterable instanceof C.List) {
            return prependList((C.List) iterable);
        } else if (iterable instanceof C.Sequence) {
            return prepend((C.Sequence) iterable);
        } else if (iterable instanceof Collection) {
            return prepend((Collection) iterable);
        } else if (isLazy()) {
            return CompositeSeq.of(IterableSeq.of(iterable), this);
        } else {
            return unLazyPrepend(iterable);
        }
    }

    @Override
    public C.Sequence prepend(Iterator iterator) {
        if (!iterator.hasNext()) {
            return this;
        }
        if (isLazy()) {
            return CompositeSeq.of(C.seq(iterator), this);
        }
        return unLazyAppend(iterator);
    }

    @Override
    public C.Sequence prepend(Enumeration enumeration) {
        if (isLazy()) {
            return CompositeSeq.of(C.seq(enumeration), this);
        }
        return unLazyAppend(enumeration);
    }

    /**
     * {@inheritDoc}
     * This method will NOT change the underline list
     *
     * @param seq the sequence to be prepended
     * @return the prepended sequence
     */
    @Override
    public C.Sequence prepend(C.Sequence seq) {
        if (seq instanceof C.List) {
            return prependList((C.List) seq);
        }
        if (isLazy()) {
            return new CompositeSeq(seq, this);
        }
        return unLazyPrepend(seq);
    }

    protected C.ReversibleSequence prependReversibleSeq(C.ReversibleSequence seq) {
        if (seq instanceof C.List) {
            return prependList((C.List) seq);
        }
        // TODO support lazy append reversible sequence
        return unLazyPrepend(seq);
    }

    public C.ReversibleSequence prepend(C.ReversibleSequence seq) {
        return prependReversibleSeq(seq);
    }

    protected C.List prependList(C.List list) {
        if (isLazy()) {
            return CompositeList.of(list, this);
        }
        return unLazyPrepend(list);
    }

    /**
     * {@inheritDoc}
     * This method will NOT change the underline list
     */
    @Override
    public C.List prepend(C.List list) {
        return prependList(list);
    }

    /**
     * {@inheritDoc}
     * For mutable list, this method will insert the
     * element at {@code 0} position.
     */
    @Override
    public C.List prepend(T t) {
        if (isMutable()) {
            add(0, t);
            return this;
        }
        // immutable
        if (isImmutable()) {
            ListBuilder lb = new ListBuilder(size() + 1);
            lb.add(t);
            lb.addAll(this);
            return lb.toList();
        }
        // readonly but mutable
        C.List l = C.newSizedList(size() + 1);
        l.add(t);
        l.addAll(this);
        return l;
    }

    @Override
    public  R reduce(R identity, $.Func2 accumulator) {
        return reduceLeft(identity, accumulator);
    }

    @Override
    public  R reduceLeft(R identity, $.Func2 accumulator) {
        R ret = identity;
        for (T t : this) {
            ret = accumulator.apply(ret, t);
        }
        return ret;
    }

    @Override
    public  R reduceRight(R identity, $.Func2 accumulator) {
        R ret = identity;
        Iterator i = reverseIterator();
        while (i.hasNext()) {
            ret = accumulator.apply(ret, i.next());
        }
        return ret;
    }

    @Override
    public $.Option reduce($.Func2 accumulator) {
        return reduceLeft(accumulator);
    }

    private $.Option reduceIterator(Iterator itr, $.Func2 accumulator) {
        if (!itr.hasNext()) {
            return $.none();
        }
        T ret = itr.next();
        while (itr.hasNext()) {
            ret = accumulator.apply(ret, itr.next());
        }
        return $.some(ret);
    }

    @Override
    public $.Option reduceLeft($.Func2 accumulator) {
        return reduceIterator(iterator(), accumulator);
    }

    @Override
    public $.Option reduceRight($.Func2 accumulator) {
        return reduceIterator(reverseIterator(), accumulator);
    }

    private $.Option findIterator(Iterator itr, $.Function predicate) {
        while (itr.hasNext()) {
            T t = itr.next();
            if (predicate.apply(t)) {
                return $.some(t);
            }
        }
        return $.none();
    }

    public $.Option findFirst($.Function predicate) {
        return findIterator(iterator(), predicate);
    }

    @Override
    public $.Option findLast($.Function predicate) {
        return findIterator(reverseIterator(), predicate);
    }

    @Override
    public  C.List<$.Binary> zip(List list) {
        return new ZippedList<>(this, list);
    }

    @Override
    public  C.List<$.Binary> zipAll(List list, T def1, T2 def2) {
        return new ZippedList<>(this, list, def1, def2);
    }

    @Override
    public C.Sequence<$.Binary> zipWithIndex() {
        return new ZippedSeq<>(this, new IndexIterable(this));
    }

    @Override
    public  C.Sequence> zip(Iterable iterable) {
        if (iterable instanceof List) {
            return zip((List) iterable);
        }
        return new ZippedSeq<>(this, iterable);
    }

    @Override
    public  C.Sequence> zipAll(Iterable iterable, T def1, T2 def2) {
        if (iterable instanceof List) {
            return zipAll((List) iterable, def1, def2);
        }
        return new ZippedSeq<>(this, iterable, def1, def2);
    }

    @Override
    public  C.ReversibleSequence<$.Binary> zip(C.ReversibleSequence rseq) {
        if (rseq instanceof C.List) {
            return zip((java.util.List) rseq);
        }
        return new ZippedRSeq<>(this, rseq);
    }

    @Override
    public  C.ReversibleSequence<$.Binary> zipAll(C.ReversibleSequence rseq, T def1, T2 def2) {
        if (rseq instanceof C.List) {
            return zipAll((java.util.List) rseq, def1, def2);
        }
        return new ZippedRSeq<>(this, rseq, def1, def2);
    }

    @Override
    public int count(T t) {
        if (sorted) {
            int pos = indexOf(t);
            if (pos < 0) {
                return 0;
            }
            int n = 1;
            for (int i = pos + 1; i < size(); ++i) {
                if ($.eq(t, get(i))) {
                    n++;
                } else {
                    break;
                }
            }
            return n;
        }
        return SequenceBase.count(this, t);
    }

    @Override
    public  C.Map toMap(Lang.Function keyExtractor, Lang.Function valExtractor) {
        C.Map map = C.newMap();
        for (T v : this) {
            map.put(keyExtractor.apply(v), valExtractor.apply(v));
        }
        return map;
    }

    @Override
    public  C.Map toMapByVal(Lang.Function keyExtractor) {
        C.Map map = C.newMap();
        for (T v : this) {
            map.put(keyExtractor.apply(v), v);
        }
        return map;
    }

    @Override
    public  C.Map toMapByKey(Lang.Function valExtractor) {
        C.Map map = C.newMap();
        for (T v : this) {
            map.put(v, valExtractor.apply(v));
        }
        return map;
    }

    int modCount() {
        return modCount;
    }

    void removeRange2(int fromIndex, int toIndex) {
        super.removeRange(fromIndex, toIndex);
    }
}

class SubList extends ListBase implements C.List {
    private ListBase l;
    private int offset;
    private int size;
    private int expectedModCount;

    SubList(ListBase list, int fromIndex, int toIndex) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > list.size())
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
                    ") > toIndex(" + toIndex + ")");
        l = list;
        offset = fromIndex;
        size = toIndex - fromIndex;
        expectedModCount = l.modCount();
    }

    @Override
    protected EnumSet initFeatures() {
        return l.features();
    }

    public E set(int index, E element) {
        rangeCheck(index);
        checkForComodification();
        return l.set(index + offset, element);
    }

    public E get(int index) {
        rangeCheck(index);
        checkForComodification();
        return l.get(index + offset);
    }

    public int size() {
        checkForComodification();
        return size;
    }

    public void add(int index, E element) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException();
        checkForComodification();
        l.add(index + offset, element);
        expectedModCount = l.modCount();
        size++;
        modCount++;
    }

    public E remove(int index) {
        rangeCheck(index);
        checkForComodification();
        E result = l.remove(index + offset);
        expectedModCount = l.modCount();
        size--;
        modCount++;
        return result;
    }

    protected void removeRange(int fromIndex, int toIndex) {
        checkForComodification();
        l.removeRange2(fromIndex + offset, toIndex + offset);
        expectedModCount = l.modCount();
        size -= (toIndex - fromIndex);
        modCount++;
    }

    public boolean addAll(Collection c) {
        return addAll(size, c);
    }

    public boolean addAll(int index, Collection c) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException(
                    "Index: " + index + ", Size: " + size);
        int cSize = c.size();
        if (cSize == 0)
            return false;

        checkForComodification();
        l.addAll(offset + index, c);
        expectedModCount = l.modCount();
        size += cSize;
        modCount++;
        return true;
    }

    public Iterator iterator() {
        return listIterator();
    }

    public ListIterator listIterator(final int index) {
        checkForComodification();
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException(
                    "Index: " + index + ", Size: " + size);

        return new ListIterator() {
            private ListIterator i = l.listIterator(index + offset);

            public boolean hasNext() {
                return nextIndex() < size;
            }

            public E next() {
                if (hasNext())
                    return i.next();
                else
                    throw new NoSuchElementException();
            }

            public boolean hasPrevious() {
                return previousIndex() >= 0;
            }

            public E previous() {
                if (hasPrevious())
                    return i.previous();
                else
                    throw new NoSuchElementException();
            }

            public int nextIndex() {
                return i.nextIndex() - offset;
            }

            public int previousIndex() {
                return i.previousIndex() - offset;
            }

            public void remove() {
                i.remove();
                expectedModCount = l.modCount();
                size--;
                modCount++;
            }

            public void set(E e) {
                i.set(e);
            }

            public void add(E e) {
                i.add(e);
                expectedModCount = l.modCount();
                size++;
                modCount++;
            }
        };
    }

    public C.List subList(int fromIndex, int toIndex) {
        if (is(C.Feature.RANDOM_ACCESS)) {
            return new RandomAccessSubList(this, fromIndex, toIndex);
        } else {
            return new SubList(this, fromIndex, toIndex);
        }
    }

    private void rangeCheck(int index) {
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException("Index: " + index +
                    ",Size: " + size);
    }

    protected void checkForComodification() {
        if (l.modCount() != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

class RandomAccessSubList extends SubList implements RandomAccess {
    RandomAccessSubList(ListBase list, int fromIndex, int toIndex) {
        super(list, fromIndex, toIndex);
    }

    public C.List subList(int fromIndex, int toIndex) {
        return new RandomAccessSubList(this, fromIndex, toIndex);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy