package moe.kageru.sekwences /** * Returns a sequences that optionally merges adjacent elements. * Heavily inspired by Itertools.coalesce() from the Rust crate. * * https://docs.rs/itertools/0.8.0/itertools/trait.Itertools.html#method.coalesce */ fun Sequence.coalesce(merger: (T, T) -> T?): Sequence { return if (this.iterator().hasNext()) { CoalescingSequence(this, merger) } else { emptySequence() } } class CoalescingSequence(private val source: Sequence, private inline val merger: (T, T) -> T?) : Sequence { override fun iterator(): Iterator { return CoalescingIterator(source.iterator(), merger) } } class CoalescingIterator(private val source: Iterator, private inline val merger: (T, T) -> T?) : Iterator { private var previous: T = if (source.hasNext()) source.next() else error("Please don’t pass empty iterators in here") private var hasNext = true override fun hasNext() = hasNext override tailrec fun next(): T { if (!source.hasNext()) { hasNext = false return previous } val current = source.next() val merged = merger(previous, current) // If the elements can’t be merged, return the first, then save the second for next time. return if (merged == null) { val ret = previous previous = current ret } else { previous = merged next() } } }