Class TupleSpliterator<T>

java.lang.Object
uk.ac.ebi.utils.collections.TupleSpliterator<T>
Type Parameters:
T -
All Implemented Interfaces:
Spliterator<T[]>

public class TupleSpliterator<T> extends Object implements Spliterator<T[]>
A Tuple Spliterator

Takes an array of spliterators and returns a spliterator of tuples. Each tuple is built by taking the next element of each spliterator. The iteration stops as soon as there is at least one spliterator which of Spliterator.tryAdvance(Consumer) method returns false.

Parallelism support is limited: trySplit() succeeds as long as all the underlining spliterators are able to return prefixes having all the same size (tails of different size have chances to be managed by the behaviour of tryAdvance(Consumer), by cutting results at the shortest one).

Another restriction is that all base spliterators must be Spliterator.IMMUTABLE and non-Spliterator.CONCURRENT.

See also StreamUtils.tupleStream(boolean, java.util.stream.Stream...) and uk.ac.ebi.utils.streams.StreamUtilsTest for usage examples.

Author:
brandizi
Date:
26 Jul 2017
  • Constructor Details

    • TupleSpliterator

      public TupleSpliterator(Spliterator<? extends T>[] spliterators)
      Initialises with base spliterators. See above for details. @see also characteristics().
  • Method Details

    • of

      @SafeVarargs public static <TT> TupleSpliterator<TT> of(Spliterator<? extends TT>... spliterators)
      Just a facility to avoid too much generics fiddling.
    • tryAdvance

      public boolean tryAdvance(Consumer<? super T[]> action)
      As explained above, if all the underlining spliterators have an element to return (ie, their tryAdvance()) is invoked to get the element they have to return and the return value checked to be true), a tuple is built with all such elements and then passed to the action parameter. If that doens't happen, returns false and the action here is not invoked.
      Specified by:
      tryAdvance in interface Spliterator<T>
    • trySplit

      public Spliterator<T[]> trySplit()
      A splits succeeds when all the base spliterators return a prefix of the same length. If that is the case, the new split result will be a new TupleSpliterator based on the prefixes returned by the #trySplit() operation invoked upon the base spliterators. This iterator is left with the base iterators it already has, so with its tails. Due to the behaviour of tryAdvance(Consumer), such tails can have different sizes, they'll determine a tuple iterator sized like the shortest tail. Examples (assume the splits happen as described)
         TupleIterator 1:
           1, 2, 3, 4, 5, 6 => 1, 2, 3 | 4, 5, 6
           a, b, c, d, e, f => a, b, c | d, e, f
           
         TupleIterator 2:
           1, 2, 3, 4, 5, 6 => 1, 2, 3 | 4, 5, 6
           a, b, c, d       => a, b, c | d
       
      trySplit() over the second tuple spliterator will return a tuple iterator yielding 3 elements (1a, 2b, 3c) and will leave an original spliterator with one element only (4d).
      Specified by:
      trySplit in interface Spliterator<T>
    • estimateSize

      public long estimateSize()
      This is the shortest size found in base spliterators. Hence, it will be Long.MAX_VALUE if all of them return that, including when they are infinite or don't know their count. Having a non-precise result doesn't prevent trySplit() from splitting the way we requires.
      Specified by:
      estimateSize in interface Spliterator<T>
    • characteristics

      public int characteristics()
      As a minimum, this will contain NONNULL | DISTINCT | IMMUTABLE. It will never contain SORTED, CONCURRENT. Might contain SIZED, SUBSIZED, ORDERED, if all the base spliterators do. Details to explain this are:
      • SORTED, we don't currently provide a Spliterator.getComparator() and hence this is not set.
      • DISTINCT, this is set, we return arrays and they're all technically distinct (as per the default Object.equals(Object))
      • CONCURRENT, is not set, we're IMMUTABLE
      • IMMUTABLE, this is set, we expect base spliterators to be immutable too (or that you know what you're doing)
      • SIZED, SUBSIZED, ORDERED, are set for the result if all the base spliterators have these flags
      • NONNULL is always set for the result, for its items are non-null tuples, which of elements might be null
      Specified by:
      characteristics in interface Spliterator<T>