/* __ __ __ __ __ ___ * \ \ / / \ \ / / __/ * \ \/ / /\ \ \/ / / * \____/__/ \__\____/__/.ɪᴏ * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ */ package io.vavr.collection; import io.vavr.collection.JavaConverters.ChangePolicy; import io.vavr.collection.JavaConverters.ListView; import io.vavr.control.Option; import java.util.ArrayList; import java.util.Collection; import java.util.Objects; import java.util.function.*; /** * Internal class, containing helpers. * * @author Daniel Dietrich */ final class Collections { // checks, if the *elements* of the given iterables are equal static boolean areEqual(Iterable<?> iterable1, Iterable<?> iterable2) { final java.util.Iterator<?> iter1 = iterable1.iterator(); final java.util.Iterator<?> iter2 = iterable2.iterator(); while (iter1.hasNext() && iter2.hasNext()) { if (!Objects.equals(iter1.next(), iter2.next())) { return false; } } return iter1.hasNext() == iter2.hasNext(); } @GwtIncompatible static <T, C extends Seq<T>> C asJava(C source, Consumer<? super java.util.List<T>> action, ChangePolicy changePolicy) { Objects.requireNonNull(action, "action is null"); final ListView<T, C> view = JavaConverters.asJava(source, changePolicy); action.accept(view); return view.getDelegate(); } @SuppressWarnings("unchecked") static <T, S extends Seq<T>> Iterator<S> crossProduct(S empty, S seq, int power) { if (power < 0) { return Iterator.empty(); } else { return Iterator.range(0, power) .foldLeft(Iterator.of(empty), (product, ignored) -> product.flatMap(el -> seq.map(t -> (S) el.append(t)))); } } @SuppressWarnings("unchecked") static <T, S extends IndexedSeq<T>> S dropRightUntil(S seq, Predicate<? super T> predicate) { Objects.requireNonNull(predicate, "predicate is null"); for (int i = seq.length() - 1; i >= 0; i--) { if (predicate.test(seq.get(i))) { return (S) seq.take(i + 1); } } return (S) seq.take(0); } @SuppressWarnings("unchecked") static <T, S extends Seq<T>> S dropUntil(S seq, Predicate<? super T> predicate) { Objects.requireNonNull(predicate, "predicate is null"); for (int i = 0; i < seq.length(); i++) { if (predicate.test(seq.get(i))) { return (S) seq.drop(i); } } return (S) seq.take(0); } @SuppressWarnings("unchecked") static <K, V> boolean equals(Map<K, V> source, Object object) { if (source == object) { return true; } else if (source != null && object instanceof Map) { final Map<K, V> map = (Map<K, V>) object; if (source.size() != map.size()) { return false; } else { try { return source.forAll(map::contains); } catch (ClassCastException e) { return false; } } } else { return false; } } @SuppressWarnings("unchecked") static <K, V> boolean equals(Multimap<K, V> source, Object object) { if (source == object) { return true; } else if (source != null && object instanceof Multimap) { final Multimap<K, V> multimap = (Multimap<K, V>) object; if (source.size() != multimap.size()) { return false; } else { try { return source.forAll(multimap::contains); } catch (ClassCastException e) { return false; } } } else { return false; } } @SuppressWarnings("unchecked") static <V> boolean equals(Seq<V> source, Object object) { if (object == source) { return true; } else if (source != null && object instanceof Seq) { final Seq<V> seq = (Seq<V>) object; return seq.size() == source.size() && areEqual(source, seq); } else { return false; } } @SuppressWarnings("unchecked") static <V> boolean equals(Set<V> source, Object object) { if (source == object) { return true; } else if (source != null && object instanceof Set) { final Set<V> set = (Set<V>) object; if (source.size() != set.size()) { return false; } else { try { return source.forAll(set::contains); } catch (ClassCastException e) { return false; } } } else { return false; } } static <T> Iterator<T> fill(int n, Supplier<? extends T> supplier) { Objects.requireNonNull(supplier, "supplier is null"); return tabulate(n, ignored -> supplier.get()); } static <C extends Traversable<T>, T> C fill(int n, Supplier<? extends T> s, C empty, Function<T[], C> of) { Objects.requireNonNull(s, "s is null"); Objects.requireNonNull(empty, "empty is null"); Objects.requireNonNull(of, "of is null"); return tabulate(n, anything -> s.get(), empty, of); } static <T, C, R extends Iterable<T>> Map<C, R> groupBy(Traversable<T> source, Function<? super T, ? extends C> classifier, Function<? super Iterable<T>, R> mapper) { Objects.requireNonNull(classifier, "classifier is null"); Objects.requireNonNull(mapper, "mapper is null"); Map<C, R> results = LinkedHashMap.empty(); for (java.util.Map.Entry<? extends C, Collection<T>> entry : groupBy(source, classifier)) { results = results.put(entry.getKey(), mapper.apply(entry.getValue())); } return results; } private static <T, C> java.util.Set<java.util.Map.Entry<C, Collection<T>>> groupBy(Traversable<T> source, Function<? super T, ? extends C> classifier) { final java.util.Map<C, Collection<T>> results = new java.util.LinkedHashMap<>(source.isTraversableAgain() ? source.size() : 16); for (T value : source) { final C key = classifier.apply(value); results.computeIfAbsent(key, k -> new ArrayList<>()).add(value); } return results.entrySet(); } // hashes the elements respecting their order static int hashOrdered(Iterable<?> iterable) { return hash(iterable, (acc, hash) -> acc * 31 + hash); } // hashes the elements regardless of their order static int hashUnordered(Iterable<?> iterable) { return hash(iterable, (acc, hash) -> acc + hash); } private static int hash(Iterable<?> iterable, IntBinaryOperator accumulator) { if (iterable == null) { return 0; } else { int hashCode = 1; for (Object o : iterable) { hashCode = accumulator.applyAsInt(hashCode, Objects.hashCode(o)); } return hashCode; } } static Option<Integer> indexOption(int index) { return Option.when(index >= 0, index); } // @param iterable may not be null static boolean isEmpty(Iterable<?> iterable) { return iterable instanceof Traversable && ((Traversable) iterable).isEmpty() || iterable instanceof Collection && ((Collection) iterable).isEmpty() || !iterable.iterator().hasNext(); } static <T> boolean isTraversableAgain(Iterable<? extends T> iterable) { return (iterable instanceof Collection) || (iterable instanceof Traversable && ((Traversable<?>) iterable).isTraversableAgain()); } @SuppressWarnings("unchecked") static <K, V, K2, U extends Map<K2, V>> U mapKeys(Map<K, V> source, U zero, Function<? super K, ? extends K2> keyMapper, BiFunction<? super V, ? super V, ? extends V> valueMerge) { Objects.requireNonNull(zero, "zero is null"); Objects.requireNonNull(keyMapper, "keyMapper is null"); Objects.requireNonNull(valueMerge, "valueMerge is null"); return source.foldLeft(zero, (acc, entry) -> { final K2 k2 = keyMapper.apply(entry._1); final V v2 = entry._2; final Option<V> v1 = acc.get(k2); final V v = v1.isDefined() ? valueMerge.apply(v1.get(), v2) : v2; return (U) acc.put(k2, v); }); } @SuppressWarnings("unchecked") static <C extends Traversable<T>, T> C removeAll(C source, Iterable<? extends T> elements) { Objects.requireNonNull(elements, "elements is null"); if (source.isEmpty()) { return source; } else { final Set<T> removed = HashSet.ofAll(elements); return removed.isEmpty() ? source : (C) source.filter(e -> !removed.contains(e)); } } @SuppressWarnings("unchecked") static <C extends Traversable<T>, T> C removeAll(C source, Predicate<? super T> predicate) { Objects.requireNonNull(predicate, "predicate is null"); if (source.isEmpty()) { return source; } else { return (C) source.filter(predicate.negate()); } } @SuppressWarnings("unchecked") static <C extends Traversable<T>, T> C removeAll(C source, T element) { if (source.isEmpty()) { return source; } else { return (C) source.filter(e -> !Objects.equals(e, element)); } } @SuppressWarnings("unchecked") static <C extends Traversable<T>, T> C retainAll(C source, Iterable<? extends T> elements) { Objects.requireNonNull(elements, "elements is null"); if (source.isEmpty()) { return source; } else { final Set<T> retained = HashSet.ofAll(elements); return (C) source.filter(retained::contains); } } static <T> Iterator<T> reverseIterator(Iterable<T> iterable) { if (iterable instanceof java.util.List) { return reverseListIterator((java.util.List<T>) iterable); } else if (iterable instanceof Seq) { return ((Seq<T>) iterable).reverseIterator(); } else { return List.<T>empty().pushAll(iterable).iterator(); } } private static <T> Iterator<T> reverseListIterator(java.util.List<T> list) { return new Iterator<T>() { private final java.util.ListIterator<T> delegate = list.listIterator(list.size()); @Override public boolean hasNext() { return delegate.hasPrevious(); } @Override public T next() { return delegate.previous(); } }; } static <T, U, R extends Traversable<U>> R scanLeft(Traversable<? extends T> source, U zero, BiFunction<? super U, ? super T, ? extends U> operation, Function<Iterator<U>, R> finisher) { Objects.requireNonNull(operation, "operation is null"); final Iterator<U> iterator = source.iterator().scanLeft(zero, operation); return finisher.apply(iterator); } static <T, U, R extends Traversable<U>> R scanRight(Traversable<? extends T> source, U zero, BiFunction<? super T, ? super U, ? extends U> operation, Function<Iterator<U>, R> finisher) { Objects.requireNonNull(operation, "operation is null"); final Iterator<? extends T> reversedElements = reverseIterator(source); return scanLeft(reversedElements, zero, (u, t) -> operation.apply(t, u), us -> finisher.apply(reverseIterator(us))); } static <T, S extends Seq<T>> S shuffle(S source, Function<? super Iterable<T>, S> ofAll) { if (source.length() <= 1) { return source; } final java.util.List<T> list = source.toJavaList(); java.util.Collections.shuffle(list); return ofAll.apply(list); } static void subSequenceRangeCheck(int beginIndex, int endIndex, int length) { if (beginIndex < 0 || endIndex > length) { throw new IndexOutOfBoundsException("subSequence(" + beginIndex + ", " + endIndex + "), length = " + length); } else if (beginIndex > endIndex) { throw new IllegalArgumentException("subSequence(" + beginIndex + ", " + endIndex + ")"); } } static <T> Iterator<T> tabulate(int n, Function<? super Integer, ? extends T> f) { Objects.requireNonNull(f, "f is null"); if (n <= 0) { return Iterator.empty(); } else { return new AbstractIterator<T>() { int i = 0; @Override public boolean hasNext() { return i < n; } @Override protected T getNext() { return f.apply(i++); } }; } } static <C extends Traversable<T>, T> C tabulate(int n, Function<? super Integer, ? extends T> f, C empty, Function<T[], C> of) { Objects.requireNonNull(f, "f is null"); Objects.requireNonNull(empty, "empty is null"); Objects.requireNonNull(of, "of is null"); if (n <= 0) { return empty; } else { @SuppressWarnings("unchecked") final T[] elements = (T[]) new Object[n]; for (int i = 0; i < n; i++) { elements[i] = f.apply(i); } return of.apply(elements); } } static <T, U extends Seq<T>, V extends Seq<U>> V transpose(V matrix, Function<Iterable<U>, V> rowFactory, Function<T[], U> columnFactory) { Objects.requireNonNull(matrix, "matrix is null"); if (matrix.isEmpty() || (matrix.length() == 1 && matrix.head().length() <= 1)) { return matrix; } else { return transposeNonEmptyMatrix(matrix, rowFactory, columnFactory); } } private static <T, U extends Seq<T>, V extends Seq<U>> V transposeNonEmptyMatrix(V matrix, Function<Iterable<U>, V> rowFactory, Function<T[], U> columnFactory) { final int newHeight = matrix.head().size(), newWidth = matrix.size(); @SuppressWarnings("unchecked") final T[][] results = (T[][]) new Object[newHeight][newWidth]; if (matrix.exists(r -> r.size() != newHeight)) { throw new IllegalArgumentException("the parameter `matrix` is invalid!"); } int rowIndex = 0; for (U row : matrix) { int columnIndex = 0; for (T element : row) { results[columnIndex][rowIndex] = element; columnIndex++; } rowIndex++; } return rowFactory.apply(Iterator.of(results).map(columnFactory)); } @SuppressWarnings("unchecked") static <T> IterableWithSize<T> withSize(Iterable<? extends T> iterable) { return isTraversableAgain(iterable) ? withSizeTraversable(iterable) : withSizeTraversable(List.ofAll(iterable)); } private static <T> IterableWithSize<T> withSizeTraversable(Iterable<? extends T> iterable) { if (iterable instanceof Collection) { return new IterableWithSize<>(iterable, ((Collection<?>) iterable).size()); } else { return new IterableWithSize<>(iterable, ((Traversable<?>) iterable).size()); } } static class IterableWithSize<T> { private final Iterable<? extends T> iterable; private final int size; IterableWithSize(Iterable<? extends T> iterable, int size) { this.iterable = iterable; this.size = size; } java.util.Iterator<? extends T> iterator() { return iterable.iterator(); } java.util.Iterator<? extends T> reverseIterator() { return Collections.reverseIterator(iterable); } int size() { return size; } @SuppressWarnings("unchecked") Object[] toArray() { if (iterable instanceof Collection<?>) { return ((Collection<? extends T>) iterable).toArray(); } else { return ArrayType.asArray(iterator(), size()); } } } }