Skip to content

Commit

Permalink
Add Iterator
Browse files Browse the repository at this point in the history
  • Loading branch information
Luka Jacobowitz committed Aug 9, 2018
1 parent 0c4cc5d commit 2854651
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 5 deletions.
2 changes: 1 addition & 1 deletion bench/src/main/scala/cats/bench/CatenableBench.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import cats.data.Catenable
import org.openjdk.jmh.annotations.{Benchmark, Scope, State}

@State(Scope.Thread)
class CatenableBenchmark {
class CatenableBench {

private val smallCatenable = Catenable(1, 2, 3, 4, 5)
private val smallVector = Vector(1, 2, 3, 4, 5)
Expand Down
35 changes: 31 additions & 4 deletions core/src/main/scala/cats/data/Catenable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -148,14 +148,13 @@ sealed abstract class Catenable[+A] {
}

/** Applies the supplied function to each element, left to right. */
private final def foreach(f: A => Unit): Unit =
foreachUntil { a => f(a); false }
private final def foreach(f: A => Unit): Unit = foreachUntil { a => f(a); false }

/** Applies the supplied function to each element, left to right, but stops when true is returned */
private final def foreachUntil(f: A => Boolean): Unit = {
var c: Catenable[A] = this
val rights = new collection.mutable.ArrayBuffer[Catenable[A]]
// scalastyle:off null
// scalastyle:off null return
while (c ne null) {
c match {
case Empty =>
Expand All @@ -175,9 +174,12 @@ sealed abstract class Catenable[+A] {
case Append(l, r) => c = l; rights += r
}
}
// scalastyle:on null
// scalastyle:on null return
}


final def iterator: Iterator[A] = new CatenableIterator[A](this)

/** Returns the number of elements in this structure */
final def length: Int = {
var i: Int = 0
Expand Down Expand Up @@ -276,6 +278,31 @@ object Catenable extends CatenableInstances {
}
case _ => fromSeq(as)
}

class CatenableIterator[A](self: Catenable[A]) extends Iterator[A] {
var c: Catenable[A] = if (self.isEmpty) null else self
val rights = new collection.mutable.ArrayBuffer[Catenable[A]]

override def hasNext: Boolean = c ne null

override def next(): A = {
@tailrec def go: A = c match {
case Empty =>
go // This can't happen
case Singleton(a) =>
c =
if (rights.isEmpty) null
else rights.reduceLeft((x, y) => Append(y, x))
rights.clear()
a
case Append(l, r) =>
c = l
rights += r
go
}
go
}
}
}

private[data] sealed abstract class CatenableInstances {
Expand Down
6 changes: 6 additions & 0 deletions tests/src/test/scala/cats/tests/CatenableSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,10 @@ class CatenableSuite extends CatsSuite {
Catenable.fromSeq(ci.toVector) === ci
}
}

test("fromSeq . toList . iterator is id") {
forAll { (ci: Catenable[Int]) =>
Catenable.fromSeq(ci.iterator.toList) === ci
}
}
}

0 comments on commit 2854651

Please sign in to comment.