Add ByteRope for concatenating ByteStrings without copying
This commit is contained in:
parent
07d9f13c3e
commit
4cc901c708
1 changed files with 74 additions and 0 deletions
|
|
@ -106,3 +106,77 @@ final class ByteString private (bytes: Array[Byte], startIndex: Int, endIndex: I
|
||||||
Array.copy(bytes, startIndex, xs, start, math.min(math.min(length, len), xs.length - start))
|
Array.copy(bytes, startIndex, xs, start, math.min(math.min(length, len), xs.length - start))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object ByteRope {
|
||||||
|
|
||||||
|
def apply(bytes: Array[Byte]): ByteRope = new ByteRope(Vector(ByteString(bytes)))
|
||||||
|
|
||||||
|
def apply(bytes: Byte*): ByteRope = new ByteRope(Vector(ByteString(bytes: _*)))
|
||||||
|
|
||||||
|
def apply[T](bytes: T*)(implicit num: Integral[T]): ByteRope = new ByteRope(Vector(ByteString(bytes: _*)(num)))
|
||||||
|
|
||||||
|
def apply(bytes: ByteBuffer): ByteRope = new ByteRope(Vector(ByteString(bytes)))
|
||||||
|
|
||||||
|
def apply(string: String): ByteRope = new ByteRope(Vector(ByteString(string)))
|
||||||
|
|
||||||
|
def apply(string: String, charset: String): ByteRope = new ByteRope(Vector(ByteString(string, charset)))
|
||||||
|
|
||||||
|
def empty: ByteRope = new ByteRope(Vector.empty)
|
||||||
|
|
||||||
|
def newBuilder: Builder[Byte, ByteRope] = new ArrayBuilder.ofByte mapResult apply
|
||||||
|
|
||||||
|
implicit def canBuildFrom = new CanBuildFrom[TraversableOnce[Byte], Byte, ByteRope] {
|
||||||
|
def apply(from: TraversableOnce[Byte]) = newBuilder
|
||||||
|
def apply() = newBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ByteRope private (bytestrings: Vector[ByteString]) extends IndexedSeq[Byte] with IndexedSeqOptimized[Byte, ByteRope] {
|
||||||
|
|
||||||
|
override protected[this] def newBuilder = ByteRope.newBuilder
|
||||||
|
|
||||||
|
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): ByteRope = {
|
||||||
|
val start = math.max(from, 0)
|
||||||
|
val end = math.min(until, length)
|
||||||
|
if (end - start <= 0)
|
||||||
|
ByteRope.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)
|
||||||
|
new ByteRope(Vector(bytestrings(startpos).slice(startidx, endidx)))
|
||||||
|
else
|
||||||
|
new ByteRope(bytestrings(startpos).drop(startpos) +: bytestrings.slice(startpos + 1, endpos) :+ bytestrings(endpos).take(endidx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def :+(that: ByteString): ByteRope = new ByteRope(bytestrings :+ that)
|
||||||
|
|
||||||
|
def toByteString: ByteString = ByteString.concat(bytestrings: _*)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue