This is an automated email from the ASF dual-hosted git repository.

pjfanning pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko.git


The following commit(s) were added to refs/heads/main by this push:
     new 29b723f043 fix: eliminate it.isEmpty and double-traversal risk in 
CompactByteString.apply(IterableOnce[Byte]) (#2875)
29b723f043 is described below

commit 29b723f043bf5343e10c1835dd83c96751e3e56c
Author: PJ Fanning <[email protected]>
AuthorDate: Mon Apr 20 10:33:30 2026 +0200

    fix: eliminate it.isEmpty and double-traversal risk in 
CompactByteString.apply(IterableOnce[Byte]) (#2875)
    
    * fix: avoid it.isEmpty and double traversal in 
CompactByteString.apply(IterableOnce[Byte]), add tests
    
    Agent-Logs-Url: 
https://github.com/pjfanning/incubator-pekko/sessions/2f07e80b-5dd8-4504-9af4-8bcc5692f3d6
    
    Co-authored-by: pjfanning <[email protected]>
    
    * Optimize ByteString creation from IterableOnce
    
    ---------
    
    Co-authored-by: copilot-swe-agent[bot] 
<[email protected]>
    Co-authored-by: pjfanning <[email protected]>
---
 .../org/apache/pekko/util/ByteStringSpec.scala     | 39 ++++++++++++++++++++++
 .../scala/org/apache/pekko/util/ByteString.scala   |  5 ++-
 2 files changed, 41 insertions(+), 3 deletions(-)

diff --git 
a/actor-tests/src/test/scala/org/apache/pekko/util/ByteStringSpec.scala 
b/actor-tests/src/test/scala/org/apache/pekko/util/ByteStringSpec.scala
index ffdc3e4e8d..fcfc4fcca7 100644
--- a/actor-tests/src/test/scala/org/apache/pekko/util/ByteStringSpec.scala
+++ b/actor-tests/src/test/scala/org/apache/pekko/util/ByteStringSpec.scala
@@ -491,6 +491,45 @@ class ByteStringSpec extends AnyWordSpec with Matchers 
with Checkers {
       verify(byteString.copyToArray(_, 3, 3))(0, 0, 0)
     }
   }
+  "CompactByteString.apply(IterableOnce[Byte])" must {
+    "return empty for an empty collection" in {
+      (CompactByteString(Seq.empty[Byte]) should 
be).theSameInstanceAs(CompactByteString.empty)
+      (CompactByteString(List.empty[Byte]) should 
be).theSameInstanceAs(CompactByteString.empty)
+      (CompactByteString(Iterator.empty[Byte]) should 
be).theSameInstanceAs(CompactByteString.empty)
+    }
+    "return the correct bytes for a non-empty collection" in {
+      CompactByteString(Seq[Byte](1, 2, 3)) should ===(ByteString(1, 2, 3))
+      CompactByteString(List[Byte](10, 20)) should ===(ByteString(10, 20))
+      CompactByteString(Iterator.single(42.toByte)) should 
===(ByteString(42.toByte))
+    }
+    "return a CompactByteString" in {
+      CompactByteString(Seq[Byte](1, 2)).isCompact should ===(true)
+    }
+    "traverse the iterator only once" in {
+      var traversalCount = 0
+      val singleUse = new IterableOnce[Byte] {
+        def iterator: Iterator[Byte] = {
+          traversalCount += 1
+          Iterator[Byte](1, 2, 3)
+        }
+      }
+      val result = CompactByteString(singleUse)
+      traversalCount should ===(1)
+      result should ===(ByteString(1, 2, 3))
+    }
+    "traverse an empty single-use IterableOnce only once" in {
+      var traversalCount = 0
+      val singleUse = new IterableOnce[Byte] {
+        def iterator: Iterator[Byte] = {
+          traversalCount += 1
+          Iterator.empty[Byte]
+        }
+      }
+      val result = CompactByteString(singleUse)
+      traversalCount should ===(1)
+      (result should be).theSameInstanceAs(CompactByteString.empty)
+    }
+  }
   "ByteStrings" must {
     "drop" in {
       ByteStrings(ByteString1.fromString(""), 
ByteString1.fromString("")).drop(Int.MinValue) should ===(ByteString(""))
diff --git a/actor/src/main/scala/org/apache/pekko/util/ByteString.scala 
b/actor/src/main/scala/org/apache/pekko/util/ByteString.scala
index 4ca63a598e..a46e383334 100644
--- a/actor/src/main/scala/org/apache/pekko/util/ByteString.scala
+++ b/actor/src/main/scala/org/apache/pekko/util/ByteString.scala
@@ -2031,9 +2031,8 @@ object CompactByteString {
    * Creates a new CompactByteString by traversing bytes.
    */
   def apply(bytes: IterableOnce[Byte]): CompactByteString = {
-    val it = bytes.iterator
-    if (it.isEmpty) empty
-    else ByteString.ByteString1C(it.toArray)
+    val iter = bytes.iterator
+    if (iter.hasNext) ByteString.ByteString1C(iter.toArray) else empty
   }
 
   /**


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to