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

org.reactfx.util.Lists Maven / Gradle / Ivy

There is a newer version: 2.0-M5
Show newest version
package org.reactfx.util;

import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;

public final class Lists {

    // private constructor to prevent instantiation
    private Lists() {}

    public static  int hashCode(List list) {
        int hashCode = 1;
        for(E e: list) {
            hashCode = 31 * hashCode + Objects.hashCode(e);
        }
        return hashCode;
    }

    public static boolean equals(List list, Object o) {
        if(o == list) return true;

        if(!(o instanceof List)) return false;

        List that = (List) o;

        if(list.size() != that.size()) return false;

        Iterator it1 = list.iterator();
        Iterator it2 = that.iterator();
        while(it1.hasNext()) {
            if(!Objects.equals(it1.next(), it2.next())) {
                return false;
            }
        }

        return true;
    }

    public static String toString(List list) {
        StringBuilder res = new StringBuilder();
        res.append('[');
        Iterator it = list.iterator();
        while(it.hasNext()) {
            res.append(it.next());
            if(it.hasNext()) {
                res.append(", ");
            }
        }
        res.append(']');
        return res.toString();
    }

    public static  Iterator readOnlyIterator(Collection col) {
        return new Iterator() {
            private final Iterator delegate = col.iterator();

            @Override
            public boolean hasNext() {
                return delegate.hasNext();
            }

            @Override
            public E next() {
                return delegate.next();
            }
        };
    }

    public static boolean isValidIndex(int index, int size) {
        return isValidIndex(0, index, size);
    }

    public static boolean isValidIndex(int min, int index, int max) {
        return min <= index && index < max;
    }

    public static void checkIndex(int index, int size) {
        checkIndex(0, index, size);
    }

    public static void checkIndex(int min, int index, int max) {
        if(!isValidIndex(min, index, max)) {
            throw new IndexOutOfBoundsException(index + " not in [" + min + ", " + max + ")");
        }
    }

    public static boolean isValidPosition(int position, int size) {
        return isValidPosition(0, position, size);
    }

    public static boolean isValidPosition(int min, int position, int max) {
        return min <= position && position <= max;
    }

    public static void checkPosition(int position, int size) {
        checkPosition(0, position, size);
    }

    public static void checkPosition(int min, int position, int max) {
        if(!isValidPosition(min, position, max)) {
            throw new IndexOutOfBoundsException(position + " not in [" + min + ", " + max + "]");
        }
    }

    public static boolean isValidRange(int from, int to, int size) {
        return isValidRange(0, from, to, size);
    }

    public static boolean isValidRange(int min, int from, int to, int max) {
        return min <= from && from <= to && to <= max;
    }

    public static void checkRange(int from, int to, int size) {
        checkRange(0, from, to, size);
    }

    public static void checkRange(int min, int from, int to, int max) {
        if(!isValidRange(min, from, to, max)) {
            throw new IndexOutOfBoundsException(
                    "[" + from + ", " + to + ") is not a valid range within " +
                    "[" + min + ", " + max + ")");
        }
    }

    public static boolean isNonEmptyRange(int from, int to, int size) {
        return isNonEmptyRange(0, from, to, size);
    }

    public static boolean isNonEmptyRange(int min, int from, int to, int max) {
        return min <= from && from < to && to <= max;
    }

    public static boolean isProperRange(int from, int to, int size) {
        return isProperRange(0, from, to, size);
    }

    public static boolean isProperRange(int min, int from, int to, int max) {
        return isValidRange(min, from, to, max) && (min < from || to < max);
    }

    public static boolean isProperNonEmptyRange(int from, int to, int size) {
        return isProperNonEmptyRange(0, from, to, size);
    }

    public static boolean isProperNonEmptyRange(int min, int from, int to, int max) {
        return isNonEmptyRange(min, from, to, max) && (min < from || to < max);
    }

    public static boolean isStrictlyInsideRange(int from, int to, int size) {
        return isStrictlyInsideRange(0, from, to, size);
    }

    public static boolean isStrictlyInsideRange(int min, int from, int to, int max) {
        return min < from && from <= to && to < max;
    }

    public static boolean isStrictlyInsideNonEmptyRange(int from, int to, int size) {
        return isStrictlyInsideNonEmptyRange(0, from, to, size);
    }

    public static boolean isStrictlyInsideNonEmptyRange(int min, int from, int to, int max) {
        return min < from && from < to && to < max;
    }

    public static  List mappedView(
            List source,
            Function f) {
        return new AbstractList() {

            @Override
            public F get(int index) {
                return f.apply(source.get(index));
            }

            @Override
            public int size() {
                return source.size();
            }
        };
    }

    @SafeVarargs
    public static  List concatView(List... lists) {
        return concatView(Arrays.asList(lists));
    }

    /**
     * Returns a list that is a concatenation of the given lists. The returned
     * list is a view of the underlying lists, without copying the elements.
     * The returned list is unmodifiable. Modifications to underlying lists
     * will be visible through the concatenation view.
     */
    public static  List concatView(List> lists) {
        if(lists.isEmpty()) {
            return Collections.emptyList();
        } else {
            return ConcatView.create(lists);
        }
    }

    @SafeVarargs
    public static  List concat(List... lists) {
        return concat(Arrays.asList(lists));
    }

    /**
     * Returns a list that is a concatenation of the given lists. The returned
     * list is a view of the underlying lists, without copying the elements.
     * As opposed to {@link #concatView(List)}, the underlying lists must not
     * be modified while the returned concatenation view is in use. On the other
     * hand, this method guarantees balanced nesting if some of the underlying
     * lists are already concatenations created by this method.
     */
    public static  List concat(List> lists) {
        return ListConcatenation.create(lists);
    }
}

class ConcatView extends AbstractList {

    static  List create(List> lists) {
        return concatView(lists, true);
    }

    private static  List concatView(
            List> lists, boolean makeUnmodifiable) {
        int len = lists.size();
        if(len < 1) {
            throw new AssertionError("Supposedly unreachable code");
        } else if(len == 1) {
            List list = lists.get(0);
            if(makeUnmodifiable) {
                return Collections.unmodifiableList(list);
            } else {
                @SuppressWarnings("unchecked")
                List lst = (List) list;
                return lst;
            }
        } else {
            int mid = len / 2;
            return new ConcatView<>(
                    concatView(lists.subList(0, mid), false),
                    concatView(lists.subList(mid, len), false));
        }
    }

    private final List first;
    private final List second;

    ConcatView(List first, List second) {
        this.first = first;
        this.second = second;
    }

    @Override
    public E get(int index) {
        if(index < first.size()) {
            return first.get(index);
        } else {
            return second.get(index - first.size());
        }
    }

    @Override
    public int size() {
        return first.size() + second.size();
    }
}

class ListConcatenation extends AbstractList {

    private static final MapToMonoid, Integer> LIST_SIZE_MONOID =
            new MapToMonoid, Integer>() {

                @Override
                public Integer apply(List t) {
                    return t.size();
                }

                @Override
                public Integer unit() {
                    return 0;
                }

                @Override
                public Integer reduce(Integer left, Integer right) {
                    return left + right;
                }

            };

    static  List create(List> lists) {
        return lists.stream()
            .filter(l -> !l.isEmpty())
            .map(l -> {
                @SuppressWarnings("unchecked") // cast safe because l is unmodifiable
                List lst = (List) l;
                return lst instanceof ListConcatenation
                    ? ((ListConcatenation) lst).ft
                    : FingerTree.mkTree(Collections.singletonList(lst), LIST_SIZE_MONOID);
            })
            .reduce(FingerTree::join)
            .>map(ListConcatenation::new)
            .orElse(Collections.emptyList());
    }

    private final FingerTree, Integer> ft;

    ListConcatenation(FingerTree, Integer> ft) {
        this.ft = ft;
    }

    @Override
    public E get(int index) {
        return ft.get(Integer::intValue, index, List::get);
    }

    @Override
    public int size() {
        return ft.getStats();
    }

    @Override
    public List subList(int from, int to) {
        Tuple3<
            FingerTree, Integer>,
            Optional, Integer>>,
            FingerTree, Integer>
        > lmr;
        final FingerTree, Integer> l;
        Optional, Integer>> m;
        final FingerTree, Integer> r;
        FingerTree, Integer> t;

        lmr = ft.split(Integer::intValue, from);
        m = lmr._2;
        r = lmr._3;

        t = m., Integer>>map(t2 -> t2.map(
                (lst, i) -> r.prepend(lst.subList(i, lst.size())))).orElse(r);

        lmr = t.split(Integer::intValue, to - from);
        l = lmr._1;
        m = lmr._2;

        t = m., Integer>>map(t2 -> t2.map(
                (lst, i) -> l.append(lst.subList(0, i)))).orElse(l);

        return new ListConcatenation<>(t);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy