All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javaslang.collection.IndexedSeq Maven / Gradle / Ivy

/*     / \____  _    _  ____   ______  / \ ____  __    _______
 *    /  /    \/ \  / \/    \ /  /\__\/  //    \/  \  //  /\__\   JΛVΛSLΛNG
 *  _/  /  /\  \  \/  /  /\  \\__\\  \  //  /\  \ /\\/ \ /__\ \   Copyright 2014-2016 Javaslang, http://javaslang.io
 * /___/\_/  \_/\____/\_/  \_/\__\/__/\__\_/  \_//  \__/\_____/   Licensed under the Apache License, Version 2.0
 */
package javaslang.collection;

import javaslang.Tuple2;
import javaslang.Tuple3;
import javaslang.control.Option;

import java.util.Comparator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntUnaryOperator;
import java.util.function.Predicate;

/**
 * Interface for immutable, indexed sequences.
 * 

* Efficient random access is characteristic for indexed sequences. * * @param component type * @author Daniel Dietrich * @since 2.0.0 */ public interface IndexedSeq extends Seq { long serialVersionUID = 1L; /** * Narrows a widened {@code IndexedSeq} to {@code IndexedSeq} * by performing a type safe-cast. This is eligible because immutable/read-only * collections are covariant. * * @param indexedSeq An {@code IndexedSeq}. * @param Component type of the {@code IndexedSeq}. * @return the given {@code indexedSeq} instance as narrowed type {@code IndexedSeq}. */ @SuppressWarnings("unchecked") static IndexedSeq narrow(IndexedSeq indexedSeq) { return (IndexedSeq) indexedSeq; } // -- Adjusted return types of Seq methods @Override IndexedSeq append(T element); @Override IndexedSeq appendAll(Iterable elements); @Override IndexedSeq> combinations(); @Override IndexedSeq> combinations(int k); @Override Iterator> crossProduct(int power); @Override IndexedSeq distinct(); @Override IndexedSeq distinctBy(Comparator comparator); @Override IndexedSeq distinctBy(Function keyExtractor); @Override IndexedSeq drop(long n); @Override IndexedSeq dropRight(long n); @Override IndexedSeq dropUntil(Predicate predicate); @Override IndexedSeq dropWhile(Predicate predicate); @Override default boolean endsWith(Seq that) { Objects.requireNonNull(that, "that is null"); if (that instanceof IndexedSeq) { int i = length() - 1; int j = that.length() - 1; if (j > i) { return false; } else { while (j >= 0) { if (!Objects.equals(this.get(i), that.get(j))) { return false; } i--; j--; } return true; } } else { return Seq.super.endsWith(that); } } @Override IndexedSeq filter(Predicate predicate); @Override IndexedSeq flatMap(Function> mapper); @Override Map> groupBy(Function classifier); @Override default int indexWhere(Predicate predicate, int from) { Objects.requireNonNull(predicate, "predicate is null"); int start = Math.max(from, 0); int n = start + segmentLength(predicate.negate(), start); return (n >= length()) ? -1 : n; } @Override Iterator> grouped(long size); @Override IndexedSeq init(); @Override Option> initOption(); @Override IndexedSeq insert(int index, T element); @Override IndexedSeq insertAll(int index, Iterable elements); @Override IndexedSeq intersperse(T element); @Override default T last() { if (isEmpty()) { throw new NoSuchElementException("last of empty IndexedSeq"); } else { return get(length() - 1); } } @Override default int lastIndexOfSlice(Iterable that, int end) { return IndexedSeqModule.LastIndexOfSlice.lastIndexOfSlice(this, unit(that), end); } @Override default int lastIndexWhere(Predicate predicate, int end) { Objects.requireNonNull(predicate, "predicate is null"); int i = Math.min(end, length() - 1); while (i >= 0 && !predicate.test(this.get(i))) { i--; } return i; } @Override IndexedSeq map(Function mapper); @Override IndexedSeq padTo(int length, T element); @Override IndexedSeq patch(int from, Iterable that, int replaced); @Override Tuple2, ? extends IndexedSeq> partition(Predicate predicate); @Override IndexedSeq peek(Consumer action); @Override IndexedSeq> permutations(); @Override IndexedSeq prepend(T element); @Override IndexedSeq prependAll(Iterable elements); @Override IndexedSeq remove(T element); @Override IndexedSeq removeFirst(Predicate predicate); @Override IndexedSeq removeLast(Predicate predicate); @Override IndexedSeq removeAt(int index); @Override IndexedSeq removeAll(T element); @Override IndexedSeq removeAll(Iterable elements); @Override IndexedSeq replace(T currentElement, T newElement); @Override IndexedSeq replaceAll(T currentElement, T newElement); @Override IndexedSeq retainAll(Iterable elements); @Override IndexedSeq reverse(); @Override default Iterator reverseIterator() { return new AbstractIterator() { private int i = IndexedSeq.this.length(); @Override public boolean hasNext() { return i > 0; } @Override public T getNext() { return IndexedSeq.this.get(--i); } }; } @Override IndexedSeq scan(T zero, BiFunction operation); @Override IndexedSeq scanLeft(U zero, BiFunction operation); @Override IndexedSeq scanRight(U zero, BiFunction operation); @Override default int segmentLength(Predicate predicate, int from) { Objects.requireNonNull(predicate, "predicate is null"); int len = length(); int i = from; while (i < len && predicate.test(this.get(i))) { i++; } return i - from; } @Override IndexedSeq slice(long beginIndex, long endIndex); @Override Iterator> sliding(long size); @Override Iterator> sliding(long size, long step); @Override IndexedSeq sorted(); @Override IndexedSeq sorted(Comparator comparator); @Override > IndexedSeq sortBy(Function mapper); @Override IndexedSeq sortBy(Comparator comparator, Function mapper); @Override Tuple2, ? extends IndexedSeq> span(Predicate predicate); @Override default boolean startsWith(Iterable that, int offset) { Objects.requireNonNull(that, "that is null"); if (offset < 0) return false; if (that instanceof IndexedSeq) { IndexedSeq thatIndexedSeq = (IndexedSeq) that; int i = offset; int j = 0; int thisLen = length(); int thatLen = thatIndexedSeq.length(); while (i < thisLen && j < thatLen && Objects.equals(this.get(i), thatIndexedSeq.get(j))) { i++; j++; } return j == thatLen; } else { int i = offset; int thisLen = length(); java.util.Iterator thatElems = that.iterator(); while (i < thisLen && thatElems.hasNext()) { if (!Objects.equals(this.get(i), thatElems.next())) { return false; } i++; } return !thatElems.hasNext(); } } @Override IndexedSeq subSequence(int beginIndex); @Override IndexedSeq subSequence(int beginIndex, int endIndex); @Override IndexedSeq tail(); @Override Option> tailOption(); @Override IndexedSeq take(long n); @Override IndexedSeq takeRight(long n); @Override IndexedSeq takeUntil(Predicate predicate); @Override IndexedSeq takeWhile(Predicate predicate); @Override IndexedSeq unit(Iterable iterable); @Override Tuple2, ? extends IndexedSeq> unzip(Function> unzipper); @Override Tuple3, ? extends IndexedSeq, ? extends IndexedSeq> unzip3(Function> unzipper); @Override IndexedSeq update(int index, T element); @Override IndexedSeq> zip(Iterable that); @Override IndexedSeq> zipAll(Iterable that, T thisElem, U thatElem); @Override IndexedSeq> zipWithIndex(); /** * Searches this sequence for a specific element using a binary search. The sequence must already be sorted into * ascending natural order. If it is not sorted, the results are undefined. * * @param element the element to find * @return the index of the search element, if it is contained in the sequence; * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * element would be inserted into the sequence. Note that this guarantees that * the return value will be >= 0 if and only if the element is found. * @throws ClassCastException if T cannot be cast to {@code Comparable} */ @Override @SuppressWarnings("unchecked") default int search(T element) { IntUnaryOperator comparison = midIndex -> { Comparable midVal = (Comparable) get(midIndex); return midVal.compareTo(element); }; return IndexedSeqModule.Search.binarySearch(this, comparison); } /** * Searches this sequence for a specific element using a binary search. The sequence must already be sorted into * ascending order according to the specified comparator. If it is not sorted, the results are undefined. * * @param element the element to find * @param comparator the comparator by which this sequence is ordered * @return the index of the search element, if it is contained in the sequence; * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * element would be inserted into the sequence. Note that this guarantees that * the return value will be >= 0 if and only if the element is found. */ @Override default int search(T element, Comparator comparator) { Objects.requireNonNull(comparator, "comparator is null"); IntUnaryOperator comparison = midIndex -> { T midVal = get(midIndex); return comparator.compare(midVal, element); }; return IndexedSeqModule.Search.binarySearch(this, comparison); } } interface IndexedSeqModule { interface LastIndexOfSlice { static int lastIndexOfSlice(IndexedSeq t, IndexedSeq slice, int end) { if (end < 0) { return -1; } if (t.isEmpty()) { return slice.isEmpty() ? 0 : -1; } if (slice.isEmpty()) { int len = t.length(); return len < end ? len : end; } int p = 0; int result = -1; final int maxPtr = t.length() - slice.length(); while (p <= maxPtr) { int r = findSlice(t, p, maxPtr, slice); if (r < 0) { return result; } if (r <= end) { result = r; p = r + 1; } else { return result; } } return result; } static int findSlice(IndexedSeq t, int p, int maxPtr, IndexedSeq slice) { while (p <= maxPtr) { if (t.startsWith(slice, p)) { return p; } p++; } return -1; } } interface Search { static int binarySearch(IndexedSeq seq, IntUnaryOperator comparison) { int low = 0; int high = seq.size() - 1; while (low <= high) { int mid = (low + high) >>> 1; int cmp = comparison.applyAsInt(mid); if (cmp < 0) { low = mid + 1; } else if (cmp > 0) { high = mid - 1; } else { return mid; } } return -(low + 1); } } }