<commit_before>// Copyright 2014 takahashikzn
//
// 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.
package jp.root42.indolently;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;

import jp.root42.indolently.bridge.ObjFactory;
import jp.root42.indolently.ref.BoolRef;
import jp.root42.indolently.ref.ByteRef;
import jp.root42.indolently.ref.CharRef;
import jp.root42.indolently.ref.CmpRef;
import jp.root42.indolently.ref.DoubleRef;
import jp.root42.indolently.ref.Duo;
import jp.root42.indolently.ref.FloatRef;
import jp.root42.indolently.ref.IntRef;
import jp.root42.indolently.ref.LongRef;
import jp.root42.indolently.ref.Ref;
import jp.root42.indolently.ref.ShortRef;
import jp.root42.indolently.ref.Trio;
import jp.root42.indolently.ref.ValueReference;

import static jp.root42.indolently.Expressive.*;


/**
 * The Java Syntactic sugar collection for indolent person (like you).
 *
 * @author takahashikzn
 */
@SuppressWarnings("javadoc")
public class Indolently {

    /** non private for subtyping. */
    protected Indolently() {}

    static int idx(final List<?> list, final int idx) {
        return 0 <= idx ? idx : list.size() + idx;
    }

    public static <T> T fatal() {
        throw new AssertionError();
    }

    public static <T> T fatal(final Object msg) {
        throw new AssertionError(msg);
    }

    /**
     * An alias of {@link #optionalEmpty(Map)}.
     *
     * @param <T> type of value
     * @param value collection value
     * @return Optional representation of collection
     */
    public static <T extends Map<?, ?>> Optional<T> nonEmpty(final T value) {
        return optionalEmpty(value);
    }

    /**
     * {@link Optional} representation of collection.
     * Equivalent to {@code empty(col) ? Optional.empty() : Optional.of(col)}.
     *
     * @param <T> type of value
     * @param value collection value
     * @return Optional representation of collection
     * @see #empty(Map)
     */
    public static <T extends Map<?, ?>> Optional<T> optionalEmpty(final T value) {
        return empty(value) ? Optional.empty() : Optional.of(value);
    }

    /**
     * An alias of {@link #optionalEmpty(Iterable)}.
     *
     * @param <T> type of value
     * @param value collection value
     * @return Optional representation of collection
     */
    public static <T extends Iterable<?>> Optional<T> nonEmpty(final T value) {
        return optionalEmpty(value);
    }

    /**
     * {@link Optional} representation of collection.
     * Equivalent to {@code empty(col) ? Optional.empty() : Optional.of(col)}.
     *
     * @param <T> type of value
     * @param value collection value
     * @return Optional representation of collection
     * @see #empty(Iterable)
     */
    public static <T extends Iterable<?>> Optional<T> optionalEmpty(final T value) {
        return empty(value) ? Optional.empty() : Optional.of(value);
    }

    /**
     * An alias of {@link #optionalEmpty(CharSequence)}.
     *
     * @param <T> type of value
     * @param value string value
     * @return Optional representation of string
     */
    public static <T extends CharSequence> Optional<T> nonEmpty(final T value) {
        return optionalEmpty(value);
    }

    /**
     * {@link Optional} representation of string.
     * Equivalent to {@code empty(str) ? Optional.empty() : Optional.of(str)}.
     *
     * @param <T> type of value
     * @param value string value
     * @return Optional representation of string
     * @see #empty(CharSequence)
     */
    public static <T extends CharSequence> Optional<T> optionalEmpty(final T value) {
        return empty(value) ? Optional.empty() : Optional.of(value);
    }

    /**
     * An alias of {@link #optionalBlank(CharSequence)}.
     *
     * @param <T> type of value
     * @param value string value
     * @return Optional representation of string
     */
    public static <T extends CharSequence> Optional<T> nonBlank(final T value) {
        return optionalBlank(value);
    }

    /**
     * {@link Optional} representation of string.
     * Equivalent to {@code blank(str) ? Optional.empty() : Optional.of(str)}.
     *
     * @param <T> type of value
     * @param value string value
     * @return Optional representation of string
     * @see #blank(CharSequence)
     */
    public static <T extends CharSequence> Optional<T> optionalBlank(final T value) {
        return blank(value) ? Optional.empty() : Optional.of(value);
    }

    /**
     * An alias of {@link #optional(Object)}.
     *
     * @param <T> type of value
     * @param value the value
     * @return Optional representation of value
     */
    public static <T> Optional<T> nonNull(final T value) {
        return optional(value);
    }

    /**
     * An alias of {@link Optional#empty()}.
     *
     * @return Optional representation of nothing
     */
    public static <T> Optional<T> none() {
        return Optional.empty();
    }

    /**
     * An alias of {@link Optional#ofNullable(Object)}.
     *
     * @param <T> type of value
     * @param value the value
     * @return Optional representation of value
     */
    public static <T> Optional<T> optional(final T value) {
        return Optional.ofNullable(value);
    }

    /**
     * An alias of {@link Optional#ofNullable(Object)}.
     *
     * @param <T> type of value
     * @param value the value
     * @param consumers invoked consumers only if value is present
     * @return Optional representation of value
     */
    @SafeVarargs
    public static <T> Optional<T> optional(final T value, final Consumer<? super T>... consumers) {
        final Optional<T> opt = optional(value);
        list(consumers).each(f -> opt.ifPresent(f));
        return opt;
    }

    /**
     * Just an alias of {@link #list(Object...)} but not overloaded one.
     * If compiler fail to do type inference on {@link #list(Object...)}, for example such a
     * {@code List<List<Integer>> nested = list(list(42))}, you can use this method instead of.
     *
     * @param <T> type of value
     * @param elems elements of list
     * @return new list
     * @see #list(Object...)
     */
    @SafeVarargs
    public static <T> SList<T> listOf(final T... elems) {
        return list(elems);
    }

    /**
     * construct new list which contains specified elements.
     *
     * @param <T> type of value
     * @param elem element of the list
     * @return new list
     */
    public static <T> SList<T> list(final Optional<? extends T> elem) {
        return new SListImpl<T>().push(elem);
    }

    /**
     * construct new list which contains specified elements.
     *
     * @param <T> type of value
     * @param elems elements of the list
     * @return new list
     */
    public static <T> SList<T> list(final Iterable<? extends T> elems) {
        return new SListImpl<T>().pushAll(optional(elems));
    }

    /**
     * construct new list which contains specified elements.
     *
     * @param <T> type of value
     * @param elems elements of the list
     * @return new list
     */
    @SafeVarargs
    public static <T> SList<T> list(final T... elems) {

        final SList<T> list = new SListImpl<>();

        if (elems != null) {
            for (final T v : elems) {
                list.add(v);
            }
        }

        return list;
    }

    @SafeVarargs
    public static <V, T extends Predicate<V>> Optional<T> find(final V cond, final T... preds) {

        for (final T p : preds) {
            if (p.test(cond)) {
                return Optional.of(p);
            }
        }

        return Optional.empty();
    }

    /**
     * Convert {@link Iterable} to typed array.
     * The array type is same as first element type.
     *
     * @param <T> type of value
     * @param elems elements
     * @return typed array
     * @throws IllegalArgumentException iterable don't contain any element.
     */
    public static <T> T[] array(final Iterable<? extends T> elems) {
        if (empty(elems)) {
            throw new IllegalArgumentException("can't infer empty array type");
        }

        final SList<? extends T> list = list(elems);

        // pseudo typing. actually this type wouldn't be T[].
        @SuppressWarnings("unchecked")
        final T[] pseudoTyped = (T[]) list.tail().toArray();

        return array(list.head(), pseudoTyped);
    }

    /**
     * Convert arguments to typed array.
     * The array type is same as first element type.
     *
     * @param <T> type of value
     * @param first first element
     * @param rest rest elements
     * @return typed array
     * @throws IllegalArgumentException first element is null..
     */
    @SafeVarargs
    public static <T> T[] array(final T first, final T... rest) {
        if (first == null) {
            throw new IllegalArgumentException("can't infer empty array type");
        }

        final int len = 1 + ((rest == null) ? 0 : rest.length);
        @SuppressWarnings("unchecked")
        final T[] ary = (T[]) Array.newInstance(first.getClass(), len);

        return list(first).pushAll(list(rest)).toArray(ary);
    }

    /**
     * Convert arguments to typed array.
     *
     * @param <T> type of array
     * @param <V> type of value
     * @param type array type
     * @param first first element
     * @param elems rest elements
     * @return typed array
     */
    @SafeVarargs
    public static <T, V extends T> T[] array(final Class<T> type, final V first, final V... rest) {

        if (first == null) {
            @SuppressWarnings("unchecked")
            final T[] ary = (T[]) Array.newInstance(type, 0);
            return ary;
        }

        final int len = 1 + ((rest == null) ? 0 : rest.length);
        @SuppressWarnings("unchecked")
        final T[] ary = (T[]) Array.newInstance(type, len);

        return list(first).pushAll(list(rest)).toArray(ary);
    }

    /**
     * Convert arguments to typed array.
     *
     * @param elems elements of array
     * @return {@link Object} array
     */
    @SafeVarargs
    public static <T> T[] arrayOf(final T... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new Object[] { ... }</code>.
     *
     * @param elems elements of array
     * @return {@link Object} array
     */
    public static Object[] oarray(final Object... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new char[] { ... }</code>.
     *
     * @param elems elements of array
     * @return char array
     */
    public static char[] parray(final char... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new int[] { ... }</code>.
     *
     * @param elems elements of array
     * @return int array
     */
    public static int[] parray(final int... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new long[] { ... }</code>.
     *
     * @param elems elements of array
     * @return long array
     */
    public static long[] parray(final long... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new float[] { ... }</code>.
     *
     * @param elems elements of array
     * @return float array
     */
    public static float[] parray(final float... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new byte[] { ... }</code>.
     *
     * @param elems elements of array
     * @return byte array
     */
    public static byte[] parray(final byte... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new double[] { ... }</code>.
     *
     * @param elems elements of array
     * @return double array
     */
    public static double[] parray(final double... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new boolean[] { ... }</code>.
     *
     * @param elems elements of array
     * @return boolean array
     */
    public static boolean[] parray(final boolean... elems) {
        return elems;
    }

    /**
     * Create a list of <code>char</code>.
     *
     * @param elems elements of array
     * @return char list
     */
    public static SList<Character> plist(final char... elems) {
        final SList<Character> list = list();
        for (final char e : elems) {
            list.add(e);
        }
        return list;
    }

    /**
     * Create a list of <code>int</code>.
     *
     * @param elems elements of array
     * @return int list
     */
    public static SList<Integer> plist(final int... elems) {
        final SList<Integer> list = list();
        for (final int e : elems) {
            list.add(e);
        }
        return list;
    }

    /**
     * Create a list of <code>long</code>.
     *
     * @param elems elements of array
     * @return long list
     */
    public static SList<Long> plist(final long... elems) {
        final SList<Long> list = list();
        for (final long e : elems) {
            list.add(e);
        }
        return list;
    }

    /**
     * Create a list of <code>float</code>.
     *
     * @param elems elements of array
     * @return float list
     */
    public static SList<Float> plist(final float... elems) {
        final SList<Float> list = list();
        for (final float e : elems) {
            list.add(e);
        }
        return list;
    }

    /**
     * Create a list of <code>short</code>.
     *
     * @param elems elements of array
     * @return short list
     */
    public static SList<Short> plist(final short... elems) {
        final SList<Short> list = list();
        for (final short e : elems) {
            list.add(e);
        }
        return list;
    }

    /**
     * Create a list of <code>double</code>.
     *
     * @param elems elements of array
     * @return double list
     */
    public static SList<Double> plist(final double... elems) {
        final SList<Double> list = list();
        for (final double e : elems) {
            list.add(e);
        }
        return list;
    }

    /**
     * Create a list of <code>boolean</code>.
     *
     * @param elems elements of array
     * @return boolean list
     */
    public static SList<Boolean> plist(final boolean... elems) {
        final SList<Boolean> list = list();
        for (final boolean e : elems) {
            list.add(e);
        }
        return list;
    }

    public static <T> SSet<T> set(final Optional<? extends T> elem) {
        return new SSetImpl<T>().push(elem);
    }

    public static <T> SSet<T> set(final Iterable<? extends T> elems) {
        return new SSetImpl<T>().pushAll(optional(elems));
    }

    /**
     * Just an alias of {@link #set(Object...)} but not overloaded one.
     * If compiler fail to do type inference on {@link #set(Object...)}, for example such a
     * {@code Set<List<Integer>> nested = set(list(42))}, you can use this method instead of.
     *
     * @param elems elements of set
     * @return new set
     * @see #set(Object...)
     */
    @SafeVarargs
    public static <T> SSet<T> setOf(final T... elems) {
        return set(elems);
    }

    @SafeVarargs
    public static <T> SSet<T> set(final T... elems) {

        final SSet<T> set = new SSetImpl<>();

        if (elems != null) {
            set.addAll(list(elems));
        }

        return set;
    }

    public static <K extends Comparable<K>, V> SMap<K, V> sort(final Map<? extends K, ? extends V> map) {
        return sort(map, Comparator.naturalOrder());
    }

    public static <K, V, S extends Comparable<S>> SMap<K, V> sort(final Map<? extends K, ? extends V> map,
        final Function<? super K, ? extends S> f) {

        return sort(map, (l, r) -> f.apply(l).compareTo(f.apply(r)));
    }

    public static <K, V> SMap<K, V> sort(final Map<? extends K, ? extends V> map, final Comparator<? super K> comp) {
        return wrap(ObjFactory.getInstance().<K, V> newSortedMap(Objects.requireNonNull(comp, "comparator")))
            .pushAll(map);
    }

    public static <T extends Comparable<T>> SSet<T> sort(final Set<? extends T> elems) {
        return sort(elems, Comparator.naturalOrder());
    }

    public static <T, S extends Comparable<S>> SSet<T> sort(final Set<? extends T> elems,
        final Function<? super T, ? extends S> f) {

        return sort(elems, (l, r) -> f.apply(l).compareTo(f.apply(r)));
    }

    public static <T> SSet<T> sort(final Set<? extends T> elems, final Comparator<? super T> comp) {
        return wrap(ObjFactory.getInstance().<T> newSortedSet(Objects.requireNonNull(comp, "comparator")))
            .pushAll(elems);
    }

    public static <T extends Comparable<T>> SList<T> sort(final List<? extends T> elems) {
        return sort(elems, Comparator.naturalOrder());
    }

    public static <T, S extends Comparable<S>> SList<T> sort(final List<? extends T> elems,
        final Function<? super T, ? extends S> f) {

        return sort(elems, (l, r) -> f.apply(l).compareTo(f.apply(r)));
    }

    public static <T> SList<T> sort(final List<? extends T> elems, final Comparator<? super T> comp) {
        final SList<T> rslt = list(elems);
        Collections.sort(rslt, Objects.requireNonNull(comp, "comparator"));
        return rslt;
    }

    public static <K, V> SMap<K, V> freeze(final Map<? extends K, ? extends V> map) {

        @SuppressWarnings("unchecked")
        final SMap<K, V> rslt = wrap(Collections.unmodifiableMap(wrap(map).map(freezer())));

        return rslt;
    }

    public static <T> SSet<T> freeze(final Set<? extends T> elems) {

        @SuppressWarnings("unchecked")
        final SSet<T> rslt = wrap(Collections.unmodifiableSet(wrap(elems).map(freezer())));

        return rslt;
    }

    public static <T> SList<T> freeze(final List<? extends T> elems) {

        @SuppressWarnings("unchecked")
        final SList<T> rslt = wrap(Collections.unmodifiableList(wrap(elems).map(freezer())));

        return rslt;
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private static Function freezer() {

        return match( //
            when(x -> (x instanceof List), x -> freeze((List) x)) //
            , when(x -> (x instanceof Set), x -> freeze((Set) x))//
            , when(x -> (x instanceof Map), x -> freeze((Map) x))) //
                .defaults((Function) Function.identity());
    }

    /**
     * test whether the argument is empty or not.
     *
     * @param i test target
     * @return test result
     */
    public static boolean empty(final Iterable<?> i) {
        if (i == null) {
            return true;
        } else if (i instanceof Collection) { // for optimization
            return ((Collection<?>) i).isEmpty();
        } else {
            return !i.iterator().hasNext();
        }
    }

    /**
     * test whether the argument is empty or not.
     *
     * @param i test target
     * @return test result
     */
    public static boolean empty(final Iterable<?>... i) {
        return empty((Object[]) i) || list(i).every(Indolently::empty);
    }

    /**
     * test whether the argument is empty or not.
     *
     * @param map test target
     * @return test result
     */
    public static boolean empty(final Map<?, ?> map) {
        return (map == null) || map.isEmpty();
    }

    /**
     * test whether the argument is empty or not.
     *
     * @param map test target
     * @return test result
     */
    public static boolean empty(final Map<?, ?>... map) {
        return empty((Object[]) map) || list(map).every(Indolently::empty);
    }

    /**
     * test whether the argument is present or not.
     *
     * @param opt test target
     * @return test result
     */
    public static boolean empty(final Optional<?> opt) {
        return (opt == null) || !opt.isPresent();
    }

    /**
     * test whether the argument is present or not.
     *
     * @param opt test target
     * @return test result
     */
    public static boolean empty(final Optional<?>... opt) {
        return empty((Object[]) opt) || list(opt).every(Indolently::empty);
    }

    /**
     * test whether the argument is empty string or not.
     *
     * @param cs test target
     * @return test result
     */
    public static boolean empty(final CharSequence cs) {
        return (cs == null) || (cs.length() == 0);
    }

    /**
     * test whether the argument is empty string or not.
     *
     * @param cs test target
     * @return test result
     */
    public static boolean empty(final CharSequence... cs) {
        return empty((Object[]) cs) || list(cs).every(Indolently::empty);
    }

    /**
     * test whether the argument is blank string or not.
     *
     * @param cs test target
     * @return test result
     */
    public static boolean blank(final CharSequence cs) {
        return empty(cs) || cs.chars().allMatch(Character::isWhitespace);
    }

    /**
     * test whether the argument is blank string or not.
     *
     * @param cs test target
     * @return test result
     */
    public static boolean blank(final CharSequence... cs) {
        return empty((Object[]) cs) || list(cs).every(Indolently::blank);
    }

    public static boolean empty(final Object[] ary) {
        return (ary == null) || (ary.length == 0);
    }

    public static String join(final Collection<? extends CharSequence> col) {
        return join(col, null);
    }

    public static String join(final Collection<? extends CharSequence> col, final String sep) {

        return optional(col).map(x -> {

            final StringBuilder sb = new StringBuilder();
            final String s = optional(sep).orElse("");

            for (final Iterator<? extends CharSequence> i = x.iterator(); i.hasNext();) {
                sb.append(i.next());

                if (i.hasNext()) {
                    sb.append(s);
                }
            }

            return sb.toString();
        } ).orElse("");
    }

    @SafeVarargs
    public static <T> T choose(final T... elems) {

        return list(elems) //
            .reduce((rem, val) -> rem != null ? rem : val) //<commit_msg>refactoring<commit_after>// Copyright 2014 takahashikzn
//
// 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.
package jp.root42.indolently;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;

import jp.root42.indolently.bridge.ObjFactory;
import jp.root42.indolently.ref.BoolRef;
import jp.root42.indolently.ref.ByteRef;
import jp.root42.indolently.ref.CharRef;
import jp.root42.indolently.ref.CmpRef;
import jp.root42.indolently.ref.DoubleRef;
import jp.root42.indolently.ref.Duo;
import jp.root42.indolently.ref.FloatRef;
import jp.root42.indolently.ref.IntRef;
import jp.root42.indolently.ref.LongRef;
import jp.root42.indolently.ref.Ref;
import jp.root42.indolently.ref.ShortRef;
import jp.root42.indolently.ref.Trio;
import jp.root42.indolently.ref.ValueReference;

import static jp.root42.indolently.Expressive.*;


/**
 * The Java Syntactic sugar collection for indolent person (like you).
 *
 * @author takahashikzn
 */
@SuppressWarnings("javadoc")
public class Indolently {

    /** non private for subtyping. */
    protected Indolently() {}

    static int idx(final List<?> list, final int idx) {
        return 0 <= idx ? idx : list.size() + idx;
    }

    public static <T> T fatal() {
        throw new AssertionError();
    }

    public static <T> T fatal(final Object msg) {
        throw new AssertionError(msg);
    }

    /**
     * An alias of {@link #optionalEmpty(Map)}.
     *
     * @param <T> type of value
     * @param value collection value
     * @return Optional representation of collection
     */
    public static <T extends Map<?, ?>> Optional<T> nonEmpty(final T value) {
        return optionalEmpty(value);
    }

    /**
     * {@link Optional} representation of collection.
     * Equivalent to {@code empty(col) ? Optional.empty() : Optional.of(col)}.
     *
     * @param <T> type of value
     * @param value collection value
     * @return Optional representation of collection
     * @see #empty(Map)
     */
    public static <T extends Map<?, ?>> Optional<T> optionalEmpty(final T value) {
        return empty(value) ? Optional.empty() : Optional.of(value);
    }

    /**
     * An alias of {@link #optionalEmpty(Iterable)}.
     *
     * @param <T> type of value
     * @param value collection value
     * @return Optional representation of collection
     */
    public static <T extends Iterable<?>> Optional<T> nonEmpty(final T value) {
        return optionalEmpty(value);
    }

    /**
     * {@link Optional} representation of collection.
     * Equivalent to {@code empty(col) ? Optional.empty() : Optional.of(col)}.
     *
     * @param <T> type of value
     * @param value collection value
     * @return Optional representation of collection
     * @see #empty(Iterable)
     */
    public static <T extends Iterable<?>> Optional<T> optionalEmpty(final T value) {
        return empty(value) ? Optional.empty() : Optional.of(value);
    }

    /**
     * An alias of {@link #optionalEmpty(CharSequence)}.
     *
     * @param <T> type of value
     * @param value string value
     * @return Optional representation of string
     */
    public static <T extends CharSequence> Optional<T> nonEmpty(final T value) {
        return optionalEmpty(value);
    }

    /**
     * {@link Optional} representation of string.
     * Equivalent to {@code empty(str) ? Optional.empty() : Optional.of(str)}.
     *
     * @param <T> type of value
     * @param value string value
     * @return Optional representation of string
     * @see #empty(CharSequence)
     */
    public static <T extends CharSequence> Optional<T> optionalEmpty(final T value) {
        return empty(value) ? Optional.empty() : Optional.of(value);
    }

    /**
     * An alias of {@link #optionalBlank(CharSequence)}.
     *
     * @param <T> type of value
     * @param value string value
     * @return Optional representation of string
     */
    public static <T extends CharSequence> Optional<T> nonBlank(final T value) {
        return optionalBlank(value);
    }

    /**
     * {@link Optional} representation of string.
     * Equivalent to {@code blank(str) ? Optional.empty() : Optional.of(str)}.
     *
     * @param <T> type of value
     * @param value string value
     * @return Optional representation of string
     * @see #blank(CharSequence)
     */
    public static <T extends CharSequence> Optional<T> optionalBlank(final T value) {
        return blank(value) ? Optional.empty() : Optional.of(value);
    }

    /**
     * An alias of {@link #optional(Object)}.
     *
     * @param <T> type of value
     * @param value the value
     * @return Optional representation of value
     */
    public static <T> Optional<T> nonNull(final T value) {
        return optional(value);
    }

    /**
     * An alias of {@link Optional#empty()}.
     *
     * @return Optional representation of nothing
     */
    public static <T> Optional<T> none() {
        return Optional.empty();
    }

    /**
     * An alias of {@link Optional#ofNullable(Object)}.
     *
     * @param <T> type of value
     * @param value the value
     * @return Optional representation of value
     */
    public static <T> Optional<T> optional(final T value) {
        return Optional.ofNullable(value);
    }

    /**
     * An alias of {@link Optional#ofNullable(Object)}.
     *
     * @param <T> type of value
     * @param value the value
     * @param consumers invoked consumers only if value is present
     * @return Optional representation of value
     */
    @SafeVarargs
    public static <T> Optional<T> optional(final T value, final Consumer<? super T>... consumers) {
        final Optional<T> opt = optional(value);
        list(consumers).each(f -> opt.ifPresent(f));
        return opt;
    }

    /**
     * Just an alias of {@link #list(Object...)} but not overloaded one.
     * If compiler fail to do type inference on {@link #list(Object...)}, for example such a
     * {@code List<List<Integer>> nested = list(list(42))}, you can use this method instead of.
     *
     * @param <T> type of value
     * @param elems elements of list
     * @return new list
     * @see #list(Object...)
     */
    @SafeVarargs
    public static <T> SList<T> listOf(final T... elems) {
        return list(elems);
    }

    /**
     * construct new list which contains specified elements.
     *
     * @param <T> type of value
     * @param elem element of the list
     * @return new list
     */
    public static <T> SList<T> list(final Optional<? extends T> elem) {
        return new SListImpl<T>().push(elem);
    }

    /**
     * construct new list which contains specified elements.
     *
     * @param <T> type of value
     * @param elems elements of the list
     * @return new list
     */
    public static <T> SList<T> list(final Iterable<? extends T> elems) {
        return new SListImpl<T>().pushAll(optional(elems));
    }

    /**
     * construct new list which contains specified elements.
     *
     * @param <T> type of value
     * @param elems elements of the list
     * @return new list
     */
    @SafeVarargs
    public static <T> SList<T> list(final T... elems) {

        final SList<T> list = new SListImpl<>();

        if (elems != null) {
            for (final T v : elems) {
                list.add(v);
            }
        }

        return list;
    }

    @SafeVarargs
    public static <V, T extends Predicate<V>> Optional<T> find(final V cond, final T... preds) {

        for (final T p : preds) {
            if (p.test(cond)) {
                return Optional.of(p);
            }
        }

        return Optional.empty();
    }

    /**
     * Convert {@link Iterable} to typed array.
     * The array type is same as first element type.
     *
     * @param <T> type of value
     * @param elems elements
     * @return typed array
     * @throws IllegalArgumentException iterable don't contain any element.
     */
    public static <T> T[] array(final Iterable<? extends T> elems) {
        if (empty(elems)) {
            throw new IllegalArgumentException("can't infer empty array type");
        }

        final SList<? extends T> list = list(elems);

        // pseudo typing. actually this type wouldn't be T[].
        @SuppressWarnings("unchecked")
        final T[] pseudoTyped = (T[]) list.tail().toArray();

        return array(list.head(), pseudoTyped);
    }

    /**
     * Convert arguments to typed array.
     * The array type is same as first element type.
     *
     * @param <T> type of value
     * @param first first element
     * @param rest rest elements
     * @return typed array
     * @throws IllegalArgumentException first element is null..
     */
    @SafeVarargs
    public static <T> T[] array(final T first, final T... rest) {
        if (first == null) {
            throw new IllegalArgumentException("can't infer empty array type");
        }

        final int len = 1 + ((rest == null) ? 0 : rest.length);
        @SuppressWarnings("unchecked")
        final T[] ary = (T[]) Array.newInstance(first.getClass(), len);

        return list(first).pushAll(list(rest)).toArray(ary);
    }

    /**
     * Convert arguments to typed array.
     *
     * @param <T> type of array
     * @param <V> type of value
     * @param type array type
     * @param first first element
     * @param elems rest elements
     * @return typed array
     */
    @SafeVarargs
    public static <T, V extends T> T[] array(final Class<T> type, final V first, final V... rest) {

        if (first == null) {
            @SuppressWarnings("unchecked")
            final T[] ary = (T[]) Array.newInstance(type, 0);
            return ary;
        }

        final int len = 1 + ((rest == null) ? 0 : rest.length);
        @SuppressWarnings("unchecked")
        final T[] ary = (T[]) Array.newInstance(type, len);

        return list(first).pushAll(list(rest)).toArray(ary);
    }

    /**
     * Convert arguments to typed array.
     *
     * @param elems elements of array
     * @return {@link Object} array
     */
    @SafeVarargs
    public static <T> T[] arrayOf(final T... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new Object[] { ... }</code>.
     *
     * @param elems elements of array
     * @return {@link Object} array
     */
    public static Object[] oarray(final Object... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new char[] { ... }</code>.
     *
     * @param elems elements of array
     * @return char array
     */
    public static char[] parray(final char... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new int[] { ... }</code>.
     *
     * @param elems elements of array
     * @return int array
     */
    public static int[] parray(final int... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new long[] { ... }</code>.
     *
     * @param elems elements of array
     * @return long array
     */
    public static long[] parray(final long... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new float[] { ... }</code>.
     *
     * @param elems elements of array
     * @return float array
     */
    public static float[] parray(final float... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new byte[] { ... }</code>.
     *
     * @param elems elements of array
     * @return byte array
     */
    public static byte[] parray(final byte... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new double[] { ... }</code>.
     *
     * @param elems elements of array
     * @return double array
     */
    public static double[] parray(final double... elems) {
        return elems;
    }

    /**
     * The shortcut notation of <code>new boolean[] { ... }</code>.
     *
     * @param elems elements of array
     * @return boolean array
     */
    public static boolean[] parray(final boolean... elems) {
        return elems;
    }

    /**
     * Create a list of <code>char</code>.
     *
     * @param elems elements of array
     * @return char list
     */
    public static SList<Character> plist(final char... elems) {
        final SList<Character> list = list();
        for (final char e : elems) {
            list.add(e);
        }
        return list;
    }

    /**
     * Create a list of <code>int</code>.
     *
     * @param elems elements of array
     * @return int list
     */
    public static SList<Integer> plist(final int... elems) {
        final SList<Integer> list = list();
        for (final int e : elems) {
            list.add(e);
        }
        return list;
    }

    /**
     * Create a list of <code>long</code>.
     *
     * @param elems elements of array
     * @return long list
     */
    public static SList<Long> plist(final long... elems) {
        final SList<Long> list = list();
        for (final long e : elems) {
            list.add(e);
        }
        return list;
    }

    /**
     * Create a list of <code>float</code>.
     *
     * @param elems elements of array
     * @return float list
     */
    public static SList<Float> plist(final float... elems) {
        final SList<Float> list = list();
        for (final float e : elems) {
            list.add(e);
        }
        return list;
    }

    /**
     * Create a list of <code>short</code>.
     *
     * @param elems elements of array
     * @return short list
     */
    public static SList<Short> plist(final short... elems) {
        final SList<Short> list = list();
        for (final short e : elems) {
            list.add(e);
        }
        return list;
    }

    /**
     * Create a list of <code>double</code>.
     *
     * @param elems elements of array
     * @return double list
     */
    public static SList<Double> plist(final double... elems) {
        final SList<Double> list = list();
        for (final double e : elems) {
            list.add(e);
        }
        return list;
    }

    /**
     * Create a list of <code>boolean</code>.
     *
     * @param elems elements of array
     * @return boolean list
     */
    public static SList<Boolean> plist(final boolean... elems) {
        final SList<Boolean> list = list();
        for (final boolean e : elems) {
            list.add(e);
        }
        return list;
    }

    public static <T> SSet<T> set(final Optional<? extends T> elem) {
        return new SSetImpl<T>().push(elem);
    }

    public static <T> SSet<T> set(final Iterable<? extends T> elems) {
        return new SSetImpl<T>().pushAll(optional(elems));
    }

    /**
     * Just an alias of {@link #set(Object...)} but not overloaded one.
     * If compiler fail to do type inference on {@link #set(Object...)}, for example such a
     * {@code Set<List<Integer>> nested = set(list(42))}, you can use this method instead of.
     *
     * @param elems elements of set
     * @return new set
     * @see #set(Object...)
     */
    @SafeVarargs
    public static <T> SSet<T> setOf(final T... elems) {
        return set(elems);
    }

    @SafeVarargs
    public static <T> SSet<T> set(final T... elems) {

        final SSet<T> set = new SSetImpl<>();

        if (elems != null) {
            set.addAll(list(elems));
        }

        return set;
    }

    public static <K extends Comparable<K>, V> SMap<K, V> sort(final Map<? extends K, ? extends V> map) {
        return sort(map, Comparator.naturalOrder());
    }

    public static <K, V, S extends Comparable<S>> SMap<K, V> sort(final Map<? extends K, ? extends V> map,
        final Function<? super K, ? extends S> f) {

        return sort(map, (l, r) -> f.apply(l).compareTo(f.apply(r)));
    }

    public static <K, V> SMap<K, V> sort(final Map<? extends K, ? extends V> map, final Comparator<? super K> comp) {
        return wrap(ObjFactory.getInstance().<K, V> newSortedMap(Objects.requireNonNull(comp, "comparator")))
            .pushAll(map);
    }

    public static <T extends Comparable<T>> SSet<T> sort(final Set<? extends T> elems) {
        return sort(elems, Comparator.naturalOrder());
    }

    public static <T, S extends Comparable<S>> SSet<T> sort(final Set<? extends T> elems,
        final Function<? super T, ? extends S> f) {

        return sort(elems, (l, r) -> f.apply(l).compareTo(f.apply(r)));
    }

    public static <T> SSet<T> sort(final Set<? extends T> elems, final Comparator<? super T> comp) {
        return wrap(ObjFactory.getInstance().<T> newSortedSet(Objects.requireNonNull(comp, "comparator")))
            .pushAll(elems);
    }

    public static <T extends Comparable<T>> SList<T> sort(final List<? extends T> elems) {
        return sort(elems, Comparator.naturalOrder());
    }

    public static <T, S extends Comparable<S>> SList<T> sort(final List<? extends T> elems,
        final Function<? super T, ? extends S> f) {

        return sort(elems, (l, r) -> f.apply(l).compareTo(f.apply(r)));
    }

    public static <T> SList<T> sort(final List<? extends T> elems, final Comparator<? super T> comp) {
        final SList<T> rslt = list(elems);
        Collections.sort(rslt, Objects.requireNonNull(comp, "comparator"));
        return rslt;
    }

    public static <K, V> SMap<K, V> freeze(final Map<? extends K, ? extends V> map) {

        @SuppressWarnings("unchecked")
        final SMap<K, V> rslt = wrap(Collections.unmodifiableMap(wrap(map).map(freezer())));

        return rslt;
    }

    public static <T> SSet<T> freeze(final Set<? extends T> elems) {

        @SuppressWarnings("unchecked")
        final SSet<T> rslt = wrap(Collections.unmodifiableSet(wrap(elems).map(freezer())));

        return rslt;
    }

    public static <T> SList<T> freeze(final List<? extends T> elems) {

        @SuppressWarnings("unchecked")
        final SList<T> rslt = wrap(Collections.unmodifiableList(wrap(elems).map(freezer())));

        return rslt;
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private static Function freezer() {

        return match( //
            when(x -> (x instanceof List), x -> freeze((List) x)) //
            , when(x -> (x instanceof Set), x -> freeze((Set) x))//
            , when(x -> (x instanceof Map), x -> freeze((Map) x))) //
                .defaults((Function) Function.identity());
    }

    /**
     * test whether the argument is empty or not.
     *
     * @param i test target
     * @return test result
     */
    public static boolean empty(final Iterable<?> i) {
        if (i == null) {
            return true;
        } else if (i instanceof Collection) { // for optimization
            return ((Collection<?>) i).isEmpty();
        } else {
            return !i.iterator().hasNext();
        }
    }

    /**
     * test whether the argument is empty or not.
     *
     * @param i test target
     * @return test result
     */
    public static boolean empty(final Iterable<?>... i) {
        return empty((Object[]) i) || list(i).every(Indolently::empty);
    }

    /**
     * test whether the argument is empty or not.
     *
     * @param map test target
     * @return test result
     */
    public static boolean empty(final Map<?, ?> map) {
        return (map == null) || map.isEmpty();
    }

    /**
     * test whether the argument is empty or not.
     *
     * @param map test target
     * @return test result
     */
    public static boolean empty(final Map<?, ?>... map) {
        return empty((Object[]) map) || list(map).every(Indolently::empty);
    }

    /**
     * test whether the argument is present or not.
     *
     * @param opt test target
     * @return test result
     */
    public static boolean empty(final Optional<?> opt) {
        return (opt == null) || !opt.isPresent();
    }

    /**
     * test whether the argument is present or not.
     *
     * @param opt test target
     * @return test result
     */
    public static boolean empty(final Optional<?>... opt) {
        return empty((Object[]) opt) || list(opt).every(Indolently::empty);
    }

    /**
     * test whether the argument is empty string or not.
     *
     * @param cs test target
     * @return test result
     */
    public static boolean empty(final CharSequence cs) {
        return (cs == null) || (cs.length() == 0);
    }

    /**
     * test whether the argument is empty string or not.
     *
     * @param cs test target
     * @return test result
     */
    public static boolean empty(final CharSequence... cs) {
        return empty((Object[]) cs) || list(cs).every(Indolently::empty);
    }

    /**
     * test whether the argument is blank string or not.
     *
     * @param cs test target
     * @return test result
     */
    public static boolean blank(final CharSequence cs) {
        return empty(cs) || cs.chars().allMatch(Character::isWhitespace);
    }

    /**
     * test whether the argument is blank string or not.
     *
     * @param cs test target
     * @return test result
     */
    public static boolean blank(final CharSequence... cs) {
        return empty((Object[]) cs) || list(cs).every(Indolently::blank);
    }

    public static boolean empty(final Object[] ary) {
        return (ary == null) || (ary.length == 0);
    }

    public static String join(final Iterable<? extends CharSequence> col) {
        return join(col, null);
    }

    public static String join(final Iterable<? extends CharSequence> col, final String sep) {

        return optional(col).map(x -> {

            final StringBuilder sb = new StringBuilder();
            final String s = optional(sep).orElse("");

            for (final Iterator<? extends CharSequence> i = x.iterator(); i.hasNext();) {
                sb.append(i.next());

                if (i.hasNext()) {
                    sb.append(s);
                }
            }

            return sb.toString();
        } ).orElse(null);
    }

    @SafeVarargs
    public static <T> T choose(final T... elems) {

        return list(elems) //
            .reduce((rem, val) -> rem != null ? rem : val) //
{'fraction_non_alphanumeric': 0.1300664668317477, 'fraction_numerical': 0.0022590034319475215, 'mean_word_length': 2.2036044812469555, 'pattern_counts': {'":': 0, '<': 411, '<?xml version=': 0, '>': 433, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3743362', 'n_tokens_mistral': 13821, 'n_tokens_neox': 13565, 'n_words': 4322}