=act improve ByteString#dropRight(...) (#21439)

#21439: =act improve ByteString#dropRight(...)
This commit is contained in:
monkey-mas 2016-12-06 23:51:11 +09:00 committed by drewhk
parent 8d05592e2e
commit c38d3850a2
3 changed files with 166 additions and 22 deletions

View file

@ -309,6 +309,23 @@ class ByteStringSpec extends WordSpec with Matchers with Checkers {
ByteString1.fromString("0123456789").drop(1).take(2) should ===(ByteString("12"))
ByteString1.fromString("0123456789").drop(5).take(4).drop(1).take(2) should ===(ByteString("67"))
}
"dropRight" in {
ByteString1.empty.dropRight(-1) should ===(ByteString(""))
ByteString1.empty.dropRight(0) should ===(ByteString(""))
ByteString1.empty.dropRight(1) should ===(ByteString(""))
ByteString1.fromString("a").dropRight(-1) should ===(ByteString("a"))
ByteString1.fromString("a").dropRight(0) should ===(ByteString("a"))
ByteString1.fromString("a").dropRight(1) should ===(ByteString(""))
ByteString1.fromString("a").dropRight(2) should ===(ByteString(""))
ByteString1.fromString("abc").dropRight(-1) should ===(ByteString("abc"))
ByteString1.fromString("abc").dropRight(0) should ===(ByteString("abc"))
ByteString1.fromString("abc").dropRight(1) should ===(ByteString("ab"))
ByteString1.fromString("abc").dropRight(2) should ===(ByteString("a"))
ByteString1.fromString("abc").dropRight(3) should ===(ByteString(""))
ByteString1.fromString("abc").dropRight(4) should ===(ByteString(""))
ByteString1.fromString("0123456789").dropRight(1).take(2) should ===(ByteString("01"))
ByteString1.fromString("0123456789").dropRight(5).take(4).drop(1).take(2) should ===(ByteString("12"))
}
"take" in {
ByteString1.empty.take(-1) should ===(ByteString(""))
ByteString1.empty.take(0) should ===(ByteString(""))
@ -341,6 +358,23 @@ class ByteStringSpec extends WordSpec with Matchers with Checkers {
ByteString1C.fromString("0123456789").drop(1).take(2) should ===(ByteString("12"))
ByteString1C.fromString("0123456789").drop(5).take(4).drop(1).take(2) should ===(ByteString("67"))
}
"dropRight" in {
ByteString1C.fromString("").dropRight(-1) should ===(ByteString(""))
ByteString1C.fromString("").dropRight(0) should ===(ByteString(""))
ByteString1C.fromString("").dropRight(1) should ===(ByteString(""))
ByteString1C.fromString("a").dropRight(-1) should ===(ByteString("a"))
ByteString1C.fromString("a").dropRight(0) should ===(ByteString("a"))
ByteString1C.fromString("a").dropRight(1) should ===(ByteString(""))
ByteString1C.fromString("a").dropRight(2) should ===(ByteString(""))
ByteString1C.fromString("abc").dropRight(-1) should ===(ByteString("abc"))
ByteString1C.fromString("abc").dropRight(0) should ===(ByteString("abc"))
ByteString1C.fromString("abc").dropRight(1) should ===(ByteString("ab"))
ByteString1C.fromString("abc").dropRight(2) should ===(ByteString("a"))
ByteString1C.fromString("abc").dropRight(3) should ===(ByteString(""))
ByteString1C.fromString("abc").dropRight(4) should ===(ByteString(""))
ByteString1C.fromString("0123456789").dropRight(1).take(2) should ===(ByteString("01"))
ByteString1C.fromString("0123456789").dropRight(5).take(4).drop(1).take(2) should ===(ByteString("12"))
}
"take" in {
ByteString1.fromString("abcdefg").drop(1).take(0) should ===(ByteString(""))
ByteString1.fromString("abcdefg").drop(1).take(-1) should ===(ByteString(""))
@ -392,6 +426,48 @@ class ByteStringSpec extends WordSpec with Matchers with Checkers {
ByteString("0123456789").drop(5).drop(3).take(1) should ===(ByteString("8"))
(ByteString1C.fromString("a") ++ ByteString1.fromString("bc")).drop(2) should ===(ByteString("c"))
}
"dropRight" in {
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("")).dropRight(Int.MinValue) should ===(ByteString(""))
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("")).dropRight(-1) should ===(ByteString(""))
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("")).dropRight(0) should ===(ByteString(""))
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("")).dropRight(1) should ===(ByteString(""))
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("")).dropRight(Int.MaxValue) should ===(ByteString(""))
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(Int.MinValue) should ===(ByteString("a"))
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(-1) should ===(ByteString("a"))
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(0) should ===(ByteString("a"))
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(1) should ===(ByteString(""))
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(2) should ===(ByteString(""))
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(Int.MaxValue) should ===(ByteString(""))
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).dropRight(Int.MinValue) should ===(ByteString("a"))
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).dropRight(-1) should ===(ByteString("a"))
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).dropRight(0) should ===(ByteString("a"))
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).dropRight(1) should ===(ByteString(""))
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).dropRight(2) should ===(ByteString(""))
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).dropRight(Int.MaxValue) should ===(ByteString(""))
val bss = ByteStrings(Vector(
ByteString1.fromString("a"),
ByteString1.fromString("bc"),
ByteString1.fromString("def")))
bss.dropRight(Int.MinValue) should ===(ByteString("abcdef"))
bss.dropRight(-1) should ===(ByteString("abcdef"))
bss.dropRight(0) should ===(ByteString("abcdef"))
bss.dropRight(1) should ===(ByteString("abcde"))
bss.dropRight(2) should ===(ByteString("abcd"))
bss.dropRight(3) should ===(ByteString("abc"))
bss.dropRight(4) should ===(ByteString("ab"))
bss.dropRight(5) should ===(ByteString("a"))
bss.dropRight(6) should ===(ByteString(""))
bss.dropRight(7) should ===(ByteString(""))
bss.dropRight(Int.MaxValue) should ===(ByteString(""))
ByteString("0123456789").dropRight(5).take(2) should ===(ByteString("01"))
ByteString("0123456789").dropRight(5).drop(3).take(1) should ===(ByteString("3"))
(ByteString1C.fromString("a") ++ ByteString1.fromString("bc")).dropRight(2) should ===(ByteString("a"))
}
"slice" in {
ByteStrings(ByteString1.fromString(""), ByteString1.fromString("a")).slice(1, 1) should ===(ByteString(""))
// We explicitly test all edge cases to always test them, refs bug #21237
@ -436,16 +512,6 @@ class ByteStringSpec extends WordSpec with Matchers with Checkers {
// Get an empty if `from` is greater than `until`
ByteStrings(ByteString1.fromString("ab"), ByteString1.fromString("cd")).slice(4, 0) should ===(ByteString(""))
}
"dropRight" in {
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(0) should ===(ByteString("a"))
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(-1) should ===(ByteString("a"))
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(Int.MinValue) should ===(ByteString("a"))
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(1) should ===(ByteString(""))
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("")).dropRight(Int.MaxValue) should ===(ByteString(""))
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("bc")).dropRight(1) should ===(ByteString("ab"))
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("bc")).dropRight(2) should ===(ByteString("a"))
ByteStrings(ByteString1.fromString("a"), ByteString1.fromString("bc")).dropRight(3) should ===(ByteString(""))
}
"take" in {
ByteString.empty.take(-1) should ===(ByteString(""))
ByteString.empty.take(0) should ===(ByteString(""))

View file

@ -487,19 +487,27 @@ object ByteString {
}
override def dropRight(n: Int): ByteString =
if (n <= 0) this
else {
val last = bytestrings.last
if (n < last.length) new ByteStrings(bytestrings.init :+ last.dropRight1(n), length - n)
else {
val remaining = bytestrings.init
if (remaining.isEmpty) ByteString.empty
else {
val s = new ByteStrings(remaining, length - last.length)
val remainingToBeDropped = n - last.length
s.dropRight(remainingToBeDropped)
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 =

View file

@ -0,0 +1,70 @@
/**
* Copyright (C) 2014-2016 Lightbend Inc. <http://www.lightbend.com>
*/
package akka.util
import java.util.concurrent.TimeUnit
import akka.util.ByteString.{ ByteString1, ByteStrings }
import org.openjdk.jmh.annotations._
import scala.util.Random
@State(Scope.Benchmark)
@Measurement(timeUnit = TimeUnit.MILLISECONDS)
class ByteString_dropRight_Benchmark {
val str = List.fill[Byte](4)(0).mkString
val numVec = 1024
val bss = ByteStrings(Vector.fill(numVec)(ByteString1.fromString(str)))
val rand = new Random()
val len = str.size * numVec
val n_greater_or_eq_to_len = len + rand.nextInt(Int.MaxValue - len)
val n_neg = rand.nextInt(Int.MaxValue) * -1
val n_avg = len / 2
val n_best = 1
val n_worst = len - 1
/*
--------------------------------- BASELINE -----------------------------------------------------------------------
commit 0f2da7b26b5c4af35be87d2bd4a1a2392365df15
[info] Benchmark Mode Cnt Score Error Units
[info] ByteString_dropRight_Benchmark.bss_avg thrpt 40 25626.311 ± 1395.662 ops/s
[info] ByteString_dropRight_Benchmark.bss_best thrpt 40 8667558.031 ± 200233.008 ops/s
[info] ByteString_dropRight_Benchmark.bss_greater_or_eq_to_len thrpt 40 12658.684 ± 376.730 ops/s
[info] ByteString_dropRight_Benchmark.bss_negative thrpt 40 1214680926.895 ± 10661843.507 ops/s
[info] ByteString_dropRight_Benchmark.bss_worst thrpt 40 13087.245 ± 246.911 ops/s
--------------------------------- AFTER --------------------------------------------------------------------------
------ TODAY
[info] Benchmark Mode Cnt Score Error Units
[info] ByteString_dropRight_Benchmark.bss_avg thrpt 40 528969.025 ± 6039.001 ops/s
[info] ByteString_dropRight_Benchmark.bss_best thrpt 40 7925951.396 ± 249279.950 ops/s
[info] ByteString_dropRight_Benchmark.bss_greater_or_eq_to_len thrpt 40 893475724.604 ± 9836471.105 ops/s
[info] ByteString_dropRight_Benchmark.bss_negative thrpt 40 1182275022.613 ± 9710755.955 ops/s
[info] ByteString_dropRight_Benchmark.bss_worst thrpt 40 244599.957 ± 3276.140 ops/s
*/
@Benchmark
def bss_negative(): ByteString =
bss.dropRight(n_neg)
@Benchmark
def bss_greater_or_eq_to_len(): ByteString =
bss.dropRight(n_greater_or_eq_to_len)
@Benchmark
def bss_avg(): ByteString =
bss.dropRight(n_avg)
@Benchmark
def bss_best(): ByteString =
bss.dropRight(n_best)
@Benchmark
def bss_worst(): ByteString =
bss.dropRight(n_worst)
}