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