pekko/akka-actor/src/main/scala/akka/util/ByteString.scala

217 lines
6.8 KiB
Scala
Raw Normal View History

package akka.util
import java.nio.ByteBuffer
import scala.collection.IndexedSeqOptimized
import scala.collection.mutable.{ Builder, ArrayBuilder }
import scala.collection.immutable.IndexedSeq
import scala.collection.generic.{ CanBuildFrom, GenericCompanion }
object ByteString {
2011-06-05 14:04:18 -06:00
def apply(bytes: Array[Byte]): ByteString = ByteString1(bytes.clone)
2011-05-22 13:53:58 -06:00
def apply(bytes: Byte*): ByteString = {
val ar = new Array[Byte](bytes.size)
bytes.copyToArray(ar)
2011-06-05 14:04:18 -06:00
ByteString1(ar)
2011-05-22 13:53:58 -06:00
}
def apply[T](bytes: T*)(implicit num: Integral[T]): ByteString =
2011-06-05 14:04:18 -06:00
ByteString1(bytes.map(x num.toInt(x).toByte)(collection.breakOut))
def apply(bytes: ByteBuffer): ByteString = {
val ar = new Array[Byte](bytes.remaining)
bytes.get(ar)
2011-06-05 14:04:18 -06:00
ByteString1(ar)
}
def apply(string: String): ByteString = apply(string, "UTF-8")
2011-06-05 14:04:18 -06:00
def apply(string: String, charset: String): ByteString = ByteString1(string.getBytes(charset))
2011-06-05 14:04:18 -06:00
val empty: ByteString = ByteString1(Array.empty[Byte])
2011-05-22 15:16:38 -06:00
def newBuilder: Builder[Byte, ByteString] = new ArrayBuilder.ofByte mapResult apply
implicit def canBuildFrom = new CanBuildFrom[TraversableOnce[Byte], Byte, ByteString] {
def apply(from: TraversableOnce[Byte]) = newBuilder
def apply() = newBuilder
}
2011-06-05 14:04:18 -06:00
private object ByteString1 {
def apply(bytes: Array[Byte]) = new ByteString1(bytes)
}
2011-06-05 14:04:18 -06:00
final class ByteString1 private (bytes: Array[Byte], startIndex: Int, endIndex: Int) extends ByteString {
2011-06-05 14:04:18 -06:00
private def this(bytes: Array[Byte]) = this(bytes, 0, bytes.length)
2011-05-22 15:16:38 -06:00
2011-06-05 14:04:18 -06:00
def apply(idx: Int): Byte = bytes(checkRangeConvert(idx))
2011-06-05 14:04:18 -06:00
private def checkRangeConvert(index: Int) = {
val idx = index + startIndex
if (0 <= index && idx < endIndex)
idx
else
throw new IndexOutOfBoundsException(index.toString)
}
2011-06-05 14:04:18 -06:00
def length: Int = endIndex - startIndex
2011-06-05 14:04:18 -06:00
def toArray: Array[Byte] = {
val ar = new Array[Byte](length)
Array.copy(bytes, startIndex, ar, 0, length)
ar
}
2011-06-05 14:04:18 -06:00
override def clone: ByteString = new ByteString1(toArray)
2011-05-22 15:16:38 -06:00
2011-06-05 14:04:18 -06:00
def compact: ByteString =
if (startIndex == 0 && endIndex == bytes.length) this
else clone
2011-06-05 14:04:18 -06:00
def asByteBuffer: ByteBuffer = {
val buffer = ByteBuffer.wrap(bytes, startIndex, length).asReadOnlyBuffer
if (buffer.remaining < bytes.length) buffer.slice
else buffer
}
2011-06-05 14:04:18 -06:00
def utf8String: String =
new String(if (startIndex == 0 && endIndex == bytes.length) bytes else toArray, "UTF-8")
2011-06-05 14:04:18 -06:00
def ++(that: ByteString): ByteString = that match {
case b: ByteString1 ByteStrings(this, b)
case bs: ByteStrings ByteStrings(this, bs)
}
2011-06-05 14:04:18 -06:00
override def slice(from: Int, until: Int): ByteString = {
val newStartIndex = math.max(from, 0) + startIndex
val newEndIndex = math.min(until, length) + startIndex
if (newEndIndex <= newStartIndex) ByteString.empty
else new ByteString1(bytes, newStartIndex, newEndIndex)
}
2011-06-05 14:04:18 -06:00
override def copyToArray[A >: Byte](xs: Array[A], start: Int, len: Int): Unit =
Array.copy(bytes, startIndex, xs, start, math.min(math.min(length, len), xs.length - start))
2011-06-05 14:04:18 -06:00
}
2011-06-05 14:04:18 -06:00
private object ByteStrings {
def apply(bytestrings: Vector[ByteString1]): ByteString = new ByteStrings(bytestrings)
2011-06-05 14:04:18 -06:00
def apply(b1: ByteString1, b2: ByteString1): ByteString = compare(b1, b2) match {
case 3 new ByteStrings(Vector(b1, b2))
case 2 b2
case 1 b1
case 0 ByteString.empty
}
2011-06-05 14:04:18 -06:00
def apply(b: ByteString1, bs: ByteStrings): ByteString = compare(b, bs) match {
case 3 new ByteStrings(b +: bs.bytestrings)
case 2 bs
case 1 b
case 0 ByteString.empty
}
2011-06-05 14:04:18 -06:00
def apply(bs: ByteStrings, b: ByteString1): ByteString = compare(bs, b) match {
case 3 new ByteStrings(bs.bytestrings :+ b)
case 2 b
case 1 bs
case 0 ByteString.empty
}
2011-06-05 14:04:18 -06:00
def apply(bs1: ByteStrings, bs2: ByteStrings): ByteString = compare(bs1, bs2) match {
case 3 new ByteStrings(bs1.bytestrings ++ bs2.bytestrings)
case 2 bs2
case 1 bs1
case 0 ByteString.empty
}
2011-06-05 14:04:18 -06:00
// 0: both empty, 1: 2nd empty, 2: 1st empty, 3: neither empty
def compare(b1: ByteString, b2: ByteString): Int =
if (b1.length == 0)
if (b2.length == 0) 0 else 2
else if (b2.length == 0) 1 else 3
}
2011-06-05 14:04:18 -06:00
final class ByteStrings private (private val bytestrings: Vector[ByteString1]) extends ByteString {
def apply(idx: Int): Byte =
if (0 <= idx && idx < length) {
var pos = 0
var seen = 0
while (idx >= seen + bytestrings(pos).length) {
seen += bytestrings(pos).length
pos += 1
}
bytestrings(pos)(idx - seen)
} else throw new IndexOutOfBoundsException(idx.toString)
val length: Int = (0 /: bytestrings)(_ + _.length)
override def slice(from: Int, until: Int): ByteString = {
val start = math.max(from, 0)
val end = math.min(until, length)
if (end <= start)
ByteString.empty
else {
var pos = 0
var seen = 0
while (from >= seen + bytestrings(pos).length) {
seen += bytestrings(pos).length
pos += 1
}
val startpos = pos
val startidx = start - seen
while (until > seen + bytestrings(pos).length) {
seen += bytestrings(pos).length
pos += 1
}
val endpos = pos
val endidx = end - seen
if (startpos == endpos)
bytestrings(startpos).slice(startidx, endidx)
else {
val first = bytestrings(startpos).drop(startidx).asInstanceOf[ByteString1]
val last = bytestrings(endpos).take(endidx).asInstanceOf[ByteString1]
if ((endpos - startpos) == 1)
new ByteStrings(Vector(first, last))
else
new ByteStrings(first +: bytestrings.slice(startpos + 1, endpos) :+ last)
}
}
2011-06-05 14:04:18 -06:00
}
2011-06-05 14:04:18 -06:00
def ++(that: ByteString): ByteString = that match {
case b: ByteString1 ByteStrings(this, b)
case bs: ByteStrings ByteStrings(this, bs)
}
2011-06-05 14:04:18 -06:00
def compact: ByteString = {
val ar = new Array[Byte](length)
var pos = 0
2011-06-05 14:04:18 -06:00
bytestrings foreach { b
b.copyToArray(ar, pos, b.length)
pos += b.length
}
2011-06-05 14:04:18 -06:00
ByteString1(ar)
}
2011-06-05 14:04:18 -06:00
def asByteBuffer: ByteBuffer = compact.asByteBuffer
def utf8String: String = compact.utf8String
}
2011-06-05 14:04:18 -06:00
}
2011-06-05 14:04:18 -06:00
sealed trait ByteString extends IndexedSeq[Byte] with IndexedSeqOptimized[Byte, ByteString] {
override protected[this] def newBuilder = ByteString.newBuilder
def ++(that: ByteString): ByteString
def compact: ByteString
def asByteBuffer: ByteBuffer
def toByteBuffer: ByteBuffer = ByteBuffer.wrap(toArray)
def utf8String: String
def mapI(f: Byte Int): ByteString = map(f andThen (_.toByte))
}