1
+ package dotty .tools .dotc
2
+ package util
3
+
4
+ import java .util .NoSuchElementException
5
+
6
+ class SparseIntArray :
7
+ import SparseIntArray ._
8
+
9
+ private var siz : Int = 0
10
+ private var root : Node = LeafNode ()
11
+
12
+ private def grow () =
13
+ val newRoot = InnerNode (root.level + 1 )
14
+ newRoot.elems(0 ) = root
15
+ root = newRoot
16
+
17
+ private def capacity : Int = root.elemSize * NodeSize
18
+
19
+ def size = siz
20
+
21
+ def contains (index : Int ): Boolean =
22
+ 0 <= index && index < capacity && root.contains(index)
23
+
24
+ def apply (index : Int ): Value =
25
+ require(index >= 0 )
26
+ if index >= capacity then throw NoSuchElementException ()
27
+ root.apply(index)
28
+
29
+ def update (index : Int , value : Value ): Unit =
30
+ require(index >= 0 )
31
+ while capacity <= index do grow()
32
+ if ! root.update(index, value) then siz += 1
33
+
34
+ /** Remove element at `index` if it is present
35
+ * @return element was present
36
+ */
37
+ def remove (index : Int ): Boolean =
38
+ require(index >= 0 )
39
+ index < capacity && {
40
+ val result = root.remove(index)
41
+ if result then siz -= 1
42
+ result
43
+ }
44
+
45
+ def foreachBinding (op : (Int , Value ) => Unit ): Unit =
46
+ root.foreachBinding(op, 0 )
47
+
48
+ def transform (op : (Int , Value ) => Value ): Unit =
49
+ root.transform(op, 0 )
50
+
51
+ /** Access to some info about low-level representation */
52
+ def repr : Repr = root
53
+
54
+ override def toString =
55
+ val b = StringBuilder () ++= " SparseIntArray("
56
+ var first = true
57
+ foreachBinding { (idx, elem) =>
58
+ if first then first = false else b ++= " , "
59
+ b ++= s " $idx -> $elem"
60
+ }
61
+ b ++= " )"
62
+ b.toString
63
+
64
+ object SparseIntArray :
65
+ type Value = Int
66
+
67
+ private inline val NodeSizeLog = 5
68
+ private inline val NodeSize = 1 << NodeSizeLog
69
+
70
+ /** The exposed representation. Should be used just for nodeCount and
71
+ * low-level toString.
72
+ */
73
+ abstract class Repr :
74
+ def nodeCount : Int
75
+
76
+ private abstract class Node (val level : Int ) extends Repr :
77
+ private [SparseIntArray ] def elemShift = level * NodeSizeLog
78
+ private [SparseIntArray ] def elemSize = 1 << elemShift
79
+ private [SparseIntArray ] def elemMask = elemSize - 1
80
+ def contains (index : Int ): Boolean
81
+ def apply (index : Int ): Value
82
+ def update (index : Int , value : Value ): Boolean
83
+ def remove (index : Int ): Boolean
84
+ def isEmpty : Boolean
85
+ def foreachBinding (op : (Int , Value ) => Unit , offset : Int ): Unit
86
+ def transform (op : (Int , Value ) => Value , offset : Int ): Unit
87
+ def nodeCount : Int
88
+ end Node
89
+
90
+ private class LeafNode extends Node (0 ):
91
+ private val elems = new Array [Value ](NodeSize )
92
+ private var present : Int = 0
93
+
94
+ def contains (index : Int ): Boolean =
95
+ (present & (1 << index)) != 0
96
+
97
+ def apply (index : Int ) =
98
+ if ! contains(index) then throw NoSuchElementException ()
99
+ elems(index)
100
+
101
+ def update (index : Int , value : Value ): Boolean =
102
+ elems(index) = value
103
+ val result = contains(index)
104
+ present = present | (1 << index)
105
+ result
106
+
107
+ def remove (index : Int ): Boolean =
108
+ val result = contains(index)
109
+ present = present & ~ (1 << index)
110
+ result
111
+
112
+ def isEmpty = present == 0
113
+
114
+ def foreachBinding (op : (Int , Value ) => Unit , offset : Int ): Unit =
115
+ var i = 0
116
+ while i < NodeSize do
117
+ if contains(i) then op(offset + i, elems(i))
118
+ i += 1
119
+
120
+ def transform (op : (Int , Value ) => Value , offset : Int ): Unit =
121
+ var i = 0
122
+ while i < NodeSize do
123
+ if contains(i) then elems(i) = op(offset + i, elems(i))
124
+ i += 1
125
+
126
+ def nodeCount = 1
127
+
128
+ override def toString =
129
+ elems
130
+ .zipWithIndex
131
+ .filter((elem, idx) => contains(idx))
132
+ .map((elem, idx) => s " $idx -> $elem" ).mkString(s " 0#( " , " , " , " )" )
133
+ end LeafNode
134
+
135
+ private class InnerNode (level : Int ) extends Node (level):
136
+ private [SparseIntArray ] val elems = new Array [Node ](NodeSize )
137
+ private var empty : Boolean = true
138
+
139
+ def contains (index : Int ): Boolean =
140
+ val elem = elems(index >>> elemShift)
141
+ elem != null && elem.contains(index & elemMask)
142
+
143
+ def apply (index : Int ): Value =
144
+ val elem = elems(index >>> elemShift)
145
+ if elem == null then throw NoSuchElementException ()
146
+ elem.apply(index & elemMask)
147
+
148
+ def update (index : Int , value : Value ): Boolean =
149
+ empty = false
150
+ var elem = elems(index >>> elemShift)
151
+ if elem == null then
152
+ elem = newNode(level - 1 )
153
+ elems(index >>> elemShift) = elem
154
+ elem.update(index & elemMask, value)
155
+
156
+ def remove (index : Int ): Boolean =
157
+ val elem = elems(index >>> elemShift)
158
+ if elem == null then false
159
+ else
160
+ val result = elem.remove(index & elemMask)
161
+ if elem.isEmpty then
162
+ elems(index >>> elemShift) = null
163
+ var i = 0
164
+ while i < NodeSize && elems(i) == null do i += 1
165
+ if i == NodeSize then empty = true
166
+ result
167
+
168
+ def isEmpty = empty
169
+
170
+ def foreachBinding (op : (Int , Value ) => Unit , offset : Int ): Unit =
171
+ var i = 0
172
+ while i < NodeSize do
173
+ if elems(i) != null then
174
+ elems(i).foreachBinding(op, offset + i * elemSize)
175
+ i += 1
176
+
177
+ def transform (op : (Int , Value ) => Value , offset : Int ): Unit =
178
+ var i = 0
179
+ while i < NodeSize do
180
+ if elems(i) != null then
181
+ elems(i).transform(op, offset + i * elemSize)
182
+ i += 1
183
+
184
+ def nodeCount =
185
+ 1 + elems.filter(_ != null ).map(_.nodeCount).sum
186
+
187
+ override def toString =
188
+ elems
189
+ .zipWithIndex
190
+ .filter((elem, idx) => elem != null )
191
+ .map((elem, idx) => s " $idx -> $elem" ).mkString(s " $level#( " , " , " , " )" )
192
+ end InnerNode
193
+
194
+ private def newNode (level : Int ): Node =
195
+ if level == 0 then LeafNode () else InnerNode (level)
196
+
197
+ end SparseIntArray
198
+
199
+ @ main def Test =
200
+ val a = SparseIntArray ()
201
+ println(s " a = $a" )
202
+ a(1 ) = 22
203
+ println(s " a = $a" )
204
+ a(222 ) = 33
205
+ println(s " a = $a" )
206
+ a(55555 ) = 44
207
+ println(s " a = $a" )
208
+ assert(a.size == 3 , a)
209
+ assert(a.contains(1 ), a)
210
+ assert(a.contains(222 ), a)
211
+ assert(a.contains(55555 ), a)
212
+ assert(! a.contains(2 ))
213
+ assert(! a.contains(20000000 ))
214
+ a(222 ) = 44
215
+ assert(a.size == 3 )
216
+ assert(a(1 ) == 22 )
217
+ assert(a(222 ) == 44 )
218
+ assert(a(55555 ) == 44 )
219
+ assert(a.remove(1 ))
220
+ println(s " a = $a" )
221
+ assert(a(222 ) == 44 , a)
222
+ assert(a.remove(55555 ))
223
+ assert(a(222 ) == 44 , a)
224
+ assert(a.size == 1 )
225
+ assert(! a.contains(1 ))
226
+ assert(! a.remove(55555 ))
227
+ assert(a.remove(222 ))
228
+ assert(a.size == 0 )
0 commit comments