-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[data] add
ChunkBuilder
to create StrictOptimizedSeqFactory[Chunk] (#…
…889) Co-authored-by: Flavio Brasil <fwbrasil@users.noreply.github.com>
- Loading branch information
Showing
4 changed files
with
163 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package kyo | ||
|
||
import scala.collection.mutable.ArrayBuilder | ||
import scala.collection.mutable.ReusableBuilder | ||
import scala.reflect.ClassTag | ||
|
||
/** A **mutable** builder for creating Chunks. | ||
* | ||
* ChunkBuilder provides an efficient way to construct Chunks by incrementally adding elements. It can be reused after calling result(). | ||
* | ||
* @tparam A | ||
* the type of elements in the Chunk being built | ||
*/ | ||
sealed abstract class ChunkBuilder[A] extends ReusableBuilder[A, Chunk.Indexed[A]] | ||
object ChunkBuilder: | ||
|
||
/** Creates a new ChunkBuilder with no size hint. | ||
* | ||
* @tparam A | ||
* the type of elements in the Chunk to be built | ||
* @return | ||
* a new ChunkBuilder instance | ||
*/ | ||
def init[A]: ChunkBuilder[A] = init(0) | ||
|
||
/** Creates a new ChunkBuilder with a size hint. | ||
* | ||
* @tparam A | ||
* the type of elements in the Chunk to be built | ||
* @param hint | ||
* the expected number of elements to be added | ||
* @return | ||
* a new ChunkBuilder instance | ||
*/ | ||
def init[A](hint: Int): ChunkBuilder[A] = | ||
new ChunkBuilder[A]: | ||
var builder = Maybe.empty[ArrayBuilder[A]] | ||
var _hint = hint | ||
|
||
override def addOne(elem: A): this.type = | ||
builder match | ||
case Absent => | ||
val arr = ArrayBuilder.make[A](using ClassTag.Any.asInstanceOf[ClassTag[A]]) | ||
if _hint > 0 then arr.sizeHint(_hint) | ||
arr.addOne(elem) | ||
builder = Maybe(arr) | ||
case Present(arr) => discard(arr.addOne(elem)) | ||
end match | ||
this | ||
end addOne | ||
|
||
override def sizeHint(n: Int): Unit = | ||
_hint = n | ||
builder.foreach(_.sizeHint(n)) | ||
|
||
override def clear(): Unit = builder.foreach(_.clear()) | ||
|
||
override def result(): Chunk.Indexed[A] = | ||
val chunk = builder.fold(Chunk.indexedEmpty[A])(b => Chunk.fromNoCopy(b.result())) | ||
builder.foreach(_.clear()) | ||
chunk | ||
end result | ||
|
||
override def knownSize: Int = builder.fold(0)(_.knownSize) | ||
|
||
override def toString(): String = | ||
if _hint > 0 then s"ChunkBuilder(size = $knownSize, hint = $_hint)" | ||
else s"ChunkBuilder(size = $knownSize)" | ||
end init | ||
end ChunkBuilder |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package kyo | ||
|
||
class ChunkBuilderTest extends Test: | ||
|
||
"ChunkBuilder" - { | ||
"empty" in { | ||
val builder = ChunkBuilder.init[Int] | ||
assert(builder.result() == Chunk.empty[Int]) | ||
} | ||
|
||
"non-empty" in { | ||
val builder = ChunkBuilder.init[Int] | ||
builder.addOne(1) | ||
builder.addOne(2) | ||
builder.addOne(3) | ||
assert(builder.result() == Chunk(1, 2, 3)) | ||
} | ||
|
||
"clear" in { | ||
val builder = ChunkBuilder.init[Boolean](10) | ||
builder.addOne(true) | ||
builder.clear() | ||
assert(builder.knownSize == 0) | ||
builder.addOne(true) | ||
assert(builder.result() == Chunk(true)) | ||
} | ||
|
||
"reusable" in { | ||
val builder = ChunkBuilder.init[Int] | ||
builder.addOne(1) | ||
builder.addOne(2) | ||
assert(builder.result() == Chunk(1, 2)) | ||
builder.addOne(3) | ||
assert(builder.result() == Chunk(3)) | ||
} | ||
|
||
"hint" in { | ||
val builder = ChunkBuilder.init[Int](1000) | ||
(0 until 1000).foreach(builder.addOne) | ||
assert(builder.result().length == 1000) | ||
} | ||
|
||
"knownSize" in { | ||
val builder = ChunkBuilder.init[Int](20) | ||
assert(builder.knownSize == 0) | ||
(0 until 10).foreach(builder.addOne) | ||
assert(builder.knownSize == 10) | ||
} | ||
|
||
"toString" in { | ||
assert(ChunkBuilder.init[Int](10).toString() == "ChunkBuilder(size = 0, hint = 10)") | ||
assert(ChunkBuilder.init[Int].toString() == "ChunkBuilder(size = 0)") | ||
val builder = ChunkBuilder.init[Int] | ||
builder.sizeHint(1) | ||
assert(builder.toString() == "ChunkBuilder(size = 0, hint = 1)") | ||
val hinted = ChunkBuilder.init[Int] | ||
hinted.addOne(1) | ||
hinted.sizeHint(2) | ||
assert(hinted.toString() == "ChunkBuilder(size = 1, hint = 2)") | ||
} | ||
} | ||
end ChunkBuilderTest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters