/* * Copyright 2000-2016 JetBrains s.r.o. * * 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 com.intellij.util.containers; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Conditions; import com.intellij.openapi.util.Ref; import com.intellij.util.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; /** * An in-house version of {@code com.google.common.collect.FluentIterable} with some Clojure-like additions. * As a bonus iterator instance is preserved during most transformations if it inherits JBIterator. * * <p/> * The original JavaDoc ('FluentIterable' replaced by 'JBIterable'): * <p/> * {@code JBIterable} provides a rich interface for manipulating {@code Iterable} instances in a * chained fashion. A {@code JBIterable} can be created from an {@code Iterable}, or from a set * of elements. The following types of methods are provided on {@code JBIterable}: * <ul> * <li>chained methods which return a new {@code JBIterable} based in some way on the contents * of the current one (for example {@link #transform}) * <li>conversion methods which copy the {@code JBIterable}'s contents into a new collection or * array (for example {@link #toList}) * <li>element extraction methods which facilitate the retrieval of certain elements (for example * {@link #last}) * </ul> * <p/> * <p>Here is an example that merges the lists returned by two separate database calls, transforms * it by invoking {@code toString()} on each element, and returns the first 10 elements as an * {@code List}: <pre> {@code * FluentIterable * .from(database.getClientList()) * .filter(activeInLastMonth()) * .transform(Functions.toStringFunction()) * .toList();}</pre> * <p/> * <p>Anything which can be done using {@code JBIterable} could be done in a different fashion * (often with {@code Iterables}), however the use of {@code JBIterable} makes many sets of * operations significantly more concise. * * @author Marcin Mikosik * * @noinspection unchecked */ public abstract class JBIterable<E> implements Iterable<E> { // We store 'iterable' and use it instead of 'this' to allow Iterables to perform instanceof // checks on the _original_ iterable when JBIterable#from is used. final Iterable<E> myIterable; /** * Constructor for use by subclasses. */ protected JBIterable() { myIterable = this; } JBIterable(@NotNull Iterable<E> iterable) { myIterable = iterable; } /** * Returns a {@code JBIterable} that wraps {@code iterable}, or {@code iterable} itself if it * is already a {@code JBIterable}. */ @NotNull public static <E> JBIterable<E> from(@Nullable Iterable<? extends E> iterable) { if (iterable == null) return empty(); if (iterable instanceof JBIterable) return (JBIterable<E>)iterable; if (iterable instanceof Collection && ((Collection)iterable).isEmpty()) return empty(); return new JBIterable<E>((Iterable<E>)iterable) { @Override public Iterator<E> iterator() { return myIterable.iterator(); } }; } /** * Returns a {@code JBIterable} that is generated by {@code generator} function applied to a previous element, * the first element is produced by the supplied {@code first} value. * * Generation stops if {@code null} is encountered. */ @NotNull public static <E> JBIterable<E> generate(@Nullable final E first, @NotNull final Function<? super E, ? extends E> generator) { if (first == null) return empty(); return new JBIterable<E>() { @Override public Iterator<E> iterator() { final Function<? super E, ? extends E> fun = Stateful.copy(generator); return new JBIterator<E>() { E cur = first; @Override public E nextImpl() { E result = cur; if (result == null) return stop(); cur = fun.fun(cur); return result; } }; } }; } @NotNull public static <E> JBIterable<E> generate(@Nullable final E first1, @Nullable final E first2, @NotNull final PairFunction<? super E, ? super E, ? extends E> generator) { if (first1 == null) return empty(); return new JBIterable<E>() { @Override public Iterator<E> iterator() { return new JBIterator<E>() { E cur1 = first1; E cur2 = first2; @Override public E nextImpl() { E result = cur1; cur1 = cur2; cur2 = generator.fun(result, cur2); if (result == null) return stop(); return result; } }; } }; } /** * Returns a {@code JBIterable} containing the one {@code element}. */ @NotNull public static <E> JBIterable<E> of(@Nullable E element) { return element == null ? JBIterable.<E>empty() : from(Collections.singletonList(element)); } /** * Returns a {@code JBIterable} containing {@code elements} in the specified order. */ @NotNull public static <E> JBIterable<E> of(@Nullable E... elements) { return elements == null || elements.length == 0 ? JBIterable.<E>empty() : from(ContainerUtilRt.newArrayList(elements)); } private static final JBIterable EMPTY = new JBIterable() { @Override public Iterator iterator() { return EmptyIterator.getInstance(); } }; @NotNull public static <E> JBIterable<E> empty() { return (JBIterable<E>)EMPTY; } @NotNull public static <E> JBIterable<E> once(@NotNull Iterator<E> iterator) { return of(Ref.create(iterator)).intercept(new Function<Iterator<Ref<Iterator<E>>>, Iterator<E>>() { @Override public Iterator<E> fun(Iterator<Ref<Iterator<E>>> iterator) { Ref<Iterator<E>> ref = iterator.next(); Iterator<E> result = ref.get(); if (result == null) throw new UnsupportedOperationException(); ref.set(null); return result; } }); } @NotNull public <T extends Iterator<E>> T typedIterator() { return (T) iterator(); } public boolean processEach(@NotNull Processor<E> processor) { return ContainerUtil.process(this, processor); } public void consumeEach(@NotNull Consumer<E> consumer) { for (E e : this) { consumer.consume(e); } } /** * Returns a string representation of this iterable up to 50 elements, with the format * {@code (e1, e2, ..., en [, ...] )} for debugging purposes. */ @NotNull @Override public String toString() { return myIterable == this ? JBIterable.class.getSimpleName() : String.valueOf(myIterable); } /** * Returns the number of elements in this iterable. */ public final int size() { if (myIterable instanceof Collection) { return ((Collection)myIterable).size(); } int count = 0; for (E ignored : myIterable) { count++; } return count; } /** * Returns {@code true} if this iterable contains any object for which * {@code equals(element)} is true. */ public final boolean contains(@Nullable Object element) { if (myIterable instanceof Collection) { return ((Collection)myIterable).contains(element); } for (E e : myIterable) { if (Comparing.equal(e, element)) return true; } return false; } /** * Returns element at index if it is present; otherwise {@code null} */ @Nullable public final E get(int index) { if (myIterable instanceof List) { return index >= ((List)myIterable).size() ? null : ((List<E>)myIterable).get(index); } return skip(index).first(); } /** * Returns a {@code JBIterable} whose iterators traverse first the elements of this iterable, * followed by those of {@code other}. The iterators are not polled until necessary. * <p/> * <p>The returned iterable's {@code Iterator} supports {@code remove()} when the corresponding * {@code Iterator} supports it. */ @NotNull public final JBIterable<E> append(@Nullable Iterable<? extends E> other) { return other == null ? this : this == EMPTY ? from(other) : of(myIterable, other).flatten(Functions.<Iterable<?>, Iterable<E>>identity()); } @NotNull public final <T> JBIterable<E> append(@Nullable Iterable<T> other, @NotNull Function<? super T, ? extends Iterable<? extends E>> fun) { return other == null ? this : this == EMPTY ? from(other).flatten(fun) : append(from(other).flatten(fun)); } @NotNull public final JBIterable<E> repeat(int count) { Function<JBIterable<E>, JBIterable<E>> fun = Functions.identity(); return generate(this, fun).take(count).flatten(fun); } /** * Returns a {@code JBIterable} whose iterators traverse first the elements of this iterable, * followed by {@code elements}. */ @NotNull public final JBIterable<E> append(@NotNull E[] elements) { return this == EMPTY ? of(elements) : append(Arrays.asList(elements)); } @NotNull public final JBIterable<E> append(@Nullable E e) { return e == null ? this : this == EMPTY ? of(e) : append(Collections.singleton(e)); } /** * Returns the elements from this iterable that satisfy a condition. */ @NotNull public final JBIterable<E> filter(@NotNull final Condition<? super E> condition) { return intercept(new Function<Iterator<E>, Iterator<E>>() { @Override public Iterator<E> fun(Iterator<E> iterator) { return JBIterator.from(iterator).filter(Stateful.copy(condition)); } }); } /** * Returns the elements from this iterable that are instances of class {@code type}. * @param type the type of elements desired */ @NotNull public final <T> JBIterable<T> filter(@NotNull Class<T> type) { return (JBIterable<T>)filter(Conditions.instanceOf(type)); } @NotNull public final JBIterable<E> take(final int count) { return intercept(new Function<Iterator<E>, Iterator<E>>() { @Override public Iterator<E> fun(Iterator<E> iterator) { return JBIterator.from(iterator).take(count); } }); } @NotNull public final JBIterable<E> takeWhile(@NotNull final Condition<? super E> condition) { return intercept(new Function<Iterator<E>, Iterator<E>>() { @Override public Iterator<E> fun(Iterator<E> iterator) { return JBIterator.from(iterator).takeWhile(Stateful.copy(condition)); } }); } @NotNull public final JBIterable<E> skip(final int count) { return intercept(new Function<Iterator<E>, Iterator<E>>() { @Override public Iterator<E> fun(Iterator<E> iterator) { return JBIterator.from(iterator).skip(count); } }); } @NotNull public final JBIterable<E> skipWhile(@NotNull final Condition<? super E> condition) { return intercept(new Function<Iterator<E>, Iterator<E>>() { @Override public Iterator<E> fun(Iterator<E> iterator) { return JBIterator.from(iterator).skipWhile(Stateful.copy(condition)); } }); } /** * Returns a {@code JBIterable} that applies {@code function} to each element of this * iterable. * <p/> * <p>The returned iterable's iterator supports {@code remove()} if this iterable's * iterator does. After a successful {@code remove()} call, this iterable no longer * contains the corresponding element. */ @NotNull public final <T> JBIterable<T> transform(@NotNull final Function<? super E, T> function) { return intercept(new Function<Iterator<E>, Iterator<T>>() { @Override public Iterator<T> fun(Iterator<E> iterator) { return JBIterator.from(iterator).transform(Stateful.copy(function)); } }); } /** * Returns a {@code JBIterable} that applies {@code function} to each element of this * iterable and concatenates the produced iterables in one. * <p/> * <p>The returned iterable's iterator supports {@code remove()} if an underlying iterable's * iterator does. After a successful {@code remove()} call, this iterable no longer * contains the corresponding element. */ @NotNull public <T> JBIterable<T> flatten(@NotNull final Function<? super E, ? extends Iterable<? extends T>> function) { return intercept(new Function<Iterator<E>, Iterator<T>>() { @Override public Iterator<T> fun(final Iterator<E> iterator) { final Function<? super E, ? extends Iterable<? extends T>> fun = Stateful.copy(function); return new JBIterator<T>() { Iterator<? extends T> cur; @Override public T nextImpl() { if (cur != null && cur.hasNext()) return cur.next(); if (!iterator.hasNext()) return stop(); Iterable<? extends T> next = fun.fun(iterator.next()); cur = next == null ? null : next.iterator(); return skip(); } }; } }); } /** * Filters out duplicate items. */ @NotNull public final JBIterable<E> unique() { return unique(Function.ID); } /** * Filters out duplicate items, where an element identity is provided by the specified function. */ @NotNull public final JBIterable<E> unique(@NotNull final Function<? super E, ?> identity) { return filter(new StatefulFilter<E>() { HashSet<Object> visited; @Override public boolean value(E e) { if (visited == null) visited = new HashSet<Object>(); return visited.add(identity.fun(e)); } }); } /** * The most generic iterator transformation. */ @NotNull public final <T, X extends Iterator<E>> JBIterable<T> intercept(@NotNull final Function<X, ? extends Iterator<T>> function) { if (this == EMPTY) return empty(); final JBIterable<E> thisIterable = this; return new JBIterable<T>() { @Override public Iterator<T> iterator() { return function.fun((X)thisIterable.iterator()); } }; } /** * Returns the first element in this iterable or null. */ @Nullable public final E first() { Iterator<E> iterator = myIterable.iterator(); return iterator.hasNext() ? iterator.next() : null; } /** * Returns the last element in this iterable or null. */ @Nullable public final E last() { if (myIterable instanceof List) { return ContainerUtil.getLastItem((List<E>)myIterable); } Iterator<E> iterator = myIterable.iterator(); E cur = null; while (iterator.hasNext()) { cur = iterator.next(); } return cur; } /** * Perform calculation over this iterable. */ public final <T> T reduce(@Nullable T first, @NotNull PairFunction<T, ? super E, T> function) { T cur = first; for (E e : this) { cur = function.fun(cur, e); } return cur; } /** * Returns the index of the first matching element. */ public final E find(@NotNull Condition<? super E> condition) { return filter(condition).first(); } /** * Returns the index of the matching element. */ public final int indexOf(@NotNull Condition<? super E> condition) { int index = 0; for (E e : this) { if (condition.value(e)) { return index; } index ++; } return -1; } /** * Synonym for transform() * * @see JBIterable#transform(Function) */ @NotNull public final <T> JBIterable<T> map(@NotNull Function<? super E, T> function) { return transform(function); } /** * "Maps" and "flattens" this iterable. * * @see JBIterable#transform(Function) */ @NotNull public final <T> JBIterable<T> flatMap(Function<? super E, ? extends Iterable<? extends T>> function) { return map(function).flatten(Function.ID); } /** * Splits this {@code JBIterable} into iterable of lists of the specified size. * If 'strict' flag is true only groups of size 'n' are returned. */ @NotNull public final JBIterable<List<E>> split(final int size, final boolean strict) { return split(size).map(new Function<JBIterable<E>, List<E>>() { @Override public List<E> fun(JBIterable<E> es) { List<E> list = es.addAllTo(ContainerUtilRt.<E>newArrayListWithCapacity(size)); return strict && list.size() < size? null : list; } }).filter(Condition.NOT_NULL); } /** * Splits this {@code JBIterable} into iterable of iterables of the specified size. * All iterations are performed in-place without data copying. */ @NotNull public final JBIterable<JBIterable<E>> split(final int size) { if (size <= 0) throw new IllegalArgumentException(size + " <= 0"); return intercept(new Function<Iterator<E>, Iterator<JBIterable<E>>>() { @Override public Iterator<JBIterable<E>> fun(Iterator<E> iterator) { final Iterator<E> orig = iterator; return new JBIterator<JBIterable<E>>() { JBIterator<E> it; @Override protected JBIterable<E> nextImpl() { // iterate through the previous result fully before proceeding while (it != null && it.advance()) /* no-op */; it = null; return orig.hasNext() ? once((it = JBIterator.wrap(orig)).take(size)) : stop(); } }; } }); } public enum Split {AFTER, BEFORE, AROUND, OFF, GROUP} /** * Splits this {@code JBIterable} into iterable of iterables with separators matched by the specified condition. * All iterations are performed in-place without data copying. */ @NotNull public final JBIterable<JBIterable<E>> split(final Split mode, final Condition<? super E> separator) { return intercept(new Function<Iterator<E>, Iterator<JBIterable<E>>>() { @Override public Iterator<JBIterable<E>> fun(Iterator<E> iterator) { final Iterator<E> orig = iterator; final Condition<? super E> condition = Stateful.copy(separator); return new JBIterator<JBIterable<E>>() { JBIterator<E> it; E stored; int st; // encode transitions: -2:sep->sep, -1:val->sep, 1:sep->val, 2:val->val @Override protected JBIterable<E> nextImpl() { // iterate through the previous result fully before proceeding while (it != null && it.advance()) /* no-op */; it = null; // empty case: check hasNext() only if nothing is stored to be compatible with JBIterator#cursor() if (stored == null && !orig.hasNext()) { if (st < 0 && mode != Split.BEFORE && mode != Split.GROUP) { st = 1; return empty(); } return stop(); } // general case: add empty between 2 separators in KEEP mode; otherwise go with some state logic if (st == -2 && mode == Split.AROUND) { st = -1; return empty(); } E tmp = stored; stored = null; return of(tmp).append(once((it = JBIterator.wrap(orig)).takeWhile(new Condition<E>() { @Override public boolean value(E e) { boolean sep = condition.value(e); int st0 = st; st = st0 < 0 && sep ? -2 : st0 > 0 && !sep? 2 : sep ? -1 : 1; boolean result; switch (mode) { case AFTER: result = st != -2 && (st != 1 || st0 == 0); break; case BEFORE: result = st != -2 && st != -1; break; case AROUND: result = st0 >= 0 && st > 0; break; case GROUP: result = st0 >= 0 && st > 0 || st0 <= 0 && st < 0; break; case OFF: result = st > 0; break; default: throw new AssertionError(st); } stored = !result && mode != Split.OFF ? e : null; return result; } }))); } }; } }); } /** * Determines whether this iterable is empty. */ public final boolean isEmpty() { if (myIterable instanceof Collection) { return ((Collection)myIterable).isEmpty(); } return !myIterable.iterator().hasNext(); } /** * Returns an {@code List} containing all of the elements from this iterable in * proper sequence. */ @NotNull public final List<E> toList() { return Collections.unmodifiableList(ContainerUtilRt.newArrayList(myIterable)); } /** * Returns an {@code Set} containing all of the elements from this iterable with * duplicates removed. */ @NotNull public final Set<E> toSet() { return Collections.unmodifiableSet(ContainerUtilRt.newLinkedHashSet(myIterable)); } /** * Returns an {@code Map} for which the elements of this {@code JBIterable} are the keys in * the same order, mapped to values by the given function. If this iterable contains duplicate * elements, the returned map will contain each distinct element once in the order it first * appears. */ @NotNull public final <V> Map<E, V> toMap(Convertor<E, V> valueFunction) { return Collections.unmodifiableMap(ContainerUtil.newMapFromKeys(iterator(), valueFunction)); } /** * Copies all the elements from this iterable to {@code collection}. This is equivalent to * calling {@code Iterables.addAll(collection, this)}. * * @param collection the collection to copy elements to * @return {@code collection}, for convenience */ @NotNull public final <C extends Collection<? super E>> C addAllTo(@NotNull C collection) { if (myIterable instanceof Collection) { collection.addAll((Collection<E>)myIterable); } else { for (E item : myIterable) { collection.add(item); } } return collection; } public abstract static class Stateful<Self extends Stateful> implements Cloneable { @NotNull static <T> T copy(@NotNull T o) { if (!(o instanceof Stateful)) return o; return (T)((Stateful)o).clone(); } public Self clone() { try { return (Self)super.clone(); } catch (CloneNotSupportedException e) { throw new AssertionError(e); } } } public abstract static class StatefulFilter<T> extends Stateful<StatefulFilter> implements Condition<T> { } public abstract static class StatefulTransform<S, T> extends Stateful<StatefulTransform> implements Function<S, T> { } }