This is an automated email from the ASF dual-hosted git repository.
fanningpj 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 78cfe25fe9 no need for separate Scala 2 and 3 ByteStrings (#2269)
78cfe25fe9 is described below
commit 78cfe25fe92b0bc9555d868a01b65d0e6a607a46
Author: PJ Fanning <[email protected]>
AuthorDate: Thu Sep 25 17:09:27 2025 +0100
no need for separate Scala 2 and 3 ByteStrings (#2269)
* no need for separate Scala 2 and 3 ByteStrings
* copy over some of the changes in Scala 3 ByteString
---
.../org/apache/pekko/util/ByteString.scala | 1505 --------------------
.../org/apache/pekko/util/ByteString.scala | 3 +-
2 files changed, 2 insertions(+), 1506 deletions(-)
diff --git a/actor/src/main/scala-2.13/org/apache/pekko/util/ByteString.scala
b/actor/src/main/scala-2.13/org/apache/pekko/util/ByteString.scala
deleted file mode 100644
index f9d8f281cb..0000000000
--- a/actor/src/main/scala-2.13/org/apache/pekko/util/ByteString.scala
+++ /dev/null
@@ -1,1505 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * license agreements; and to You under the Apache License, version 2.0:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * This file is part of the Apache Pekko project, which was derived from Akka.
- */
-
-/*
- * Copyright (C) 2009-2022 Lightbend Inc. <https://www.lightbend.com>
- */
-
-package org.apache.pekko.util
-
-import java.io.{ ByteArrayInputStream, InputStream, ObjectInputStream,
ObjectOutputStream, SequenceInputStream }
-import java.lang.{ Iterable => JIterable }
-import java.nio.{ ByteBuffer, ByteOrder }
-import java.nio.charset.{ Charset, StandardCharsets }
-import java.util.Base64
-
-import scala.annotation.{ nowarn, tailrec, varargs }
-import scala.collection.{ immutable, mutable }
-import scala.collection.immutable.{ IndexedSeq, IndexedSeqOps,
StrictOptimizedSeqOps, VectorBuilder }
-import scala.collection.mutable.{ Builder, WrappedArray }
-import scala.jdk.CollectionConverters._
-import scala.reflect.ClassTag
-
-object ByteString {
-
- /**
- * Creates a new ByteString by copying a byte array.
- */
- def apply(bytes: Array[Byte]): ByteString = CompactByteString(bytes)
-
- /**
- * Creates a new ByteString by copying bytes.
- */
- def apply(bytes: Byte*): ByteString = CompactByteString(bytes: _*)
-
- /**
- * Creates a new ByteString by iterating over bytes.
- */
- def apply(bytes: IterableOnce[Byte]): ByteString = CompactByteString(bytes)
-
- /**
- * Creates a new ByteString by converting from integral numbers to bytes.
- */
- def apply[T](bytes: T*)(implicit num: Integral[T]): ByteString =
- CompactByteString(bytes: _*)(num)
-
- /**
- * Creates a new ByteString by copying bytes from a ByteBuffer.
- */
- def apply(bytes: ByteBuffer): ByteString = CompactByteString(bytes)
-
- /**
- * Creates a new ByteString by encoding a String as UTF-8.
- */
- def apply(string: String): ByteString = apply(string, StandardCharsets.UTF_8)
-
- /**
- * Creates a new ByteString by encoding a String with a charset.
- */
- def apply(string: String, charset: String): ByteString =
CompactByteString(string, charset)
-
- /**
- * Creates a new ByteString by encoding a String with a charset.
- */
- def apply(string: String, charset: Charset): ByteString =
CompactByteString(string, charset)
-
- /**
- * Creates a new ByteString by copying a byte array.
- */
- def fromArray(array: Array[Byte]): ByteString = apply(array)
-
- /**
- * Unsafe API: Use only in situations you are completely confident that this
is what
- * you need, and that you understand the implications documented below.
- *
- * Creates a ByteString without copying the passed in byte array, unlike
other factory
- * methods defined on ByteString. This method of creating a ByteString saves
one array
- * copy and allocation and therefore can lead to better performance, however
it also means
- * that one MUST NOT modify the passed in array, or unexpected immutable
data structure
- * contract-breaking behavior will manifest itself.
- *
- * This API is intended for users who have obtained an byte array from some
other API, and
- * want wrap it into an ByteArray, and from there on only use that reference
(the ByteString)
- * to operate on the wrapped data. For all other intents and purposes,
please use the usual
- * apply and create methods - which provide the immutability guarantees by
copying the array.
- */
- def fromArrayUnsafe(array: Array[Byte]): ByteString = ByteString1C(array)
-
- /**
- * Creates a new ByteString by copying length bytes starting at offset from
- * an Array.
- */
- def fromArray(array: Array[Byte], offset: Int, length: Int): ByteString =
- CompactByteString.fromArray(array, offset, length)
-
- /**
- * Unsafe API: Use only in situations you are completely confident that this
is what
- * you need, and that you understand the implications documented below.
- *
- * Creates a ByteString without copying the passed in byte array, unlike
other factory
- * methods defined on ByteString. This method of creating a ByteString saves
one array
- * copy and allocation and therefore can lead to better performance, however
it also means
- * that one MUST NOT modify the passed in array, or unexpected immutable
data structure
- * contract-breaking behavior will manifest itself.
- *
- * This API is intended for users who have obtained an byte array from some
other API, and
- * want wrap it into an ByteArray, and from there on only use that reference
(the ByteString)
- * to operate on the wrapped data. For all other intents and purposes,
please use the usual
- * apply and create methods - which provide the immutability guarantees by
copying the array.
- */
- def fromArrayUnsafe(array: Array[Byte], offset: Int, length: Int):
ByteString = ByteString1(array, offset, length)
-
- /**
- * JAVA API
- * Creates a new ByteString by copying an int array by converting from
integral numbers to bytes.
- */
- @varargs
- def fromInts(array: Int*): ByteString =
- apply(array: _*)(scala.math.Numeric.IntIsIntegral)
-
- /**
- * Creates a new ByteString which will contain the UTF-8 representation of
the given String
- */
- def fromString(string: String): ByteString = apply(string)
-
- /**
- * Creates a new ByteString which will contain the representation of the
given String in the given charset
- */
- def fromString(string: String, charset: String): ByteString = apply(string,
charset)
-
- /**
- * Creates a new ByteString which will contain the representation of the
given String in the given charset
- */
- def fromString(string: String, charset: Charset): ByteString = apply(string,
charset)
-
- /**
- * Standard "UTF-8" charset
- */
- val UTF_8: String = StandardCharsets.UTF_8.name()
-
- /**
- * Creates a new ByteString by copying bytes out of a ByteBuffer.
- */
- def fromByteBuffer(buffer: ByteBuffer): ByteString = apply(buffer)
-
- val empty: ByteString = ByteString1C.empty
-
- /** Java API */
- def emptyByteString: ByteString = empty
-
- def newBuilder: ByteStringBuilder = new ByteStringBuilder
-
- /** Java API */
- def createBuilder: ByteStringBuilder = new ByteStringBuilder
-
- // implicit val canBuildFrom: CanBuildFrom[TraversableOnce[Byte], Byte,
ByteString] =
- // new CanBuildFrom[TraversableOnce[Byte], Byte, ByteString] {
- // override def apply(ignore: TraversableOnce[Byte]): ByteStringBuilder
= new ByteStringBuilder
- // }
-
- private[pekko] object ByteString1C extends Companion {
- val empty = new ByteString1C(Array.emptyByteArray)
-
- def fromString(s: String): ByteString1C = new
ByteString1C(s.getBytes(StandardCharsets.UTF_8))
- def apply(bytes: Array[Byte]): ByteString1C = new ByteString1C(bytes)
- val SerializationIdentity = 1.toByte
-
- def readFromInputStream(is: ObjectInputStream): ByteString1C = {
- val length = is.readInt()
- val arr = new Array[Byte](length)
- is.readFully(arr, 0, length)
- ByteString1C(arr)
- }
- }
-
- /**
- * A compact (unsliced) and unfragmented ByteString, implementation of
ByteString1C.
- */
- @SerialVersionUID(3956956327691936932L)
- final class ByteString1C private (private val bytes: Array[Byte]) extends
CompactByteString {
- def apply(idx: Int): Byte = bytes(idx)
-
- override def length: Int = bytes.length
-
- // Avoid `iterator` in performance sensitive code, call ops directly on
ByteString instead
- override def iterator: ByteIterator.ByteArrayIterator =
ByteIterator.ByteArrayIterator(bytes, 0, bytes.length)
-
- /** INTERNAL API */
- private[pekko] def toByteString1: ByteString1 = ByteString1(bytes, 0,
bytes.length)
-
- /** INTERNAL API */
- private[pekko] def byteStringCompanion = ByteString1C
-
- override def asByteBuffer: ByteBuffer = toByteString1.asByteBuffer
-
- override def asByteBuffers:
scala.collection.immutable.Iterable[ByteBuffer] = List(asByteBuffer)
-
- override def decodeString(charset: String): String =
- if (isEmpty) "" else new String(bytes, charset)
-
- override def decodeString(charset: Charset): String =
- if (isEmpty) "" else new String(bytes, charset)
-
- override def decodeBase64: ByteString =
- if (isEmpty) this else ByteString1C(Base64.getDecoder.decode(bytes))
-
- override def encodeBase64: ByteString =
- if (isEmpty) this else ByteString1C(Base64.getEncoder.encode(bytes))
-
- override def ++(that: ByteString): ByteString = {
- if (that.isEmpty) this
- else if (this.isEmpty) that
- else toByteString1 ++ that
- }
-
- override def take(n: Int): ByteString =
- if (n <= 0) ByteString.empty
- else if (n >= length) this
- else toByteString1.take(n)
-
- override def dropRight(n: Int): ByteString =
- if (n <= 0) this
- else toByteString1.dropRight(n)
-
- override def drop(n: Int): ByteString =
- if (n <= 0) this
- else toByteString1.drop(n)
-
- override def indexOf[B >: Byte](elem: B, from: Int): Int = {
- if (from >= length) -1
- else {
- var found = -1
- var i = math.max(from, 0)
- while (i < length && found == -1) {
- if (bytes(i) == elem) found = i
- i += 1
- }
- found
- }
- }
-
- override def indexOf(elem: Byte, from: Int): Int = {
- if (from >= length) -1
- else {
- var found = -1
- var i = math.max(from, 0)
- while (i < length && found == -1) {
- if (bytes(i) == elem) found = i
- i += 1
- }
- found
- }
- }
-
- override def slice(from: Int, until: Int): ByteString =
- if (from <= 0 && until >= length) this
- else if (from >= length || until <= 0 || from >= until) ByteString.empty
- else toByteString1.slice(from, until)
-
- private[pekko] override def writeToOutputStream(os: ObjectOutputStream):
Unit =
- toByteString1.writeToOutputStream(os)
-
- override def copyToBuffer(buffer: ByteBuffer): Int =
- writeToBuffer(buffer, offset = 0)
-
- /** INTERNAL API: Specialized for internal use, writing multiple
ByteString1C into the same ByteBuffer. */
- private[pekko] def writeToBuffer(buffer: ByteBuffer, offset: Int): Int = {
- val copyLength = Math.min(buffer.remaining, offset + length)
- if (copyLength > 0) {
- buffer.put(bytes, offset, copyLength)
- }
- copyLength
- }
-
- /** INTERNAL API: Specialized for internal use, appending ByteString1C to
a ByteStringBuilder. */
- private[pekko] def appendToBuilder(buffer: ByteStringBuilder) = {
- buffer.putByteArrayUnsafe(bytes)
- }
-
- override def copyToArray[B >: Byte](dest: Array[B], start: Int, len: Int):
Int = {
- val toCopy = math.min(math.min(len, bytes.length), dest.length - start)
- if (toCopy > 0) {
- Array.copy(bytes, 0, dest, start, toCopy)
- }
- toCopy
- }
-
- override def toArrayUnsafe(): Array[Byte] = bytes
-
- override def asInputStream: InputStream = new ByteArrayInputStream(bytes)
- }
-
- /** INTERNAL API: ByteString backed by exactly one array, with start / end
markers */
- private[pekko] object ByteString1 extends Companion {
- val empty: ByteString1 = new ByteString1(Array.emptyByteArray, 0, 0)
- def fromString(s: String): ByteString1 =
apply(s.getBytes(StandardCharsets.UTF_8))
- def apply(bytes: Array[Byte]): ByteString1 = apply(bytes, 0, bytes.length)
- def apply(bytes: Array[Byte], startIndex: Int, length: Int): ByteString1 =
- if (length == 0) empty
- else new ByteString1(bytes, Math.max(0, startIndex), Math.max(0, length))
-
- val SerializationIdentity = 0.toByte
-
- def readFromInputStream(is: ObjectInputStream): ByteString1 =
- ByteString1C.readFromInputStream(is).toByteString1
- }
-
- /**
- * An unfragmented ByteString.
- */
- final class ByteString1 private (private val bytes: Array[Byte], private val
startIndex: Int, val length: Int)
- extends ByteString
- with Serializable {
-
- def apply(idx: Int): Byte = bytes(checkRangeConvert(idx))
-
- // Avoid `iterator` in performance sensitive code, call ops directly on
ByteString instead
- override def iterator: ByteIterator.ByteArrayIterator =
- ByteIterator.ByteArrayIterator(bytes, startIndex, startIndex + length)
-
- private def checkRangeConvert(index: Int): Int = {
- if (0 <= index && length > index)
- index + startIndex
- else
- throw new IndexOutOfBoundsException(index.toString)
- }
-
- private[pekko] def writeToOutputStream(os: ObjectOutputStream): Unit = {
- os.writeInt(length)
- os.write(bytes, startIndex, length)
- }
-
- def isCompact: Boolean = length == bytes.length
-
- private[pekko] def byteStringCompanion = ByteString1
-
- override def dropRight(n: Int): ByteString =
- dropRight1(n)
-
- /** INTERNAL API */
- private[pekko] def dropRight1(n: Int): ByteString1 =
- if (n <= 0) this
- else if (length - n <= 0) ByteString1.empty
- else new ByteString1(bytes, startIndex, length - n)
-
- override def drop(n: Int): ByteString =
- if (n <= 0) this else drop1(n)
-
- /** INTERNAL API */
- private[pekko] def drop1(n: Int): ByteString1 = {
- val nextStartIndex = startIndex + n
- if (nextStartIndex >= bytes.length) ByteString1.empty
- else ByteString1(bytes, nextStartIndex, length - n)
- }
-
- override def take(n: Int): ByteString =
- if (n <= 0) ByteString.empty else take1(n)
-
- private[pekko] def take1(n: Int): ByteString1 =
- if (n >= length) this
- else ByteString1(bytes, startIndex, n)
-
- override def slice(from: Int, until: Int): ByteString =
- drop(from).take(until - Math.max(0, from))
-
- override def copyToBuffer(buffer: ByteBuffer): Int =
- writeToBuffer(buffer)
-
- /** INTERNAL API: Specialized for internal use, writing multiple
ByteString1C into the same ByteBuffer. */
- private[pekko] def writeToBuffer(buffer: ByteBuffer): Int = {
- val copyLength = Math.min(buffer.remaining, length)
- if (copyLength > 0) {
- buffer.put(bytes, startIndex, copyLength)
- }
- copyLength
- }
-
- def compact: CompactByteString =
- if (isCompact) ByteString1C(bytes) else ByteString1C(toArray)
-
- def asByteBuffer: ByteBuffer = {
- val buffer = ByteBuffer.wrap(bytes, startIndex, length).asReadOnlyBuffer
- if (buffer.remaining < bytes.length) buffer.slice
- else buffer
- }
-
- def asByteBuffers: scala.collection.immutable.Iterable[ByteBuffer] =
List(asByteBuffer)
-
- override def decodeString(charset: String): String =
- if (isEmpty) ""
- else new String(bytes, startIndex, length, charset)
-
- override def decodeString(charset: Charset): String = // avoids
Charset.forName lookup in String internals
- if (isEmpty) ""
- else new String(bytes, startIndex, length, charset)
-
- override def decodeBase64: ByteString =
- if (isEmpty) this
- else if (isCompact) ByteString1C(Base64.getDecoder.decode(bytes))
- else {
- val dst = Base64.getDecoder.decode(ByteBuffer.wrap(bytes, startIndex,
length))
- if (dst.hasArray) {
- if (dst.array.length == dst.remaining) ByteString1C(dst.array)
- else ByteString1(dst.array, dst.arrayOffset + dst.position(),
dst.remaining)
- } else CompactByteString(dst)
- }
-
- override def encodeBase64: ByteString =
- if (isEmpty) this
- else if (isCompact) ByteString1C(Base64.getEncoder.encode(bytes))
- else {
- val dst = Base64.getEncoder.encode(ByteBuffer.wrap(bytes, startIndex,
length))
- if (dst.hasArray) {
- if (dst.array.length == dst.remaining) ByteString1C(dst.array)
- else ByteString1(dst.array, dst.arrayOffset + dst.position(),
dst.remaining)
- } else CompactByteString(dst)
- }
-
- def ++(that: ByteString): ByteString = {
- if (that.isEmpty) this
- else if (this.isEmpty) that
- else
- that match {
- case b: ByteString1C => ByteStrings(this, b.toByteString1)
- case b: ByteString1 =>
- if ((bytes eq b.bytes) && (startIndex + length == b.startIndex))
- new ByteString1(bytes, startIndex, length + b.length)
- else ByteStrings(this, b)
- case bs: ByteStrings => ByteStrings(this, bs)
- }
- }
-
- override def indexOf[B >: Byte](elem: B, from: Int): Int = {
- if (from >= length) -1
- else {
- var found = -1
- var i = math.max(from, 0)
- while (i < length && found == -1) {
- if (bytes(startIndex + i) == elem) found = i
- i += 1
- }
- found
- }
- }
-
- override def indexOf(elem: Byte, from: Int): Int = {
- if (from >= length) -1
- else {
- var found = -1
- var i = math.max(from, 0)
- while (i < length && found == -1) {
- if (bytes(startIndex + i) == elem) found = i
- i += 1
- }
- found
- }
- }
-
- override def copyToArray[B >: Byte](dest: Array[B], start: Int, len: Int):
Int = {
- // min of the bytes available to copy, bytes there is room for in dest
and the requested number of bytes
- val toCopy = math.min(math.min(len, length), dest.length - start)
- if (toCopy > 0) {
- Array.copy(bytes, startIndex, dest, start, toCopy)
- }
- toCopy
- }
-
- protected def writeReplace(): AnyRef = new SerializationProxy(this)
-
- override def toArrayUnsafe(): Array[Byte] = {
- if (startIndex == 0 && length == bytes.length) bytes
- else toArray
- }
-
- override def asInputStream: InputStream =
- new ByteArrayInputStream(bytes, startIndex, length)
- }
-
- private[pekko] object ByteStrings extends Companion {
- def apply(bytestrings: Vector[ByteString1]): ByteString =
- new ByteStrings(bytestrings, bytestrings.foldLeft(0)(_ + _.length))
-
- def apply(bytestrings: Vector[ByteString1], length: Int): ByteString = new
ByteStrings(bytestrings, length)
-
- def apply(b1: ByteString1, b2: ByteString1): ByteString = compare(b1, b2)
match {
- case 3 => new ByteStrings(Vector(b1, b2), b1.length + b2.length)
- case 2 => b2
- case 1 => b1
- case 0 => ByteString.empty
- }
-
- def apply(b: ByteString1, bs: ByteStrings): ByteString = compare(b, bs)
match {
- case 3 => new ByteStrings(b +: bs.bytestrings, bs.length + b.length)
- case 2 => bs
- case 1 => b
- case 0 => ByteString.empty
- }
-
- def apply(bs: ByteStrings, b: ByteString1): ByteString = compare(bs, b)
match {
- case 3 => new ByteStrings(bs.bytestrings :+ b, bs.length + b.length)
- case 2 => b
- case 1 => bs
- case 0 => ByteString.empty
- }
-
- def apply(bs1: ByteStrings, bs2: ByteStrings): ByteString = compare(bs1,
bs2) match {
- case 3 => new ByteStrings(bs1.bytestrings ++ bs2.bytestrings, bs1.length
+ bs2.length)
- case 2 => bs2
- case 1 => bs1
- case 0 => ByteString.empty
- }
-
- // 0: both empty, 1: 2nd empty, 2: 1st empty, 3: neither empty
- def compare(b1: ByteString, b2: ByteString): Int =
- if (b1.isEmpty)
- if (b2.isEmpty) 0 else 2
- else if (b2.isEmpty) 1
- else 3
-
- val SerializationIdentity = 2.toByte
-
- def readFromInputStream(is: ObjectInputStream): ByteStrings = {
- val nByteStrings = is.readInt()
-
- val builder = new VectorBuilder[ByteString1]
- var length = 0
-
- builder.sizeHint(nByteStrings)
-
- var i = 0
- while (i < nByteStrings) {
- val bs = ByteString1.readFromInputStream(is)
- builder += bs
- length += bs.length
- i += 1
- }
- new ByteStrings(builder.result(), length)
- }
- }
-
- /**
- * A ByteString with 2 or more fragments.
- */
- final class ByteStrings private (private[pekko] val bytestrings:
Vector[ByteString1], val length: Int)
- extends ByteString
- with Serializable {
- if (bytestrings.isEmpty) throw new IllegalArgumentException("bytestrings
must not be empty")
- if (bytestrings.head.isEmpty) throw new
IllegalArgumentException("bytestrings.head must not be empty")
-
- def apply(idx: Int): Byte = {
- if (0 <= idx && idx < length) {
- var pos = 0
- var seen = 0
- var frag = bytestrings(pos)
- while (idx >= seen + frag.length) {
- seen += frag.length
- pos += 1
- frag = bytestrings(pos)
- }
- frag(idx - seen)
- } else throw new IndexOutOfBoundsException(idx.toString)
- }
-
- /** Avoid `iterator` in performance sensitive code, call ops directly on
ByteString instead */
- override def iterator: ByteIterator.MultiByteArrayIterator =
- ByteIterator.MultiByteArrayIterator(bytestrings.to(LazyList).map {
_.iterator })
-
- def ++(that: ByteString): ByteString = {
- if (that.isEmpty) this
- else if (this.isEmpty) that
- else
- that match {
- case b: ByteString1C => ByteStrings(this, b.toByteString1)
- case b: ByteString1 => ByteStrings(this, b)
- case bs: ByteStrings => ByteStrings(this, bs)
- }
- }
-
- private[pekko] def byteStringCompanion = ByteStrings
-
- def isCompact: Boolean = if (bytestrings.length == 1)
bytestrings.head.isCompact else false
-
- override def copyToBuffer(buffer: ByteBuffer): Int = {
- @tailrec def copyItToTheBuffer(buffer: ByteBuffer, i: Int, written:
Int): Int =
- if (i < bytestrings.length) copyItToTheBuffer(buffer, i + 1, written +
bytestrings(i).writeToBuffer(buffer))
- else written
-
- copyItToTheBuffer(buffer, 0, 0)
- }
-
- def compact: CompactByteString = {
- if (isCompact) bytestrings.head.compact
- else {
- val ar = new Array[Byte](length)
- var pos = 0
- bytestrings.foreach { b =>
- b.copyToArray(ar, pos, b.length)
- pos += b.length
- }
- ByteString1C(ar)
- }
- }
-
- def asByteBuffer: ByteBuffer = compact.asByteBuffer
-
- def asByteBuffers: scala.collection.immutable.Iterable[ByteBuffer] =
bytestrings.map { _.asByteBuffer }
-
- override def asInputStream: InputStream =
- new
SequenceInputStream(bytestrings.iterator.map(_.asInputStream).asJavaEnumeration)
-
- def decodeString(charset: String): String = compact.decodeString(charset)
-
- def decodeString(charset: Charset): String = compact.decodeString(charset)
-
- override def decodeBase64: ByteString = compact.decodeBase64
-
- override def encodeBase64: ByteString = compact.encodeBase64
-
- private[pekko] def writeToOutputStream(os: ObjectOutputStream): Unit = {
- os.writeInt(bytestrings.length)
- bytestrings.foreach(_.writeToOutputStream(os))
- }
-
- override def take(n: Int): ByteString =
- if (n <= 0) ByteString.empty
- else if (n >= length) this
- else take0(n)
-
- private[pekko] def take0(n: Int): ByteString = {
- @tailrec def go(last: Int, restToTake: Int): (Int, Int) = {
- val bs = bytestrings(last)
- if (bs.length > restToTake) (last, restToTake)
- else go(last + 1, restToTake - bs.length)
- }
-
- val (last, restToTake) = go(0, n)
-
- if (last == 0) bytestrings(last).take(restToTake)
- else if (restToTake == 0) new ByteStrings(bytestrings.take(last), n)
- else new ByteStrings(bytestrings.take(last) :+
bytestrings(last).take1(restToTake), n)
- }
-
- override def dropRight(n: Int): ByteString =
- if (0 < n && n < length) dropRight0(n)
- else if (n >= length) ByteString.empty
- else this
-
- private def dropRight0(n: Int): ByteString = {
- val byteStringsSize = bytestrings.length
- @tailrec def dropRightWithFullDropsAndRemainig(fullDrops: Int,
remainingToDrop: Int): ByteString = {
- val bs = bytestrings(byteStringsSize - fullDrops - 1)
- if (bs.length > remainingToDrop) {
- if (fullDrops == byteStringsSize - 1)
- bytestrings(0).dropRight(remainingToDrop)
- else if (remainingToDrop == 0)
- new ByteStrings(bytestrings.dropRight(fullDrops), length - n)
- else
- new ByteStrings(
- bytestrings.dropRight(fullDrops + 1) :+
bytestrings(byteStringsSize - fullDrops - 1)
- .dropRight1(remainingToDrop),
- length - n)
- } else {
- dropRightWithFullDropsAndRemainig(fullDrops + 1, remainingToDrop -
bs.length)
- }
- }
-
- dropRightWithFullDropsAndRemainig(0, n)
- }
-
- override def slice(from: Int, until: Int): ByteString =
- if (from <= 0 && until >= length) this
- else if (from > length || until <= from) ByteString.empty
- else drop(from).dropRight(length - until)
-
- override def drop(n: Int): ByteString =
- if (n <= 0) this
- else if (n >= length) ByteString.empty
- else drop0(n)
-
- private def drop0(n: Int): ByteString = {
- // impl note: could be optimised a bit by using VectorIterator instead,
- // however then we're forced to call .toVector which halfs
performance
- // We can work around that, as there's a Scala private method
"remainingVector" which is fast,
- // but let's not go into calling private APIs here just yet.
- @tailrec def findSplit(fullDrops: Int, remainingToDrop: Int): (Int, Int)
= {
- val bs = bytestrings(fullDrops)
- if (bs.length > remainingToDrop) (fullDrops, remainingToDrop)
- else findSplit(fullDrops + 1, remainingToDrop - bs.length)
- }
-
- val (fullDrops, remainingToDrop) = findSplit(0, n)
-
- if (remainingToDrop == 0)
- new ByteStrings(bytestrings.drop(fullDrops), length - n)
- else if (fullDrops == bytestrings.length - 1)
- bytestrings(fullDrops).drop(remainingToDrop)
- else
- new ByteStrings(bytestrings(fullDrops).drop1(remainingToDrop) +:
bytestrings.drop(fullDrops + 1), length - n)
- }
-
- override def indexOf[B >: Byte](elem: B, from: Int): Int = {
- if (from >= length) -1
- else {
- val byteStringsSize = bytestrings.size
-
- @tailrec
- def find(bsIdx: Int, relativeIndex: Int, bytesPassed: Int): Int = {
- if (bsIdx >= byteStringsSize) -1
- else {
- val bs = bytestrings(bsIdx)
-
- if (bs.length <= relativeIndex) {
- find(bsIdx + 1, relativeIndex - bs.length, bytesPassed +
bs.length)
- } else {
- val subIndexOf = bs.indexOf(elem, relativeIndex)
- if (subIndexOf < 0) {
- find(bsIdx + 1, relativeIndex - bs.length, bytesPassed +
bs.length)
- } else subIndexOf + bytesPassed
- }
- }
- }
-
- find(0, math.max(from, 0), 0)
- }
- }
-
- override def indexOf(elem: Byte, from: Int): Int = {
- if (from >= length) -1
- else {
- val byteStringsSize = bytestrings.size
-
- @tailrec
- def find(bsIdx: Int, relativeIndex: Int, bytesPassed: Int): Int = {
- if (bsIdx >= byteStringsSize) -1
- else {
- val bs = bytestrings(bsIdx)
-
- if (bs.length <= relativeIndex) {
- find(bsIdx + 1, relativeIndex - bs.length, bytesPassed +
bs.length)
- } else {
- val subIndexOf = bs.indexOf(elem, relativeIndex)
- if (subIndexOf < 0) {
- find(bsIdx + 1, relativeIndex - bs.length, bytesPassed +
bs.length)
- } else subIndexOf + bytesPassed
- }
- }
- }
-
- find(0, math.max(from, 0), 0)
- }
- }
-
- override def copyToArray[B >: Byte](dest: Array[B], start: Int, len: Int):
Int = {
- if (bytestrings.size == 1) bytestrings.head.copyToArray(dest, start, len)
- else {
- // min of the bytes available to copy, bytes there is room for in dest
and the requested number of bytes
- val totalToCopy = math.min(math.min(len, length), dest.length - start)
- if (totalToCopy > 0) {
- val bsIterator = bytestrings.iterator
- var copied = 0
- while (copied < totalToCopy) {
- val current = bsIterator.next()
- copied += current.copyToArray(dest, start + copied, totalToCopy -
copied)
- }
- }
- totalToCopy
- }
- }
-
- protected def writeReplace(): AnyRef = new SerializationProxy(this)
- }
-
- @SerialVersionUID(1L)
- private class SerializationProxy(@transient private var orig: ByteString)
extends Serializable {
- private def writeObject(out: ObjectOutputStream): Unit = {
- out.writeByte(orig.byteStringCompanion.SerializationIdentity)
- orig.writeToOutputStream(out)
- }
-
- private def readObject(in: ObjectInputStream): Unit = {
- val serializationId = in.readByte()
-
- orig = Companion(from = serializationId).readFromInputStream(in)
- }
-
- private def readResolve(): AnyRef = orig
- }
-
- private[pekko] object Companion {
- private val companionMap = Seq(ByteString1, ByteString1C, ByteStrings)
- .map(x => x.SerializationIdentity -> x)
- .toMap
- .withDefault(x => throw new IllegalArgumentException("Invalid
serialization id " + x))
-
- def apply(from: Byte): Companion = companionMap(from)
- }
-
- private[pekko] sealed trait Companion {
- def SerializationIdentity: Byte
- def readFromInputStream(is: ObjectInputStream): ByteString
- }
-}
-
-/**
- * A rope-like immutable data structure containing bytes.
- * The goal of this structure is to reduce copying of arrays
- * when concatenating and slicing sequences of bytes,
- * and also providing a thread safe way of working with bytes.
- *
- * TODO: Add performance characteristics
- */
-sealed abstract class ByteString
- extends IndexedSeq[Byte]
- with IndexedSeqOps[Byte, IndexedSeq, ByteString]
- with StrictOptimizedSeqOps[Byte, IndexedSeq, ByteString] {
-
- override protected def fromSpecific(coll: IterableOnce[Byte]): ByteString =
ByteString(coll)
- override protected def newSpecificBuilder: mutable.Builder[Byte, ByteString]
= ByteString.newBuilder
- override def empty: ByteString = ByteString.empty
-
- def apply(idx: Int): Byte
- private[pekko] def byteStringCompanion: ByteString.Companion
- // override so that toString will also be `ByteString(...)` for the concrete
subclasses
- // of ByteString which changed for Scala 2.12, see
https://github.com/akka/akka/issues/21774
- override final def className: String = "ByteString"
-
- override def isEmpty: Boolean = length == 0
-
- // override protected[this] def newBuilder: ByteStringBuilder =
ByteString.newBuilder
-
- // *must* be overridden by derived classes. This construction is necessary
- // to specialize the return type, as the method is already implemented in
- // a parent trait.
- //
- // Avoid `iterator` in performance sensitive code, call ops directly on
ByteString instead
- override def iterator: ByteIterator =
- throw new UnsupportedOperationException("Method iterator is not
implemented in ByteString")
-
- override def head: Byte = apply(0)
- override def tail: ByteString = drop(1)
- override def last: Byte = apply(length - 1)
- override def init: ByteString = dropRight(1)
-
- // *must* be overridden by derived classes.
- override def take(n: Int): ByteString =
- throw new UnsupportedOperationException("Method take is not implemented in
ByteString")
- override def takeRight(n: Int): ByteString = slice(length - n, length)
-
- // these methods are optimized in derived classes utilising the maximum
knowlage about data layout available to them:
- // *must* be overridden by derived classes.
- override def slice(from: Int, until: Int): ByteString =
- throw new UnsupportedOperationException("Method slice is not implemented
in ByteString")
-
- // *must* be overridden by derived classes.
- override def drop(n: Int): ByteString =
- throw new UnsupportedOperationException("Method drop is not implemented in
ByteString")
-
- // *must* be overridden by derived classes.
- override def dropRight(n: Int): ByteString =
- throw new UnsupportedOperationException("Method dropRight is not
implemented in ByteString")
-
- override def takeWhile(p: Byte => Boolean): ByteString =
iterator.takeWhile(p).toByteString
- override def dropWhile(p: Byte => Boolean): ByteString =
iterator.dropWhile(p).toByteString
- override def span(p: Byte => Boolean): (ByteString, ByteString) = {
- val (a, b) = iterator.span(p); (a.toByteString, b.toByteString)
- }
-
- override def splitAt(n: Int): (ByteString, ByteString) = (take(n), drop(n))
-
- override def indexWhere(p: Byte => Boolean, from: Int): Int =
iterator.indexWhere(p, from)
-
- // optimized version of indexOf for bytes, optimized in subclasses
- /**
- * Finds index of first occurrence of some byte in this ByteString after or
at some start index.
- *
- * Similar to indexOf, but it avoids boxing if the value is already a byte.
- *
- * @param elem the element value to search for.
- * @param from the start index
- * @return the index `>= from` of the first element of this ByteString
that is equal (as determined by `==`)
- * to `elem`, or `-1`, if none exists.
- * @since 1.1.0
- */
- def indexOf(elem: Byte, from: Int): Int = indexOf[Byte](elem, from)
-
- /**
- * Finds index of first occurrence of some byte in this ByteString.
- *
- * Similar to indexOf, but it avoids boxing if the value is already a byte.
- *
- * @param elem the element value to search for.
- * @return the index `>= from` of the first element of this ByteString
that is equal (as determined by `==`)
- * to `elem`, or `-1`, if none exists.
- * @since 1.1.0
- */
- def indexOf(elem: Byte): Int = indexOf(elem, 0)
-
- override def grouped(size: Int): Iterator[ByteString] = {
- if (size <= 0) {
- throw new IllegalArgumentException(s"size=$size must be positive")
- }
-
-
Iterator.iterate(this)(_.drop(size)).takeWhile(_.nonEmpty).map(_.take(size))
- }
-
- override def toString(): String = {
- val maxSize = 100
- if (size > maxSize)
- take(maxSize).toString + s"... and [${size - maxSize}] more"
- else
- super.toString
- }
-
- /**
- * Java API: copy this ByteString into a fresh byte array
- *
- * @return this ByteString copied into a byte array
- */
- @nowarn("msg=easy to mistake")
- protected[ByteString] def toArray: Array[Byte] = toArray[Byte]
-
- final override def toArray[B >: Byte](implicit arg0: ClassTag[B]): Array[B]
= {
- // super uses byteiterator
- val array = new Array[B](size)
- copyToArray(array, 0, size)
- array
- }
-
- @nowarn("msg=deprecated")
- final override def copyToArray[B >: Byte](xs: Array[B], start: Int): Int = {
- // super uses byteiterator
- copyToArray(xs, start, size.min(xs.size))
- }
-
- // optimized in all subclasses, avoiding usage of the iterator to save
allocations/transformations
- override def copyToArray[B >: Byte](xs: Array[B], start: Int, len: Int): Int
=
- throw new UnsupportedOperationException("Method copyToArray is not
implemented in ByteString")
-
- /**
- * Unsafe API: Use only in situations you are completely confident that this
is what
- * you need, and that you understand the implications documented below.
- *
- * If the ByteString is backed by a single array it is returned without any
copy. If it is backed by a rope
- * of multiple ByteString instances a new array will be allocated and the
contents will be copied
- * into it before returning it.
- *
- * This method of exposing the bytes of a ByteString can save one array
- * copy and allocation in the happy path scenario which can lead to better
performance,
- * however it also means that one MUST NOT modify the returned array, or
unexpected
- * immutable data structure contract-breaking behavior will manifest itself.
- *
- * This API is intended for users who need to pass the byte array to some
other API, which will
- * only read the bytes and never mutate then. For all other intents and
purposes, please use the usual
- * toArray method - which provide the immutability guarantees by copying the
backing array.
- */
- def toArrayUnsafe(): Array[Byte] = toArray
-
- /**
- * Return the bytes in this ByteString as an InputStream.
- *
- * @return the bytes in this ByteString accessible as an InputStream
- * @see [[asByteBuffer]]
- * @since 1.1.0
- */
- def asInputStream: InputStream
-
- override def foreach[@specialized U](f: Byte => U): Unit =
iterator.foreach(f)
-
- private[pekko] def writeToOutputStream(os: ObjectOutputStream): Unit
-
- /**
- * Efficiently concatenate another ByteString.
- */
- def ++(that: ByteString): ByteString
-
- /**
- * Java API: efficiently concatenate another ByteString.
- */
- def concat(that: ByteString): ByteString = this ++ that
-
- /**
- * Copy as many bytes as possible to a ByteBuffer, starting from it's
- * current position. This method will not overflow the buffer.
- *
- * @param buffer a ByteBuffer to copy bytes to
- * @return the number of bytes actually copied
- */
- def copyToBuffer(@nowarn("msg=never used") buffer: ByteBuffer): Int
-
- /**
- * Create a new ByteString with all contents compacted into a single,
- * full byte array.
- * If isCompact returns true, compact is an O(1) operation, but
- * might return a different object with an optimized implementation.
- */
- def compact: CompactByteString
-
- /**
- * Check whether this ByteString is compact in memory.
- * If the ByteString is compact, it might, however, not be represented
- * by an object that takes full advantage of that fact. Use compact to
- * get such an object.
- */
- def isCompact: Boolean
-
- /**
- * Returns a read-only ByteBuffer that directly wraps this ByteString
- * if it is not fragmented.
- */
- def asByteBuffer: ByteBuffer
-
- /**
- * Scala API: Returns an immutable Iterable of read-only ByteBuffers that
directly wraps this ByteStrings
- * all fragments. Will always have at least one entry.
- */
- def asByteBuffers: immutable.Iterable[ByteBuffer]
-
- /**
- * Java API: Returns an Iterable of read-only ByteBuffers that directly
wraps this ByteStrings
- * all fragments. Will always have at least one entry.
- */
- def getByteBuffers(): JIterable[ByteBuffer] = {
- asByteBuffers.asJava
- }
-
- /**
- * Creates a new ByteBuffer with a copy of all bytes contained in this
- * ByteString.
- */
- def toByteBuffer: ByteBuffer = ByteBuffer.wrap(toArray)
-
- /**
- * Decodes this ByteString as a UTF-8 encoded String.
- */
- final def utf8String: String = decodeString(StandardCharsets.UTF_8)
-
- /**
- * Decodes this ByteString using a charset to produce a String.
- * If you have a [[Charset]] instance available, use `decodeString(charset:
java.nio.charset.Charset` instead.
- */
- def decodeString(charset: String): String
-
- /**
- * Decodes this ByteString using a charset to produce a String.
- * Avoids Charset.forName lookup in String internals, thus is preferable to
`decodeString(charset: String)`.
- */
- def decodeString(charset: Charset): String
-
- /*
- * Returns a ByteString which is the binary representation of this ByteString
- * if this ByteString is Base64-encoded.
- */
- def decodeBase64: ByteString
-
- /**
- * Returns a ByteString which is the Base64 representation of this ByteString
- */
- def encodeBase64: ByteString
-
- /**
- * map method that will automatically cast Int back into Byte.
- */
- final def mapI(f: Byte => Int): ByteString = map(f.andThen(_.toByte))
-
- def map[A](f: Byte => Byte): ByteString = fromSpecific(super.map(f))
-}
-
-object CompactByteString {
-
- /**
- * Creates a new CompactByteString by copying a byte array.
- */
- def apply(bytes: Array[Byte]): CompactByteString =
- if (bytes.isEmpty) empty else ByteString.ByteString1C(bytes.clone)
-
- /**
- * Creates a new CompactByteString by copying bytes.
- */
- def apply(bytes: Byte*): CompactByteString = {
- if (bytes.isEmpty) empty
- else {
- val ar = new Array[Byte](bytes.size)
- bytes.copyToArray(ar)
- ByteString.ByteString1C(ar)
- }
- }
-
- /**
- * 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)
- }
-
- /**
- * Creates a new CompactByteString by converting from integral numbers to
bytes.
- */
- def apply[T](bytes: T*)(implicit num: Integral[T]): CompactByteString = {
- if (bytes.isEmpty) empty
- else ByteString.ByteString1C(bytes.iterator.map(x =>
num.toInt(x).toByte).to(Array))
- }
-
- /**
- * Creates a new CompactByteString by copying bytes from a ByteBuffer.
- */
- def apply(bytes: ByteBuffer): CompactByteString = {
- if (bytes.remaining < 1) empty
- else {
- val ar = new Array[Byte](bytes.remaining)
- bytes.get(ar)
- ByteString.ByteString1C(ar)
- }
- }
-
- /**
- * Creates a new CompactByteString by encoding a String as UTF-8.
- */
- def apply(string: String): CompactByteString = apply(string,
StandardCharsets.UTF_8)
-
- /**
- * Creates a new CompactByteString by encoding a String with a charset.
- */
- def apply(string: String, charset: String): CompactByteString =
- if (string.isEmpty) empty else
ByteString.ByteString1C(string.getBytes(charset))
-
- /**
- * Creates a new CompactByteString by encoding a String with a charset.
- */
- def apply(string: String, charset: Charset): CompactByteString =
- if (string.isEmpty) empty else
ByteString.ByteString1C(string.getBytes(charset))
-
- /**
- * Creates a new CompactByteString by copying length bytes starting at
offset from
- * an Array.
- */
- def fromArray(array: Array[Byte], offset: Int, length: Int):
CompactByteString = {
- val copyOffset = Math.max(offset, 0)
- val copyLength = Math.max(Math.min(array.length - copyOffset, length), 0)
- if (copyLength == 0) empty
- else {
- val copyArray = new Array[Byte](copyLength)
- System.arraycopy(array, copyOffset, copyArray, 0, copyLength)
- ByteString.ByteString1C(copyArray)
- }
- }
-
- val empty: CompactByteString = ByteString.ByteString1C.empty
-}
-
-/**
- * A compact ByteString.
- *
- * The ByteString is guarantied to be contiguous in memory and to use only
- * as much memory as required for its contents.
- */
-sealed abstract class CompactByteString extends ByteString with Serializable {
- def isCompact: Boolean = true
- def compact: this.type = this
-}
-
-/**
- * A mutable builder for efficiently creating a
[[org.apache.pekko.util.ByteString]].
- *
- * The created ByteString is not automatically compacted.
- */
-final class ByteStringBuilder extends Builder[Byte, ByteString] {
- builder =>
-
- import ByteString.{ ByteString1, ByteString1C, ByteStrings }
- private var _length: Int = 0
- private val _builder: VectorBuilder[ByteString1] = new
VectorBuilder[ByteString1]()
- private var _temp: Array[Byte] = _
- private var _tempLength: Int = 0
- private var _tempCapacity: Int = 0
-
- protected def fillArray(len: Int)(fill: (Array[Byte], Int) => Unit):
this.type = {
- ensureTempSize(_tempLength + len)
- fill(_temp, _tempLength)
- _tempLength += len
- _length += len
- this
- }
-
- protected final def fillByteBuffer(len: Int, byteOrder: ByteOrder)(fill:
ByteBuffer => Unit): this.type = {
- fillArray(len) {
- case (array, start) =>
- val buffer = ByteBuffer.wrap(array, start, len)
- buffer.order(byteOrder)
- fill(buffer)
- }
- }
-
- def length: Int = _length
-
- override def sizeHint(len: Int): Unit = {
- resizeTemp(len - (_length - _tempLength))
- }
-
- private def clearTemp(): Unit = {
- if (_tempLength > 0) {
- val arr = new Array[Byte](_tempLength)
- System.arraycopy(_temp, 0, arr, 0, _tempLength)
- _builder += ByteString1(arr)
- _tempLength = 0
- }
- }
-
- private def resizeTemp(size: Int): Unit = {
- val newtemp = new Array[Byte](size)
- if (_tempLength > 0) System.arraycopy(_temp, 0, newtemp, 0, _tempLength)
- _temp = newtemp
- _tempCapacity = _temp.length
- }
-
- private def shouldResizeTempFor(size: Int): Boolean = _tempCapacity < size
|| _tempCapacity == 0
-
- private def ensureTempSize(size: Int): Unit = {
- if (shouldResizeTempFor(size)) {
- var newSize = if (_tempCapacity == 0) 16 else _tempCapacity * 2
- while (newSize < size) newSize *= 2
- resizeTemp(newSize)
- }
- }
-
- // We'd really like to have this overload to prevent boxing, but it's
forbidden because sc.mutable.Growable makes
- // it final. I guess it assumes to prevent the boxing overhead by using
@inline but that doesn't seem to be true.
- // def +=(elem: Byte): this.type = addOne(elem)
-
- override def addOne(elem: Byte): this.type = {
- ensureTempSize(_tempLength + 1)
- _temp(_tempLength) = elem
- _tempLength += 1
- _length += 1
- this
- }
-
- def ++=(bytes: ByteString): this.type = addAll(bytes)
- def addAll(bytes: ByteString): this.type = {
- if (bytes.nonEmpty) {
- clearTemp()
- bytes match {
- case b: ByteString1C =>
- _builder += b.toByteString1
- _length += b.length
- case b: ByteString1 =>
- _builder += b
- _length += b.length
- case bs: ByteStrings =>
- _builder ++= bs.bytestrings
- _length += bs.length
- }
- }
- this
- }
-
- override def addAll(xs: IterableOnce[Byte]): this.type = {
- xs match {
- case bs: ByteString => addAll(bs)
- case xs: WrappedArray.ofByte =>
- if (xs.nonEmpty) putByteArrayUnsafe(xs.array.clone)
- case seq: collection.IndexedSeq[Byte] if shouldResizeTempFor(seq.length)
=>
- if (seq.nonEmpty) {
- val copied = Array.from(xs)
-
- clearTemp()
- _builder += ByteString.ByteString1(copied)
- _length += seq.length
- }
- case seq: collection.IndexedSeq[Byte] =>
- if (seq.nonEmpty) {
- ensureTempSize(_tempLength + seq.size)
- seq.copyToArray(_temp, _tempLength)
- _tempLength += seq.length
- _length += seq.length
- }
- case _ =>
- super.addAll(xs)
- }
- this
- }
-
- private[pekko] def putByteArrayUnsafe(xs: Array[Byte]): this.type = {
- clearTemp()
- _builder += ByteString1(xs)
- _length += xs.length
- this
- }
-
- /**
- * Java API: append a ByteString to this builder.
- */
- def append(bs: ByteString): this.type = if (bs.isEmpty) this else this ++= bs
-
- /**
- * Add a single Byte to this builder.
- */
- def putByte(x: Byte): this.type = this += x
-
- /**
- * Add a single Short to this builder.
- */
- def putShort(x: Int)(implicit byteOrder: ByteOrder): this.type = {
- if (byteOrder == ByteOrder.BIG_ENDIAN) {
- this += (x >>> 8).toByte
- this += (x >>> 0).toByte
- } else if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
- this += (x >>> 0).toByte
- this += (x >>> 8).toByte
- } else throw new IllegalArgumentException("Unknown byte order " +
byteOrder)
- }
-
- /**
- * Add a single Int to this builder.
- */
- def putInt(x: Int)(implicit byteOrder: ByteOrder): this.type = {
- fillArray(4) { (target, offset) =>
- if (byteOrder == ByteOrder.BIG_ENDIAN) {
- target(offset + 0) = (x >>> 24).toByte
- target(offset + 1) = (x >>> 16).toByte
- target(offset + 2) = (x >>> 8).toByte
- target(offset + 3) = (x >>> 0).toByte
- } else if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
- target(offset + 0) = (x >>> 0).toByte
- target(offset + 1) = (x >>> 8).toByte
- target(offset + 2) = (x >>> 16).toByte
- target(offset + 3) = (x >>> 24).toByte
- } else throw new IllegalArgumentException("Unknown byte order " +
byteOrder)
- }
- this
- }
-
- /**
- * Add a single Long to this builder.
- */
- def putLong(x: Long)(implicit byteOrder: ByteOrder): this.type = {
- fillArray(8) { (target, offset) =>
- if (byteOrder == ByteOrder.BIG_ENDIAN) {
- target(offset + 0) = (x >>> 56).toByte
- target(offset + 1) = (x >>> 48).toByte
- target(offset + 2) = (x >>> 40).toByte
- target(offset + 3) = (x >>> 32).toByte
- target(offset + 4) = (x >>> 24).toByte
- target(offset + 5) = (x >>> 16).toByte
- target(offset + 6) = (x >>> 8).toByte
- target(offset + 7) = (x >>> 0).toByte
- } else if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
- target(offset + 0) = (x >>> 0).toByte
- target(offset + 1) = (x >>> 8).toByte
- target(offset + 2) = (x >>> 16).toByte
- target(offset + 3) = (x >>> 24).toByte
- target(offset + 4) = (x >>> 32).toByte
- target(offset + 5) = (x >>> 40).toByte
- target(offset + 6) = (x >>> 48).toByte
- target(offset + 7) = (x >>> 56).toByte
- } else throw new IllegalArgumentException("Unknown byte order " +
byteOrder)
- }
- this
- }
-
- /**
- * Add the `n` least significant bytes of the given Long to this builder.
- */
- def putLongPart(x: Long, n: Int)(implicit byteOrder: ByteOrder): this.type =
{
- fillArray(n) { (target, offset) =>
- if (byteOrder == ByteOrder.BIG_ENDIAN) {
- val start = n * 8 - 8
- (0 until n).foreach { i =>
- target(offset + i) = (x >>> start - 8 * i).toByte
- }
- } else if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
- (0 until n).foreach { i =>
- target(offset + i) = (x >>> 8 * i).toByte
- }
- } else throw new IllegalArgumentException("Unknown byte order " +
byteOrder)
- }
- }
-
- /**
- * Add a single Float to this builder.
- */
- def putFloat(x: Float)(implicit byteOrder: ByteOrder): this.type =
- putInt(java.lang.Float.floatToRawIntBits(x))(byteOrder)
-
- /**
- * Add a single Double to this builder.
- */
- def putDouble(x: Double)(implicit byteOrder: ByteOrder): this.type =
- putLong(java.lang.Double.doubleToRawLongBits(x))(byteOrder)
-
- /**
- * Add a number of Bytes from an array to this builder.
- */
- def putBytes(array: Array[Byte]): this.type =
- putBytes(array, 0, array.length)
-
- /**
- * Add a number of Bytes from an array to this builder.
- */
- def putBytes(array: Array[Byte], start: Int, len: Int): this.type =
- fillArray(len) { case (target, targetOffset) => System.arraycopy(array,
start, target, targetOffset, len) }
-
- /**
- * Add a number of Shorts from an array to this builder.
- */
- def putShorts(array: Array[Short])(implicit byteOrder: ByteOrder): this.type
=
- putShorts(array, 0, array.length)(byteOrder)
-
- /**
- * Add a number of Shorts from an array to this builder.
- */
- def putShorts(array: Array[Short], start: Int, len: Int)(implicit byteOrder:
ByteOrder): this.type =
- fillByteBuffer(len * 2, byteOrder) { _.asShortBuffer.put(array, start,
len) }
-
- /**
- * Add a number of Ints from an array to this builder.
- */
- def putInts(array: Array[Int])(implicit byteOrder: ByteOrder): this.type =
- putInts(array, 0, array.length)(byteOrder)
-
- /**
- * Add a number of Ints from an array to this builder.
- */
- def putInts(array: Array[Int], start: Int, len: Int)(implicit byteOrder:
ByteOrder): this.type =
- fillByteBuffer(len * 4, byteOrder) { _.asIntBuffer.put(array, start, len) }
-
- /**
- * Add a number of Longs from an array to this builder.
- */
- def putLongs(array: Array[Long])(implicit byteOrder: ByteOrder): this.type =
- putLongs(array, 0, array.length)(byteOrder)
-
- /**
- * Add a number of Longs from an array to this builder.
- */
- def putLongs(array: Array[Long], start: Int, len: Int)(implicit byteOrder:
ByteOrder): this.type =
- fillByteBuffer(len * 8, byteOrder) { _.asLongBuffer.put(array, start, len)
}
-
- /**
- * Add a number of Floats from an array to this builder.
- */
- def putFloats(array: Array[Float])(implicit byteOrder: ByteOrder): this.type
=
- putFloats(array, 0, array.length)(byteOrder)
-
- /**
- * Add a number of Floats from an array to this builder.
- */
- def putFloats(array: Array[Float], start: Int, len: Int)(implicit byteOrder:
ByteOrder): this.type =
- fillByteBuffer(len * 4, byteOrder) { _.asFloatBuffer.put(array, start,
len) }
-
- /**
- * Add a number of Doubles from an array to this builder.
- */
- def putDoubles(array: Array[Double])(implicit byteOrder: ByteOrder):
this.type =
- putDoubles(array, 0, array.length)(byteOrder)
-
- /**
- * Add a number of Doubles from an array to this builder.
- */
- def putDoubles(array: Array[Double], start: Int, len: Int)(implicit
byteOrder: ByteOrder): this.type =
- fillByteBuffer(len * 8, byteOrder) { _.asDoubleBuffer.put(array, start,
len) }
-
- def clear(): Unit = {
- _builder.clear()
- _length = 0
- _tempLength = 0
- }
-
- def result(): ByteString =
- if (_length == 0) ByteString.empty
- else {
- clearTemp()
- val bytestrings = _builder.result()
- if (bytestrings.size == 1)
- bytestrings.head
- else
- ByteStrings(bytestrings, _length)
- }
-
- /**
- * Directly wraps this ByteStringBuilder in an OutputStream. Write
- * operations on the stream are forwarded to the builder.
- */
- def asOutputStream: java.io.OutputStream = new java.io.OutputStream {
- def write(b: Int): Unit = builder += b.toByte
-
- override def write(b: Array[Byte], off: Int, len: Int): Unit = {
builder.putBytes(b, off, len) }
- }
-
- /**
- * Tests whether this ByteStringBuilder is empty.
- */
- def isEmpty: Boolean = _length == 0
-
- /**
- * Tests whether this ByteStringBuilder is not empty.
- */
- def nonEmpty: Boolean = _length > 0
-}
diff --git a/actor/src/main/scala-3/org/apache/pekko/util/ByteString.scala
b/actor/src/main/scala/org/apache/pekko/util/ByteString.scala
similarity index 99%
rename from actor/src/main/scala-3/org/apache/pekko/util/ByteString.scala
rename to actor/src/main/scala/org/apache/pekko/util/ByteString.scala
index e5698ecb1c..e07c6f5edb 100644
--- a/actor/src/main/scala-3/org/apache/pekko/util/ByteString.scala
+++ b/actor/src/main/scala/org/apache/pekko/util/ByteString.scala
@@ -539,7 +539,6 @@ object ByteString {
length += bs.length
i += 1
}
-
new ByteStrings(builder.result(), length)
}
}
@@ -925,6 +924,7 @@ sealed abstract class ByteString
*
* @return this ByteString copied into a byte array
*/
+ @nowarn("msg=easy to mistake")
protected[ByteString] def toArray: Array[Byte] = toArray[Byte]
final override def toArray[B >: Byte](implicit arg0: ClassTag[B]): Array[B]
= {
@@ -934,6 +934,7 @@ sealed abstract class ByteString
array
}
+ @nowarn("msg=deprecated")
final override def copyToArray[B >: Byte](xs: Array[B], start: Int): Int = {
// super uses byteiterator
copyToArray(xs, start, size.min(xs.size))
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]