Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ChunkBuilder#isEmpty method #8805

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions core-tests/shared/src/test/scala/zio/ChunkBuilderSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ object ChunkBuilderSpec extends ZIOBaseSpec {
test("toString") {
val builder = new ChunkBuilder.Boolean
assert(builder.toString)(equalTo("ChunkBuilder.Boolean"))
},
test("isEmpty") {
check(Gen.chunkOf1(Gen.boolean)) { as =>
val builder = new ChunkBuilder.Boolean
testIsEmpty(builder, builder.isEmpty, as)
}
}
),
suite("Byte")(
Expand All @@ -44,6 +50,12 @@ object ChunkBuilderSpec extends ZIOBaseSpec {
test("toString") {
val builder = new ChunkBuilder.Byte
assert(builder.toString)(equalTo("ChunkBuilder.Byte"))
},
test("isEmpty") {
check(Gen.chunkOf1(Gen.byte)) { as =>
val builder = new ChunkBuilder.Byte
testIsEmpty(builder, builder.isEmpty, as)
}
}
),
suite("Char")(
Expand All @@ -64,6 +76,12 @@ object ChunkBuilderSpec extends ZIOBaseSpec {
test("toString") {
val builder = new ChunkBuilder.Char
assert(builder.toString)(equalTo("ChunkBuilder.Char"))
},
test("isEmpty") {
check(Gen.chunkOf1(Gen.char)) { as =>
val builder = new ChunkBuilder.Char
testIsEmpty(builder, builder.isEmpty, as)
}
}
),
suite("Double")(
Expand All @@ -84,6 +102,12 @@ object ChunkBuilderSpec extends ZIOBaseSpec {
test("toString") {
val builder = new ChunkBuilder.Double
assert(builder.toString)(equalTo("ChunkBuilder.Double"))
},
test("isEmpty") {
check(Gen.chunkOf1(Gen.double)) { as =>
val builder = new ChunkBuilder.Double
testIsEmpty(builder, builder.isEmpty, as)
}
}
),
suite("Float")(
Expand All @@ -104,6 +128,12 @@ object ChunkBuilderSpec extends ZIOBaseSpec {
test("toString") {
val builder = new ChunkBuilder.Float
assert(builder.toString)(equalTo("ChunkBuilder.Float"))
},
test("isEmpty") {
check(Gen.chunkOf1(Gen.float)) { as =>
val builder = new ChunkBuilder.Float
testIsEmpty(builder, builder.isEmpty, as)
}
}
),
suite("Int")(
Expand All @@ -124,6 +154,12 @@ object ChunkBuilderSpec extends ZIOBaseSpec {
test("toString") {
val builder = new ChunkBuilder.Int
assert(builder.toString)(equalTo("ChunkBuilder.Int"))
},
test("isEmpty") {
check(Gen.chunkOf1(Gen.int)) { as =>
val builder = new ChunkBuilder.Int
testIsEmpty(builder, builder.isEmpty, as)
}
}
),
suite("Long")(
Expand All @@ -144,6 +180,12 @@ object ChunkBuilderSpec extends ZIOBaseSpec {
test("toString") {
val builder = new ChunkBuilder.Long
assert(builder.toString)(equalTo("ChunkBuilder.Long"))
},
test("isEmpty") {
check(Gen.chunkOf1(Gen.long)) { as =>
val builder = new ChunkBuilder.Long
testIsEmpty(builder, builder.isEmpty, as)
}
}
),
suite("Short")(
Expand All @@ -164,7 +206,48 @@ object ChunkBuilderSpec extends ZIOBaseSpec {
test("toString") {
val builder = new ChunkBuilder.Short
assert(builder.toString)(equalTo("ChunkBuilder.Short"))
},
test("isEmpty") {
check(Gen.chunkOf1(Gen.short)) { as =>
val builder = new ChunkBuilder.Short
testIsEmpty(builder, builder.isEmpty, as)
}
}
),
suite("Obj")(
test("addOne")(
check(Gen.chunkOf(Gen.string)) { as =>
val builder = ChunkBuilder.make[String]()
as.foreach(builder += _)
assert(builder.result())(equalTo(as))
}
),
test("addAll") {
check(Gen.chunkOf(Gen.string)) { as =>
val builder = ChunkBuilder.make[String]()
builder ++= as
assert(builder.result())(equalTo(as))
}
},
test("isEmpty") {
check(Gen.chunkOf1(Gen.string)) { as =>
val builder = new ChunkBuilder.Obj[String]
testIsEmpty(builder, builder.isEmpty, as)
}
}
)
)

private def testIsEmpty[A](builder: ChunkBuilder[A], check: => Boolean, as: NonEmptyChunk[A]): TestResult = {
val a0 = check
builder.sizeHint(16)
val a1 = check
builder += as(0)
val a2 = check
builder ++= as
val a3 = check
builder.clear()
val a4 = check
assertTrue(a0, a1, !a2, !a3, a4)
}
}
105 changes: 63 additions & 42 deletions core/shared/src/main/scala-2.13+/zio/ChunkBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,48 +45,7 @@ object ChunkBuilder {
* Constructs a generic `ChunkBuilder`.
*/
def make[A](): ChunkBuilder[A] =
new ChunkBuilder[A] {
var arrayBuilder: ArrayBuilder[A] = null
var size: SInt = -1
def addOne(a: A): this.type = {
if (arrayBuilder eq null) {
implicit val tag = Chunk.Tags.fromValue(a)
arrayBuilder = ArrayBuilder.make
if (size != -1) {
arrayBuilder.sizeHint(size)
}
}
try {
arrayBuilder.addOne(a)
} catch {
case _: ClassCastException =>
val as = arrayBuilder.result()
arrayBuilder = ArrayBuilder.make[AnyRef].asInstanceOf[ArrayBuilder[A]]
if (size != -1) {
arrayBuilder.sizeHint(size)
}
arrayBuilder.addAll(as)
arrayBuilder.addOne(a)
}
this
}
def clear(): Unit =
if (arrayBuilder ne null) {
arrayBuilder.clear()
}
def result(): Chunk[A] =
if (arrayBuilder eq null) {
Chunk.empty
} else {
Chunk.fromArray(arrayBuilder.result())
}
override def sizeHint(n: SInt): Unit =
if (arrayBuilder eq null) {
size = n
} else {
arrayBuilder.sizeHint(n)
}
}
new Obj[A]

/**
* Constructs a generic `ChunkBuilder` with size hint.
Expand Down Expand Up @@ -148,6 +107,8 @@ object ChunkBuilder {
self.lastByte == that.lastByte
case _ => false
}
def isEmpty: SBoolean =
maxBitIndex == 0
def result(): Chunk[SBoolean] = {
val bytes: Chunk[SByte] = Chunk.fromArray(arrayBuilder.result() :+ lastByte)
BitChunkByte(bytes, 0, 8 * (bytes.length - 1) + maxBitIndex)
Expand Down Expand Up @@ -182,6 +143,8 @@ object ChunkBuilder {
case that: Byte => self.arrayBuilder == that.arrayBuilder
case _ => false
}
def isEmpty: SBoolean =
arrayBuilder.length == 0
def result(): Chunk[SByte] =
Chunk.fromArray(arrayBuilder.result())
override def sizeHint(n: SInt): Unit =
Expand Down Expand Up @@ -212,6 +175,8 @@ object ChunkBuilder {
case that: Char => self.arrayBuilder == that.arrayBuilder
case _ => false
}
def isEmpty: SBoolean =
arrayBuilder.length == 0
def result(): Chunk[SChar] =
Chunk.fromArray(arrayBuilder.result())
override def sizeHint(n: SInt): Unit =
Expand Down Expand Up @@ -243,6 +208,8 @@ object ChunkBuilder {
case that: Double => self.arrayBuilder == that.arrayBuilder
case _ => false
}
def isEmpty: SBoolean =
arrayBuilder.length == 0
def result(): Chunk[SDouble] =
Chunk.fromArray(arrayBuilder.result())
override def sizeHint(n: SInt): Unit =
Expand Down Expand Up @@ -273,6 +240,8 @@ object ChunkBuilder {
case that: Float => self.arrayBuilder == that.arrayBuilder
case _ => false
}
def isEmpty: SBoolean =
arrayBuilder.length == 0
def result(): Chunk[SFloat] =
Chunk.fromArray(arrayBuilder.result())
override def sizeHint(n: SInt): Unit =
Expand Down Expand Up @@ -303,6 +272,8 @@ object ChunkBuilder {
case that: Int => self.arrayBuilder == that.arrayBuilder
case _ => false
}
def isEmpty: SBoolean =
arrayBuilder.length == 0
def result(): Chunk[SInt] =
Chunk.fromArray(arrayBuilder.result())
override def sizeHint(n: SInt): Unit =
Expand Down Expand Up @@ -333,6 +304,8 @@ object ChunkBuilder {
case that: Long => self.arrayBuilder == that.arrayBuilder
case _ => false
}
def isEmpty: SBoolean =
arrayBuilder.length == 0
def result(): Chunk[SLong] =
Chunk.fromArray(arrayBuilder.result())
override def sizeHint(n: SInt): Unit =
Expand Down Expand Up @@ -363,11 +336,59 @@ object ChunkBuilder {
case that: Short => self.arrayBuilder == that.arrayBuilder
case _ => false
}
def isEmpty: SBoolean =
arrayBuilder.length == 0
def result(): Chunk[SShort] =
Chunk.fromArray(arrayBuilder.result())
override def sizeHint(n: SInt): Unit =
arrayBuilder.sizeHint(n)
override def toString: String =
"ChunkBuilder.Short"
}

final class Obj[A] extends ChunkBuilder[A] {
Copy link
Member

@guizmaii guizmaii May 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you choose Obj as the name for this class? Why not something like ChunkBuilderLive for example? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly because it's meant for objects (i.e., non-primitives). But yeah Obj doesn't sound too great. We could go with a similar name as ArrayBuilder and use OfRef

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh ok I understand now. Thanks! I let you choose what you prefer :)

private[this] var arrayBuilder: ArrayBuilder[A] = null
private[this] var size: SInt = -1

def addOne(a: A): this.type = {
if (arrayBuilder eq null) {
implicit val tag = Chunk.Tags.fromValue(a)
arrayBuilder = ArrayBuilder.make
if (size != -1) {
arrayBuilder.sizeHint(size)
}
}
try {
arrayBuilder.addOne(a)
} catch {
case _: ClassCastException =>
val as = arrayBuilder.result()
arrayBuilder = ArrayBuilder.make[AnyRef].asInstanceOf[ArrayBuilder[A]]
if (size != -1) {
arrayBuilder.sizeHint(size)
}
arrayBuilder.addAll(as)
arrayBuilder.addOne(a)
}
this
}
def clear(): Unit =
if (arrayBuilder ne null) {
arrayBuilder.clear()
}
def isEmpty: SBoolean =
(arrayBuilder eq null) || arrayBuilder.length == 0
def result(): Chunk[A] =
if (arrayBuilder eq null) {
Chunk.empty
} else {
Chunk.fromArray(arrayBuilder.result())
}
override def sizeHint(n: SInt): Unit =
if (arrayBuilder eq null) {
size = n
} else {
arrayBuilder.sizeHint(n)
}
}
}
Loading