Skip to content

Commit a84ce5b

Browse files
authored
Merge pull request scala#7193 from odd/vectormap-tombstones
Add tombstones to VectorMap.
2 parents c3a2b3d + 3d90137 commit a84ce5b

File tree

2 files changed

+145
-88
lines changed

2 files changed

+145
-88
lines changed

src/library/scala/collection/immutable/VectorMap.scala

Lines changed: 136 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ package scala
1414
package collection
1515
package immutable
1616

17-
import scala.collection.mutable.{Builder, ImmutableBuilder}
18-
import scala.annotation.unchecked.{uncheckedVariance => uV}
17+
import scala.annotation.tailrec
1918

2019
/** This class implements immutable maps using a vector/map-based data structure, which preserves insertion order.
2120
*
@@ -26,140 +25,194 @@ import scala.annotation.unchecked.{uncheckedVariance => uV}
2625
* @tparam V the type of the values associated with the keys in this vector map.
2726
*
2827
* @author Matthew de Detrich
28+
* @author Odd Möller
2929
* @version 2.13
3030
* @since 2.13
3131
* @define coll immutable vector map
3232
* @define Coll `immutable.VectorMap`
3333
*/
34-
final class VectorMap[K, +V] private[immutable] (
35-
private[immutable] val fields: Vector[K],
36-
private[immutable] val underlying: Map[K, (Int, V)])
37-
extends AbstractMap[K, V]
34+
final class VectorMap[K, +V] private (
35+
private[immutable] val fields: Vector[Any],
36+
private[immutable] val underlying: Map[K, (Int, V)], dummy: Boolean)
37+
extends AbstractMap[K, V]
3838
with SeqMap[K, V]
3939
with MapOps[K, V, VectorMap, VectorMap[K, V]]
4040
with StrictOptimizedIterableOps[(K, V), Iterable, VectorMap[K, V]] {
41+
42+
import VectorMap._
43+
4144
override protected[this] def className: String = "VectorMap"
4245

46+
private[immutable] def this(fields: Vector[K], underlying: Map[K, (Int, V)]) = {
47+
this(fields, underlying, false)
48+
}
49+
50+
override val size = underlying.size
51+
52+
override def knownSize: Int = size
53+
54+
override def isEmpty: Boolean = size == 0
55+
4356
def updated[V1 >: V](key: K, value: V1): VectorMap[K, V1] = {
4457
underlying.get(key) match {
45-
case Some(oldIndexWithValue) =>
46-
new VectorMap(fields,
47-
underlying.updated(key, (oldIndexWithValue._1, value)))
58+
case Some((slot, _)) =>
59+
new VectorMap(fields, underlying.updated[(Int, V1)](key, (slot, value)), false)
4860
case None =>
49-
new VectorMap(
50-
fields :+ key,
51-
underlying.updated(key, (fields.length, value)))
61+
new VectorMap(fields :+ key, underlying.updated[(Int, V1)](key, (fields.length, value)), false)
5262
}
5363
}
5464

5565
override def withDefault[V1 >: V](d: K => V1): Map.WithDefault[K, V1] =
5666
new Map.WithDefault(this, d)
5767

58-
override def withDefaultValue[V1 >: V](d: V1): Map.WithDefault[K, V1] = new Map.WithDefault[K, V1](this, _ => d)
68+
override def withDefaultValue[V1 >: V](d: V1): Map.WithDefault[K, V1] =
69+
new Map.WithDefault[K, V1](this, _ => d)
70+
71+
def get(key: K): Option[V] = underlying.get(key) match {
72+
case Some(v) => Some(v._2)
73+
case None => None
74+
}
75+
76+
@tailrec
77+
private def field(slot: Int): (Int, K) = {
78+
fields(slot) match {
79+
case Tombstone.Kinless =>
80+
(-1, null.asInstanceOf[K])
81+
case Tombstone.NextOfKin(distance) =>
82+
field(slot + distance)
83+
case k: K =>
84+
(slot, k)
85+
}
86+
}
5987

6088
def iterator: Iterator[(K, V)] = new AbstractIterator[(K, V)] {
61-
private val fieldsIterator = fields.iterator
89+
private[this] val fieldsLength = fields.length
90+
private[this] var slot = -1
91+
private[this] var key: K = null.asInstanceOf[K]
92+
93+
private[this] def advance(): Unit = {
94+
val nextSlot = slot + 1
95+
if (nextSlot >= fieldsLength) {
96+
slot = fieldsLength
97+
key = null.asInstanceOf[K]
98+
} else {
99+
field(nextSlot) match {
100+
case (-1, _)
101+
slot = fieldsLength
102+
key = null.asInstanceOf[K]
103+
case (s, k)
104+
slot = s
105+
key = k
106+
}
107+
}
108+
}
109+
110+
advance()
62111

63-
override def hasNext: Boolean = fieldsIterator.hasNext
112+
override def hasNext: Boolean = slot < fieldsLength
64113

65114
override def next(): (K, V) = {
66-
val field = fieldsIterator.next()
67-
(field, underlying(field)._2)
115+
if (!hasNext) throw new NoSuchElementException("next called on depleted iterator")
116+
val result = (key, underlying(key)._2)
117+
advance()
118+
result
68119
}
69120
}
70121

71-
def get(key: K): Option[V] = underlying.get(key) match {
72-
case Some(v) => Some(v._2)
73-
case None => None
74-
}
75-
76122
def remove(key: K): VectorMap[K, V] = {
77-
underlying.get(key) match {
78-
case Some((index, _)) =>
79-
val finalUnderlying = (underlying - key).map{ case (k, (currentIndex,v)) =>
80-
if (currentIndex > index)
81-
(k, (currentIndex - 1, v))
82-
else
83-
(k, (currentIndex, v))
84-
}
85-
new VectorMap(fields.patch(index, Nil, 1), finalUnderlying)
86-
case _ =>
87-
this
123+
if (isEmpty) empty
124+
else {
125+
var fs = fields
126+
val sz = fs.size
127+
underlying.get(key) match {
128+
case Some((slot, _)) =>
129+
val s = field(slot)._1
130+
// Calculate distance to next of kin
131+
val d =
132+
if (s < sz - 1) fs(s + 1) match {
133+
case Tombstone.Kinless => 0
134+
case Tombstone.NextOfKin(d) => d + 1
135+
case _ => 1
136+
} else 0
137+
fs = fs.updated(s, Tombstone(d))
138+
if (s > 0) {
139+
// Adjust distance to next of kin for all preceding tombstones
140+
var t = s - 1
141+
var prev = fs(t)
142+
while (t >= 0 && prev.isInstanceOf[Tombstone]) {
143+
fs = prev match {
144+
case Tombstone.Kinless => throw new IllegalStateException("kinless tombstone found in prefix: " + key)
145+
case Tombstone.NextOfKin(_) if d == 0 => fs.updated(t, Tombstone.Kinless)
146+
case Tombstone.NextOfKin(d) => fs.updated(t, Tombstone(d + 1))
147+
case _ => fs
148+
}
149+
t -= 1
150+
if (t >= 0) prev = fs(t)
151+
}
152+
}
153+
new VectorMap(fs, underlying - key, false)
154+
case _ =>
155+
this
156+
}
88157
}
89158
}
90159

91160
override def mapFactory: MapFactory[VectorMap] = VectorMap
92161

93-
override def size: Int = fields.size
94-
95-
override def knownSize: Int = fields.size
96-
97-
override def isEmpty: Boolean = fields.isEmpty
98-
99-
override final def contains(key: K): Boolean = underlying.contains(key)
162+
override def contains(key: K): Boolean = underlying.contains(key)
100163

101164
override def head: (K, V) = iterator.next()
102165

103166
override def last: (K, V) = {
104-
val last = fields.last
167+
val last = fields
168+
.reverseIterator
169+
.find(!_.isInstanceOf[Tombstone])
170+
.get
171+
.asInstanceOf[K]
105172
(last, underlying(last)._2)
106173
}
107174

108175
override def lastOption: Option[(K, V)] = {
109-
fields.lastOption match {
110-
case Some(last) => Some((last, underlying(last)._2))
111-
case None => None
112-
}
176+
fields
177+
.reverseIterator
178+
.find(!_.isInstanceOf[Tombstone])
179+
.map { f
180+
val last = f.asInstanceOf[K]
181+
(last, underlying(last)._2)
182+
}
113183
}
114184

115185
override def tail: VectorMap[K, V] = {
116-
new VectorMap(fields.tail, underlying.remove(fields.head))
186+
val (slot, key) = field(0)
187+
new VectorMap(fields.drop(slot + 1), underlying - key, false)
117188
}
118189

119190
override def init: VectorMap[K, V] = {
120-
new VectorMap(fields.init, underlying.remove(fields.last))
191+
val (slot, key) = field(size - 1)
192+
new VectorMap(fields.dropRight(size - 1 - slot + 1), underlying - key, false)
121193
}
122194

123-
// Only care about content, not ordering for equality
124-
override def equals(that: Any): Boolean =
125-
that match {
126-
case map: Map[K, V] =>
127-
(this eq map) ||
128-
(this.size == map.size) && {
129-
try {
130-
var i = 0
131-
val _size = size
132-
while (i < _size) {
133-
val k = fields(i)
134-
135-
map.get(k) match {
136-
case Some(value) =>
137-
if (!(value == underlying(k)._2)) {
138-
return false
139-
}
140-
case None =>
141-
return false
142-
}
143-
i += 1
144-
}
145-
true
146-
} catch {
147-
case _: ClassCastException => false
148-
}
149-
}
150-
case _ => super.equals(that)
151-
}
152-
153-
override def foreach[U](f: ((K, V)) => U): Unit = iterator.foreach(f)
154-
155-
override def keys: Iterable[K] = fields
195+
def keyIterator: Iterator[K] = iterator.map(_._1)
196+
override def keys: Vector[K] = keyIterator.toVector
156197

157198
override def values: Iterable[V] = new Iterable[V] {
158-
override def iterator: Iterator[V] = fields.iterator.map(underlying(_)._2)
199+
override def iterator: Iterator[V] = keyIterator.map(underlying(_)._2)
159200
}
160201
}
161202

162203
object VectorMap extends MapFactory[VectorMap] {
204+
private[VectorMap] sealed trait Tombstone
205+
private[VectorMap] object Tombstone {
206+
final case object Kinless extends Tombstone {
207+
override def toString = ""
208+
}
209+
final case class NextOfKin private (distance: Int) extends Tombstone {
210+
override def toString = "" + distance
211+
}
212+
def apply(distance: Int): Tombstone =
213+
if (distance <= 0) Kinless
214+
else NextOfKin(distance)
215+
}
163216

164217
def empty[K, V]: VectorMap[K, V] =
165218
new VectorMap[K, V](
@@ -172,8 +225,8 @@ object VectorMap extends MapFactory[VectorMap] {
172225
case _ => (newBuilder[K, V] ++= it).result()
173226
}
174227

175-
def newBuilder[K, V]: Builder[(K, V), VectorMap[K, V]] =
176-
new ImmutableBuilder[(K, V), VectorMap[K, V]](empty) {
228+
def newBuilder[K, V]: mutable.Builder[(K, V), VectorMap[K, V]] =
229+
new mutable.ImmutableBuilder[(K, V), VectorMap[K, V]](empty) {
177230
def addOne(elem: (K, V)): this.type = { elems = elems + elem; this }
178231
}
179232

test/scalacheck/scala/collection/immutable/VectorMapProperties.scala

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,28 @@ object VectorMapProperties extends Properties("immutable.VectorMap") {
1414
property("internal underlying index match") = forAll { m: Map[K, V] =>
1515
!m.isEmpty ==> {
1616
val vm = VectorMap.from(m)
17-
val last = vm.fields.last
18-
vm.underlying(last)._1 == vm.size - 1
17+
val last = vm.keys.last
18+
vm.fields(vm.underlying(last)._1) == last
1919
}
2020
}
2121

2222
property("internal underlying and field length") = forAll { m: Map[K, V] => {
2323
val vm = VectorMap.from(m)
24-
vm.underlying.size == vm.fields.length
24+
vm.underlying.size == vm.keys.length
2525
}
2626
}
2727

28-
property("internal underlying has consistent index") = forAll { m: Map[K, V] =>
28+
property("internal underlying and index are consistent after removal") = forAll { (m: Map[K, V]) =>
2929
m.size >= 3 ==> {
3030
val v = Vector.from(m)
3131
val random = v(new scala.util.Random().nextInt(v.size))
3232
val vm = VectorMap.from(v)
3333
val removed = vm - random._1
34-
removed.underlying.toList.map{case (k, v) => v._1}.sorted.sliding(2).forall(x => x(1) - x(0) == 1 )
34+
removed.underlying.forall { case (k, (s, v)) => removed.fields(s) == k }
35+
removed.fields.zipWithIndex.forall {
36+
case (k: K, s) => removed.underlying(k)._1 == s
37+
case _ => true
38+
}
3539
}
3640
}
3741
}

0 commit comments

Comments
 (0)