Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart.collection; | 5 part of dart.collection; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * A node in a splay tree. It holds the key, the value and the left | 8 * A node in a splay tree. It holds the key, the value and the left |
| 9 * and right children in the tree. | 9 * and right children in the tree. |
| 10 */ | 10 */ |
| 11 class SplayTreeNode<K, V> { | 11 class SplayTreeNode<K, V> { |
| 12 SplayTreeNode(K this.key, V this.value); | 12 final K key; |
| 13 | |
| 14 K key; | |
| 15 V value; | 13 V value; |
| 16 SplayTreeNode<K, V> left; | 14 SplayTreeNode<K, V> left; |
| 17 SplayTreeNode<K, V> right; | 15 SplayTreeNode<K, V> right; |
| 16 | |
| 17 SplayTreeNode(K this.key, V this.value); | |
| 18 } | 18 } |
| 19 | 19 |
| 20 /** | 20 /** |
| 21 * A splay tree is a self-balancing binary | 21 * A splay tree is a self-balancing binary |
| 22 * search tree with the additional property that recently accessed | 22 * search tree with the additional property that recently accessed |
| 23 * elements are quick to access again. It performs basic operations | 23 * elements are quick to access again. It performs basic operations |
| 24 * such as insertion, look-up and removal in O(log(n)) amortized time. | 24 * such as insertion, look-up and removal in O(log(n)) amortized time. |
| 25 * | 25 * |
| 26 * This implementation is a Dart version of the JavaScript | 26 * This implementation is a Dart version of the JavaScript |
| 27 * implementation in the V8 project. | 27 * implementation in the V8 project. |
| 28 */ | 28 */ |
| 29 class SplayTreeMap<K extends Comparable, V> implements Map<K, V> { | 29 class SplayTreeMap<K extends Comparable, V> implements Map<K, V> { |
| 30 | 30 |
| 31 // The root node of the splay tree. It will contain either the last | 31 // The root node of the splay tree. It will contain either the last |
| 32 // element inserted, or the last element looked up. | 32 // element inserted, or the last element looked up. |
| 33 SplayTreeNode<K, V> _root; | 33 SplayTreeNode<K, V> _root; |
| 34 | 34 |
| 35 // The dummy node used when performing a splay on the tree. It is a | 35 // The dummy node used when performing a splay on the tree. It is a |
| 36 // local field of the class to avoid allocating a node each time a | 36 // local field of the class to avoid allocating a node each time a |
| 37 // splay is performed. | 37 // splay is performed. |
| 38 SplayTreeNode<K, V> _dummy; | 38 SplayTreeNode<K, V> _dummy; |
| 39 | 39 |
| 40 // Number of elements in the splay tree. | 40 // Number of elements in the splay tree. |
| 41 int _count; | 41 int _count; |
| 42 | 42 |
| 43 SplayTreeMap() { | 43 /** |
| 44 _dummy = new SplayTreeNode<K, V>(null, null); | 44 * Counter incremented whenever the keys in the map changes. |
| 45 * | |
| 46 * Used to detect concurrent modifications. | |
| 47 */ | |
| 48 int _modificationCount = 0; | |
| 49 /** | |
| 50 * Counter incremented whenever the tree structure changes. | |
| 51 * | |
| 52 * Used to detect that an in-place traversal | |
|
floitsch
2013/02/15 10:04:49
unfinished sentence.
Lasse Reichstein Nielsen
2013/02/15 13:46:37
Finished.
| |
| 53 */ | |
| 54 int _splayCount = 0; | |
| 55 | |
| 56 SplayTreeMap() : | |
| 57 _dummy = new SplayTreeNode<K, V>(null, null), | |
| 45 _count = 0; | 58 _count = 0; |
| 46 } | |
| 47 | 59 |
| 48 /** | 60 /** |
| 49 * Perform the splay operation for the given key. Moves the node with | 61 * Perform the splay operation for the given key. Moves the node with |
| 50 * the given key to the top of the tree. If no node has the given | 62 * the given key to the top of the tree. If no node has the given |
| 51 * key, the last node on the search path is moved to the top of the | 63 * key, the last node on the search path is moved to the top of the |
| 52 * tree. This is the simplified top-down splaying algorithm from: | 64 * tree. This is the simplified top-down splaying algorithm from: |
| 53 * "Self-adjusting Binary Search Trees" by Sleator and Tarjan. | 65 * "Self-adjusting Binary Search Trees" by Sleator and Tarjan. |
| 66 * | |
| 67 * Returns the result of comparing the new root of the tree to [key]. | |
| 68 * Returns -1 if the table is empty. | |
| 54 */ | 69 */ |
| 55 void splay_(K key) { | 70 int _splay(K key) { |
| 56 if (isEmpty) return; | 71 if (_root == null) return -1; |
| 57 | 72 |
| 58 // The right child of the dummy node will hold | 73 // The right child of the dummy node will hold |
| 59 // the L tree of the algorithm. The left child of the dummy node | 74 // the L tree of the algorithm. The left child of the dummy node |
| 60 // will hold the R tree of the algorithm. Using a dummy node, left | 75 // will hold the R tree of the algorithm. Using a dummy node, left |
| 61 // and right will always be nodes and we avoid special cases. | 76 // and right will always be nodes and we avoid special cases. |
| 62 SplayTreeNode<K, V> left = _dummy; | 77 SplayTreeNode<K, V> left = _dummy; |
| 63 SplayTreeNode<K, V> right = _dummy; | 78 SplayTreeNode<K, V> right = _dummy; |
| 64 SplayTreeNode<K, V> current = _root; | 79 SplayTreeNode<K, V> current = _root; |
| 80 int comp; | |
| 65 while (true) { | 81 while (true) { |
| 66 int comp = key.compareTo(current.key); | 82 comp = current.key.compareTo(key); |
| 67 if (comp < 0) { | 83 if (comp > 0) { |
| 68 if (current.left == null) break; | 84 if (current.left == null) break; |
| 69 if (key.compareTo(current.left.key) < 0) { | 85 comp = current.left.key.compareTo(key); |
| 86 if (comp > 0) { | |
| 70 // Rotate right. | 87 // Rotate right. |
| 71 SplayTreeNode<K, V> tmp = current.left; | 88 SplayTreeNode<K, V> tmp = current.left; |
| 72 current.left = tmp.right; | 89 current.left = tmp.right; |
| 73 tmp.right = current; | 90 tmp.right = current; |
| 74 current = tmp; | 91 current = tmp; |
| 75 if (current.left == null) break; | 92 if (current.left == null) break; |
| 76 } | 93 } |
| 77 // Link right. | 94 // Link right. |
| 78 right.left = current; | 95 right.left = current; |
| 79 right = current; | 96 right = current; |
| 80 current = current.left; | 97 current = current.left; |
| 81 } else if (comp > 0) { | 98 } else if (comp < 0) { |
| 82 if (current.right == null) break; | 99 if (current.right == null) break; |
| 83 if (key.compareTo(current.right.key) > 0) { | 100 comp = current.right.key.compareTo(key); |
| 101 if (comp < 0) { | |
| 84 // Rotate left. | 102 // Rotate left. |
| 85 SplayTreeNode<K, V> tmp = current.right; | 103 SplayTreeNode<K, V> tmp = current.right; |
| 86 current.right = tmp.left; | 104 current.right = tmp.left; |
| 87 tmp.left = current; | 105 tmp.left = current; |
| 88 current = tmp; | 106 current = tmp; |
| 89 if (current.right == null) break; | 107 if (current.right == null) break; |
| 90 } | 108 } |
| 91 // Link left. | 109 // Link left. |
| 92 left.right = current; | 110 left.right = current; |
| 93 left = current; | 111 left = current; |
| 94 current = current.right; | 112 current = current.right; |
| 95 } else { | 113 } else { |
| 96 break; | 114 break; |
| 97 } | 115 } |
| 98 } | 116 } |
| 99 // Assemble. | 117 // Assemble. |
| 100 left.right = current.left; | 118 left.right = current.left; |
| 101 right.left = current.right; | 119 right.left = current.right; |
| 102 current.left = _dummy.right; | 120 current.left = _dummy.right; |
| 103 current.right = _dummy.left; | 121 current.right = _dummy.left; |
| 104 _root = current; | 122 _root = current; |
| 105 | 123 |
| 106 _dummy.right = null; | 124 _dummy.right = null; |
| 107 _dummy.left = null; | 125 _dummy.left = null; |
| 126 _splayCount++; | |
| 127 return comp; | |
| 108 } | 128 } |
| 109 | 129 |
| 110 V operator [](K key) { | 130 V operator [](K key) { |
| 111 if (!isEmpty) { | 131 if (_root != null) { |
| 112 splay_(key); | 132 int comp = _splay(key); |
| 113 if (_root.key.compareTo(key) == 0) return _root.value; | 133 if (comp == 0) return _root.value; |
| 114 } | 134 } |
| 115 return null; | 135 return null; |
| 116 } | 136 } |
| 117 | 137 |
| 118 V remove(K key) { | 138 V remove(K key) { |
| 119 if (isEmpty) return null; | 139 if (_root == null) return null; |
| 120 splay_(key); | 140 int comp = _splay(key); |
| 121 if (_root.key.compareTo(key) != 0) return null; | 141 if (comp != 0) return null; |
| 122 V value = _root.value; | 142 V value = _root.value; |
| 123 | 143 |
| 124 _count--; | 144 _count--; |
| 125 // assert(_count >= 0); | 145 // assert(_count >= 0); |
| 126 if (_root.left == null) { | 146 if (_root.left == null) { |
| 127 _root = _root.right; | 147 _root = _root.right; |
| 128 } else { | 148 } else { |
| 129 SplayTreeNode<K, V> right = _root.right; | 149 SplayTreeNode<K, V> right = _root.right; |
| 130 _root = _root.left; | 150 _root = _root.left; |
| 131 // Splay to make sure that the new root has an empty right child. | 151 // Splay to make sure that the new root has an empty right child. |
| 132 splay_(key); | 152 _splay(key); |
| 133 // Insert the original right child as the right child of the new | 153 // Insert the original right child as the right child of the new |
| 134 // root. | 154 // root. |
| 135 _root.right = right; | 155 _root.right = right; |
| 136 } | 156 } |
| 157 _modificationCount++; | |
| 137 return value; | 158 return value; |
| 138 } | 159 } |
| 139 | 160 |
| 140 void operator []=(K key, V value) { | 161 void operator []=(K key, V value) { |
| 141 if (isEmpty) { | 162 if (_root == null) { |
| 142 _count++; | 163 _count++; |
| 143 _root = new SplayTreeNode(key, value); | 164 _root = new SplayTreeNode(key, value); |
| 165 _modificationCount++; | |
| 144 return; | 166 return; |
| 145 } | 167 } |
| 146 // Splay on the key to move the last node on the search path for | 168 // Splay on the key to move the last node on the search path for |
| 147 // the key to the root of the tree. | 169 // the key to the root of the tree. |
| 148 splay_(key); | 170 int comp = _splay(key); |
| 149 if (_root.key.compareTo(key) == 0) { | 171 if (comp == 0) { |
| 150 _root.value = value; | 172 _root.value = value; |
| 151 return; | 173 return; |
| 152 } | 174 } |
| 175 _addNewRoot(key, value, comp); | |
| 176 } | |
| 177 | |
| 178 /** | |
| 179 * Adds a new root node with the given [key] or [value]. | |
| 180 * | |
| 181 * The [comp] value is the result of comparing the existing root's key | |
| 182 * with key. | |
| 183 */ | |
| 184 void _addNewRoot(K key, V value, int comp) { | |
| 153 SplayTreeNode<K, V> node = new SplayTreeNode(key, value); | 185 SplayTreeNode<K, V> node = new SplayTreeNode(key, value); |
| 154 // assert(_count >= 0); | 186 // assert(_count >= 0); |
| 155 _count++; | 187 _count++; |
| 156 if (key.compareTo(_root.key) > 0) { | 188 if (comp < 0) { |
| 157 node.left = _root; | 189 node.left = _root; |
| 158 node.right = _root.right; | 190 node.right = _root.right; |
| 159 _root.right = null; | 191 _root.right = null; |
| 160 } else { | 192 } else { |
| 161 node.right = _root; | 193 node.right = _root; |
| 162 node.left = _root.left; | 194 node.left = _root.left; |
| 163 _root.left = null; | 195 _root.left = null; |
| 164 } | 196 } |
| 165 _root = node; | 197 _root = node; |
| 198 _modificationCount++; | |
| 166 } | 199 } |
| 167 | 200 |
| 168 V putIfAbsent(K key, V ifAbsent()) { | 201 V putIfAbsent(K key, V ifAbsent()) { |
| 169 if (containsKey(key)) return this[key]; | 202 if (_root == null) { |
| 203 V value = ifAbsent(); | |
| 204 if (_root != null) { | |
| 205 throw new ConcurrentModificationError(this); | |
| 206 } | |
| 207 _root = new SplayTreeNode(key, value); | |
| 208 _count++; | |
| 209 _modificationCount++; | |
| 210 return value; | |
| 211 } | |
| 212 int comp = _splay(key); | |
| 213 if (comp == 0) return _root.value; | |
| 214 int modificationCount = _modificationCount; | |
| 215 int splayCount = _splayCount; | |
| 170 V value = ifAbsent(); | 216 V value = ifAbsent(); |
| 171 this[key] = value; | 217 if (modificationCount != _modificationCount) { |
| 218 throw new ConcurrentModificationError(this); | |
| 219 } | |
| 220 if (splayCount != _splayCount) { | |
| 221 comp = _splay(key); | |
| 222 if (comp == 0) { | |
|
floitsch
2013/02/15 10:04:49
Can this happen?
We didn't find the comp before, a
Lasse Reichstein Nielsen
2013/02/15 13:46:37
Good catch.
| |
| 223 _root.value = value; | |
| 224 return value; | |
| 225 } | |
| 226 } | |
| 227 _addNewRoot(key, value, comp); | |
| 172 return value; | 228 return value; |
| 173 } | 229 } |
| 174 | 230 |
| 175 bool get isEmpty { | 231 bool get isEmpty { |
| 176 // assert(!((_root == null) && (_count != 0))); | 232 // assert(!((_root == null) && (_count != 0))); |
| 177 // assert(!((_count == 0) && (_root != null))); | 233 // assert(!((_count == 0) && (_root != null))); |
| 178 return (_root == null); | 234 return (_root == null); |
| 179 } | 235 } |
| 180 | 236 |
| 181 void forEach(void f(K key, V value)) { | 237 void forEach(void f(K key, V value)) { |
| 182 List<SplayTreeNode<K, V>> list = new List<SplayTreeNode<K, V>>(); | 238 Iterator<SplayTreeNode<K, V>> nodes = |
| 183 SplayTreeNode<K, V> current = _root; | 239 new _SplayTreeNodeIterator<K, V>(this); |
| 184 while (current != null) { | 240 while (nodes.moveNext()) { |
| 185 if (current.left != null) { | 241 SplayTreeNode<K, V> node = nodes.current; |
| 186 list.add(current); | 242 f(node.key, node.value); |
| 187 current = current.left; | |
| 188 } else { | |
| 189 f(current.key, current.value); | |
| 190 while (current.right == null) { | |
| 191 if (list.isEmpty) return; | |
| 192 current = list.removeLast(); | |
| 193 f(current.key, current.value); | |
| 194 } | |
| 195 current = current.right; | |
| 196 } | |
| 197 } | 243 } |
| 198 } | 244 } |
| 199 | 245 |
| 200 int get length { | 246 int get length { |
| 201 return _count; | 247 return _count; |
| 202 } | 248 } |
| 203 | 249 |
| 204 void clear() { | 250 void clear() { |
| 205 _root = null; | 251 _root = null; |
| 206 _count = 0; | 252 _count = 0; |
| 207 } | 253 } |
| 208 | 254 |
| 209 bool containsKey(K key) { | 255 bool containsKey(K key) { |
| 210 if (!isEmpty) { | 256 return _splay(key) == 0; |
| 211 splay_(key); | |
| 212 if (_root.key.compareTo(key) == 0) return true; | |
| 213 } | |
| 214 return false; | |
| 215 } | 257 } |
| 216 | 258 |
| 217 bool containsValue(V value) { | 259 bool containsValue(V value) { |
| 218 bool found = false; | 260 bool found = false; |
| 219 bool visit(SplayTreeNode node) { | 261 bool visit(SplayTreeNode node) { |
| 220 if (node == null) return false; | 262 if (node == null) return false; |
| 221 if (node.value == value) return true; | 263 if (node.value == value) return true; |
| 264 // TODO(lrn): Do we want to handle the case where node.value.operator== | |
|
floitsch
2013/02/15 10:04:49
I guess we need to eventually.
Lasse Reichstein Nielsen
2013/02/15 13:46:37
We have to do the same for compareTo in _splay. Th
floitsch
2013/02/15 13:58:25
Let's look at that later.
| |
| 265 // modifies the map? | |
| 222 return visit(node.left) || visit(node.right); | 266 return visit(node.left) || visit(node.right); |
| 223 } | 267 } |
| 224 return visit(_root); | 268 return visit(_root); |
| 225 } | 269 } |
| 226 | 270 |
| 227 Collection<K> get keys { | 271 Iterable<K> get keys => new _SplayTreeKeyIterable(this); |
| 228 List<K> list = new List<K>(); | |
| 229 forEach((K k, V v) { list.add(k); }); | |
| 230 return list; | |
| 231 } | |
| 232 | 272 |
| 233 Collection<V> get values { | 273 Iterable<V> get values => new _SplayTreeValueIterable(this); |
| 234 List<V> list = new List<V>(); | |
| 235 forEach((K k, V v) { list.add(v); }); | |
| 236 return list; | |
| 237 } | |
| 238 | 274 |
| 239 String toString() { | 275 String toString() { |
| 240 return Maps.mapToString(this); | 276 return Maps.mapToString(this); |
| 241 } | 277 } |
| 242 | 278 |
| 243 /** | 279 /** |
| 244 * Get the first key in the map. Returns [null] if the map is empty. | 280 * Get the first key in the map. Returns [null] if the map is empty. |
| 245 */ | 281 */ |
| 246 K firstKey() { | 282 K firstKey() { |
| 247 if (_root == null) return null; | 283 if (_root == null) return null; |
| 248 SplayTreeNode<K, V> node = _root; | 284 SplayTreeNode<K, V> node = _root; |
| 249 while (node.left != null) { | 285 while (node.left != null) { |
| 250 node = node.left; | 286 node = node.left; |
| 251 } | 287 } |
| 252 // Maybe implement a splay-method that can splay the minimum without | 288 // Maybe implement a splay-method that can splay the minimum without |
| 253 // performing comparisons. | 289 // performing comparisons. |
| 254 splay_(node.key); | 290 _splay(node.key); |
| 255 return node.key; | 291 return node.key; |
| 256 } | 292 } |
| 257 | 293 |
| 258 /** | 294 /** |
| 259 * Get the last key in the map. Returns [null] if the map is empty. | 295 * Get the last key in the map. Returns [null] if the map is empty. |
| 260 */ | 296 */ |
| 261 K lastKey() { | 297 K lastKey() { |
| 262 if (_root == null) return null; | 298 if (_root == null) return null; |
| 263 SplayTreeNode<K, V> node = _root; | 299 SplayTreeNode<K, V> node = _root; |
| 264 while (node.right != null) { | 300 while (node.right != null) { |
| 265 node = node.right; | 301 node = node.right; |
| 266 } | 302 } |
| 267 // Maybe implement a splay-method that can splay the maximum without | 303 // Maybe implement a splay-method that can splay the maximum without |
| 268 // performing comparisons. | 304 // performing comparisons. |
| 269 splay_(node.key); | 305 _splay(node.key); |
| 270 return node.key; | 306 return node.key; |
| 271 } | 307 } |
| 272 | 308 |
| 273 /** | 309 /** |
| 274 * Get the last key in the map that is strictly smaller than [key]. Returns | 310 * Get the last key in the map that is strictly smaller than [key]. Returns |
| 275 * [null] if no key was not found. | 311 * [null] if no key was not found. |
| 276 */ | 312 */ |
| 277 K lastKeyBefore(K key) { | 313 K lastKeyBefore(K key) { |
| 278 splay_(key); | 314 if (_root == null) return null; |
| 279 K visit(SplayTreeNode node, K ifEmpty) { | 315 int comp = _splay(key); |
| 280 if (node == null) return ifEmpty; | 316 if (comp < 0) return _root.key; |
| 281 if (node.key.compareTo(key) >= 0) { | 317 SplayTreeNode<K, V> node = _root.left; |
| 282 return visit(node.left, ifEmpty); | 318 if (node == null) return null; |
| 283 } | 319 while (node.right != null) { |
| 284 if (node.key.compareTo(key) < 0) { | 320 node = node.right; |
| 285 return visit(node.right, node.key); | |
| 286 } | |
| 287 } | 321 } |
| 288 return visit(_root, null); | 322 return node.key; |
| 289 } | 323 } |
| 290 | 324 |
| 291 /** | 325 /** |
| 292 * Get the first key in the map that is strictly larger than [key]. Returns | 326 * Get the first key in the map that is strictly larger than [key]. Returns |
| 293 * [null] if no key was not found. | 327 * [null] if no key was not found. |
| 294 */ | 328 */ |
| 295 K firstKeyAfter(K key) { | 329 K firstKeyAfter(K key) { |
| 296 splay_(key); | 330 if (_root == null) return null; |
| 297 K visit(SplayTreeNode node, K ifEmpty) { | 331 int comp = _splay(key); |
| 298 if (node == null) return ifEmpty; | 332 if (comp > 0) return _root.key; |
| 299 if (node.key.compareTo(key) > 0) { | 333 SplayTreeNode<K, V> node = _root.right; |
| 300 return visit(node.left, node.key); | 334 if (node == null) return null; |
| 301 } | 335 while (node.left != null) { |
| 302 if (node.key.compareTo(key) <= 0) { | 336 node = node.left; |
| 303 return visit(node.right, ifEmpty); | |
| 304 } | |
| 305 } | 337 } |
| 306 return visit(_root, null); | 338 return node.key; |
| 307 } | 339 } |
| 308 } | 340 } |
| 341 | |
| 342 abstract class _SplayTreeIterator<T> implements Iterator<T> { | |
| 343 final SplayTreeMap _map; | |
| 344 /** | |
| 345 * Worklist of nodes to visit. | |
| 346 * | |
| 347 * These nodes have been passed over on the way down in a | |
| 348 * depth-first left-to-right traversal. Visiting each node, | |
| 349 * and their right subtrees will visit the remainder of | |
| 350 * the nodes of a full traversal. | |
| 351 * | |
| 352 * Only valid as long as the original tree map isn't reordered. | |
| 353 */ | |
| 354 final List<SplayTreeNode> _workList = <SplayTreeNode>[]; | |
| 355 | |
| 356 /** | |
| 357 * Original modification counter of [_map]. | |
| 358 * | |
| 359 * Incremented on [_map] when a key is added or removed. | |
| 360 * If it changes, iteration is aborted. | |
| 361 */ | |
| 362 final int _modificationCount; | |
| 363 /** | |
| 364 * Count of splay operations on [_map] when [_path] was build. | |
| 365 * | |
| 366 * If the splay count on [_map] increases, [_path] becomes invalid. | |
|
floitsch
2013/02/15 10:04:49
_workList
Lasse Reichstein Nielsen
2013/02/15 13:46:37
Done.
| |
| 367 */ | |
| 368 int _splayCount; | |
| 369 | |
| 370 /** Current node. */ | |
| 371 SplayTreeNode _currentNode; | |
| 372 | |
| 373 _SplayTreeIterator(SplayTreeMap map) | |
| 374 : _map = map, | |
| 375 _modificationCount = map._modificationCount, | |
| 376 _splayCount = map._splayCount { | |
| 377 _findLeftMostDescendent(map._root); | |
| 378 } | |
| 379 | |
| 380 T get current { | |
| 381 if (_currentNode == null) return null; | |
| 382 return _getValue(_currentNode); | |
| 383 } | |
| 384 | |
| 385 void _findLeftMostDescendent(SplayTreeNode node) { | |
| 386 while (node != null) { | |
| 387 _workList.add(node); | |
| 388 node = node.left; | |
| 389 } | |
| 390 } | |
| 391 | |
| 392 /** | |
| 393 * Called when the tree structure of the map has changed. | |
| 394 * | |
| 395 * This can be caused by a splay operation. | |
| 396 * If the key-set changes, iteration is aborted before getting | |
| 397 * here, so we know that the keys are the same as before, it's | |
| 398 * only the tree that has been reordered. | |
| 399 */ | |
| 400 void _rebuildWorkList(SplayTreeNode currentNode) { | |
| 401 assert(!_workList.isEmpty); | |
| 402 _workList.clear(); | |
| 403 if (currentNode == null) { | |
| 404 _findLeftMostDescendent(_map._root); | |
| 405 } else { | |
| 406 _map._splay(currentNode.key); | |
| 407 _findLeftMostDescendent(_map._root.right); | |
| 408 assert(!_workList.isEmpty); | |
| 409 } | |
| 410 } | |
| 411 | |
| 412 bool moveNext() { | |
| 413 if (_modificationCount != _map._modificationCount) { | |
| 414 throw new ConcurrentModificationError(_map); | |
| 415 } | |
| 416 // Picks the next element in the worklist as current. | |
| 417 // Updates the worklist with the left-most path of the current node's | |
| 418 // right-hand child. | |
| 419 // If the worklist is no longer valid (after a splay), it is rebuild | |
| 420 // from scratch. | |
| 421 if (_workList.isEmpty) { | |
| 422 _currentNode = null; | |
| 423 return false; | |
| 424 } | |
| 425 if (_map._splayCount != _splayCount) { | |
| 426 _rebuildWorkList(_currentNode); | |
| 427 } | |
| 428 _currentNode = _workList.removeLast(); | |
| 429 _findLeftMostDescendent(_currentNode.right); | |
| 430 return true; | |
| 431 } | |
| 432 | |
| 433 T _getValue(SplayTreeNode node); | |
| 434 } | |
| 435 | |
| 436 | |
| 437 class _SplayTreeKeyIterable<K, V> extends Iterable<K> { | |
| 438 SplayTreeMap<K, V> _map; | |
| 439 _SplayTreeKeyIterable(this._map); | |
| 440 Iterator<K> get iterator => new _SplayTreeKeyIterator<K, V>(_map); | |
| 441 } | |
| 442 | |
| 443 class _SplayTreeValueIterable<K, V> extends Iterable<V> { | |
| 444 SplayTreeMap<K, V> _map; | |
| 445 _SplayTreeValueIterable(this._map) ; | |
| 446 Iterator<V> get iterator => new _SplayTreeValueIterator<K, V>(_map); | |
| 447 } | |
| 448 | |
| 449 class _SplayTreeKeyIterator<K, V> extends _SplayTreeIterator<K> { | |
| 450 _SplayTreeKeyIterator(SplayTreeMap<K, V> map): super(map); | |
| 451 K _getValue(SplayTreeNode node) => node.key; | |
| 452 } | |
| 453 | |
| 454 class _SplayTreeValueIterator<K, V> extends _SplayTreeIterator<V> { | |
| 455 _SplayTreeValueIterator(SplayTreeMap<K, V> map): super(map); | |
| 456 V _getValue(SplayTreeNode node) => node.value; | |
| 457 } | |
| 458 | |
| 459 class _SplayTreeNodeIterator<K, V> | |
| 460 extends _SplayTreeIterator<SplayTreeNode<K, V>> { | |
| 461 _SplayTreeNodeIterator(SplayTreeMap<K, V> map): super(map); | |
| 462 SplayTreeNode<K, V> _getValue(SplayTreeNode node) => node; | |
| 463 } | |
| OLD | NEW |