summaryrefslogtreecommitdiff
path: root/src/library/scala/collection/BitSetLike.scala
diff options
context:
space:
mode:
authorRex Kerr <ichoran@gmail.com>2015-08-29 18:10:26 -0700
committerRex Kerr <ichoran@gmail.com>2016-02-17 15:29:44 -0800
commit3db50837cca2f92aee48fe44bc38106dbc5f4c59 (patch)
tree9a5170650d0cc42fff40637450a11f3f6679b79b /src/library/scala/collection/BitSetLike.scala
parent1564f28fe594da85b53b403346636adadbb4b8db (diff)
downloadscala-3db50837cca2f92aee48fe44bc38106dbc5f4c59.tar.gz
scala-3db50837cca2f92aee48fe44bc38106dbc5f4c59.tar.bz2
scala-3db50837cca2f92aee48fe44bc38106dbc5f4c59.zip
SI-9347 Efficient head/tail, if possible, for immutable maps & sets
Most immutable collections, including sets and maps, have a better-than-O(n) method for removing an element. In those cases, tail and possibly head were overridden so the head/tail pattern can be used with less of a performance penalty. Speed improvements on head/tail pattern are (for sets/maps of size 1024, unless otherwise specified): ``` BitSet 190x HashSet 250x Set 400x Set2 9x Set4 12x HashMap 430x ListMap 2500x // size 128 Map 430x ``` Note: `ListMap` is actually `init`/`last` because it's maintained in reverse order. Altered ListMap docs to explain that reverse traversal is the fast way to do it. All tested sets/maps that were already fast are still fast. Test code is reproduced below, except it does ListSet with head/tail which doesn't show the improvement: ```scala object BenchTailSetMap { val th = new ichi.bench.Thyme val standard = 1 to 1024 val sets = Map[String, Set[Int]]( "Set" -> (Set.empty[Int] ++ standard), "Set4"-> Set(4, 7, 2, 1), "Set2"-> Set(3, 4), "HashSet" -> (collection.immutable.HashSet.empty[Int] ++ standard), "BitSet" -> (collection.immutable.BitSet.empty ++ standard), "SortedSet" -> (collection.immutable.SortedSet.empty[Int] ++ standard), "ListSet" -> (collection.immutable.ListSet.empty[Int] ++ standard) ) val pairs = standard.map(i => i -> i.toString) // ListMap implementation is HORRIBLE, O(n^3) tail! Cut down size. val maps = Map[String, Map[Int, String]]( "Map" -> (Map.empty[Int, String] ++ pairs), "HashMap" -> (collection.immutable.HashMap.empty[Int, String] ++ pairs), "SortedMap" -> (collection.immutable.SortedMap.empty[Int, String] ++ pairs), "ListMap" -> (collection.immutable.ListMap.empty[Int, String] ++ pairs.take(128)) ) def hts(s: Set[Int]) = { var si = s var x = 0 while (si.nonEmpty) { x += si.head si = si.tail } x } def htm(m: Map[Int, String]) = { var mi = m var x = 0 while (mi.nonEmpty) { x += mi.head._2.length mi = mi.tail } x } def run() { sets.toList.sortBy(_._1).foreach{ case (name, s) => th.pbench(hts(s), s.size, name) } maps.toList.sortBy(_._1).foreach{ case (name, m) => th.pbench(htm(m), m.size, name) } } } ```
Diffstat (limited to 'src/library/scala/collection/BitSetLike.scala')
-rw-r--r--src/library/scala/collection/BitSetLike.scala21
1 files changed, 21 insertions, 0 deletions
diff --git a/src/library/scala/collection/BitSetLike.scala b/src/library/scala/collection/BitSetLike.scala
index 29369447d1..209b00ebf9 100644
--- a/src/library/scala/collection/BitSetLike.scala
+++ b/src/library/scala/collection/BitSetLike.scala
@@ -204,6 +204,27 @@ trait BitSetLike[+This <: BitSetLike[This] with SortedSet[Int]] extends SortedSe
def subsetOf(other: BitSet): Boolean =
(0 until nwords) forall (idx => (this.word(idx) & ~ other.word(idx)) == 0L)
+ override def head: Int = {
+ val n = nwords
+ var i = 0
+ while (i < n) {
+ val wi = word(i)
+ if (wi != 0L) return WordLength*i + java.lang.Long.numberOfTrailingZeros(wi)
+ i += 1
+ }
+ throw new NoSuchElementException("Empty BitSet")
+ }
+
+ override def last: Int = {
+ var i = nwords - 1
+ while (i >= 0) {
+ val wi = word(i)
+ if (wi != 0L) return WordLength*i + 63 - java.lang.Long.numberOfLeadingZeros(wi)
+ i += 1
+ }
+ throw new NoSuchElementException("Empty BitSet")
+ }
+
override def addString(sb: StringBuilder, start: String, sep: String, end: String) = {
sb append start
var pre = ""