| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 library index.b_plus_tree; | |
| 6 | |
| 7 import 'dart:collection'; | |
| 8 | |
| 9 | |
| 10 /** | |
| 11 * A simple B+ tree (http://en.wikipedia.org/wiki/B+_tree) implementation. | |
| 12 * | |
| 13 * [K] is the keys type. | |
| 14 * [V] is the values type. | |
| 15 * [N] is the type of node identifiers using by the [NodeManager]. | |
| 16 */ | |
| 17 class BPlusTree<K, V, N> { | |
| 18 /** | |
| 19 * The [Comparator] to compare keys. | |
| 20 */ | |
| 21 final Comparator<K> _comparator; | |
| 22 | |
| 23 /** | |
| 24 * The [NodeManager] to manage nodes. | |
| 25 */ | |
| 26 final NodeManager<K, V, N> _manager; | |
| 27 | |
| 28 /** | |
| 29 * The maximum number of keys in an index node. | |
| 30 */ | |
| 31 final int _maxIndexKeys; | |
| 32 | |
| 33 /** | |
| 34 * The maximum number of keys in a leaf node. | |
| 35 */ | |
| 36 final int _maxLeafKeys; | |
| 37 | |
| 38 /** | |
| 39 * The root node. | |
| 40 */ | |
| 41 _Node<K, V, N> _root; | |
| 42 | |
| 43 /** | |
| 44 * Creates a new [BPlusTree] instance. | |
| 45 */ | |
| 46 BPlusTree(this._comparator, NodeManager<K, V, N> manager) | |
| 47 : _manager = manager, | |
| 48 _maxIndexKeys = manager.maxIndexKeys, | |
| 49 _maxLeafKeys = manager.maxLeafKeys { | |
| 50 _root = _newLeafNode(); | |
| 51 _writeLeafNode(_root); | |
| 52 } | |
| 53 | |
| 54 /** | |
| 55 * Returns the value for [key] or `null` if [key] is not in the tree. | |
| 56 */ | |
| 57 V find(K key) { | |
| 58 return _root.find(key); | |
| 59 } | |
| 60 | |
| 61 /** | |
| 62 * Associates the [key] with the given [value]. | |
| 63 * | |
| 64 * If the key was already in the tree, its associated value is changed. | |
| 65 * Otherwise the key-value pair is added to the tree. | |
| 66 */ | |
| 67 void insert(K key, V value) { | |
| 68 _Split<K, N> result = _root.insert(key, value); | |
| 69 if (result != null) { | |
| 70 _IndexNode<K, V, N> newRoot = _newIndexNode(); | |
| 71 newRoot.keys.add(result.key); | |
| 72 newRoot.children.add(result.left); | |
| 73 newRoot.children.add(result.right); | |
| 74 _root = newRoot; | |
| 75 _writeIndexNode(_root); | |
| 76 } | |
| 77 } | |
| 78 | |
| 79 /** | |
| 80 * Removes the association for the given [key]. | |
| 81 * | |
| 82 * Returns the value associated with [key] in the tree or `null` if [key] is | |
| 83 * not in the tree. | |
| 84 */ | |
| 85 V remove(K key) { | |
| 86 _Remove<K, V> result = _root.remove(key, null, null, null); | |
| 87 if (_root is _IndexNode<K, V, N>) { | |
| 88 List<N> children = (_root as _IndexNode<K, V, N>).children; | |
| 89 if (children.length == 1) { | |
| 90 _manager.delete(_root.id); | |
| 91 _root = _readNode(children[0]); | |
| 92 } | |
| 93 } | |
| 94 return result.value; | |
| 95 } | |
| 96 | |
| 97 /** | |
| 98 * Writes a textual presentation of the tree into [buffer]. | |
| 99 */ | |
| 100 void writeOn(StringBuffer buffer) { | |
| 101 _root.writeOn(buffer, ''); | |
| 102 } | |
| 103 | |
| 104 /** | |
| 105 * Creates a new [_IndexNode] instance. | |
| 106 */ | |
| 107 _IndexNode<K, V, N> _newIndexNode() { | |
| 108 N id = _manager.createIndex(); | |
| 109 return new _IndexNode<K, V, N>(this, id, _maxIndexKeys); | |
| 110 } | |
| 111 | |
| 112 /** | |
| 113 * Creates a new [_LeafNode] instance. | |
| 114 */ | |
| 115 _LeafNode<K, V, N> _newLeafNode() { | |
| 116 N id = _manager.createLeaf(); | |
| 117 return new _LeafNode<K, V, N>(this, id, _maxLeafKeys); | |
| 118 } | |
| 119 | |
| 120 /** | |
| 121 * Reads the [_IndexNode] with [id] from the manager. | |
| 122 */ | |
| 123 _IndexNode<K, V, N> _readIndexNode(N id) { | |
| 124 IndexNodeData<K, N> data = _manager.readIndex(id); | |
| 125 _IndexNode<K, V, N> node = new _IndexNode<K, V, N>(this, id, _maxIndexKeys); | |
| 126 node.keys = data.keys; | |
| 127 node.children = data.children; | |
| 128 return node; | |
| 129 } | |
| 130 | |
| 131 /** | |
| 132 * Reads the [_LeafNode] with [id] from the manager. | |
| 133 */ | |
| 134 _LeafNode<K, V, N> _readLeafNode(N id) { | |
| 135 _LeafNode<K, V, N> node = new _LeafNode<K, V, N>(this, id, _maxLeafKeys); | |
| 136 LeafNodeData<K, V> data = _manager.readLeaf(id); | |
| 137 node.keys = data.keys; | |
| 138 node.values = data.values; | |
| 139 return node; | |
| 140 } | |
| 141 | |
| 142 /** | |
| 143 * Reads the [_IndexNode] or [_LeafNode] with [id] from the manager. | |
| 144 */ | |
| 145 _Node<K, V, N> _readNode(N id) { | |
| 146 if (_manager.isIndex(id)) { | |
| 147 return _readIndexNode(id); | |
| 148 } else { | |
| 149 return _readLeafNode(id); | |
| 150 } | |
| 151 } | |
| 152 | |
| 153 /** | |
| 154 * Writes [node] into the manager. | |
| 155 */ | |
| 156 void _writeIndexNode(_IndexNode<K, V, N> node) { | |
| 157 _manager.writeIndex(node.id, new IndexNodeData<K, N>(node.keys, node.childre
n)); | |
| 158 } | |
| 159 | |
| 160 /** | |
| 161 * Writes [node] into the manager. | |
| 162 */ | |
| 163 void _writeLeafNode(_LeafNode<K, V, N> node) { | |
| 164 _manager.writeLeaf(node.id, new LeafNodeData<K, V>(node.keys, node.values)); | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 | |
| 169 /** | |
| 170 * A container with information about an index node. | |
| 171 */ | |
| 172 class IndexNodeData<K, N> { | |
| 173 final List<N> children; | |
| 174 final List<K> keys; | |
| 175 IndexNodeData(this.keys, this.children); | |
| 176 } | |
| 177 | |
| 178 | |
| 179 /** | |
| 180 * A container with information about a leaf node. | |
| 181 */ | |
| 182 class LeafNodeData<K, V> { | |
| 183 final List<K> keys; | |
| 184 final List<V> values; | |
| 185 LeafNodeData(this.keys, this.values); | |
| 186 } | |
| 187 | |
| 188 | |
| 189 /** | |
| 190 * An implementation of [NodeManager] that keeps node information in memory. | |
| 191 */ | |
| 192 class MemoryNodeManager<K, V> implements NodeManager<K, V, int> { | |
| 193 final int maxIndexKeys; | |
| 194 final int maxLeafKeys; | |
| 195 Map<int, IndexNodeData> _indexDataMap = new HashMap<int, IndexNodeData>(); | |
| 196 Map<int, LeafNodeData> _leafDataMap = new HashMap<int, LeafNodeData>(); | |
| 197 | |
| 198 int _nextPageIndexId = 0; | |
| 199 int _nextPageLeafId = 1; | |
| 200 | |
| 201 MemoryNodeManager(this.maxIndexKeys, this.maxLeafKeys); | |
| 202 | |
| 203 @override | |
| 204 int createIndex() { | |
| 205 int id = _nextPageIndexId; | |
| 206 _nextPageIndexId += 2; | |
| 207 return id; | |
| 208 } | |
| 209 | |
| 210 @override | |
| 211 int createLeaf() { | |
| 212 int id = _nextPageLeafId; | |
| 213 _nextPageLeafId += 2; | |
| 214 return id; | |
| 215 } | |
| 216 | |
| 217 @override | |
| 218 void delete(int id) { | |
| 219 if (isIndex(id)) { | |
| 220 _indexDataMap.remove(id); | |
| 221 } else { | |
| 222 _leafDataMap.remove(id); | |
| 223 } | |
| 224 } | |
| 225 | |
| 226 @override | |
| 227 bool isIndex(int id) { | |
| 228 return id.isEven; | |
| 229 } | |
| 230 | |
| 231 @override | |
| 232 IndexNodeData<K, int> readIndex(int id) { | |
| 233 return _indexDataMap[id]; | |
| 234 } | |
| 235 | |
| 236 @override | |
| 237 LeafNodeData<K, V> readLeaf(int id) { | |
| 238 return _leafDataMap[id]; | |
| 239 } | |
| 240 | |
| 241 @override | |
| 242 void writeIndex(int id, IndexNodeData<K, int> data) { | |
| 243 _indexDataMap[id] = data; | |
| 244 } | |
| 245 | |
| 246 @override | |
| 247 void writeLeaf(int id, LeafNodeData<K, V> data) { | |
| 248 _leafDataMap[id] = data; | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 | |
| 253 /** | |
| 254 * A manager that manages nodes. | |
| 255 */ | |
| 256 abstract class NodeManager<K, V, N> { | |
| 257 /** | |
| 258 * The maximum number of keys in an index node. | |
| 259 */ | |
| 260 int get maxIndexKeys; | |
| 261 | |
| 262 /** | |
| 263 * The maximum number of keys in a leaf node. | |
| 264 */ | |
| 265 int get maxLeafKeys; | |
| 266 | |
| 267 /** | |
| 268 * Generates an identifier for a new index node. | |
| 269 */ | |
| 270 N createIndex(); | |
| 271 | |
| 272 /** | |
| 273 * Generates an identifier for a new leaf node. | |
| 274 */ | |
| 275 N createLeaf(); | |
| 276 | |
| 277 /** | |
| 278 * Deletes the node with the given identifier. | |
| 279 */ | |
| 280 void delete(N id); | |
| 281 | |
| 282 /** | |
| 283 * Checks if the node with the given identifier is an index or a leaf node. | |
| 284 */ | |
| 285 bool isIndex(N id); | |
| 286 | |
| 287 /** | |
| 288 * Reads information about the index node with the given identifier. | |
| 289 */ | |
| 290 IndexNodeData<K, N> readIndex(N id); | |
| 291 | |
| 292 /** | |
| 293 * Reads information about the leaf node with the given identifier. | |
| 294 */ | |
| 295 LeafNodeData<K, V> readLeaf(N id); | |
| 296 | |
| 297 /** | |
| 298 * Writes information about the index node with the given identifier. | |
| 299 */ | |
| 300 void writeIndex(N id, IndexNodeData<K, N> data); | |
| 301 | |
| 302 /** | |
| 303 * Writes information about the leaf node with the given identifier. | |
| 304 */ | |
| 305 void writeLeaf(N id, LeafNodeData<K, V> data); | |
| 306 } | |
| 307 | |
| 308 | |
| 309 /** | |
| 310 * An index node with keys and children references. | |
| 311 */ | |
| 312 class _IndexNode<K, V, N> extends _Node<K, V, N> { | |
| 313 List<N> children = new List<N>(); | |
| 314 final int maxKeys; | |
| 315 final int minKeys; | |
| 316 | |
| 317 _IndexNode(BPlusTree<K, V, N> tree, N id, int maxKeys) | |
| 318 : super(tree, id), | |
| 319 maxKeys = maxKeys, | |
| 320 minKeys = maxKeys ~/ 2; | |
| 321 | |
| 322 @override | |
| 323 V find(K key) { | |
| 324 int index = _findChildIndex(key); | |
| 325 _Node<K, V, N> child = tree._readNode(children[index]); | |
| 326 return child.find(key); | |
| 327 } | |
| 328 | |
| 329 _Split<K, N> insert(K key, V value) { | |
| 330 // Early split. | |
| 331 if (keys.length == maxKeys) { | |
| 332 int middle = (maxKeys + 1) ~/ 2; | |
| 333 K splitKey = keys[middle]; | |
| 334 // Overflow into a new sibling. | |
| 335 _IndexNode<K, V, N> sibling = tree._newIndexNode(); | |
| 336 sibling.keys.addAll(keys.getRange(middle + 1, keys.length)); | |
| 337 sibling.children.addAll(children.getRange(middle + 1, children.length)); | |
| 338 keys.length = middle; | |
| 339 children.length = middle + 1; | |
| 340 // Insert into this node or sibling. | |
| 341 if (comparator(key, splitKey) < 0) { | |
| 342 _insertNotFull(key, value); | |
| 343 } else { | |
| 344 sibling._insertNotFull(key, value); | |
| 345 } | |
| 346 // Prepare split. | |
| 347 tree._writeIndexNode(this); | |
| 348 tree._writeIndexNode(sibling); | |
| 349 return new _Split<K, N>(splitKey, id, sibling.id); | |
| 350 } | |
| 351 // No split. | |
| 352 _insertNotFull(key, value); | |
| 353 return null; | |
| 354 } | |
| 355 | |
| 356 @override | |
| 357 _Remove<K, V> remove(K key, _Node<K, V, N> left, K anchor, _Node<K, V, | |
| 358 N> right) { | |
| 359 int index = _findChildIndex(key); | |
| 360 K thisAnchor = index == 0 ? keys[0] : keys[index - 1]; | |
| 361 // Prepare children. | |
| 362 _Node<K, V, N> child = tree._readNode(children[index]); | |
| 363 _Node<K, V, N> leftChild; | |
| 364 _Node<K, V, N> rightChild; | |
| 365 if (index != 0) { | |
| 366 leftChild = tree._readNode(children[index - 1]); | |
| 367 } else { | |
| 368 leftChild = null; | |
| 369 } | |
| 370 if (index < children.length - 1) { | |
| 371 rightChild = tree._readNode(children[index + 1]); | |
| 372 } else { | |
| 373 rightChild = null; | |
| 374 } | |
| 375 // Ask child to remove. | |
| 376 _Remove<K, V> result = child.remove(key, leftChild, thisAnchor, rightChild); | |
| 377 V value = result.value; | |
| 378 if (value == null) { | |
| 379 return new _Remove<K, V>(value); | |
| 380 } | |
| 381 // Do keys / children updates | |
| 382 bool hasUpdates = false; | |
| 383 { | |
| 384 // Update anchor if borrowed. | |
| 385 if (result.leftAnchor != null) { | |
| 386 keys[index - 1] = result.leftAnchor; | |
| 387 hasUpdates = true; | |
| 388 } | |
| 389 if (result.rightAnchor != null) { | |
| 390 keys[index] = result.rightAnchor; | |
| 391 hasUpdates = true; | |
| 392 } | |
| 393 // Update keys / children if merged. | |
| 394 if (result.mergedLeft) { | |
| 395 keys.removeAt(index - 1); | |
| 396 N child = children.removeAt(index); | |
| 397 manager.delete(child); | |
| 398 hasUpdates = true; | |
| 399 } | |
| 400 if (result.mergedRight) { | |
| 401 keys.removeAt(index); | |
| 402 N child = children.removeAt(index); | |
| 403 manager.delete(child); | |
| 404 hasUpdates = true; | |
| 405 } | |
| 406 } | |
| 407 // Write if updated. | |
| 408 if (!hasUpdates) { | |
| 409 return new _Remove<K, V>(value); | |
| 410 } | |
| 411 tree._writeIndexNode(this); | |
| 412 // Perform balancing. | |
| 413 if (keys.length < minKeys) { | |
| 414 // Try left sibling. | |
| 415 if (left is _IndexNode<K, V, N>) { | |
| 416 // Try to redistribute. | |
| 417 int leftLength = left.keys.length; | |
| 418 if (leftLength > minKeys) { | |
| 419 int halfExcess = (leftLength - minKeys + 1) ~/ 2; | |
| 420 int newLeftLength = leftLength - halfExcess; | |
| 421 keys.insert(0, anchor); | |
| 422 keys.insertAll(0, left.keys.getRange(newLeftLength, leftLength)); | |
| 423 children.insertAll(0, left.children.getRange(newLeftLength, leftLength | |
| 424 + 1)); | |
| 425 K newAnchor = left.keys[newLeftLength - 1]; | |
| 426 left.keys.length = newLeftLength - 1; | |
| 427 left.children.length = newLeftLength; | |
| 428 tree._writeIndexNode(this); | |
| 429 tree._writeIndexNode(left); | |
| 430 return new _Remove<K, V>.borrowLeft(value, newAnchor); | |
| 431 } | |
| 432 // Do merge. | |
| 433 left.keys.add(anchor); | |
| 434 left.keys.addAll(keys); | |
| 435 left.children.addAll(children); | |
| 436 tree._writeIndexNode(this); | |
| 437 tree._writeIndexNode(left); | |
| 438 return new _Remove<K, V>.mergeLeft(value); | |
| 439 } | |
| 440 // Try right sibling. | |
| 441 if (right is _IndexNode<K, V, N>) { | |
| 442 // Try to redistribute. | |
| 443 int rightLength = right.keys.length; | |
| 444 if (rightLength > minKeys) { | |
| 445 int halfExcess = (rightLength - minKeys + 1) ~/ 2; | |
| 446 keys.add(anchor); | |
| 447 keys.addAll(right.keys.getRange(0, halfExcess - 1)); | |
| 448 children.addAll(right.children.getRange(0, halfExcess)); | |
| 449 K newAnchor = right.keys[halfExcess - 1]; | |
| 450 right.keys.removeRange(0, halfExcess); | |
| 451 right.children.removeRange(0, halfExcess); | |
| 452 tree._writeIndexNode(this); | |
| 453 tree._writeIndexNode(right); | |
| 454 return new _Remove<K, V>.borrowRight(value, newAnchor); | |
| 455 } | |
| 456 // Do merge. | |
| 457 right.keys.insert(0, anchor); | |
| 458 right.keys.insertAll(0, keys); | |
| 459 right.children.insertAll(0, children); | |
| 460 tree._writeIndexNode(this); | |
| 461 tree._writeIndexNode(right); | |
| 462 return new _Remove<K, V>.mergeRight(value); | |
| 463 } | |
| 464 } | |
| 465 // No balancing required. | |
| 466 return new _Remove<K, V>(value); | |
| 467 } | |
| 468 | |
| 469 @override | |
| 470 void writeOn(StringBuffer buffer, String indent) { | |
| 471 buffer.write(indent); | |
| 472 buffer.write('INode {\n'); | |
| 473 for (int i = 0; i < keys.length; i++) { | |
| 474 _Node<K, V, N> child = tree._readNode(children[i]); | |
| 475 child.writeOn(buffer, indent + ' '); | |
| 476 buffer.write(indent); | |
| 477 buffer.write(' '); | |
| 478 buffer.write(keys[i]); | |
| 479 buffer.write('\n'); | |
| 480 } | |
| 481 _Node<K, V, N> child = tree._readNode(children[keys.length]); | |
| 482 child.writeOn(buffer, indent + ' '); | |
| 483 buffer.write(indent); | |
| 484 buffer.write('}\n'); | |
| 485 } | |
| 486 | |
| 487 /** | |
| 488 * Returns the index of the child into which [key] should be inserted. | |
| 489 */ | |
| 490 int _findChildIndex(K key) { | |
| 491 int lo = 0; | |
| 492 int hi = keys.length - 1; | |
| 493 while (lo <= hi) { | |
| 494 int mid = lo + (hi - lo) ~/ 2; | |
| 495 int compare = comparator(key, keys[mid]); | |
| 496 if (compare < 0) { | |
| 497 hi = mid - 1; | |
| 498 } else if (compare > 0) { | |
| 499 lo = mid + 1; | |
| 500 } else { | |
| 501 return mid + 1; | |
| 502 } | |
| 503 } | |
| 504 return lo; | |
| 505 } | |
| 506 | |
| 507 void _insertNotFull(K key, V value) { | |
| 508 int index = _findChildIndex(key); | |
| 509 _Node<K, V, N> child = tree._readNode(children[index]); | |
| 510 _Split<K, N> result = child.insert(key, value); | |
| 511 if (result != null) { | |
| 512 keys.insert(index, result.key); | |
| 513 children[index] = result.left; | |
| 514 children.insert(index + 1, result.right); | |
| 515 tree._writeIndexNode(this); | |
| 516 } | |
| 517 } | |
| 518 } | |
| 519 | |
| 520 | |
| 521 /** | |
| 522 * A leaf node with keys and values. | |
| 523 */ | |
| 524 class _LeafNode<K, V, N> extends _Node<K, V, N> { | |
| 525 final int maxKeys; | |
| 526 final int minKeys; | |
| 527 List<V> values = new List<V>(); | |
| 528 | |
| 529 _LeafNode(BPlusTree<K, V, N> tree, N id, int maxKeys) | |
| 530 : super(tree, id), | |
| 531 maxKeys = maxKeys, | |
| 532 minKeys = maxKeys ~/ 2; | |
| 533 | |
| 534 @override | |
| 535 V find(K key) { | |
| 536 int index = _findKeyIndex(key); | |
| 537 if (index < 0) { | |
| 538 return null; | |
| 539 } | |
| 540 if (index >= keys.length) { | |
| 541 return null; | |
| 542 } | |
| 543 if (keys[index] != key) { | |
| 544 return null; | |
| 545 } | |
| 546 return values[index]; | |
| 547 } | |
| 548 | |
| 549 _Split<K, N> insert(K key, V value) { | |
| 550 int index = _findKeyIndex(key); | |
| 551 // The node is full. | |
| 552 if (keys.length == maxKeys) { | |
| 553 int middle = (maxKeys + 1) ~/ 2; | |
| 554 _LeafNode<K, V, N> sibling = tree._newLeafNode(); | |
| 555 sibling.keys.addAll(keys.getRange(middle, keys.length)); | |
| 556 sibling.values.addAll(values.getRange(middle, values.length)); | |
| 557 keys.length = middle; | |
| 558 values.length = middle; | |
| 559 // Insert into the left / right sibling. | |
| 560 if (index < middle) { | |
| 561 _insertNotFull(key, value, index); | |
| 562 } else { | |
| 563 sibling._insertNotFull(key, value, index - middle); | |
| 564 } | |
| 565 // Notify the parent about the split. | |
| 566 tree._writeLeafNode(this); | |
| 567 tree._writeLeafNode(sibling); | |
| 568 return new _Split<K, N>(sibling.keys[0], id, sibling.id); | |
| 569 } | |
| 570 // The node was not full. | |
| 571 _insertNotFull(key, value, index); | |
| 572 return null; | |
| 573 } | |
| 574 | |
| 575 @override | |
| 576 _Remove<K, V> remove(K key, _Node<K, V, N> left, K anchor, _Node<K, V, | |
| 577 N> right) { | |
| 578 // Find the key. | |
| 579 int index = keys.indexOf(key); | |
| 580 if (index == -1) { | |
| 581 return new _Remove<K, V>(null); | |
| 582 } | |
| 583 // Remove key / value. | |
| 584 keys.removeAt(index); | |
| 585 V value = values.removeAt(index); | |
| 586 tree._writeLeafNode(this); | |
| 587 // Perform balancing. | |
| 588 if (keys.length < minKeys) { | |
| 589 // Try left sibling. | |
| 590 if (left is _LeafNode<K, V, N>) { | |
| 591 // Try to redistribute. | |
| 592 int leftLength = left.keys.length; | |
| 593 if (leftLength > minKeys) { | |
| 594 int halfExcess = (leftLength - minKeys + 1) ~/ 2; | |
| 595 int newLeftLength = leftLength - halfExcess; | |
| 596 keys.insertAll(0, left.keys.getRange(newLeftLength, leftLength)); | |
| 597 values.insertAll(0, left.values.getRange(newLeftLength, leftLength)); | |
| 598 left.keys.length = newLeftLength; | |
| 599 left.values.length = newLeftLength; | |
| 600 tree._writeLeafNode(this); | |
| 601 tree._writeLeafNode(left); | |
| 602 return new _Remove<K, V>.borrowLeft(value, keys.first); | |
| 603 } | |
| 604 // Do merge. | |
| 605 left.keys.addAll(keys); | |
| 606 left.values.addAll(values); | |
| 607 tree._writeLeafNode(this); | |
| 608 tree._writeLeafNode(left); | |
| 609 return new _Remove<K, V>.mergeLeft(value); | |
| 610 } | |
| 611 // Try right sibling. | |
| 612 if (right is _LeafNode<K, V, N>) { | |
| 613 // Try to redistribute. | |
| 614 int rightLength = right.keys.length; | |
| 615 if (rightLength > minKeys) { | |
| 616 int halfExcess = (rightLength - minKeys + 1) ~/ 2; | |
| 617 keys.addAll(right.keys.getRange(0, halfExcess)); | |
| 618 values.addAll(right.values.getRange(0, halfExcess)); | |
| 619 right.keys.removeRange(0, halfExcess); | |
| 620 right.values.removeRange(0, halfExcess); | |
| 621 tree._writeLeafNode(this); | |
| 622 tree._writeLeafNode(right); | |
| 623 return new _Remove<K, V>.borrowRight(value, right.keys.first); | |
| 624 } | |
| 625 // Do merge. | |
| 626 right.keys.insertAll(0, keys); | |
| 627 right.values.insertAll(0, values); | |
| 628 tree._writeLeafNode(this); | |
| 629 tree._writeLeafNode(right); | |
| 630 return new _Remove<K, V>.mergeRight(value); | |
| 631 } | |
| 632 } | |
| 633 // No balancing required. | |
| 634 return new _Remove<K, V>(value); | |
| 635 } | |
| 636 | |
| 637 @override | |
| 638 void writeOn(StringBuffer buffer, String indent) { | |
| 639 buffer.write(indent); | |
| 640 buffer.write('LNode {'); | |
| 641 for (int i = 0; i < keys.length; i++) { | |
| 642 if (i != 0) { | |
| 643 buffer.write(', '); | |
| 644 } | |
| 645 buffer.write(keys[i]); | |
| 646 buffer.write(': '); | |
| 647 buffer.write(values[i]); | |
| 648 } | |
| 649 buffer.write('}\n'); | |
| 650 } | |
| 651 | |
| 652 /** | |
| 653 * Returns the index where [key] should be inserted. | |
| 654 */ | |
| 655 int _findKeyIndex(K key) { | |
| 656 int lo = 0; | |
| 657 int hi = keys.length - 1; | |
| 658 while (lo <= hi) { | |
| 659 int mid = lo + (hi - lo) ~/ 2; | |
| 660 int compare = comparator(key, keys[mid]); | |
| 661 if (compare < 0) { | |
| 662 hi = mid - 1; | |
| 663 } else if (compare > 0) { | |
| 664 lo = mid + 1; | |
| 665 } else { | |
| 666 return mid; | |
| 667 } | |
| 668 } | |
| 669 return lo; | |
| 670 } | |
| 671 | |
| 672 void _insertNotFull(K key, V value, int index) { | |
| 673 if (index < keys.length && comparator(keys[index], key) == 0) { | |
| 674 values[index] = value; | |
| 675 } else { | |
| 676 keys.insert(index, key); | |
| 677 values.insert(index, value); | |
| 678 } | |
| 679 tree._writeLeafNode(this); | |
| 680 } | |
| 681 } | |
| 682 | |
| 683 | |
| 684 /** | |
| 685 * An internal or leaf node. | |
| 686 */ | |
| 687 abstract class _Node<K, V, N> { | |
| 688 /** | |
| 689 * The [Comparator] to compare keys. | |
| 690 */ | |
| 691 final Comparator<K> comparator; | |
| 692 | |
| 693 /** | |
| 694 * The identifier of this node. | |
| 695 */ | |
| 696 final N id; | |
| 697 | |
| 698 /** | |
| 699 * The list of keys. | |
| 700 */ | |
| 701 List<K> keys = new List<K>(); | |
| 702 | |
| 703 /** | |
| 704 * The [NodeManager] for this tree. | |
| 705 */ | |
| 706 final NodeManager<K, V, N> manager; | |
| 707 | |
| 708 /** | |
| 709 * The [BPlusTree] this node belongs to. | |
| 710 */ | |
| 711 final BPlusTree<K, V, N> tree; | |
| 712 | |
| 713 _Node(BPlusTree<K, V, N> tree, this.id) | |
| 714 : tree = tree, | |
| 715 comparator = tree._comparator, | |
| 716 manager = tree._manager; | |
| 717 | |
| 718 /** | |
| 719 * Looks for [key]. | |
| 720 * | |
| 721 * Returns the associated value if found. | |
| 722 * Returns `null` if not found. | |
| 723 */ | |
| 724 V find(K key); | |
| 725 | |
| 726 /** | |
| 727 * Inserts the [key] / [value] pair into this [_Node]. | |
| 728 * | |
| 729 * Returns a [_Split] object if split happens, or `null` otherwise. | |
| 730 */ | |
| 731 _Split<K, N> insert(K key, V value); | |
| 732 | |
| 733 /** | |
| 734 * Removes the association for the given [key]. | |
| 735 * | |
| 736 * Returns the [_Remove] information about an operation performed. | |
| 737 * It may be restructuring or merging, with [left] or [left] siblings. | |
| 738 */ | |
| 739 _Remove<K, V> remove(K key, _Node<K, V, N> left, K anchor, _Node<K, V, | |
| 740 N> right); | |
| 741 | |
| 742 /** | |
| 743 * Writes a textual presentation of the tree into [buffer]. | |
| 744 */ | |
| 745 void writeOn(StringBuffer buffer, String indent); | |
| 746 } | |
| 747 | |
| 748 | |
| 749 /** | |
| 750 * A container with information about redistribute / merge. | |
| 751 */ | |
| 752 class _Remove<K, V> { | |
| 753 K leftAnchor; | |
| 754 bool mergedLeft = false; | |
| 755 bool mergedRight = false; | |
| 756 K rightAnchor; | |
| 757 final V value; | |
| 758 _Remove(this.value); | |
| 759 _Remove.borrowLeft(this.value, this.leftAnchor); | |
| 760 _Remove.borrowRight(this.value, this.rightAnchor); | |
| 761 _Remove.mergeLeft(this.value) : mergedLeft = true; | |
| 762 _Remove.mergeRight(this.value) : mergedRight = true; | |
| 763 } | |
| 764 | |
| 765 | |
| 766 /** | |
| 767 * A container with information about split during insert. | |
| 768 */ | |
| 769 class _Split<K, N> { | |
| 770 final K key; | |
| 771 final N left; | |
| 772 final N right; | |
| 773 _Split(this.key, this.left, this.right); | |
| 774 } | |
| OLD | NEW |