diff --git a/src/main/java/ix/Ix.java b/src/main/java/ix/Ix.java index 91b5897..82c9b64 100644 --- a/src/main/java/ix/Ix.java +++ b/src/main/java/ix/Ix.java @@ -440,7 +440,8 @@ public static Ix repeatValue(T value) { /** * Repeats the given value at most count times. - *

A count of zero will yield an empty sequence, a count of one + *

+ * A count of zero will yield an empty sequence, a count of one * will yield a sequence with only one element and so forth. *

* The result's iterator() doesn't support remove(). @@ -457,7 +458,8 @@ public static Ix repeatValue(T value, long count) { /** * Repeats the given value until the given predicate returns true. - *

A count of zero will yield an empty sequence, a count of one + *

+ * A count of zero will yield an empty sequence, a count of one * will yield a sequence with only one element and so forth. *

* The result's iterator() doesn't support remove(). @@ -475,7 +477,8 @@ public static Ix repeatValue(T value, Pred0 stopPredicate) { /** * Repeats the given value at most count times or until the given predicate returns true. - *

A count of zero will yield an empty sequence, a count of one + *

+ * A count of zero will yield an empty sequence, a count of one * will yield a sequence with only one element and so forth. *

* The result's iterator() doesn't support remove(). @@ -797,11 +800,14 @@ public final Ix concatMap(Func1 + * Note that mergeWith and concatWith operations are the same in the Iterable world. + *

* The result's iterator() forwards the call remove() to the current Iterator. * @param other the other sequence to emits elements of * @return the new Ix instance * @throws NullPointerException if other is null * @since 1.0 + * @see #mergeWith(Iterable) */ public final Ix concatWith(Iterable other) { return concat(this, other); @@ -1165,171 +1171,598 @@ public final Ix map(Func1 mapper) { return new IxMap(this, mapper); } + /** + * Emits the first maximum element according to the given comparator. + *

+ * The result's iterator() doesn't support remove(). + * @param comparator the comparator called with the latest maximum element and + * the current element; if it returns a positive value, the current element + * becomes the maximum element. + * @return the new Ix instance + * @throws NullPointerException if comparator is null + * @since 1.0 + * @see #min(Comparator) + */ public final Ix max(Comparator comparator) { return new IxMinMax(this, comparator, -1); } + /** + * Emits the first maximum element according to their natural order. + *

+ * The sequence may throw a ClassCastException if any of the elements is + * not self-comparable (i.e., doesn't implement the Comparable interface). + *

+ * The result's iterator() doesn't support remove(). + * @return the new Ix instance + * @since 1.0 + * @see #min() + */ @SuppressWarnings({ "rawtypes", "unchecked" }) public final Ix max() { return max((Comparator)SelfComparator.INSTANCE); } + /** + * Returns the first maximum integer value. + *

+ * The sequence may throw a ClassCastException if any of the elements is not + * an Integer object. + *

+ * The result's iterator() doesn't support remove(). + * @return the new Ix instance + * @since 1.0 + */ @SuppressWarnings("unchecked") public final Ix maxInt() { return new IxMaxInt((Ix)this); } + /** + * Returns the first maximum long value. + *

+ * The sequence may throw a ClassCastException if any of the elements is not + * a Long object. + *

+ * The result's iterator() doesn't support remove(). + * @return the new Ix instance + * @since 1.0 + */ @SuppressWarnings("unchecked") public final Ix maxLong() { return new IxMaxLong((Ix)this); } + /** + * Emits elements of this sequence followed by the elements of the other sequence. + *

+ * Note that mergeWith and concatWith operations are the same in the Iterable world. + *

+ * The result's iterator() forwards the call remove() to the current Iterator. + * @param other the other sequence to emits elements of + * @return the new Ix instance + * @throws NullPointerException if other is null + * @since 1.0 + * @see #concatWith(Iterable) + */ public final Ix mergeWith(Iterable other) { return concatWith(other); } + /** + * Emits the first minimum element according to the given comparator. + *

+ * The result's iterator() doesn't support remove(). + * @param comparator the comparator called with the latest minimum element and + * the current element; if it returns a negative value, the current element + * becomes the minimum element. + * @return the new Ix instance + * @throws NullPointerException if comparator is null + * @since 1.0 + * @see #max(Comparator) + */ public final Ix min(Comparator comparator) { return new IxMinMax(this, comparator, 1); } + /** + * Emits the first minimum element according to their natural order. + *

+ * The sequence may throw a ClassCastException if any of the element is + * not self-comparable (i.e., doesn't implement the Comparable interface). + *

+ * The result's iterator() doesn't support remove(). + * @return the new Ix instance + * @since 1.0 + * @see #min() + */ @SuppressWarnings({ "rawtypes", "unchecked" }) public final Ix min() { return min((Comparator)SelfComparator.INSTANCE); } + /** + * Returns the first minimum integer value. + *

+ * The sequence may throw a ClassCastException if any of the elements is not + * an Integer object. + *

+ * The result's iterator() doesn't support remove(). + * @return the new Ix instance + * @since 1.0 + */ @SuppressWarnings("unchecked") public final Ix minInt() { return new IxMinInt((Ix)this); } + /** + * Returns the first minimum long value. + *

+ * The sequence may throw a ClassCastException if any of the elements is not + * a Long object. + *

+ * The result's iterator() doesn't support remove(). + * @return the new Ix instance + * @since 1.0 + */ @SuppressWarnings("unchecked") public final Ix minLong() { return new IxMinLong((Ix)this); } + /** + * Orders elements according to their natural order. + *

+ * The sequence may throw a ClassCastException if any of the elements is not + * a self-comparable object (i.e., doesn't implement the Comparable interface). + *

+ * The result's iterator() doesn't support remove(). + * @return the new Ix instance + * @since 1.0 + * @see #orderByReverse() + * @see #orderBy(Comparator) + */ @SuppressWarnings({ "unchecked", "rawtypes" }) public final Ix orderBy() { return orderBy((Comparator)SelfComparator.INSTANCE); } + /** + * Orders elements according to the comparator. + *

+ * The result's iterator() doesn't support remove(). + * @param comparator the comparator comparing two elements; if it returns a negative value, + * the first element will be before the second; if it returns a positive value, + * the first element will be after the second. + * @return the new Ix instance + * @throws NullPointerException if comparator is null + * @since 1.0 + * @see #orderBy() + * @see #orderByReverse(Comparator) + */ public final Ix orderBy(Comparator comparator) { - return new IxOrderBy(this, IdentityHelper.instance(), comparator, 1); + return new IxOrderBy(this, IdentityHelper.instance(), nullCheck(comparator, "comparator is null"), 1); } + /** + * Orders elements according to the natural order of the extracted keys from these elements. + *

+ * The result's iterator() doesn't support remove(). + * @param the key type + * @param keySelector the function receiving each element and returns a self-comparable key for them. + * @return the new Ix instance + * @throws NullPointerException if keySelector is null + * @since 1.0 + * @see #orderByReverse(Func1) + */ public final > Ix orderBy(Func1 keySelector) { - return new IxOrderBy(this, keySelector, SelfComparator.INSTANCE, 1); + return new IxOrderBy(this, nullCheck(keySelector, "keySelector is null"), SelfComparator.INSTANCE, 1); } + /** + * Orders elements according to their reverse natural order. + *

+ * The sequence may throw a ClassCastException if any of the elements is not + * a self-comparable object (i.e., doesn't implement the Comparable interface). + *

+ * The result's iterator() doesn't support remove(). + * @return the new Ix instance + * @since 1.0 + * @see #orderBy() + * @see #orderByReverse(Comparator) + */ @SuppressWarnings({ "unchecked", "rawtypes" }) public final Ix orderByReverse() { return orderByReverse((Comparator)SelfComparator.INSTANCE); } + /** + * Orders elements according to the reversed comparator. + *

+ * The result's iterator() doesn't support remove(). + * @param comparator the comparator comparing two elements; if it returns a negative value, + * the first element will be after the second; if it returns a positive value, + * the first element will be before the second. + * @return the new Ix instance + * @throws NullPointerException if comparator is null + * @since 1.0 + * @see #orderByReverse() + * @see #orderBy(Comparator) + */ public final Ix orderByReverse(Comparator comparator) { - return new IxOrderBy(this, IdentityHelper.instance(), comparator, -1); + return new IxOrderBy(this, IdentityHelper.instance(), nullCheck(comparator, "comparator is null"), -1); } + /** + * Orders elements according to the reverse natural order of the extracted keys from these elements. + *

+ * The result's iterator() doesn't support remove(). + * @param the key type + * @param keySelector the function receiving each element and returns a self-comparable key for them. + * @return the new Ix instance + * @throws NullPointerException if keySelector is null + * @since 1.0 + * @see #orderByReverse(Func1) + */ public final > Ix orderByReverse(Func1 keySelector) { - return new IxOrderBy(this, keySelector, SelfComparator.INSTANCE, -1); + return new IxOrderBy(this, nullCheck(keySelector, "keySelector is null"), SelfComparator.INSTANCE, -1); } + /** + * Shares an underlying Iterator that is consumed only once and each created iterator() that calls + * next() will receive the elements; other iterator() instances may receive different or no elements + * at all. + *

+ * The result's iterator() doesn't support remove(). + * @return the new iterator sequence + * @since 1.0 + */ public final Ix publish() { return new IxPublish(this); } + /** + * Shares an Iterator, exposed as an Ix sequence, for the duration of the transform function called + * for each iterator() invocation and emits elements of the resulting iterable sequence of the function. + *

+ * The result's iterator() doesn't support remove(). + * @param the result value type + * @param transform the function that receives an Ix instance sharing a single underlying Iterator to this + * sequence and returns another Iterable to be the result sequence + * @return the new Iterable sequence + * @throws NullPointerException if transform is null + * @since 1.0 + */ public final Ix publish(Func1, ? extends Iterable> transform) { - return new IxPublishSelector(this, transform); + return new IxPublishSelector(this, nullCheck(transform, "transfrom is null")); } + /** + * Reduces the elements of this sequence into a single value via a reducer function. + *

+ * The result's iterator() doesn't support remove(). + * @param reducer the function that receives the previous reduced element (or the first) and the current element + * and returns a new reduced element + * @return the new Ix instance + * @throws NullPointerException if reducer is null + * @since 1.0 + * @see #reduce(Func0, Func2) + */ public final Ix reduce(Func2 reducer) { - return new IxAggregate(this, reducer); + return new IxAggregate(this, nullCheck(reducer, "reducer is null")); } + /** + * Given a per-iterator() initial value, reduces the elements of this sequence into a single + * value via a reducer function. + *

+ * The result's iterator() doesn't support remove(). + * @param the reduced value type + * @param initialFactory a function called for each iterator() invocation and returns the first + * reduced value + * @param reducer the function called with the previous (or initial) reduced value and the current element + * and returns a new reduced value + * @return the new Ix instance + * @throws NullPointerException if initialFactory or reducer is null + * @since 1.0 + * @see #reduce(Func2) + */ public final Ix reduce(Func0 initialFactory, Func2 reducer) { return new IxReduce(this, initialFactory, reducer); } + /** + * Removes those elements via Iterator.remove() from this sequence that match the + * given predicate. + *

+ * The result's iterator() forwards the calls to remove() to this' Iterator. + * @param predicate the function called with the current element and returns true + * if that particular element should be removed. + * @return the new Ix instance + * @throws NullPointerException if predicate is null + * @since 1.0 + * @see #retain(Pred) + */ public final Ix remove(Pred predicate) { - return new IxRemove(this, predicate); + return new IxRemove(this, nullCheck(predicate, "predicate is null")); } + /** + * Repeats this sequence indefinitely. + *

+ * The result's iterator() doesn't support remove(). + * @return the new Ix instance + * @since 1.0 + */ public final Ix repeat() { return concat(repeatValue(this)); } + /** + * Repeats this sequence at most the given number of times. + *

A count of zero will yield an empty sequence, a count of one + * will yield a sequence with only one element and so forth. + *

+ * The result's iterator() doesn't support remove(). + * @param times the number of times to emit the value, non-negative + * @return the new Ix instance + * @throws IllegalArgumentException if count is negative + * @since 1.0 + */ public final Ix repeat(long times) { return concat(repeatValue(this, times)); } - public final Ix repeat(Pred0 predicate) { - return concat(repeatValue(this, predicate)); + /** + * Repeats this sequence if the given predicate returns true after the sequence + * completes in a round. + *

+ * The result's iterator() doesn't support remove(). + * @param stopPredicate the predicate called before any emission; returning + * false keeps repeating the value, returning true terminates the sequence + * @return the new Ix instance + * @throws NullPointerException if stopPredicate is null + * @since 1.0 + */ + public final Ix repeat(Pred0 stopPredicate) { + return concat(repeatValue(this, stopPredicate)); } - public final Ix repeat(long times, Pred0 predicate) { - return concat(repeatValue(this, times, predicate)); + /** + * Repeats this sequence if the given predicate returns true after the sequence + * completes in a round or at most the given number of times. + *

+ * A count of zero will yield an empty sequence, a count of one + * will yield a sequence with only one element and so forth. + *

+ * The result's iterator() doesn't support remove(). + * @param times the number of times to emit the value, non-negative + * @param stopPredicate the predicate called before any emission; returning + * false keeps repeating the value, returning true terminates the sequence + * @return the new Ix instance + * @throws IllegalArgumentException if count is negative + * @throws NullPointerException if stopPredicate is null + * @since 1.0 + */ + public final Ix repeat(long times, Pred0 stopPredicate) { + return concat(repeatValue(this, times, stopPredicate)); } + /** + * Caches and replays all elements of this sequence to consumers of this' iterator(). + *

+ * The result's iterator() doesn't support remove(). + * @return the new Ix instance + * @since 1.0 + */ public final Ix replay() { return new IxReplay(this); } + /** + * Caches and replays the last {@code size} elements of this sequence to consumers of this' iterator(). + *

+ * Consumption by any of the iterator() may move the source sequence forward and subsequent iterator() + * consumers may get a different set of values + *

+ * The result's iterator() doesn't support remove(). + * @param size the maximum number of elements to keep replaying to new iterator() consumers, positive + * @return the new Ix instance + * @throws IllegalArgumentException if size is non-positive + * @since 1.0 + */ public final Ix replay(int size) { - return new IxReplaySize(this, size); + return new IxReplaySize(this, positive(size, "size")); } + /** + * Caches and replays the elements of this sequence for the duration of the given transform function + * without consuming this sequence multiple times. + *

+ * The result's iterator() doesn't support remove(). + * @param the result value type + * @param transform the function receiving a view into the cache and returns an Iterable sequence whose + * elements will be emitted by this Ix. + * @return the new Ix instance + * @throws NullPointerException + * @since 1.0 + */ public final Ix replay(Func1, ? extends Iterable> transform) { - return new IxReplaySelector(this, transform); + return new IxReplaySelector(this, nullCheck(transform, "transformer is null")); } + /** + * Caches and replays the the last {@code size} elements of this sequence for the duration of the given transform function + * without consuming this sequence multiple times. + *

+ * Consumption by any of the inner Ix' iterator() may move the shared sequence forward and subsequent iterator() + * consumers may get a different set of values + *

+ * The result's iterator() doesn't support remove(). + * @param the result value type + * @param size the maximum number of elements to keep replaying to new inner Ix iterator() consumers, positive + * @param transform the function receiving a view into the cache and returns an Iterable sequence whose + * elements will be emitted by this Ix. + * @return the new Ix instance + * @throws NullPointerException + * @since 1.0 + */ public final Ix replay(int size, Func1, ? extends Iterable> transform) { - return new IxReplaySizeSelector(this, size, transform); + return new IxReplaySizeSelector(this, positive(size, "size"), nullCheck(transform, "transform is null")); } + /** + * Removes those elements via Iterator.remove() from this sequence that don't match the + * given predicate. + *

+ * The result's iterator() forwards the calls to remove() to this' Iterator. + * @param predicate the function called with the current element and returns false + * if that particular element should be removed. + * @return the new Ix instance + * @throws NullPointerException if predicate is null + * @since 1.0 + * @see #remove(Pred) + */ public final Ix retain(Pred predicate) { - return new IxRetain(this, predicate); + return new IxRetain(this, nullCheck(predicate, "predicate is null")); } + /** + * Plays this sequence in reverse. + *

+ * The reversal requires consuming the entire sequence and doesn't work with + * infinite sequences. + *

+ * The result's iterator() doesn't support remove(). + * @return the new Ix instance + * @since 1.0 + */ public final Ix reverse() { return new IxReverse(this); } + /** + * Performs a running accumulation, that is, returns intermediate elements returned by the + * scanner function. + *

+ * The result's iterator() doesn't support remove(). + * @param scanner the function that receives the previous (or first) accumulated element and the current + * element and returns a value to be emitted and to become the accumulated element + * @return the new Ix instance + * @throws NullPointerException if scanner is null + * @since 1.0 + */ public final Ix scan(Func2 scanner) { - return new IxScan(this, scanner); + return new IxScan(this, nullCheck(scanner, "scanner is null")); } + /** + * Performs a running accumulation, that is, returns intermediate elements returned by the + * scanner function, starting with a per-iterator initial value. + *

+ * The result's iterator() doesn't support remove(). + * @param the accumulated value type + * @param initialFactory function called for each iterator() and returns the initial accumulator value + * @param scanner the function that receives the previous (or first) accumulated element and the current + * element and returns a value to be emitted and to become the accumulated element + * @return the new Ix instance + * @throws NullPointerException if initialFactory or scanner is null + * @since 1.0 + */ public final Ix scan(Func0 initialFactory, Func2 scanner) { - return new IxScanSeed(this, initialFactory, scanner); + return new IxScanSeed(this, nullCheck(initialFactory, "initialFactory is null"), nullCheck(scanner, "scanner is null")); } + /** + * Determines if two sequences have the same elements in the same order and are the same length based + * on null-safe object equality. + *

+ * The result's iterator() doesn't support remove(). + * @param other the other sequence to compare with + * @return the new Ix instance + * @throws NullPointerException if other is null + * @since 1.0 + */ public final Ix sequenceEqual(Iterable other) { - return sequenceEqual(other, EqualityHelper.INSTANCE); + return sequenceEqual(nullCheck(other, "other is null"), EqualityHelper.INSTANCE); } + /** + * Determines if two sequences have the same elements in the same order and are the same length based + * on the given comparer's boolean value. + *

+ * The result's iterator() doesn't support remove(). + * @param other the other sequence to compare with + * @param comparer the predicate receiving elements from this and the other sequence and returns true if those + * elements are equal + * @return the new Ix instance + * @throws NullPointerException if other is null + * @since 1.0 + */ public final Ix sequenceEqual(Iterable other, Pred2 comparer) { - return new IxSequenceEqual(this, other, comparer); + return new IxSequenceEqual(this, nullCheck(other, "other is null"), nullCheck(comparer, "comparer is null")); } + /** + * Skips the first n elements from this sequence. + *

+ * The result's iterator() forwards the calls to remove() to this' Iterator. + * @param n the elements to skip, non-positive values won't skip any elements + * @return the new Ix instance + * @since 1.0 + * @see #take(int) + */ public final Ix skip(int n) { - if (n == 0) { + if (n <= 0) { return this; } return new IxSkip(this, n); } + /** + * Skips the last n elements from this sequence. + *

+ * The result's iterator() doesn't support remove(). + * @param n the elements to skip, non-positive values won't skip any elements + * @return the new Ix instance + * @since 1.0 + * @see #takeLast(int) + */ public final Ix skipLast(int n) { - if (n == 0) { + if (n <= 0) { return this; } return new IxSkipLast(this, n); } + /** + * Skips the first elements while the given predicate returns true; once it returns false + * all subsequent elements are emitted. + *

+ * The result's iterator() forwards the calls to remove() to this' Iterator. + * @param predicate the predicate called with the current element and returns true + * to skip that element + * @return the new Ix instance + * @throws NullPointerException if predicate is null + * @since 1.0 + * @see #takeWhile(Pred) + */ public final Ix skipWhile(Pred predicate) { - return new IxSkipWhile(this, predicate); + return new IxSkipWhile(this, nullCheck(predicate, "predicate is null")); } - @SuppressWarnings("unchecked") + /** + * Emits elements of the given array followed by the elements of this sequence. + *

+ * The result's iterator() doesn't support remove(). + * @param values the array of values to emit first + * @return the new Ix instance + * @throws NullPointerException if values is null + * @since 1.0 + */ public final Ix startWith(T... values) { - return concatArray(fromArray(values), this); + return concat(fromArray(values), this); } @SuppressWarnings("unchecked")