diff --git a/src/main/kotlin/moe/kageru/sekwences/PeekableSequence.kt b/src/main/kotlin/moe/kageru/sekwences/PeekableSequence.kt new file mode 100644 index 0000000..cb155f2 --- /dev/null +++ b/src/main/kotlin/moe/kageru/sekwences/PeekableSequence.kt @@ -0,0 +1,37 @@ +package moe.kageru.sekwences + +class PeekableSequence(source: Sequence) : Sequence { + private val iterator: PeekableIterator = PeekableIterator(source.iterator()) + + override fun iterator(): Iterator = iterator + + fun peek(): T? = iterator.peek() +} + +internal class PeekableIterator(private val source: Iterator) : Iterator { + private var peeked: T? = null + override fun hasNext(): Boolean { + return source.hasNext() || peeked != null + } + + override fun next(): T { + return if (peeked == null) { + source.next() + } else { + val ret = peeked + peeked = null + ret!! + } + } + + fun peek(): T? { + return when { + peeked != null -> peeked + hasNext() -> { + peeked = next() + peeked!! + } + else -> null + } + } +} diff --git a/src/main/kotlin/moe/kageru/sekwences/Sekwences.kt b/src/main/kotlin/moe/kageru/sekwences/Sekwences.kt index 6284abc..3f08af5 100644 --- a/src/main/kotlin/moe/kageru/sekwences/Sekwences.kt +++ b/src/main/kotlin/moe/kageru/sekwences/Sekwences.kt @@ -18,3 +18,12 @@ fun Sequence.coalesce(merger: (T, T) -> T?): Sequence { emptySequence() } } + +/** + * Modifies the current [Sequence] by adding a peek() method + * that returns the next element or null without advancing the sequence. + * Calling peek() multiple times without next() will return the same value. + */ +fun Sequence.peekable(): PeekableSequence { + return PeekableSequence(this) +} diff --git a/src/test/kotlin/moe/kageru/sekwences/SekwencesTest.kt b/src/test/kotlin/moe/kageru/sekwences/CoalesceTest.kt similarity index 97% rename from src/test/kotlin/moe/kageru/sekwences/SekwencesTest.kt rename to src/test/kotlin/moe/kageru/sekwences/CoalesceTest.kt index 07b9404..4e6ec9d 100644 --- a/src/test/kotlin/moe/kageru/sekwences/SekwencesTest.kt +++ b/src/test/kotlin/moe/kageru/sekwences/CoalesceTest.kt @@ -3,7 +3,7 @@ package moe.kageru.sekwences import io.kotlintest.shouldBe import io.kotlintest.specs.ShouldSpec -class SekwencesTest : ShouldSpec({ +class CoalesceTest : ShouldSpec({ "should merge numbers" { val input = sequenceOf(1, 2, 3, 4, 5, 6, 4) val output = input.coalesce { first, second -> diff --git a/src/test/kotlin/moe/kageru/sekwences/PeekableTest.kt b/src/test/kotlin/moe/kageru/sekwences/PeekableTest.kt new file mode 100644 index 0000000..082ad9d --- /dev/null +++ b/src/test/kotlin/moe/kageru/sekwences/PeekableTest.kt @@ -0,0 +1,24 @@ +package moe.kageru.sekwences + +import io.kotlintest.shouldBe +import io.kotlintest.specs.ShouldSpec + +class PeekableTest : ShouldSpec({ + "peek should return correct values" { + val input = sequenceOf(1, 2, 3, 4).peekable() + input.peek() shouldBe 1 + input.peek() shouldBe input.peek() + input.iterator().next() shouldBe 1 + input.peek() shouldBe 2 + input.iterator().next() shouldBe 2 + input.iterator().next() shouldBe 3 + input.iterator().next() shouldBe 4 + input.peek() shouldBe null + } + + "sequence should operate normally" { + val input = sequenceOf(1, 2, 3, 4).peekable() + input.peek() shouldBe 1 + input.map { it * it }.toList() shouldBe listOf(1, 4, 9, 16) + } +})