package org.reactfx.util;

import java.util.AbstractList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;

public final class Lists {

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

    public static <E> int hashCode(List<E> 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 <E, F> List<F> mappedView(
            List<? extends E> source,
            Function<? super E, ? extends F> f) {
        return new AbstractList<F>() {

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

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

@@ -47,24 +47,107 @@
 stractList;%0A
+import java.util.ArrayList;%0Aimport java.util.Arrays;%0Aimport java.util.Collections;%0A
 import java.
@@ -1852,10 +1852,2089 @@
 ;%0A    %7D%0A
-%7D
 %0A
+    @SafeVarargs%0A    public static %3CE%3E List%3CE%3E concatView(List%3C? extends E%3E... lists) %7B%0A        return concatView(Arrays.asList(lists));%0A    %7D%0A%0A    public static %3CE%3E List%3CE%3E concatView(List%3CList%3C? extends E%3E%3E lists) %7B%0A        List%3CList%3C? extends E%3E%3E lsts = new ArrayList%3C%3E(lists);%0A        lsts.removeIf(List::isEmpty);%0A%0A        if(lsts.isEmpty()) %7B%0A            return Collections.emptyList();%0A        %7D else %7B%0A            return ListsHelper.concatView(lsts);%0A        %7D%0A    %7D%0A%7D%0A%0Aclass ListsHelper %7B%0A%0A    static %3CE%3E List%3CE%3E concatView(List%3CList%3C? extends E%3E%3E lists) %7B%0A        return concatView(lists, true);%0A    %7D%0A%0A    private static %3CE%3E List%3CE%3E concatView(%0A            List%3CList%3C? extends E%3E%3E lists, boolean makeUnmodifiable) %7B%0A        int len = lists.size();%0A        if(len %3C 1) %7B%0A            throw new AssertionError(%22Supposedly unreachable code%22);%0A        %7D else if(len == 1) %7B%0A            List%3C? extends E%3E list = lists.get(0);%0A            if(makeUnmodifiable) %7B%0A                return Collections.unmodifiableList(list);%0A            %7D else %7B%0A                @SuppressWarnings(%22unchecked%22)%0A                List%3CE%3E lst = (List%3CE%3E) list;%0A                return lst;%0A            %7D%0A        %7D else %7B%0A            int mid = len / 2;%0A            return new ConcatListView%3C%3E(%0A                    concatView(lists.subList(0, mid), false),%0A                    concatView(lists.subList(mid, len), false));%0A        %7D%0A    %7D%0A%0A    private static class ConcatListView%3CE%3E extends AbstractList%3CE%3E %7B%0A        private final List%3C? extends E%3E first;%0A        private final List%3C? extends E%3E second;%0A%0A        ConcatListView(List%3C? extends E%3E first, List%3C? extends E%3E second) %7B%0A            this.first = first;%0A            this.second = second;%0A        %7D%0A%0A        @Override%0A        public E get(int index) %7B%0A            if(index %3C first.size()) %7B%0A                return first.get(index);%0A            %7D else %7B%0A                return second.get(index - first.size());%0A            %7D%0A        %7D%0A%0A        @Override%0A        public int size() %7B%0A            return first.size() + second.size();%0A        %7D%0A%0A    %7D%0A%7D

Add Lists.concatView(List<? extends E>... lists).