package com.codepoetics.protonpack; import java.util.*; import java.util.function.Consumer; class GroupRunsSpliterator<T> implements Spliterator<List<T>> { private Spliterator<T> source; private Comparator<T> comparator; class Box<Y>{ public Y item; } Optional<T> last = Optional.empty(); public GroupRunsSpliterator(Spliterator<T> source, Comparator<T> comparator) { this.source = source; this.comparator = comparator; } @Override public boolean tryAdvance(Consumer<? super List<T>> action) { Box<T> current = new Box<>(); List<T> neighbors = new LinkedList<>(); Boolean runBroken = false; if(last.isPresent()){ neighbors.add(last.get()); } for(;;){ if(source.tryAdvance(i -> current.item = i)) { if( !last.isPresent() || comparator.compare(current.item, last.get()) == 0) { neighbors.add(current.item); } else{ runBroken = true; } last = Optional.of(current.item); if(runBroken){ action.accept(neighbors); return true; } } // read to the end and its the last run else if(!neighbors.isEmpty()){ action.accept(neighbors); last = Optional.empty(); return true; } // source is empty else { return false; } } } @Override public Spliterator<List<T>> trySplit() { return null; } @Override public long estimateSize() { return source.estimateSize(); } @Override public int characteristics() { return source.characteristics() & ~(Spliterator.SIZED | Spliterator.ORDERED); } }