/* __ __ __ __ __ ___ * \ \ / / \ \ / / __/ * \ \/ / /\ \ \/ / / * \____/__/ \__\____/__/.ɪᴏ * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ */ package io.vavr.collection; import io.vavr.PartialFunction; import io.vavr.Tuple; import io.vavr.Tuple3; import io.vavr.control.Option; import io.vavr.Tuple2; import java.io.Serializable; import java.util.Comparator; import java.util.Objects; import java.util.Spliterator; import java.util.function.*; public final class IntMap<T> implements Traversable<T>, Serializable { private static final long serialVersionUID = 1L; private final Map<Integer, T> original; private static final IntMap<?> EMPTY = new IntMap<>(HashMap.empty()); @SuppressWarnings("unchecked") public static <T> IntMap<T> of(Map<Integer, T> original) { return original.isEmpty() ? (IntMap<T>) EMPTY : new IntMap<>(original); } // DEV-NOTE: needs to be used internally to ensure the isSameAs property of the original is reflected by this impl private IntMap<T> unit(Map<Integer, T> original) { return (this.original == original) ? this : of(original); } private IntMap(Map<Integer, T> original) { this.original = original; } @Override public boolean isAsync() { return original.isAsync(); } @Override public boolean isDistinct() { return original.isDistinct(); } @Override public boolean isLazy() { return original.isLazy(); } @Override public boolean equals(Object o) { final Object that = (o instanceof IntMap) ?((IntMap) o).original : o; return Collections.equals(original, that); } @Override public int hashCode() { return original.hashCode(); } @Override public String stringPrefix() { return "IntMap"; } @Override public String toString() { return mkString(stringPrefix() + "(", ", ", ")"); } @Override public <R> Seq<R> collect(PartialFunction<? super T, ? extends R> partialFunction) { Objects.requireNonNull(partialFunction, "partialFunction is null"); final PartialFunction<Tuple2<Integer, T>, R> pf = new PartialFunction<Tuple2<Integer, T>, R>() { @Override public R apply(Tuple2<Integer, T> entry) { return partialFunction.apply(entry._2); } @Override public boolean isDefinedAt(Tuple2<Integer, T> entry) { return partialFunction.isDefinedAt(entry._2); } }; return original.collect(pf); } @Override public IntMap<T> distinct() { return unit(original.distinct()); } @Override public IntMap<T> distinctBy(Comparator<? super T> comparator) { return unit(original.distinctBy((o1, o2) -> comparator.compare(o1._2, o2._2))); } @Override public <U> IntMap<T> distinctBy(Function<? super T, ? extends U> keyExtractor) { return unit(original.distinctBy(f -> keyExtractor.apply(f._2))); } @Override public IntMap<T> drop(int n) { final Map<Integer, T> dropped = original.drop(n); return dropped == original ? this : unit(dropped); } @Override public IntMap<T> dropRight(int n) { final Map<Integer, T> dropped = original.dropRight(n); return dropped == original ? this : unit(dropped); } @Override public IntMap<T> dropUntil(Predicate<? super T> predicate) { return unit(original.dropUntil(p -> predicate.test(p._2))); } @Override public IntMap<T> dropWhile(Predicate<? super T> predicate) { return unit(original.dropWhile(p -> predicate.test(p._2))); } @Override public IntMap<T> filter(Predicate<? super T> predicate) { return unit(original.filter(p -> predicate.test(p._2))); } @Override public <U> Seq<U> flatMap(Function<? super T, ? extends Iterable<? extends U>> mapper) { return original.flatMap(e -> mapper.apply(e._2)); } @Override public <U> U foldRight(U zero, BiFunction<? super T, ? super U, ? extends U> f) { Objects.requireNonNull(f, "f is null"); return original.foldRight(zero, (e, u) -> f.apply(e._2, u)); } @Override public <C> Map<C, ? extends IntMap<T>> groupBy(Function<? super T, ? extends C> classifier) { return original.groupBy(e -> classifier.apply(e._2)).map((k, v) -> Tuple.of(k, IntMap.of(v))); } @Override public Iterator<IntMap<T>> grouped(int size) { return original.grouped(size).map(IntMap::of); } @Override public boolean hasDefiniteSize() { return original.hasDefiniteSize(); } @Override public T head() { return original.head()._2; } @Override public Option<T> headOption() { return original.headOption().map(o -> o._2); } @Override public IntMap<T> init() { return IntMap.of(original.init()); } @Override public Option<? extends IntMap<T>> initOption() { return original.initOption().map(IntMap::of); } @Override public boolean isEmpty() { return original.isEmpty(); } @Override public boolean isTraversableAgain() { return original.isTraversableAgain(); } @Override public int length() { return original.length(); } @Override public <U> Seq<U> map(Function<? super T, ? extends U> mapper) { return original.map(e -> mapper.apply(e._2)); } @Override public IntMap<T> orElse(Iterable<? extends T> other) { return unit(original.orElse(List.ofAll(other).zipWithIndex().map(t -> Tuple.of(t._2, t._1)))); } @SuppressWarnings("unchecked") @Override public IntMap<T> orElse(Supplier<? extends Iterable<? extends T>> supplier) { return unit(original.orElse(() -> (Iterable<? extends Tuple2<Integer, T>>) List.ofAll(supplier.get()).zipWithIndex().map(t -> Tuple.of(t._2, t._1)))); } @Override public Tuple2<IntMap<T>, IntMap<T>> partition(Predicate<? super T> predicate) { Objects.requireNonNull(predicate, "predicate is null"); return original.partition(p -> predicate.test(p._2)).map(IntMap::of, IntMap::of); } @Override public IntMap<T> peek(Consumer<? super T> action) { original.peek(e -> action.accept(e._2)); return this; } @Override public IntMap<T> replace(T currentElement, T newElement) { final Option<Tuple2<Integer, T>> currentEntryOpt = original.find(e -> e._2.equals(currentElement)); if (currentEntryOpt.isDefined()) { final Tuple2<Integer, T> currentEntry = currentEntryOpt.get(); return unit(original.replace(currentEntry, Tuple.of(original.size() + 1, newElement))); } else { return this; } } @Override public IntMap<T> replaceAll(T currentElement, T newElement) { Map<Integer, T> result = original; for (Tuple2<Integer, T> entry : original.filter(e -> e._2.equals(currentElement))) { result = result.replaceAll(entry, Tuple.of(entry._1, newElement)); } return unit(result); } @Override public IntMap<T> retainAll(Iterable<? extends T> elements) { final Set<T> elementsSet = HashSet.ofAll(elements); return unit(original.retainAll(original.filter(e -> elementsSet.contains(e._2)))); } @Override public Traversable<T> scan(T zero, BiFunction<? super T, ? super T, ? extends T> operation) { final int[] index = new int[] { 0 }; return original.scan(Tuple.of(-1, zero), (i, t) -> Tuple.of(index[0]++, operation.apply(i._2, t._2))).values(); } @Override public <U> Traversable<U> scanLeft(U zero, BiFunction<? super U, ? super T, ? extends U> operation) { return original.scanLeft(zero, (i, t) -> operation.apply(i, t._2)); } @Override public <U> Traversable<U> scanRight(U zero, BiFunction<? super T, ? super U, ? extends U> operation) { return original.scanRight(zero, (t, i) -> operation.apply(t._2, i)); } @Override public Iterator<IntMap<T>> slideBy(Function<? super T, ?> classifier) { return original.slideBy(e -> classifier.apply(e._2)).map(IntMap::of); } @Override public Iterator<IntMap<T>> sliding(int size) { return original.sliding(size).map(IntMap::of); } @Override public Iterator<IntMap<T>> sliding(int size, int step) { return original.sliding(size, step).map(IntMap::of); } @Override public Tuple2<? extends IntMap<T>, ? extends IntMap<T>> span(Predicate<? super T> predicate) { return original.span(p -> predicate.test(p._2)).map(IntMap::of, IntMap::of); } public Spliterator<T> spliterator() { class SpliteratorProxy implements Spliterator<T> { private final Spliterator<Tuple2<Integer, T>> spliterator; private SpliteratorProxy(Spliterator<Tuple2<Integer, T>> spliterator) { this.spliterator = spliterator; } @Override public boolean tryAdvance(Consumer<? super T> action) { return spliterator.tryAdvance(a -> action.accept(a._2)); } @Override public Spliterator<T> trySplit() { return new SpliteratorProxy(spliterator.trySplit()); } @Override public long estimateSize() { return spliterator.estimateSize(); } @Override public int characteristics() { return spliterator.characteristics(); } @Override public Comparator<? super T> getComparator() { if (hasCharacteristics(Spliterator.SORTED)) { return null; } throw new IllegalStateException(); } } return new SpliteratorProxy(original.spliterator()); } @Override public IntMap<T> tail() { return IntMap.of(original.tail()); } @Override public Option<IntMap<T>> tailOption() { return original.tailOption().map(IntMap::of); } @Override public IntMap<T> take(int n) { return unit(original.take(n)); } @Override public IntMap<T> takeRight(int n) { return unit(original.takeRight(n)); } @Override public Traversable<T> takeUntil(Predicate<? super T> predicate) { return unit(original.takeUntil(p -> predicate.test(p._2))); } @Override public IntMap<T> takeWhile(Predicate<? super T> predicate) { return unit(original.takeWhile(p -> predicate.test(p._2))); } @Override public <T1, T2> Tuple2<Seq<T1>, Seq<T2>> unzip(Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper) { Objects.requireNonNull(unzipper, "unzipper is null"); return iterator().unzip(unzipper).map(Stream::ofAll, Stream::ofAll); } @Override public <T1, T2, T3> Tuple3<Seq<T1>, Seq<T2>, Seq<T3>> unzip3(Function<? super T, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper) { Objects.requireNonNull(unzipper, "unzipper is null"); return iterator().unzip3(unzipper).map(Stream::ofAll, Stream::ofAll, Stream::ofAll); } @Override public <U> Seq<Tuple2<T, U>> zip(Iterable<? extends U> that) { return zipWith(that, Tuple::of); } @Override public <U, R> Seq<R> zipWith(Iterable<? extends U> that, BiFunction<? super T, ? super U, ? extends R> mapper) { Objects.requireNonNull(that, "that is null"); Objects.requireNonNull(mapper, "mapper is null"); return Stream.ofAll(iterator().zipWith(that, mapper)); } @Override public <U> Seq<Tuple2<T, U>> zipAll(Iterable<? extends U> that, T thisElem, U thatElem) { Objects.requireNonNull(that, "that is null"); return Stream.ofAll(iterator().zipAll(that, thisElem, thatElem)); } @Override public Seq<Tuple2<T, Integer>> zipWithIndex() { return zipWithIndex(Tuple::of); } @Override public <U> Seq<U> zipWithIndex(BiFunction<? super T, ? super Integer, ? extends U> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return Stream.ofAll(iterator().zipWithIndex(mapper)); } }