com.tinspx.util.collect.CollectUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.tinspx.util.collect.CollectUtils.java

Source

/* Copyright (C) 2013-2014 Ian Teune <ian.teune@gmail.com>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package com.tinspx.util.collect;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import static com.google.common.base.Preconditions.*;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ForwardingCollection;
import com.google.common.collect.ForwardingList;
import com.google.common.collect.ForwardingSet;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multiset;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Table;
import com.tinspx.util.base.Base;
import java.io.Serializable;
import java.util.AbstractList;
import java.util.AbstractSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.NavigableSet;
import java.util.NoSuchElementException;
import java.util.RandomAccess;
import java.util.Set;
import java.util.SortedSet;
import javax.annotation.Nullable;

/**
 * Basic Collection and Iterator related utility methods
 * 
 * @author Ian
 */
public class CollectUtils {
    private CollectUtils() {
    };

    /**
     * Adds all elements in the {@code add} Iterable to the {@code collection}
     * Collection. If {@code add} is a Collection, the
     * {@link Collection#addAll(java.util.Collection)} method will be used,
     * else each element of the Iterbale will be added one at a time
     * 
     * @param collection the Collection that id added to
     * @param add the Iterable of elements that will be added to the collection 
     * @return the {@code collection} argument
     */
    @SuppressWarnings("unchecked")
    public static <C extends Collection<E>, E> C addAll(C collection, Iterable<? extends E> add) {
        if (add instanceof Collection) {
            collection.addAll((Collection<E>) add);
        } else {
            for (E a : add) {
                collection.add(a);
            }
        }
        return collection;
    }

    /**
     * Differs from
     * {@link Lists#transform(java.util.List, com.google.common.base.Function)}
     * in that the transformation is not lazy. Rather, a new List is created and
     * the items are all copied and transformed once into the new List.
     */
    public static <F, T> List<T> transformCopy(List<F> from, Function<? super F, ? extends T> function) {
        List<T> to = Lists.newArrayListWithCapacity(from.size());
        for (F item : from) {
            to.add(function.apply(item));
        }
        return to;
    }

    /**
     * Returns a new ArrayList from a nullable list of elements. If
     * {@code elements} is null or empty, an empty ArrayList is returned.
     *
     * @param elements the initial elements of the returned ArrayList, may be
     * null
     * @return a new ArrayList with initially containing {@code elements}
     */
    public static <E> java.util.ArrayList<E> newArrayList(@Nullable Iterable<? extends E> elements) {
        return elements != null ? Lists.<E>newArrayList(elements) : Lists.<E>newArrayList();
    }

    /**
     * Determines the size of the nullable {@code collection} argument,
     * returning 0 if it is null.
     *
     * @param collection the nullable Collection to determine its size
     * @return the size of {@code collection} or 0 if null
     */
    public static int size(@Nullable Collection<?> collection) {
        return collection != null ? collection.size() : 0;
    }

    /**
     * Determines if the Collection is null or empty
     * 
     * @param collection the Collection to check
     * @return true of {@code collection} is null or empty
     */
    public static boolean isNullOrEmpty(@Nullable Collection<?> collection) {
        return collection != null ? collection.isEmpty() : true;
    }

    public static <T> Iterable<T> synchronizedIterable(final Iterable<T> iterable) {
        checkNotNull(iterable);
        return new Iterable<T>() {
            @Override
            public Iterator<T> iterator() {
                return synchronizedIterator(iterable.iterator());
            }
        };
    }

    public static <T> Iterator<T> synchronizedIterator(final Iterator<T> iter) {
        checkNotNull(iter);
        return new Iterator<T>() {
            @Override
            public synchronized boolean hasNext() {
                return iter.hasNext();
            }

            @Override
            public synchronized T next() {
                return iter.next();
            }

            @Override
            public synchronized void remove() {
                iter.remove();
            }
        };
    }

    /**
     * Creates a singleton Iterable for {@code element}
     * 
     * @param element the sole element of the returned Iterable
     * @return a singleton Iterable whose sole element is {@code element}
     */
    public static <T> Iterable<T> iterable(@Nullable final T element) {
        return iterable(element, null);
    }

    /**
     * Creates a singleton Iterable for {@code element}. If {@code onRemove}
     * is not null, {@link Iterator#remove()} will call the Function with
     * {@code element} as the apply argument. {@code onRemove} should return
     * a Boolean determining if the remove is allowed; if {@code onRemove}
     * returns false from apply, an UnsupportedOperationException will be
     * thrown.
     * 
     * @param element the sole element of the returned Iterable
     * @param onRemove Function called when when {@code element} is removed. The
     * Function may throw any unchecked exception; if false is returned from
     * the Function, an UnsupportedOperationException is thrown from remove.
     * @return a singleton Iterable whose sole element is {@code element}
     */
    public static <T> Iterable<T> iterable(@Nullable final T element,
            @Nullable final Function<? super T, Boolean> onRemove) {
        return new Iterable<T>() {
            @Override
            public Iterator<T> iterator() {
                return CollectUtils.iterator(element, onRemove);
            }
        };
    }

    /**
     * Creates a singleton Iterator for {@code element}
     * 
     * @param element the sole element of the returned Iterator
     * @return a singleton Iterator whose sole element is {@code element}
     */
    public static <T> Iterator<T> iterator(@Nullable final T element) {
        return iterator(element, null);
    }

    /**
     * Creates a singleton Iterator for {@code element}. If {@code onRemove}
     * is not null, {@link Iterator#remove()} will call the Function with
     * {@code element} as the apply argument. {@code onRemove} should return
     * a Boolean determining if the remove is allowed; if {@code onRemove}
     * returns false from apply, an UnsupportedOperationException will be
     * thrown.
     * 
     * @param element the sole element of the returned Iterable
     * @param onRemove Function called when when {@code element} is removed. The
     * Function may throw any unchecked exception; if false is returned from
     * the Function, an UnsupportedOperationException is thrown from remove.
     * @return a singleton Iterable whose sole element is {@code element}
     */
    public static <T> Iterator<T> iterator(@Nullable final T element,
            @Nullable final Function<? super T, Boolean> onRemove) {
        return new Iterator<T>() {
            private boolean returned;
            private boolean removed;

            @Override
            public boolean hasNext() {
                return !returned;
            }

            @Override
            public T next() {
                if (returned) {
                    throw new NoSuchElementException();
                }
                returned = true;
                return element;
            }

            @Override
            public void remove() {
                if (returned) {
                    if (removed) {
                        throw new IllegalStateException("removed already called");
                    } else {
                        removed = true;
                    }
                    if (onRemove == null || !onRemove.apply(element)) {
                        throw new UnsupportedOperationException();
                    }
                } else {
                    throw new IllegalStateException("next never called");
                }
            }
        };
    }

    /**
     * appends {@code value} to the <i>end</i> of {@code iter}
     */
    public static <T> Iterable<T> concat(Iterable<? extends T> iter, T value) {
        return Iterables.concat(iter, iterable(value));
    }

    /**
     * appends {@code value} to the <i>end</i> of {@code iter}
     */
    public static <T> Iterator<T> concat(Iterator<? extends T> iter, T value) {
        return Iterators.concat(iter, iterator(value));
    }

    /**
     * prepends {@code value} to the <i>beginning</i> of {@code iter}
     */
    public static <T> Iterable<T> concat(T value, Iterable<? extends T> iter) {
        return Iterables.concat(iterable(value), iter);
    }

    /**
     * prepends {@code value} to the <i>beginning</i> of {@code iter}
     */
    public static <T> Iterator<T> concat(T value, Iterator<? extends T> iter) {
        return Iterators.concat(iterator(value), iter);
    }

    public static <T> Iterable<T> copy(Iterable<T> iter) {
        return ImmutableList.copyOf(iter);
    }

    public static <T> Iterable<T> copy(T... items) {
        return Arrays.asList(items.clone());
    }

    /**
     * Returns {@code iterable} as is if not null or an empty Iterable if
     * {@code iterable} is null.
     *
     * @param iterable the Iterable to convert to an empty Iterable if null
     * @return {@code iterable} or an empty Iterable if {@code iterable} is
     * null.
     */
    public static <T> Iterable<T> nullToEmptyIterable(@Nullable Iterable<T> iterable) {
        return iterable != null ? iterable : Collections.<T>emptyList();
    }

    /**
     * Returns {@code iterator} as is if not null or an empty Iterator if
     * {@code iterator} is null.
     *
     * @param iterator the Iterator to convert to an empty Iterator if null
     * @return {@code iterator} or an empty Iterable if {@code iterator} is
     * null.
     */
    public static <T> Iterator<T> nullToEmptyIterator(@Nullable Iterator<T> iterator) {
        return iterator != null ? iterator : ImmutableSet.<T>of().iterator();
    }

    /**
     * Returns a Collection that forwards all {@link Collection} methods to
     * {@code view}, but modifications to the returned Collection are applied to
     * both {@code source} and {@code view}.
     * <p>
     * {@code view} is intended to be a "view" or subset of {@code source} (this
     * is not a requirement however). The returned Collection forwards all
     * {@link Collection} interface method calls to {@code view}
     * unconditionally. Therefore, any modifications made to the returned
     * Collection are done in exactly the same manner to {@code view}. However,
     * any changes made to {@code view} are also done to {@code source}. All
     * elements added to the returned Collection are added to both {@code view}
     * and {@code source}. Likewise, any elements removed are removed from both
     * {@code view} and {@code source}. In cases like removeAll and retainAll,
     * only the elements <i>actually</i> removed from {@code view} are then
     * removed from {@code source} (retainAll and removeAll are not directly
     * forwarded to {@code source} - exactly what elements that were removed
     * from {@code view} must be determined and then those elements are
     * removed from {@code source}).
     * <p>
     * This function returns a Collection that essentially links {@code view} to
     * {@code source}. The intended use case is when {@code view} is a subset of
     * {@code source} acquired through some filtering mechanism, and it is
     * desired that any changes made to {@code view} be reflected in
     * {@code source}.
     * <p>
     * Although the returned Collection forwards all Collection methods to
     * {@code view}, {@code linkCollections(source, view).equals(view)} will
     * return false.
     * <p>
     * If {@code source} and {@code view} are the same reference, then that
     * reference is returned as is.
     * <p>
     * {@link #linkSets(java.util.Set, java.util.Set)} and
     * {@link #linkSortedSets(java.util.Set, java.util.SortedSet)} perform the
     * exact same thing, except return a Set and SortedSet, respectively.
     * 
     * @param source the source Collection, all modifications done to
     * {@code view} are mirrored to source
     * @param view the view Collection, the returned Collection forwards all
     * calls to view
     * @return a Collection that wraps {@code view} but modifications are
     * applied to both {@code source} and {@code view}
     */
    public static <T> Collection<T> linkCollections(Collection<T> source, Collection<T> view) {
        if (source == view) {
            return checkNotNull(view);
        }
        return LinkingCollection.linkCollections(source, view);
    }

    /**
     * Returns a Set equal to {@code view}, but all modifications made to the
     * returned Set are performed to both {@code source} and {@code view}.
     * <p>
     * See {@link #linkCollections(java.util.Collection, java.util.Collection)}
     * for more detailed documentation. This function performs the exact same
     * operation on its arguments except on Sets rather than Collections and
     * therefore {@code linkSets(source, view).equals(view)} will return true.
     *
     * @param source the source Set, all modifications done to {@code view} are
     * mirrored to source
     * @param view the view Set, the returned Set is equal to view and forwards
     * all calls to view
     * @return a Set that wraps {@code view} but modifications are applied to
     * both {@code source} and {@code view}
     */
    public static <T> Set<T> linkSets(Set<T> source, Set<T> view) {
        if (source == view) {
            return checkNotNull(view);
        }
        return LinkingSet.linkSets(source, view);
    }

    /**
     * Returns a SortedSet equal to {@code view}, but all modifications made to
     * the returned SortedSet are performed to both {@code source} and
     * {@code view}.
     * <p>
     * See {@link #linkCollections(java.util.Collection, java.util.Collection)}
     * for more detailed documentation. This function performs the exact same
     * operation on its arguments except on SortedSets rather than Collections
     * and therefore {@code linkSortedSets(source, view).equals(view)} will
     * return true.
     *
     * @param source the source Set, all modifications done to {@code view} are
     * mirrored to source
     * @param view the view SortedSet, the returned SortedSet is equal to view
     * and forwards all calls to view
     * @return a SortedSet that wraps {@code view} but modifications are applied
     * to both {@code source} and {@code view}
     */
    public static <T> SortedSet<T> linkSortedSets(Set<T> source, SortedSet<T> view) {
        if (source == view) {
            return checkNotNull(view);
        }
        return LinkingSortedSet.linkSortedSets(source, view);
    }

    /**
     * 
     * @param <S> the source collection type
     * @param <D> the delegate collection type
     * @param <T> the element type of both source and delegate
     */
    static class LinkingCollection<S extends Collection<T>, D extends Collection<T>, T>
            extends ForwardingCollection<T> {

        static <S extends Collection<T>, D extends Collection<T>, T> LinkingCollection<S, D, T> linkCollections(
                S source, D delegate) {
            return new LinkingCollection<S, D, T>(source, delegate);
        }

        final S source;
        final D delegate;

        public LinkingCollection(S source, D delegate) {
            this.source = checkNotNull(source);
            this.delegate = checkNotNull(delegate);
        }

        @Override
        protected D delegate() {
            return delegate;
        }

        @Override
        public boolean add(T e) {
            if (delegate.add(e)) {
                source.add(e);
                return true;
            } else {
                return false;
            }
        }

        @Override
        public boolean remove(Object o) {
            if (delegate.remove(o)) {
                source.remove(o);
                return true;
            } else {
                return false;
            }
        }

        @Override
        public boolean addAll(Collection<? extends T> c) {
            if (delegate.addAll(c)) {
                source.addAll(c);
                return true;
            } else {
                return false;
            }
        }

        @Override
        public boolean retainAll(Collection<?> retain) {
            List<Object> removed = new java.util.ArrayList<Object>();
            Iterator<?> it = delegate.iterator();
            while (it.hasNext()) {
                Object object = it.next();
                if (!retain.contains(object)) {
                    removed.add(object);
                }
            }
            if (removed.isEmpty()) {
                return false;
            } else {
                delegate.retainAll(retain);
                source.removeAll(removed);
                return true;
            }
        }

        @Override
        public boolean removeAll(Collection<?> remove) {
            List<Object> removed = new java.util.ArrayList<Object>();
            Iterator<?> it = delegate.iterator();
            while (it.hasNext()) {
                Object object = it.next();
                if (remove.contains(object)) {
                    removed.add(object);
                }
            }
            if (removed.isEmpty()) {
                return false;
            } else {
                delegate.removeAll(remove);
                source.removeAll(removed);
                return true;
            }
        }

        @Override
        public void clear() {
            source.removeAll(delegate);
            delegate.clear();
        }

        @Override
        public Iterator<T> iterator() {
            return new LinkedIterator<T>(delegate.iterator(), source);
        }
    }

    static class LinkedIterator<T> implements Iterator<T> {

        final Iterator<T> delegate;
        final Collection<T> source;
        T current;

        public LinkedIterator(Iterator<T> delegate, Collection<T> source) {
            this.delegate = checkNotNull(delegate);
            this.source = checkNotNull(source);
        }

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

        @Override
        public T next() {
            current = delegate.next();
            return current;
        }

        @Override
        public void remove() {
            delegate.remove();
            source.remove(current);
        }
    }

    static class LinkingSet<S extends Set<T>, D extends Set<T>, T> extends LinkingCollection<S, D, T>
            implements Set<T> {

        static <S extends Set<T>, D extends Set<T>, T> LinkingSet<S, D, T> linkSets(S source, D delegate) {
            return new LinkingSet<S, D, T>(source, delegate);
        }

        public LinkingSet(S source, D delegate) {
            super(source, delegate);
        }

        @Override
        @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
        public boolean equals(Object object) {
            return object == this || delegate.equals(object);
        }

        @Override
        public int hashCode() {
            return delegate.hashCode();
        }
    }

    static class LinkingSortedSet<S extends Set<T>, D extends SortedSet<T>, T> extends LinkingSet<S, D, T>
            implements SortedSet<T> {

        static <S extends Set<T>, D extends SortedSet<T>, T> LinkingSortedSet<S, D, T> linkSortedSets(S source,
                D delegate) {
            return new LinkingSortedSet<S, D, T>(source, delegate);
        }

        public LinkingSortedSet(S source, D delegate) {
            super(source, delegate);
        }

        @Override
        public Comparator<? super T> comparator() {
            return delegate.comparator();
        }

        private SortedSet<T> link(SortedSet<T> newDelegate) {
            if (newDelegate == delegate) {
                return this;
            } else {
                return linkSortedSets(source, newDelegate);
            }
        }

        @Override
        public SortedSet<T> subSet(T fromElement, T toElement) {
            return link(delegate.subSet(fromElement, toElement));
        }

        @Override
        public SortedSet<T> headSet(T toElement) {
            return link(delegate.headSet(toElement));
        }

        @Override
        public SortedSet<T> tailSet(T fromElement) {
            return link(delegate.tailSet(fromElement));
        }

        @Override
        public T first() {
            return delegate.first();
        }

        @Override
        public T last() {
            return delegate.last();
        }
    }

    /**
     * Ensures that all elements in the specified Iterable have type
     * {@code cls}. An empty Iterable will always return true.
     *
     * @param elements the elements to check all have type {@code cls}
     * @param cls the type that all {@code elements} must be
     * @return true if all {@code elements} are instances of or a subtype of
     * {@code cls}
     */
    public static boolean verifyType(Iterable<?> elements, Class<?> cls) {
        checkNotNull(cls);
        for (Object o : elements) {
            if (!cls.isInstance(o)) {
                return false;
            }
        }
        return true;
    }

    static class EmptyNavigableSet<E> extends ForwardingSet<E> implements NavigableSet<E>, Serializable {

        private static final long serialVersionUID = 0;

        static final EmptyNavigableSet<Object> INSTANCE = new EmptyNavigableSet<Object>();

        @Override
        protected Set<E> delegate() {
            return Collections.emptySet();
        }

        @Override
        public E lower(E e) {
            return null;
        }

        @Override
        public E floor(E e) {
            return null;
        }

        @Override
        public E ceiling(E e) {
            return null;
        }

        @Override
        public E higher(E e) {
            return null;
        }

        @Override
        public E pollFirst() {
            return null;
        }

        @Override
        public E pollLast() {
            return null;
        }

        @Override
        public NavigableSet<E> descendingSet() {
            return this;
        }

        @Override
        public Iterator<E> descendingIterator() {
            return ImmutableSet.<E>of().iterator();
        }

        @Override
        public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
            return this;
        }

        @Override
        public NavigableSet<E> headSet(E toElement, boolean inclusive) {
            return this;
        }

        @Override
        public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
            return this;
        }

        @Override
        public SortedSet<E> subSet(E fromElement, E toElement) {
            return this;
        }

        @Override
        public SortedSet<E> headSet(E toElement) {
            return this;
        }

        @Override
        public SortedSet<E> tailSet(E fromElement) {
            return this;
        }

        @Override
        public Comparator<? super E> comparator() {
            return null;
        }

        @Override
        public E first() {
            throw new NoSuchElementException();
        }

        @Override
        public E last() {
            throw new NoSuchElementException();
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> SortedSet<T> emptySortedSet() {
        return (SortedSet<T>) EmptyNavigableSet.INSTANCE;
    }

    @SuppressWarnings("unchecked")
    public static <T> NavigableSet<T> emptyNavigableSet() {
        return (NavigableSet<T>) EmptyNavigableSet.INSTANCE;
    }

    /**
     * returns true if all elements in the Iterable are nonnull (true when
     * the Iterable is empty)
     */
    public static boolean allNonNull(Iterable<?> iter) {
        for (Object o : iter) {
            if (o == null) {
                return false;
            }
        }
        return true;
    }

    public static <T extends Iterable<?>> T checkAllNotNull(T iter) {
        if (!allNonNull(iter)) {
            throw new NullPointerException();
        }
        return iter;
    }

    public static <T extends Iterable<?>> T checkAllNotNull(T iter, String msg) {
        if (!allNonNull(iter)) {
            throw new NullPointerException(msg);
        }
        return iter;
    }

    /**
     * Wraps the given Collection as a Set. If {@code collection} is already a
     * Set, it is returned as is. If {@code collection} is not a Set, it is
     * wrapped in a Set thats simply forwards the Set methods to the 
     * Collection methods of {@code collection} (the interfaces are identical).
     * The equals/hashCode of the returned Set have identical behavior from
     * those of {@link AbstractSet}.
     * <p>
     * Obviously there are some caveats of wrapping non-Set Collection as a
     * Set. This is provided as a utility when this hack is needed and may be
     * useful if a non-Set Collection is known to have only unique elements.
     * 
     * @param <T>
     * @param collection the Collection to wrap as a Set
     * @return {@code collection} as is if already a Set or wrapped as a Set
     */
    public static <T> Set<T> asSet(Collection<T> collection) {
        return collection instanceof Set ? (Set<T>) collection : new CollectionSet<T>(collection);
    }

    static final class CollectionSet<T> extends ForwardingCollection<T> implements Set<T>, Serializable {

        private static final long serialVersionUID = 0;

        private final Collection<T> delegate;

        public CollectionSet(Collection<T> delegate) {
            this.delegate = checkNotNull(delegate);
        }

        @Override
        protected Collection<T> delegate() {
            return delegate;
        }

        /**
         * delegate is not a Set so cannot forward to delegate. equals logic
         * here comes from {@link AbstractSet#equals(java.lang.Object)}.
         */
        @Override
        public boolean equals(Object object) {
            if (object == this) {
                return true;
            }
            if (object == null || !(object instanceof Set)) {
                return false;
            }
            Collection<?> c = (Collection<?>) object;
            if (c.size() != size()) {
                return false;
            }
            try {
                return containsAll(c);
            } catch (ClassCastException ex) {
                return false;
            }
        }

        /**
         * delegate may not be a Set so cannot be forwarded to delegate. hash
         * logic comes from {@link AbstractSet#hashCode()}.
         */
        @Override
        public int hashCode() {
            int h = 0;
            for (T element : delegate) {
                if (element != null) {
                    h += element.hashCode();
                }
            }
            return h;
        }
    }

    /**
     * Returns a fixed-length List containing the elements in the specified
     * array. The returned list is backed by the provided array and changes to
     * the List "write through" and are reflected in the provided array.
     *
     * @param <T> the type of the objects in the array
     * @param elements the array to wrap as a List
     * @return a List view of {@code elements}
     */
    public static <T> List<T> asList(T... elements) {
        return new SubArrayList<T>(elements, 0, elements.length);
    }

    /**
     * Returns a fixed-length List of the first {@code len} elements in
     * the specified array. The returned list is backed by the provided array
     * and changes to the List "write through" and are reflected in the provided
     * array.
     * 
     * @param <T> the type of the objects in the array
     * @param len the length of the returned array, must not be larger than
     * the length of {@code elements}
     * @param elements the array to wrap as a List
     * @return a List view of the first {@code len} elements in {@code elements}
     * @throws IndexOutOfBoundsException if {@code len > elements.length}
     */
    public static <T> List<T> asList(int len, T... elements) {
        return new SubArrayList<T>(elements, 0, len);
    }

    /**
     * Returns a fixed-length List of a range of the specified array. The
     * returned list is backed by the provided array and changes to the List
     * "write through" and are reflected in the provided array. The returned
     * List will start at {@code off} in {@code elements} and will have a length
     * of {@code len}
     *
     * @param <T> the type of the objects in the array
     * @param off the index of the first element to include in the returned List
     * @param len the length of the returned List, starting at index {@code off}
     * @param elements the array to wrap as a List
     * @return a List view of the {@code len} elements starting at index
     * {@code off} in {@code elements}
     * @throws IndexOutOfBoundsException if {@code off} and {@code len} specify
     * an invalid range of {@code elements}
     */
    public static <T> List<T> asList(int off, int len, T... elements) {
        return new SubArrayList<T>(elements, off, len);
    }

    static class SubArrayList<T> extends AbstractList<T> implements RandomAccess, Serializable {
        private static final long serialVersionUID = 0;

        private transient Object[] elements; //final
        private transient final int off;
        private final int len;

        public SubArrayList(Object[] elements, int off, int len) {
            this.elements = checkNotNull(elements);
            checkPositionIndexes(off, off + len, elements.length);
            this.off = off;
            this.len = len;
        }

        @Override
        @SuppressWarnings("unchecked")
        public T get(int index) {
            return (T) elements[off + checkElementIndex(index, len)];
        }

        @Override
        public int size() {
            return len;
        }

        @Override
        @SuppressWarnings("unchecked")
        public T set(int index, T element) {
            index = off + checkElementIndex(index, len);
            T prev = (T) elements[index];
            elements[index] = element;
            return prev;
        }

        @Override
        public int indexOf(Object o) {
            if (o == null) {
                for (int i = off, end = off + len; i < end; i++) {
                    if (elements[i] == null) {
                        return i - off;
                    }
                }
            } else {
                for (int i = off, end = off + len; i < end; i++) {
                    if (o.equals(elements[i])) {
                        return i - off;
                    }
                }
            }
            return -1;
        }

        @Override
        public int lastIndexOf(Object o) {
            if (o == null) {
                for (int i = off + len - 1; i >= off; i--) {
                    if (elements[i] == null) {
                        return i - off;
                    }
                }
            } else {
                for (int i = off + len - 1; i >= off; i--) {
                    if (o.equals(elements[i])) {
                        return i - off;
                    }
                }
            }
            return -1;
        }

        @Override
        public boolean contains(Object o) {
            return indexOf(o) != -1;
        }

        @Override
        public Object[] toArray() {
            Object[] a = new Object[len];
            System.arraycopy(elements, off, a, 0, len);
            return a;
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T[] toArray(T[] a) {
            if (a.length < len) {
                return Arrays.copyOfRange(elements, off, off + len, (Class<? extends T[]>) a.getClass());
            }
            System.arraycopy(this.elements, off, a, 0, len);
            if (a.length > len) {
                a[len] = null;
            }
            return a;
        }

        @Override
        public List<T> subList(int fromIndex, int toIndex) {
            checkPositionIndexes(fromIndex, toIndex, len);
            return new SubArrayList<T>(elements, off + fromIndex, toIndex - fromIndex);
        }

        @Override
        public Iterator<T> iterator() {
            return new ListItr(0);
        }

        @Override
        public ListIterator<T> listIterator() {
            return new ListItr(0);
        }

        @Override
        public ListIterator<T> listIterator(int index) {
            return new ListItr(checkPositionIndex(index, len));
        }

        private class ListItr implements ListIterator<T> {

            /**
             * the next index to return
             */
            private int next;
            /**
             * the last index returned
             */
            private int last = -1;

            public ListItr(int next) {
                this.next = next;
            }

            @Override
            public boolean hasNext() {
                return next < len;
            }

            @Override
            @SuppressWarnings("unchecked")
            public T next() {
                if (next < len) {
                    return (T) elements[off + (last = next++)];
                }
                throw new NoSuchElementException();
            }

            @Override
            public boolean hasPrevious() {
                return next > 0;
            }

            @Override
            @SuppressWarnings("unchecked")
            public T previous() {
                if (next > 0) {
                    return (T) elements[off + (last = --next)];
                }
                throw new NoSuchElementException();
            }

            @Override
            public int nextIndex() {
                return next;
            }

            @Override
            public int previousIndex() {
                return next - 1;
            }

            @Override
            public void set(T e) {
                if (last != -1) {
                    elements[off + last] = e;
                } else {
                    throw new IllegalStateException();
                }
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }

            @Override
            public void add(T e) {
                throw new UnsupportedOperationException();
            }
        }

        private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            elements = new Object[len];
            for (int i = 0; i < len; i++) {
                elements[i] = s.readObject();
            }
            assert off == 0;
        }

        private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
            s.defaultWriteObject();
            for (int i = 0; i < len; i++) {
                s.writeObject(elements[off + i]);
            }
        }
    }

    /**
     * Wraps {@code list}, forcing its toString() method to return
     * {@code toString}
     *
     * @param list the List to force to have a toString() result of
     * {@code toString}
     * @param toString a non-null String that will be returned from toString()
     * of the returned List
     * @return a List equal to {@code list} but whose toString() returns
     * {@code toString}
     */
    public static <T> List<T> wrapListWithToString(List<T> list, String toString) {
        return new ListWrapper<T>(list, toString);
    }

    static final class ListWrapper<T> extends ForwardingList<T> {
        final List<T> list;
        final String toString;

        public ListWrapper(List<T> list, String toString) {
            this.list = checkNotNull(list);
            this.toString = checkNotNull(toString);
        }

        @Override
        public String toString() {
            return toString;
        }

        @Override
        protected List<T> delegate() {
            return list;
        }
    }

    /**
     * Returns an Iterable that returns all elements in {@code iter}
     * {@code repeat + 1} times. Each element is "repeated" {@code repeat}
     * times, so a {@code repeat} of 1 causes all elements of {@code iter} to be
     * returned twice. If {@code repeat} is 0, {@code iter} is returned as is
     * (repeating 0 times has no effect). The returned Iterable supports removal
     * if {@code iter} supports removal.
     *
     * @param iter the Iterable to repeat
     * @param repeat the number of times each element is repeated. This is in
     * addition to the first time each element is returned, so a repeat of 2
     * causes the each element in {@code iter} to be returned 3 times.
     * @return an Iterable that returns each element in {@code iter}
     * {@code repeat + 1} times
     */
    public static <T> Iterable<T> repeatingIterable(Iterable<T> iter, int repeat) {
        checkArgument(repeat >= 0);
        return repeat > 0 ? new RepeatingIterable<T>(iter, repeat) : checkNotNull(iter);
    }

    /**
     * Returns an Iterator that returns all elements in {@code iter}
     * {@code repeat + 1} times. Each element is "repeated" {@code repeat}
     * times, so a {@code repeat} of 1 causes all elements of {@code iter} to be
     * returned twice. If {@code repeat} is 0, {@code iter} is returned as is
     * (repeating 0 times has no effect). The returned Iterator supports removal
     * if {@code iter} supports removal.
     *
     * @param iter the Iterator to repeat
     * @param repeat the number of times each element is repeated. This is in
     * addition to the first time each element is returned, so a repeat of 2
     * causes the each element in {@code iter} to be returned 3 times.
     * @return an Iterator that returns each element in {@code iter}
     * {@code repeat + 1} times
     */
    public static <T> Iterator<T> repeatingIterator(Iterator<T> iter, int repeat) {
        checkArgument(repeat >= 0);
        return repeat > 0 ? new RepeatingIterator<T>(iter, repeat) : checkNotNull(iter);
    }

    private static int checkRepeat(int repeat) {
        if (repeat <= 0) {
            throw new IllegalArgumentException(String.format("invalid repeat (%s)", repeat));
        }
        return repeat;
    }

    static final class RepeatingIterable<T> implements Iterable<T> {

        final Iterable<T> delegate;
        final int repeat;

        public RepeatingIterable(Iterable<T> delegate, int repeat) {
            this.delegate = checkNotNull(delegate);
            this.repeat = checkRepeat(repeat);
        }

        @Override
        public Iterator<T> iterator() {
            return new RepeatingIterator<T>(delegate.iterator(), repeat);
        }
    }

    static final class RepeatingIterator<T> implements Iterator<T> {

        final Iterator<T> delegate;
        final int repeat;
        T current;
        int count;
        boolean canRemove, removed;

        public RepeatingIterator(Iterator<T> delegate, int repeat) {
            this.delegate = checkNotNull(delegate);
            this.repeat = this.count = checkRepeat(repeat);
        }

        @Override
        public boolean hasNext() {
            return count < repeat || delegate.hasNext();
        }

        @Override
        public T next() {
            if (count < repeat) {
                count++;
            } else {
                current = delegate.next();
                removed = false;
                count = 0;
            }
            canRemove = true;
            return current;
        }

        @Override
        public void remove() {
            if (canRemove) {
                canRemove = false;
                if (!removed) {
                    removed = true;
                    delegate.remove();
                }
            } else {
                throw new IllegalStateException();
            }
        }
    }

    /**
     * Adds all {@code key/value} entries from {@code map} to {@code map}.
     * 
     * @return {@code true} if {@code multimap} was modified
     */
    public static <K, V> boolean putAll(@lombok.NonNull Multimap<K, V> multimap,
            @lombok.NonNull Map<? extends K, ? extends Iterable<? extends V>> map) {
        boolean changed = false;
        for (Map.Entry<? extends K, ? extends Iterable<? extends V>> e : map.entrySet()) {
            if (multimap.putAll(e.getKey(), e.getValue())) {
                changed = true;
            }
        }
        return changed;
    }

    /**
     * Adds all {@code key/value} entries from {@code map} to {@code map}.
     * 
     * @return {@code true} if {@code multimap} was modified
     */
    public static <K, V> boolean putAllFrom(@lombok.NonNull Multimap<K, V> multimap,
            @lombok.NonNull Map<? extends K, ? extends V> map) {
        boolean changed = false;
        for (Map.Entry<? extends K, ? extends V> e : map.entrySet()) {
            if (multimap.put(e.getKey(), e.getValue())) {
                changed = true;
            }
        }
        return changed;
    }

    private static <T> Multiset<T> multiset(Collection<T> c) {
        return c instanceof Multiset ? (Multiset<T>) c : HashMultiset.create(c);
    }

    public static boolean equalIgnoreOrder(@Nullable Collection<?> a, @Nullable Collection<?> b) {
        if (a == null || b == null) {
            return a == null && b == null;
        }
        if (a.size() != b.size()) {
            return false;
        }
        if (a.equals(b)) {
            return true;
        }
        if (a instanceof Set && b instanceof Set) {
            return false;
        }
        if (a instanceof Multiset && b instanceof Multiset) {
            return false;
        }
        return multiset(a).equals(multiset(b));
    }

    public static <K> boolean equalIgnoreOrder(@Nullable Multimap<K, ?> a, @Nullable Multimap<? super K, ?> b) {
        if (a == null || b == null) {
            return a == null && b == null;
        }
        if (a.size() != b.size()) {
            return false;
        }
        if (a.keySet().size() != b.keySet().size()) {
            return false;
        }
        if (a.equals(b)) {
            return true;
        }
        if (a instanceof SetMultimap && b instanceof SetMultimap) {
            return false;
        }
        for (K key : a.keySet()) {
            if (!equalIgnoreOrder(a.get(key), b.get(key))) {
                return false;
            }
        }
        //a and b have the same number distinct keys so don't need to iterate
        //over b keys
        return true;
    }

    public interface Selector<T> extends Function<Object, T> {
        /**
         * Convenience method equivalent to
         * {@code Optional.fromNullable(apply(input))}.
         */
        Optional<T> select(Object input);
    }

    @SuppressWarnings("rawtypes")
    private static Collection<?> toCollection(@Nullable Object input) {
        if (input instanceof Collection) {
            return (Collection) input;
        } else if (input instanceof Map) {
            return ((Map) input).values();
        } else if (input instanceof Multimap) {
            return ((Multimap) input).asMap().values();
        } else if (input instanceof Table) {
            return ((Table) input).values();
        } else {
            return Collections.emptyList();
        }
    }

    @SuppressWarnings("rawtypes")
    private static Map<?, ?> toMap(@Nullable Object input) {
        if (input instanceof Map) {
            return (Map) input;
        } else if (input instanceof Multimap) {
            return ((Multimap) input).asMap();
        } else {
            return Collections.emptyMap();
        }
    }

    private static final Object ABSENT = new Object();

    /**
     * Returns the element at the given index in source. index may be negative
     * in which it represents the number of indices from the end of the source.
     */
    @SuppressWarnings("rawtypes")
    private static @Nullable Object find(Iterable source, int index) {
        if (source instanceof List) {
            List list = (List) source;
            if (index < 0) {
                index += list.size();
            }
            return index >= 0 && index < list.size() ? list.get(index) : ABSENT;
        } else {
            return find(source, Predicates.alwaysTrue(), index);
        }
    }

    @SuppressWarnings("rawtypes")
    private static @Nullable Object find(Iterable source, Predicate predicate, int index) {
        if (source instanceof Collection
                && (Math.abs(index) + (index < 0 ? 0 : 1)) > ((Collection) source).size()) {
            return ABSENT;
        }
        if (index < 0) {
            if (source instanceof List) {
                return findBackwardNegative((List) source, predicate, Math.abs(index));
            } else {
                return findForwardNegative(source, predicate, Math.abs(index));
            }
        } else {
            return findForwardPositive(source, predicate, index);
        }
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private static @Nullable Object findForwardPositive(Iterable source, Predicate predicate, int index) {
        assert index >= 0 : index;
        int count = 0;
        for (Object value : source) {
            if (predicate.apply(value) && count++ >= index) {
                return value;
            }
        }
        return ABSENT;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private static @Nullable Object findForwardNegative(Iterable source, Predicate predicate, int index) {
        assert index > 0 : index;
        int count = 0;
        Object[] values = new Object[index];
        for (Object value : source) {
            if (predicate.apply(value)) {
                values[count++ % index] = value;
            }
        }
        return count >= index ? values[count % index] : ABSENT;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private static @Nullable Object findBackwardNegative(List source, Predicate predicate, int index) {
        assert index > 0 : index;
        index--;
        int count = 0;
        ListIterator iter = source.listIterator(source.size());
        while (iter.hasPrevious()) {
            Object value = iter.previous();
            if (predicate.apply(value) && count++ >= index) {
                return value;
            }
        }
        return ABSENT;
    }

    private static @Nullable Object absentToNull(@Nullable Object result) {
        return result == ABSENT ? null : result;
    }

    private static class ValueIndexSelector implements Function<Object, Object> {
        final int index;

        public ValueIndexSelector(int index) {
            this.index = index;
        }

        @Override
        public Object apply(Object root) {
            if (root == null) {
                return null;
            }
            return absentToNull(find(toCollection(root), index));
        }
    }

    private static class ValuePredicateSelector implements Function<Object, Object> {
        final int index;
        final Predicate<Object> predicate;

        public ValuePredicateSelector(int index, Predicate<Object> predicate) {
            this.index = index;
            this.predicate = checkNotNull(predicate);
        }

        @Override
        @SuppressWarnings("rawtypes")
        public Object apply(Object root) {
            if (root == null) {
                return null;
            }
            return absentToNull(find(toCollection(root), predicate, index));
        }
    }

    private static class KeyIndexSelector implements Function<Object, Object> {
        final int index;

        public KeyIndexSelector(int index) {
            this.index = index;
        }

        @Override
        @SuppressWarnings({ "rawtypes", "null" })
        public Object apply(Object root) {
            if (root == null) {
                return null;
            }
            Map map = toMap(root);
            if (map.isEmpty()) {
                return null;
            }
            Object result = find(map.keySet(), index);
            return result == ABSENT ? null : map.get(result);
        }
    }

    private static class KeyPredicateSelector implements Function<Object, Object> {
        final int index;
        final Predicate<Object> predicate;

        public KeyPredicateSelector(int index, Predicate<Object> predicate) {
            this.index = index;
            this.predicate = checkNotNull(predicate);
        }

        @Override
        @SuppressWarnings({ "rawtypes", "null" })
        public Object apply(Object root) {
            if (root == null) {
                return null;
            }
            Map map = toMap(root);
            if (map.isEmpty()) {
                return null;
            }
            Object result = find(map.keySet(), predicate, index);
            return result == ABSENT ? null : map.get(result);
        }
    }

    private static class KeySelector implements Function<Object, Object> {
        final @Nullable Object key;

        public KeySelector(@Nullable Object key) {
            this.key = key;
        }

        @Override
        @SuppressWarnings("null")
        public Object apply(Object root) {
            if (root == null) {
                return null;
            }
            return toMap(root).get(key);
        }
    }

    private static class PredicateSelector implements Function<Object, Object> {
        final Predicate<Object> predicate;

        public PredicateSelector(Predicate<Object> predicate) {
            this.predicate = checkNotNull(predicate);
        }

        @Override
        public Object apply(Object root) {
            return predicate.apply(root) ? root : null;
        }
    }

    private static final Predicate<Object> MAP_OR_MULTIMAP = Predicates.or(Predicates.instanceOf(Map.class),
            Predicates.instanceOf(Multimap.class));

    /**
     * Returns a new {@code SelectorBuilder}. 
     */
    public static SelectorBuilder selector() {
        return new SelectorBuilder();
    }

    /**
     * Builds a {@link Selector} for searching collection hierarchies. Create an
     * instance through {@link #selector()} or create a subclass. Selectors
     * built with this class understand following collection types:
     * {@code Collection} (and therefore also {@code Set} and
     * {@link Multiset}), {@code List}, {@code Map}, {@link Multimap}, and
     * {@link Table}. Note that all {@code index} parameters may be negative, in
     * which case the index indicates the number of positions from the end of
     * the collection.
     */
    public static class SelectorBuilder extends Base.FunctionBuilder<Object> {

        protected SelectorBuilder() {
        }

        @Override
        public SelectorBuilder append(Function<? super Object, ? extends Object> function) {
            super.append(function);
            return this;
        }

        @Override
        public Base.FunctionBuilder<Object> prepend(Function<? super Object, ? extends Object> function) {
            super.prepend(function);
            return this;
        }

        /**
         * Returns true as selection cannot continue on null input.
         */
        @Override
        protected boolean stopWhenNull() {
            return true;
        }

        /**
         * unsupported, throws {@code UnsupportedOperationException}.
         */
        @Override
        public Base.FunctionBuilder<Object> notNull() {
            throw new UnsupportedOperationException();
        }

        /**
         * selects the value at the given index, if possible. applies to
         * collections, maps, multimaps, and tables. if the collection is not a
         * list, index applies to the iteration order.
         */
        public SelectorBuilder value(int index) {
            return append(new ValueIndexSelector(index));
        }

        /**
         * selects the first value that satisfies the specified predicate.
         * applies to collections, maps, multimaps, and tables.
         */
        public SelectorBuilder value(Predicate<Object> predicate) {
            return value(0, predicate);
        }

        /**
         * selects the first value that satisfies the specified predicate
         * <i>after</i> skipping the first {@code index} values that satisfy
         * the predicate. applies to collections, maps, multimaps, and tables.
         */
        public SelectorBuilder value(int index, Predicate<Object> predicate) {
            return append(new ValuePredicateSelector(index, predicate));
        }

        /**
         * selects the value mapped to the key at the specified index in the
         * map entry set. applies to maps and mulitmaps.
         */
        public SelectorBuilder key(int index) {
            return append(new KeyIndexSelector(index));
        }

        /**
         * selects the value mapped to the first key that satisfies the
         * specified predicate. applies to maps and mulitmaps.
         */
        public SelectorBuilder key(Predicate<Object> predicate) {
            return key(0, predicate);
        }

        /**
         * selects the value mapped to the first key that satisfies the
         * specified predicate <i>after</i> skipping the first {@code index}
         * keys that satisfy the predicate. applies to maps and mulitmaps.
         */
        public SelectorBuilder key(int index, Predicate<Object> predicate) {
            return append(new KeyPredicateSelector(index, predicate));
        }

        /**
         * selects the value mapped to the specified key. applies to maps and
         * mulitmaps.
         */
        public SelectorBuilder key(@Nullable Object key) {
            return append(new KeySelector(key));
        }

        /**
         * requires the currently selected value to be a Map or Multimap.
         */
        public SelectorBuilder mapOrMultimap() {
            return require(MAP_OR_MULTIMAP);
        }

        /**
         * requires the currently selected value to be a Collection.
         */
        public SelectorBuilder collection() {
            return require(Collection.class);
        }

        /**
         * requires the currently selected value to be a Set.
         */
        public SelectorBuilder set() {
            return require(Set.class);
        }

        /**
         * requires the currently selected value to be a List.
         */
        public SelectorBuilder list() {
            return require(List.class);
        }

        /**
         * requires the currently selected value to be an instance of
         * {@code cls}.
         */
        public SelectorBuilder require(Class<?> cls) {
            return require(Predicates.instanceOf(cls));
        }

        /**
         * requires the currently selected value to satisfy the specified
         * predicate.
         */
        public SelectorBuilder require(Predicate<Object> predicate) {
            return append(new PredicateSelector(predicate));
        }

        @Override
        public Selector<Object> get() {
            return get(Object.class);
        }

        public <T> Selector<T> get(Class<T> cls) {
            return new CheckedSelector<T>(super.get(), cls);
        }
    }

    private static class CheckedSelector<T> implements Selector<T> {
        final Function<Object, Object> delegate;
        final Class<T> cls;

        public CheckedSelector(Function<Object, Object> delegate, Class<T> cls) {
            this.delegate = checkNotNull(delegate);
            this.cls = checkNotNull(cls);
        }

        @Override
        public Optional<T> select(Object root) {
            return Optional.fromNullable(apply(root));
        }

        @Override
        public T apply(Object input) {
            input = delegate.apply(input);
            return cls.isInstance(input) ? cls.cast(input) : null;
        }
    }
}