1
+ /*
2
+ * Copyright 2016-2019 JetBrains s.r.o.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ package kotlinx.collections.immutable.implementations.immutableList
18
+
19
+ /* *
20
+ * The class responsible for iterating over elements of the [PersistentVectorBuilder].
21
+ *
22
+ * There are two parts where the elements of the builder are located: root and tail.
23
+ * [TrieIterator] is responsible for iterating over elements located at root,
24
+ * whereas tail elements are iterated directly from this class.
25
+ */
26
+ internal class PersistentVectorMutableIterator <T >(
27
+ private val builder : PersistentVectorBuilder <T >,
28
+ index : Int
29
+ ) : MutableListIterator<T>, AbstractListIterator<T>(index, builder.size) {
30
+
31
+ /* *
32
+ * The modCount this iterator is aware of.
33
+ * Used to check if the [PersistentVectorBuilder] was modified outside this iterator.
34
+ */
35
+ private var expectedModCount = builder.getModCount()
36
+ /* *
37
+ * Iterates over leaves of the builder.root trie.
38
+ * This property is equal to null if builder.root is null.
39
+ */
40
+ private var trieIterator: TrieIterator <T >? = null
41
+ /* *
42
+ * Index of the element this iterator returned from last invocation of next() or previous().
43
+ * Used to remove or set new value at this index.
44
+ * This property is set to -1 when method `add(element: T)` or `remove()` gets invoked.
45
+ */
46
+ private var lastIteratedIndex = - 1
47
+
48
+ init {
49
+ setupTrieIterator()
50
+ }
51
+
52
+ override fun previous (): T {
53
+ checkForComodification()
54
+ checkHasPrevious()
55
+
56
+ lastIteratedIndex = index - 1
57
+
58
+ val trieIterator = this .trieIterator ? : return builder.tail[-- index] as T
59
+ if (index > trieIterator.size) {
60
+ return builder.tail[-- index - trieIterator.size] as T
61
+ }
62
+ index--
63
+ return trieIterator.previous()
64
+ }
65
+
66
+ override fun next (): T {
67
+ checkForComodification()
68
+ checkHasNext()
69
+
70
+ lastIteratedIndex = index
71
+
72
+ val trieIterator = this .trieIterator ? : return builder.tail[index++ ] as T
73
+ if (trieIterator.hasNext()) {
74
+ index++
75
+ return trieIterator.next()
76
+ }
77
+ return builder.tail[index++ - trieIterator.size] as T
78
+ }
79
+
80
+ private fun reset () {
81
+ size = builder.size
82
+ expectedModCount = builder.getModCount()
83
+ lastIteratedIndex = - 1
84
+
85
+ setupTrieIterator()
86
+ }
87
+
88
+ private fun setupTrieIterator () {
89
+ val root = builder.root
90
+ if (root == null ) {
91
+ trieIterator = null
92
+ return
93
+ }
94
+
95
+ val trieSize = rootSize(builder.size)
96
+ val trieIndex = index.coerceAtMost(trieSize)
97
+ val trieHeight = builder.rootShift / LOG_MAX_BUFFER_SIZE + 1
98
+ if (trieIterator == null ) {
99
+ trieIterator = TrieIterator (root, trieIndex, trieSize, trieHeight)
100
+ } else {
101
+ trieIterator!! .reset(root, trieIndex, trieSize, trieHeight)
102
+ }
103
+ }
104
+
105
+ override fun add (element : T ) {
106
+ checkForComodification()
107
+
108
+ builder.add(index, element)
109
+ index++
110
+ reset()
111
+ }
112
+
113
+ override fun remove () {
114
+ checkForComodification()
115
+ checkHasIterated()
116
+
117
+ builder.removeAt(lastIteratedIndex)
118
+ if (lastIteratedIndex < index) index = lastIteratedIndex
119
+ reset()
120
+ }
121
+
122
+ override fun set (element : T ) {
123
+ checkForComodification()
124
+ checkHasIterated()
125
+
126
+ builder[lastIteratedIndex] = element
127
+
128
+ expectedModCount = builder.getModCount()
129
+ setupTrieIterator()
130
+ }
131
+
132
+ private fun checkForComodification () {
133
+ if (expectedModCount != builder.getModCount())
134
+ throw ConcurrentModificationException ()
135
+ }
136
+
137
+ private fun checkHasIterated () {
138
+ if (lastIteratedIndex == - 1 )
139
+ throw IllegalStateException ()
140
+ }
141
+
142
+ private fun checkHasNext () {
143
+ if (! hasNext())
144
+ throw NoSuchElementException ()
145
+ }
146
+
147
+ private fun checkHasPrevious () {
148
+ if (! hasPrevious())
149
+ throw NoSuchElementException ()
150
+ }
151
+ }
0 commit comments