1
1
/*
2
- * Copyright 2016-2018 JetBrains s.r.o.
2
+ * Copyright 2016-2019 JetBrains s.r.o.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
@@ -20,59 +20,81 @@ package kotlinx.collections.immutable.implementations.immutableSet
20
20
internal const val MAX_BRANCHING_FACTOR = 32
21
21
internal const val LOG_MAX_BRANCHING_FACTOR = 5
22
22
internal const val MAX_BRANCHING_FACTOR_MINUS_ONE = MAX_BRANCHING_FACTOR - 1
23
- internal const val ENTRY_SIZE = 2
24
23
internal const val MAX_SHIFT = 30
25
24
26
-
27
- internal class TrieNode <E >(var bitmap : Int ,
28
- var buffer : Array <Any ?>,
29
- var marker : Marker ? ) {
25
+ /* *
26
+ * Gets trie index segment of the specified [index] at the level specified by [shift].
27
+ *
28
+ * `shift` equal to zero corresponds to the root level.
29
+ * For each lower level `shift` increments by [LOG_MAX_BRANCHING_FACTOR].
30
+ */
31
+ internal fun indexSegment (index : Int , shift : Int ): Int =
32
+ (index shr shift) and MAX_BRANCHING_FACTOR_MINUS_ONE
33
+
34
+
35
+ private fun <E > Array<Any?>.addElementAtIndex (index : Int , element : E ): Array <Any ?> {
36
+ val newBuffer = arrayOfNulls<Any ?>(this .size + 1 )
37
+ this .copyInto(newBuffer, endIndex = index)
38
+ this .copyInto(newBuffer, index + 1 , index, this .size)
39
+ newBuffer[index] = element
40
+ return newBuffer
41
+ }
42
+
43
+ private fun Array<Any?>.removeCellAtIndex (cellIndex : Int ): Array <Any ?> {
44
+ val newBuffer = arrayOfNulls<Any ?>(this .size - 1 )
45
+ this .copyInto(newBuffer, endIndex = cellIndex)
46
+ this .copyInto(newBuffer, cellIndex, cellIndex + 1 , this .size)
47
+ return newBuffer
48
+ }
49
+
50
+ internal class TrieNode <E >(
51
+ var bitmap : Int ,
52
+ var buffer : Array <Any ?>,
53
+ var marker : Marker ?
54
+ ) {
30
55
31
56
constructor (bitmap: Int , buffer: Array <Any ?>) : this (bitmap, buffer, null )
32
57
33
- private fun isNullCellAt (position : Int ): Boolean {
34
- return bitmap and position == 0
58
+ // here and later:
59
+ // positionMask — an int in form 2^n, i.e. having the single bit set, whose ordinal is a logical position in buffer
60
+
61
+ private fun hasNoCellAt (positionMask : Int ): Boolean {
62
+ return bitmap and positionMask == 0
35
63
}
36
64
37
- private fun indexOfCellAt (position : Int ): Int {
38
- return Integer .bitCount(bitmap and (position - 1 ))
65
+ private fun indexOfCellAt (positionMask : Int ): Int {
66
+ return Integer .bitCount(bitmap and (positionMask - 1 ))
39
67
}
40
68
41
69
private fun elementAtIndex (index : Int ): E {
70
+ @Suppress(" UNCHECKED_CAST" )
42
71
return buffer[index] as E
43
72
}
44
73
45
74
private fun nodeAtIndex (index : Int ): TrieNode <E > {
75
+ @Suppress(" UNCHECKED_CAST" )
46
76
return buffer[index] as TrieNode <E >
47
77
}
48
78
49
- private fun bufferAddElementAtIndex (index : Int , element : E ): Array <Any ?> {
50
- val newBuffer = arrayOfNulls<Any ?>(buffer.size + 1 )
51
- System .arraycopy(buffer, 0 , newBuffer, 0 , index)
52
- System .arraycopy(buffer, index, newBuffer, index + 1 , buffer.size - index)
53
- newBuffer[index] = element
54
- return newBuffer
55
- }
79
+ private fun addElementAt (positionMask : Int , element : E ): TrieNode <E > {
80
+ // assert(hasNoCellAt(positionMask))
56
81
57
- private fun addElementAt (position : Int , element : E ): TrieNode <E > {
58
- // assert(isNullCellAt(position))
59
-
60
- val index = indexOfCellAt(position)
61
- val newBuffer = bufferAddElementAtIndex(index, element)
62
- return TrieNode (bitmap or position, newBuffer)
82
+ val index = indexOfCellAt(positionMask)
83
+ val newBuffer = buffer.addElementAtIndex(index, element)
84
+ return TrieNode (bitmap or positionMask, newBuffer)
63
85
}
64
86
65
- private fun mutableAddElementAt (position : Int , element : E , mutatorMarker : Marker ): TrieNode <E > {
66
- // assert(isNullCellAt(position ))
87
+ private fun mutableAddElementAt (positionMask : Int , element : E , mutatorMarker : Marker ): TrieNode <E > {
88
+ // assert(hasNoCellAt(positionMask ))
67
89
68
- val index = indexOfCellAt(position )
90
+ val index = indexOfCellAt(positionMask )
69
91
if (marker == = mutatorMarker) {
70
- buffer = bufferAddElementAtIndex (index, element)
71
- bitmap = bitmap or position
92
+ buffer = buffer.addElementAtIndex (index, element)
93
+ bitmap = bitmap or positionMask
72
94
return this
73
95
}
74
- val newBuffer = bufferAddElementAtIndex (index, element)
75
- return TrieNode (bitmap or position , newBuffer, mutatorMarker)
96
+ val newBuffer = buffer.addElementAtIndex (index, element)
97
+ return TrieNode (bitmap or positionMask , newBuffer, mutatorMarker)
76
98
}
77
99
78
100
private fun updateNodeAtIndex (nodeIndex : Int , newNode : TrieNode <E >): TrieNode <E > {
@@ -104,17 +126,13 @@ internal class TrieNode<E>(var bitmap: Int,
104
126
105
127
private fun moveElementToNode (elementIndex : Int , newElementHash : Int , newElement : E ,
106
128
shift : Int ): TrieNode <E > {
107
- // assert(!isNullCellAt(position))
108
-
109
129
val newBuffer = buffer.copyOf()
110
130
newBuffer[elementIndex] = makeNodeAtIndex(elementIndex, newElementHash, newElement, shift, null )
111
131
return TrieNode (bitmap, newBuffer)
112
132
}
113
133
114
134
private fun mutableMoveElementToNode (elementIndex : Int , newElementHash : Int , newElement : E ,
115
135
shift : Int , mutatorMarker : Marker ): TrieNode <E > {
116
- // assert(!isNullCellAt(position))
117
-
118
136
if (marker == = mutatorMarker) {
119
137
buffer[elementIndex] = makeNodeAtIndex(elementIndex, newElementHash, newElement, shift, mutatorMarker)
120
138
return this
@@ -128,67 +146,63 @@ internal class TrieNode<E>(var bitmap: Int,
128
146
shift : Int , mutatorMarker : Marker ? ): TrieNode <E > {
129
147
if (shift > MAX_SHIFT ) {
130
148
// assert(element1 != element2)
149
+ // when two element hashes are entirely equal: the last level subtrie node stores them just as unordered list
131
150
return TrieNode <E >(0 , arrayOf(element1, element2), mutatorMarker)
132
151
}
133
152
134
- val setBit1 = (elementHash1 shr shift) and MAX_BRANCHING_FACTOR_MINUS_ONE
135
- val setBit2 = (elementHash2 shr shift) and MAX_BRANCHING_FACTOR_MINUS_ONE
153
+ val setBit1 = indexSegment (elementHash1, shift)
154
+ val setBit2 = indexSegment (elementHash2, shift)
136
155
137
156
if (setBit1 != setBit2) {
138
- val nodeBuffer = if (setBit1 < setBit2) {
157
+ val nodeBuffer = if (setBit1 < setBit2) {
139
158
arrayOf<Any ?>(element1, element2)
140
159
} else {
141
160
arrayOf<Any ?>(element2, element1)
142
161
}
143
162
return TrieNode ((1 shl setBit1) or (1 shl setBit2), nodeBuffer, mutatorMarker)
144
163
}
164
+ // hash segments at the given shift are equal: move these elements into the subtrie
145
165
val node = makeNode(elementHash1, element1, elementHash2, element2, shift + LOG_MAX_BRANCHING_FACTOR , mutatorMarker)
146
166
return TrieNode <E >(1 shl setBit1, arrayOf(node), mutatorMarker)
147
167
}
148
168
149
- private fun bufferRemoveCellAtIndex (cellIndex : Int ): Array <Any ?> {
150
- val newBuffer = arrayOfNulls<Any ?>(buffer.size - 1 )
151
- System .arraycopy(buffer, 0 , newBuffer, 0 , cellIndex)
152
- System .arraycopy(buffer, cellIndex + 1 , newBuffer, cellIndex, buffer.size - cellIndex - 1 )
153
- return newBuffer
154
- }
155
169
156
- private fun removeCellAtIndex (cellIndex : Int , position : Int ): TrieNode <E >? {
157
- // assert(!isNullCellAt(position ))
158
- if (buffer.size == 1 ) { return null }
170
+ private fun removeCellAtIndex (cellIndex : Int , positionMask : Int ): TrieNode <E >? {
171
+ // assert(!hasNoCellAt(positionMask ))
172
+ if (buffer.size == 1 ) return null
159
173
160
- val newBuffer = bufferRemoveCellAtIndex (cellIndex)
161
- return TrieNode (bitmap xor position , newBuffer)
174
+ val newBuffer = buffer.removeCellAtIndex (cellIndex)
175
+ return TrieNode (bitmap xor positionMask , newBuffer)
162
176
}
163
177
164
- private fun mutableRemoveCellAtIndex (cellIndex : Int , position : Int , mutatorMarker : Marker ): TrieNode <E >? {
165
- // assert(!isNullCellAt(position ))
166
- if (buffer.size == 1 ) { return null }
178
+ private fun mutableRemoveCellAtIndex (cellIndex : Int , positionMask : Int , mutatorMarker : Marker ): TrieNode <E >? {
179
+ // assert(!hasNoCellAt(positionMask ))
180
+ if (buffer.size == 1 ) return null
167
181
168
182
if (marker == = mutatorMarker) {
169
- buffer = bufferRemoveCellAtIndex (cellIndex)
170
- bitmap = bitmap xor position
183
+ buffer = buffer.removeCellAtIndex (cellIndex)
184
+ bitmap = bitmap xor positionMask
171
185
return this
172
186
}
173
- val newBuffer = bufferRemoveCellAtIndex (cellIndex)
174
- return TrieNode (bitmap xor position , newBuffer, mutatorMarker)
187
+ val newBuffer = buffer.removeCellAtIndex (cellIndex)
188
+ return TrieNode (bitmap xor positionMask , newBuffer, mutatorMarker)
175
189
}
176
190
177
191
private fun collisionRemoveElementAtIndex (i : Int ): TrieNode <E >? {
178
- if (buffer.size == 1 ) { return null }
192
+ if (buffer.size == 1 ) return null
179
193
180
- val newBuffer = bufferRemoveCellAtIndex (i)
194
+ val newBuffer = buffer.removeCellAtIndex (i)
181
195
return TrieNode (0 , newBuffer)
182
196
}
183
197
184
198
private fun mutableCollisionRemoveElementAtIndex (i : Int , mutatorMarker : Marker ): TrieNode <E >? {
185
- if (buffer.size == 1 ) { return null }
199
+ if (buffer.size == 1 ) return null
186
200
187
201
if (marker == = mutatorMarker) {
188
- buffer = bufferRemoveCellAtIndex (i)
202
+ buffer = buffer.removeCellAtIndex (i)
189
203
return this
190
204
}
191
- val newBuffer = bufferRemoveCellAtIndex (i)
205
+ val newBuffer = buffer.removeCellAtIndex (i)
192
206
return TrieNode (0 , newBuffer, mutatorMarker)
193
207
}
194
208
@@ -197,19 +211,19 @@ internal class TrieNode<E>(var bitmap: Int,
197
211
}
198
212
199
213
private fun collisionAdd (element : E ): TrieNode <E > {
200
- if (collisionContainsElement(element)) { return this }
201
- val newBuffer = bufferAddElementAtIndex (0 , element)
214
+ if (collisionContainsElement(element)) return this
215
+ val newBuffer = buffer.addElementAtIndex (0 , element)
202
216
return TrieNode (0 , newBuffer)
203
217
}
204
218
205
219
private fun mutableCollisionAdd (element : E , mutator : PersistentHashSetBuilder <* >): TrieNode <E > {
206
- if (collisionContainsElement(element)) { return this }
220
+ if (collisionContainsElement(element)) return this
207
221
mutator.size++
208
222
if (marker == = mutator.marker) {
209
- buffer = bufferAddElementAtIndex (0 , element)
223
+ buffer = buffer.addElementAtIndex (0 , element)
210
224
return this
211
225
}
212
- val newBuffer = bufferAddElementAtIndex (0 , element)
226
+ val newBuffer = buffer.addElementAtIndex (0 , element)
213
227
return TrieNode (0 , newBuffer, mutator.marker)
214
228
}
215
229
@@ -231,13 +245,13 @@ internal class TrieNode<E>(var bitmap: Int,
231
245
}
232
246
233
247
fun contains (elementHash : Int , element : E , shift : Int ): Boolean {
234
- val cellPosition = 1 shl (( elementHash shr shift) and MAX_BRANCHING_FACTOR_MINUS_ONE )
248
+ val cellPositionMask = 1 shl indexSegment( elementHash, shift)
235
249
236
- if (isNullCellAt(cellPosition )) { // element is absent
250
+ if (hasNoCellAt(cellPositionMask )) { // element is absent
237
251
return false
238
252
}
239
253
240
- val cellIndex = indexOfCellAt(cellPosition )
254
+ val cellIndex = indexOfCellAt(cellPositionMask )
241
255
if (buffer[cellIndex] is TrieNode <* >) { // element may be in node
242
256
val targetNode = nodeAtIndex(cellIndex)
243
257
if (shift == MAX_SHIFT ) {
@@ -250,32 +264,32 @@ internal class TrieNode<E>(var bitmap: Int,
250
264
}
251
265
252
266
fun add (elementHash : Int , element : E , shift : Int ): TrieNode <E > {
253
- val cellPosition = 1 shl (( elementHash shr shift) and MAX_BRANCHING_FACTOR_MINUS_ONE )
267
+ val cellPositionMask = 1 shl indexSegment( elementHash, shift)
254
268
255
- if (isNullCellAt(cellPosition )) { // element is absent
256
- return addElementAt(cellPosition , element)
269
+ if (hasNoCellAt(cellPositionMask )) { // element is absent
270
+ return addElementAt(cellPositionMask , element)
257
271
}
258
272
259
- val cellIndex = indexOfCellAt(cellPosition )
273
+ val cellIndex = indexOfCellAt(cellPositionMask )
260
274
if (buffer[cellIndex] is TrieNode <* >) { // element may be in node
261
275
val targetNode = nodeAtIndex(cellIndex)
262
276
val newNode = if (shift == MAX_SHIFT ) {
263
277
targetNode.collisionAdd(element)
264
278
} else {
265
279
targetNode.add(elementHash, element, shift + LOG_MAX_BRANCHING_FACTOR )
266
280
}
267
- if (targetNode == = newNode) { return this }
281
+ if (targetNode == = newNode) return this
268
282
return updateNodeAtIndex(cellIndex, newNode)
269
283
}
270
284
// element is directly in buffer
271
- if (element == buffer[cellIndex]) { return this }
285
+ if (element == buffer[cellIndex]) return this
272
286
return moveElementToNode(cellIndex, elementHash, element, shift)
273
287
}
274
288
275
289
fun mutableAdd (elementHash : Int , element : E , shift : Int , mutator : PersistentHashSetBuilder <* >): TrieNode <E > {
276
- val cellPosition = 1 shl (( elementHash shr shift) and MAX_BRANCHING_FACTOR_MINUS_ONE )
290
+ val cellPosition = 1 shl indexSegment( elementHash, shift)
277
291
278
- if (isNullCellAt (cellPosition)) { // element is absent
292
+ if (hasNoCellAt (cellPosition)) { // element is absent
279
293
mutator.size++
280
294
return mutableAddElementAt(cellPosition, element, mutator.marker)
281
295
}
@@ -288,64 +302,68 @@ internal class TrieNode<E>(var bitmap: Int,
288
302
} else {
289
303
targetNode.mutableAdd(elementHash, element, shift + LOG_MAX_BRANCHING_FACTOR , mutator)
290
304
}
291
- if (targetNode == = newNode) { return this }
305
+ if (targetNode == = newNode) return this
292
306
return mutableUpdateNodeAtIndex(cellIndex, newNode, mutator.marker)
293
307
}
294
308
// element is directly in buffer
295
- if (element == buffer[cellIndex]) { return this }
309
+ if (element == buffer[cellIndex]) return this
296
310
mutator.size++
297
311
return mutableMoveElementToNode(cellIndex, elementHash, element, shift, mutator.marker)
298
312
}
299
313
300
314
fun remove (elementHash : Int , element : E , shift : Int ): TrieNode <E >? {
301
- val cellPosition = 1 shl (( elementHash shr shift) and MAX_BRANCHING_FACTOR_MINUS_ONE )
315
+ val cellPositionMask = 1 shl indexSegment( elementHash, shift)
302
316
303
- if (isNullCellAt(cellPosition )) { // element is absent
317
+ if (hasNoCellAt(cellPositionMask )) { // element is absent
304
318
return this
305
319
}
306
320
307
- val cellIndex = indexOfCellAt(cellPosition )
321
+ val cellIndex = indexOfCellAt(cellPositionMask )
308
322
if (buffer[cellIndex] is TrieNode <* >) { // element may be in node
309
323
val targetNode = nodeAtIndex(cellIndex)
310
324
val newNode = if (shift == MAX_SHIFT ) {
311
325
targetNode.collisionRemove(element)
312
326
} else {
313
327
targetNode.remove(elementHash, element, shift + LOG_MAX_BRANCHING_FACTOR )
314
328
}
315
- if (targetNode == = newNode) { return this }
316
- if (newNode == null ) { return removeCellAtIndex(cellIndex, cellPosition) }
317
- return updateNodeAtIndex(cellIndex, newNode)
329
+ return when {
330
+ targetNode == = newNode -> this
331
+ newNode == null -> removeCellAtIndex(cellIndex, cellPositionMask)
332
+ else -> updateNodeAtIndex(cellIndex, newNode)
333
+ }
318
334
}
319
335
// element is directly in buffer
320
336
if (element == buffer[cellIndex]) {
321
- return removeCellAtIndex(cellIndex, cellPosition )
337
+ return removeCellAtIndex(cellIndex, cellPositionMask )
322
338
}
323
339
return this
324
340
}
325
341
326
342
fun mutableRemove (elementHash : Int , element : E , shift : Int , mutator : PersistentHashSetBuilder <* >): TrieNode <E >? {
327
- val cellPosition = 1 shl (( elementHash shr shift) and MAX_BRANCHING_FACTOR_MINUS_ONE )
343
+ val cellPositionMask = 1 shl indexSegment( elementHash, shift)
328
344
329
- if (isNullCellAt(cellPosition )) { // element is absent
345
+ if (hasNoCellAt(cellPositionMask )) { // element is absent
330
346
return this
331
347
}
332
348
333
- val cellIndex = indexOfCellAt(cellPosition )
349
+ val cellIndex = indexOfCellAt(cellPositionMask )
334
350
if (buffer[cellIndex] is TrieNode <* >) { // element may be in node
335
351
val targetNode = nodeAtIndex(cellIndex)
336
352
val newNode = if (shift == MAX_SHIFT ) {
337
353
targetNode.mutableCollisionRemove(element, mutator)
338
354
} else {
339
355
targetNode.mutableRemove(elementHash, element, shift + LOG_MAX_BRANCHING_FACTOR , mutator)
340
356
}
341
- if (targetNode == = newNode) { return this }
342
- if (newNode == null ) { return mutableRemoveCellAtIndex(cellIndex, cellPosition, mutator.marker) }
343
- return mutableUpdateNodeAtIndex(cellIndex, newNode, mutator.marker)
357
+ return when {
358
+ targetNode == = newNode -> this
359
+ newNode == null -> mutableRemoveCellAtIndex(cellIndex, cellPositionMask, mutator.marker)
360
+ else -> mutableUpdateNodeAtIndex(cellIndex, newNode, mutator.marker)
361
+ }
344
362
}
345
363
// element is directly in buffer
346
364
if (element == buffer[cellIndex]) {
347
365
mutator.size--
348
- return mutableRemoveCellAtIndex(cellIndex, cellPosition , mutator.marker) // check is empty
366
+ return mutableRemoveCellAtIndex(cellIndex, cellPositionMask , mutator.marker) // check is empty
349
367
}
350
368
return this
351
369
}
0 commit comments