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

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

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

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.IntFunction;

public abstract class ListHelper {

    public static  ListHelper add(ListHelper listHelper, T elem) {
        if(listHelper == null) {
            return new SingleElemHelper<>(elem);
        } else {
            return listHelper.add(elem);
        }
    }

    public static  ListHelper remove(ListHelper listHelper, T elem) {
        if(listHelper == null) {
            return listHelper;
        } else {
            return listHelper.remove(elem);
        }
    }

    public static  void forEach(ListHelper listHelper, Consumer f) {
        if(listHelper != null) {
            listHelper.forEach(f);
        }
    }

    public static  Optional reduce(ListHelper listHelper, BinaryOperator f) {
        if(listHelper == null) {
            return Optional.empty();
        } else {
            return listHelper.reduce(f);
        }
    }

    public static  U reduce(ListHelper listHelper, U unit, BiFunction f) {
        if(listHelper == null) {
            return unit;
        } else {
            return listHelper.reduce(unit, f);
        }
    }

    public static  T[] toArray(ListHelper listHelper, IntFunction allocator) {
        if(listHelper == null) {
            return allocator.apply(0);
        } else {
            return listHelper.toArray(allocator);
        }
    }

    public static  boolean isEmpty(ListHelper listHelper) {
        return listHelper == null;
    }

    public static  int size(ListHelper listHelper) {
        if(listHelper == null) {
            return 0;
        } else {
            return listHelper.size();
        }
    }

    private ListHelper() {
        // private constructor to prevent subclassing
    };

    protected abstract ListHelper add(T elem);

    protected abstract ListHelper remove(T elem);

    protected abstract void forEach(Consumer f);

    protected abstract Optional reduce(BinaryOperator f);

    protected abstract  U reduce(U unit, BiFunction f);

    protected abstract T[] toArray(IntFunction allocator);

    protected abstract int size();


    private static class SingleElemHelper extends ListHelper {
        private final T elem;

        public SingleElemHelper(T elem) {
            this.elem = elem;
        }

        @Override
        protected ListHelper add(T elem) {
            return new MultiElemHelper<>(this.elem, elem);
        }

        @Override
        protected ListHelper remove(T elem) {
            if(Objects.equals(this.elem, elem)) {
                return null;
            } else {
                return this;
            }
        }

        @Override
        protected void forEach(Consumer f) {
            f.accept(elem);
        }

        @Override
        protected Optional reduce(BinaryOperator f) {
            return Optional.of(elem);
        }

        @Override
        protected  U reduce(U unit, BiFunction f) {
            return f.apply(unit, elem);
        }

        @Override
        protected T[] toArray(IntFunction allocator) {
            T[] res = allocator.apply(1);
            res[0] = elem;
            return res;
        }

        @Override
        protected int size() {
            return 1;
        }
    }

    private static class MultiElemHelper extends ListHelper {
        private final List elems = new ArrayList<>();

        @SafeVarargs
        public MultiElemHelper(T... elems) {
            this.elems.addAll(Arrays.asList(elems));
        }

        @Override
        protected ListHelper add(T elem) {
            elems.add(elem);
            return this;
        }

        @Override
        protected ListHelper remove(T elem) {
            elems.remove(elem);
            switch(elems.size()) {
                case 0: return null;
                case 1: return new SingleElemHelper<>(elems.get(0));
                default: return this;
            }
        }

        @SuppressWarnings("unchecked")
        @Override
        protected void forEach(Consumer f) {
            for(Object elem: elems.toArray()) {
                f.accept((T) elem);
            }
        }

        @Override
        protected Optional reduce(BinaryOperator f) {
            return elems.stream().reduce(f);
        }

        @Override
        protected  U reduce(U unit, BiFunction f) {
            U u = unit;
            for(T elem: elems) {
                u = f.apply(u, elem);
            }
            return u;
        }

        @Override
        protected T[] toArray(IntFunction allocator) {
            return elems.toArray(allocator.apply(size()));
        }

        @Override
        protected int size() {
            return elems.size();
        }
    }
}