Index: pkg/analysis_server/lib/src/index/b_plus_tree.dart |
diff --git a/pkg/analysis_server/lib/src/index/b_plus_tree.dart b/pkg/analysis_server/lib/src/index/b_plus_tree.dart |
deleted file mode 100644 |
index f4b52d7c5a93a586fb1be8b92feed3889c589566..0000000000000000000000000000000000000000 |
--- a/pkg/analysis_server/lib/src/index/b_plus_tree.dart |
+++ /dev/null |
@@ -1,774 +0,0 @@ |
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-library index.b_plus_tree; |
- |
-import 'dart:collection'; |
- |
- |
-/** |
- * A simple B+ tree (http://en.wikipedia.org/wiki/B+_tree) implementation. |
- * |
- * [K] is the keys type. |
- * [V] is the values type. |
- * [N] is the type of node identifiers using by the [NodeManager]. |
- */ |
-class BPlusTree<K, V, N> { |
- /** |
- * The [Comparator] to compare keys. |
- */ |
- final Comparator<K> _comparator; |
- |
- /** |
- * The [NodeManager] to manage nodes. |
- */ |
- final NodeManager<K, V, N> _manager; |
- |
- /** |
- * The maximum number of keys in an index node. |
- */ |
- final int _maxIndexKeys; |
- |
- /** |
- * The maximum number of keys in a leaf node. |
- */ |
- final int _maxLeafKeys; |
- |
- /** |
- * The root node. |
- */ |
- _Node<K, V, N> _root; |
- |
- /** |
- * Creates a new [BPlusTree] instance. |
- */ |
- BPlusTree(this._comparator, NodeManager<K, V, N> manager) |
- : _manager = manager, |
- _maxIndexKeys = manager.maxIndexKeys, |
- _maxLeafKeys = manager.maxLeafKeys { |
- _root = _newLeafNode(); |
- _writeLeafNode(_root); |
- } |
- |
- /** |
- * Returns the value for [key] or `null` if [key] is not in the tree. |
- */ |
- V find(K key) { |
- return _root.find(key); |
- } |
- |
- /** |
- * Associates the [key] with the given [value]. |
- * |
- * If the key was already in the tree, its associated value is changed. |
- * Otherwise the key-value pair is added to the tree. |
- */ |
- void insert(K key, V value) { |
- _Split<K, N> result = _root.insert(key, value); |
- if (result != null) { |
- _IndexNode<K, V, N> newRoot = _newIndexNode(); |
- newRoot.keys.add(result.key); |
- newRoot.children.add(result.left); |
- newRoot.children.add(result.right); |
- _root = newRoot; |
- _writeIndexNode(_root); |
- } |
- } |
- |
- /** |
- * Removes the association for the given [key]. |
- * |
- * Returns the value associated with [key] in the tree or `null` if [key] is |
- * not in the tree. |
- */ |
- V remove(K key) { |
- _Remove<K, V> result = _root.remove(key, null, null, null); |
- if (_root is _IndexNode<K, V, N>) { |
- List<N> children = (_root as _IndexNode<K, V, N>).children; |
- if (children.length == 1) { |
- _manager.delete(_root.id); |
- _root = _readNode(children[0]); |
- } |
- } |
- return result.value; |
- } |
- |
- /** |
- * Writes a textual presentation of the tree into [buffer]. |
- */ |
- void writeOn(StringBuffer buffer) { |
- _root.writeOn(buffer, ''); |
- } |
- |
- /** |
- * Creates a new [_IndexNode] instance. |
- */ |
- _IndexNode<K, V, N> _newIndexNode() { |
- N id = _manager.createIndex(); |
- return new _IndexNode<K, V, N>(this, id, _maxIndexKeys); |
- } |
- |
- /** |
- * Creates a new [_LeafNode] instance. |
- */ |
- _LeafNode<K, V, N> _newLeafNode() { |
- N id = _manager.createLeaf(); |
- return new _LeafNode<K, V, N>(this, id, _maxLeafKeys); |
- } |
- |
- /** |
- * Reads the [_IndexNode] with [id] from the manager. |
- */ |
- _IndexNode<K, V, N> _readIndexNode(N id) { |
- IndexNodeData<K, N> data = _manager.readIndex(id); |
- _IndexNode<K, V, N> node = new _IndexNode<K, V, N>(this, id, _maxIndexKeys); |
- node.keys = data.keys; |
- node.children = data.children; |
- return node; |
- } |
- |
- /** |
- * Reads the [_LeafNode] with [id] from the manager. |
- */ |
- _LeafNode<K, V, N> _readLeafNode(N id) { |
- _LeafNode<K, V, N> node = new _LeafNode<K, V, N>(this, id, _maxLeafKeys); |
- LeafNodeData<K, V> data = _manager.readLeaf(id); |
- node.keys = data.keys; |
- node.values = data.values; |
- return node; |
- } |
- |
- /** |
- * Reads the [_IndexNode] or [_LeafNode] with [id] from the manager. |
- */ |
- _Node<K, V, N> _readNode(N id) { |
- if (_manager.isIndex(id)) { |
- return _readIndexNode(id); |
- } else { |
- return _readLeafNode(id); |
- } |
- } |
- |
- /** |
- * Writes [node] into the manager. |
- */ |
- void _writeIndexNode(_IndexNode<K, V, N> node) { |
- _manager.writeIndex(node.id, new IndexNodeData<K, N>(node.keys, node.children)); |
- } |
- |
- /** |
- * Writes [node] into the manager. |
- */ |
- void _writeLeafNode(_LeafNode<K, V, N> node) { |
- _manager.writeLeaf(node.id, new LeafNodeData<K, V>(node.keys, node.values)); |
- } |
-} |
- |
- |
-/** |
- * A container with information about an index node. |
- */ |
-class IndexNodeData<K, N> { |
- final List<N> children; |
- final List<K> keys; |
- IndexNodeData(this.keys, this.children); |
-} |
- |
- |
-/** |
- * A container with information about a leaf node. |
- */ |
-class LeafNodeData<K, V> { |
- final List<K> keys; |
- final List<V> values; |
- LeafNodeData(this.keys, this.values); |
-} |
- |
- |
-/** |
- * An implementation of [NodeManager] that keeps node information in memory. |
- */ |
-class MemoryNodeManager<K, V> implements NodeManager<K, V, int> { |
- final int maxIndexKeys; |
- final int maxLeafKeys; |
- Map<int, IndexNodeData> _indexDataMap = new HashMap<int, IndexNodeData>(); |
- Map<int, LeafNodeData> _leafDataMap = new HashMap<int, LeafNodeData>(); |
- |
- int _nextPageIndexId = 0; |
- int _nextPageLeafId = 1; |
- |
- MemoryNodeManager(this.maxIndexKeys, this.maxLeafKeys); |
- |
- @override |
- int createIndex() { |
- int id = _nextPageIndexId; |
- _nextPageIndexId += 2; |
- return id; |
- } |
- |
- @override |
- int createLeaf() { |
- int id = _nextPageLeafId; |
- _nextPageLeafId += 2; |
- return id; |
- } |
- |
- @override |
- void delete(int id) { |
- if (isIndex(id)) { |
- _indexDataMap.remove(id); |
- } else { |
- _leafDataMap.remove(id); |
- } |
- } |
- |
- @override |
- bool isIndex(int id) { |
- return id.isEven; |
- } |
- |
- @override |
- IndexNodeData<K, int> readIndex(int id) { |
- return _indexDataMap[id]; |
- } |
- |
- @override |
- LeafNodeData<K, V> readLeaf(int id) { |
- return _leafDataMap[id]; |
- } |
- |
- @override |
- void writeIndex(int id, IndexNodeData<K, int> data) { |
- _indexDataMap[id] = data; |
- } |
- |
- @override |
- void writeLeaf(int id, LeafNodeData<K, V> data) { |
- _leafDataMap[id] = data; |
- } |
-} |
- |
- |
-/** |
- * A manager that manages nodes. |
- */ |
-abstract class NodeManager<K, V, N> { |
- /** |
- * The maximum number of keys in an index node. |
- */ |
- int get maxIndexKeys; |
- |
- /** |
- * The maximum number of keys in a leaf node. |
- */ |
- int get maxLeafKeys; |
- |
- /** |
- * Generates an identifier for a new index node. |
- */ |
- N createIndex(); |
- |
- /** |
- * Generates an identifier for a new leaf node. |
- */ |
- N createLeaf(); |
- |
- /** |
- * Deletes the node with the given identifier. |
- */ |
- void delete(N id); |
- |
- /** |
- * Checks if the node with the given identifier is an index or a leaf node. |
- */ |
- bool isIndex(N id); |
- |
- /** |
- * Reads information about the index node with the given identifier. |
- */ |
- IndexNodeData<K, N> readIndex(N id); |
- |
- /** |
- * Reads information about the leaf node with the given identifier. |
- */ |
- LeafNodeData<K, V> readLeaf(N id); |
- |
- /** |
- * Writes information about the index node with the given identifier. |
- */ |
- void writeIndex(N id, IndexNodeData<K, N> data); |
- |
- /** |
- * Writes information about the leaf node with the given identifier. |
- */ |
- void writeLeaf(N id, LeafNodeData<K, V> data); |
-} |
- |
- |
-/** |
- * An index node with keys and children references. |
- */ |
-class _IndexNode<K, V, N> extends _Node<K, V, N> { |
- List<N> children = new List<N>(); |
- final int maxKeys; |
- final int minKeys; |
- |
- _IndexNode(BPlusTree<K, V, N> tree, N id, int maxKeys) |
- : super(tree, id), |
- maxKeys = maxKeys, |
- minKeys = maxKeys ~/ 2; |
- |
- @override |
- V find(K key) { |
- int index = _findChildIndex(key); |
- _Node<K, V, N> child = tree._readNode(children[index]); |
- return child.find(key); |
- } |
- |
- _Split<K, N> insert(K key, V value) { |
- // Early split. |
- if (keys.length == maxKeys) { |
- int middle = (maxKeys + 1) ~/ 2; |
- K splitKey = keys[middle]; |
- // Overflow into a new sibling. |
- _IndexNode<K, V, N> sibling = tree._newIndexNode(); |
- sibling.keys.addAll(keys.getRange(middle + 1, keys.length)); |
- sibling.children.addAll(children.getRange(middle + 1, children.length)); |
- keys.length = middle; |
- children.length = middle + 1; |
- // Insert into this node or sibling. |
- if (comparator(key, splitKey) < 0) { |
- _insertNotFull(key, value); |
- } else { |
- sibling._insertNotFull(key, value); |
- } |
- // Prepare split. |
- tree._writeIndexNode(this); |
- tree._writeIndexNode(sibling); |
- return new _Split<K, N>(splitKey, id, sibling.id); |
- } |
- // No split. |
- _insertNotFull(key, value); |
- return null; |
- } |
- |
- @override |
- _Remove<K, V> remove(K key, _Node<K, V, N> left, K anchor, _Node<K, V, |
- N> right) { |
- int index = _findChildIndex(key); |
- K thisAnchor = index == 0 ? keys[0] : keys[index - 1]; |
- // Prepare children. |
- _Node<K, V, N> child = tree._readNode(children[index]); |
- _Node<K, V, N> leftChild; |
- _Node<K, V, N> rightChild; |
- if (index != 0) { |
- leftChild = tree._readNode(children[index - 1]); |
- } else { |
- leftChild = null; |
- } |
- if (index < children.length - 1) { |
- rightChild = tree._readNode(children[index + 1]); |
- } else { |
- rightChild = null; |
- } |
- // Ask child to remove. |
- _Remove<K, V> result = child.remove(key, leftChild, thisAnchor, rightChild); |
- V value = result.value; |
- if (value == null) { |
- return new _Remove<K, V>(value); |
- } |
- // Do keys / children updates |
- bool hasUpdates = false; |
- { |
- // Update anchor if borrowed. |
- if (result.leftAnchor != null) { |
- keys[index - 1] = result.leftAnchor; |
- hasUpdates = true; |
- } |
- if (result.rightAnchor != null) { |
- keys[index] = result.rightAnchor; |
- hasUpdates = true; |
- } |
- // Update keys / children if merged. |
- if (result.mergedLeft) { |
- keys.removeAt(index - 1); |
- N child = children.removeAt(index); |
- manager.delete(child); |
- hasUpdates = true; |
- } |
- if (result.mergedRight) { |
- keys.removeAt(index); |
- N child = children.removeAt(index); |
- manager.delete(child); |
- hasUpdates = true; |
- } |
- } |
- // Write if updated. |
- if (!hasUpdates) { |
- return new _Remove<K, V>(value); |
- } |
- tree._writeIndexNode(this); |
- // Perform balancing. |
- if (keys.length < minKeys) { |
- // Try left sibling. |
- if (left is _IndexNode<K, V, N>) { |
- // Try to redistribute. |
- int leftLength = left.keys.length; |
- if (leftLength > minKeys) { |
- int halfExcess = (leftLength - minKeys + 1) ~/ 2; |
- int newLeftLength = leftLength - halfExcess; |
- keys.insert(0, anchor); |
- keys.insertAll(0, left.keys.getRange(newLeftLength, leftLength)); |
- children.insertAll(0, left.children.getRange(newLeftLength, leftLength |
- + 1)); |
- K newAnchor = left.keys[newLeftLength - 1]; |
- left.keys.length = newLeftLength - 1; |
- left.children.length = newLeftLength; |
- tree._writeIndexNode(this); |
- tree._writeIndexNode(left); |
- return new _Remove<K, V>.borrowLeft(value, newAnchor); |
- } |
- // Do merge. |
- left.keys.add(anchor); |
- left.keys.addAll(keys); |
- left.children.addAll(children); |
- tree._writeIndexNode(this); |
- tree._writeIndexNode(left); |
- return new _Remove<K, V>.mergeLeft(value); |
- } |
- // Try right sibling. |
- if (right is _IndexNode<K, V, N>) { |
- // Try to redistribute. |
- int rightLength = right.keys.length; |
- if (rightLength > minKeys) { |
- int halfExcess = (rightLength - minKeys + 1) ~/ 2; |
- keys.add(anchor); |
- keys.addAll(right.keys.getRange(0, halfExcess - 1)); |
- children.addAll(right.children.getRange(0, halfExcess)); |
- K newAnchor = right.keys[halfExcess - 1]; |
- right.keys.removeRange(0, halfExcess); |
- right.children.removeRange(0, halfExcess); |
- tree._writeIndexNode(this); |
- tree._writeIndexNode(right); |
- return new _Remove<K, V>.borrowRight(value, newAnchor); |
- } |
- // Do merge. |
- right.keys.insert(0, anchor); |
- right.keys.insertAll(0, keys); |
- right.children.insertAll(0, children); |
- tree._writeIndexNode(this); |
- tree._writeIndexNode(right); |
- return new _Remove<K, V>.mergeRight(value); |
- } |
- } |
- // No balancing required. |
- return new _Remove<K, V>(value); |
- } |
- |
- @override |
- void writeOn(StringBuffer buffer, String indent) { |
- buffer.write(indent); |
- buffer.write('INode {\n'); |
- for (int i = 0; i < keys.length; i++) { |
- _Node<K, V, N> child = tree._readNode(children[i]); |
- child.writeOn(buffer, indent + ' '); |
- buffer.write(indent); |
- buffer.write(' '); |
- buffer.write(keys[i]); |
- buffer.write('\n'); |
- } |
- _Node<K, V, N> child = tree._readNode(children[keys.length]); |
- child.writeOn(buffer, indent + ' '); |
- buffer.write(indent); |
- buffer.write('}\n'); |
- } |
- |
- /** |
- * Returns the index of the child into which [key] should be inserted. |
- */ |
- int _findChildIndex(K key) { |
- int lo = 0; |
- int hi = keys.length - 1; |
- while (lo <= hi) { |
- int mid = lo + (hi - lo) ~/ 2; |
- int compare = comparator(key, keys[mid]); |
- if (compare < 0) { |
- hi = mid - 1; |
- } else if (compare > 0) { |
- lo = mid + 1; |
- } else { |
- return mid + 1; |
- } |
- } |
- return lo; |
- } |
- |
- void _insertNotFull(K key, V value) { |
- int index = _findChildIndex(key); |
- _Node<K, V, N> child = tree._readNode(children[index]); |
- _Split<K, N> result = child.insert(key, value); |
- if (result != null) { |
- keys.insert(index, result.key); |
- children[index] = result.left; |
- children.insert(index + 1, result.right); |
- tree._writeIndexNode(this); |
- } |
- } |
-} |
- |
- |
-/** |
- * A leaf node with keys and values. |
- */ |
-class _LeafNode<K, V, N> extends _Node<K, V, N> { |
- final int maxKeys; |
- final int minKeys; |
- List<V> values = new List<V>(); |
- |
- _LeafNode(BPlusTree<K, V, N> tree, N id, int maxKeys) |
- : super(tree, id), |
- maxKeys = maxKeys, |
- minKeys = maxKeys ~/ 2; |
- |
- @override |
- V find(K key) { |
- int index = _findKeyIndex(key); |
- if (index < 0) { |
- return null; |
- } |
- if (index >= keys.length) { |
- return null; |
- } |
- if (keys[index] != key) { |
- return null; |
- } |
- return values[index]; |
- } |
- |
- _Split<K, N> insert(K key, V value) { |
- int index = _findKeyIndex(key); |
- // The node is full. |
- if (keys.length == maxKeys) { |
- int middle = (maxKeys + 1) ~/ 2; |
- _LeafNode<K, V, N> sibling = tree._newLeafNode(); |
- sibling.keys.addAll(keys.getRange(middle, keys.length)); |
- sibling.values.addAll(values.getRange(middle, values.length)); |
- keys.length = middle; |
- values.length = middle; |
- // Insert into the left / right sibling. |
- if (index < middle) { |
- _insertNotFull(key, value, index); |
- } else { |
- sibling._insertNotFull(key, value, index - middle); |
- } |
- // Notify the parent about the split. |
- tree._writeLeafNode(this); |
- tree._writeLeafNode(sibling); |
- return new _Split<K, N>(sibling.keys[0], id, sibling.id); |
- } |
- // The node was not full. |
- _insertNotFull(key, value, index); |
- return null; |
- } |
- |
- @override |
- _Remove<K, V> remove(K key, _Node<K, V, N> left, K anchor, _Node<K, V, |
- N> right) { |
- // Find the key. |
- int index = keys.indexOf(key); |
- if (index == -1) { |
- return new _Remove<K, V>(null); |
- } |
- // Remove key / value. |
- keys.removeAt(index); |
- V value = values.removeAt(index); |
- tree._writeLeafNode(this); |
- // Perform balancing. |
- if (keys.length < minKeys) { |
- // Try left sibling. |
- if (left is _LeafNode<K, V, N>) { |
- // Try to redistribute. |
- int leftLength = left.keys.length; |
- if (leftLength > minKeys) { |
- int halfExcess = (leftLength - minKeys + 1) ~/ 2; |
- int newLeftLength = leftLength - halfExcess; |
- keys.insertAll(0, left.keys.getRange(newLeftLength, leftLength)); |
- values.insertAll(0, left.values.getRange(newLeftLength, leftLength)); |
- left.keys.length = newLeftLength; |
- left.values.length = newLeftLength; |
- tree._writeLeafNode(this); |
- tree._writeLeafNode(left); |
- return new _Remove<K, V>.borrowLeft(value, keys.first); |
- } |
- // Do merge. |
- left.keys.addAll(keys); |
- left.values.addAll(values); |
- tree._writeLeafNode(this); |
- tree._writeLeafNode(left); |
- return new _Remove<K, V>.mergeLeft(value); |
- } |
- // Try right sibling. |
- if (right is _LeafNode<K, V, N>) { |
- // Try to redistribute. |
- int rightLength = right.keys.length; |
- if (rightLength > minKeys) { |
- int halfExcess = (rightLength - minKeys + 1) ~/ 2; |
- keys.addAll(right.keys.getRange(0, halfExcess)); |
- values.addAll(right.values.getRange(0, halfExcess)); |
- right.keys.removeRange(0, halfExcess); |
- right.values.removeRange(0, halfExcess); |
- tree._writeLeafNode(this); |
- tree._writeLeafNode(right); |
- return new _Remove<K, V>.borrowRight(value, right.keys.first); |
- } |
- // Do merge. |
- right.keys.insertAll(0, keys); |
- right.values.insertAll(0, values); |
- tree._writeLeafNode(this); |
- tree._writeLeafNode(right); |
- return new _Remove<K, V>.mergeRight(value); |
- } |
- } |
- // No balancing required. |
- return new _Remove<K, V>(value); |
- } |
- |
- @override |
- void writeOn(StringBuffer buffer, String indent) { |
- buffer.write(indent); |
- buffer.write('LNode {'); |
- for (int i = 0; i < keys.length; i++) { |
- if (i != 0) { |
- buffer.write(', '); |
- } |
- buffer.write(keys[i]); |
- buffer.write(': '); |
- buffer.write(values[i]); |
- } |
- buffer.write('}\n'); |
- } |
- |
- /** |
- * Returns the index where [key] should be inserted. |
- */ |
- int _findKeyIndex(K key) { |
- int lo = 0; |
- int hi = keys.length - 1; |
- while (lo <= hi) { |
- int mid = lo + (hi - lo) ~/ 2; |
- int compare = comparator(key, keys[mid]); |
- if (compare < 0) { |
- hi = mid - 1; |
- } else if (compare > 0) { |
- lo = mid + 1; |
- } else { |
- return mid; |
- } |
- } |
- return lo; |
- } |
- |
- void _insertNotFull(K key, V value, int index) { |
- if (index < keys.length && comparator(keys[index], key) == 0) { |
- values[index] = value; |
- } else { |
- keys.insert(index, key); |
- values.insert(index, value); |
- } |
- tree._writeLeafNode(this); |
- } |
-} |
- |
- |
-/** |
- * An internal or leaf node. |
- */ |
-abstract class _Node<K, V, N> { |
- /** |
- * The [Comparator] to compare keys. |
- */ |
- final Comparator<K> comparator; |
- |
- /** |
- * The identifier of this node. |
- */ |
- final N id; |
- |
- /** |
- * The list of keys. |
- */ |
- List<K> keys = new List<K>(); |
- |
- /** |
- * The [NodeManager] for this tree. |
- */ |
- final NodeManager<K, V, N> manager; |
- |
- /** |
- * The [BPlusTree] this node belongs to. |
- */ |
- final BPlusTree<K, V, N> tree; |
- |
- _Node(BPlusTree<K, V, N> tree, this.id) |
- : tree = tree, |
- comparator = tree._comparator, |
- manager = tree._manager; |
- |
- /** |
- * Looks for [key]. |
- * |
- * Returns the associated value if found. |
- * Returns `null` if not found. |
- */ |
- V find(K key); |
- |
- /** |
- * Inserts the [key] / [value] pair into this [_Node]. |
- * |
- * Returns a [_Split] object if split happens, or `null` otherwise. |
- */ |
- _Split<K, N> insert(K key, V value); |
- |
- /** |
- * Removes the association for the given [key]. |
- * |
- * Returns the [_Remove] information about an operation performed. |
- * It may be restructuring or merging, with [left] or [left] siblings. |
- */ |
- _Remove<K, V> remove(K key, _Node<K, V, N> left, K anchor, _Node<K, V, |
- N> right); |
- |
- /** |
- * Writes a textual presentation of the tree into [buffer]. |
- */ |
- void writeOn(StringBuffer buffer, String indent); |
-} |
- |
- |
-/** |
- * A container with information about redistribute / merge. |
- */ |
-class _Remove<K, V> { |
- K leftAnchor; |
- bool mergedLeft = false; |
- bool mergedRight = false; |
- K rightAnchor; |
- final V value; |
- _Remove(this.value); |
- _Remove.borrowLeft(this.value, this.leftAnchor); |
- _Remove.borrowRight(this.value, this.rightAnchor); |
- _Remove.mergeLeft(this.value) : mergedLeft = true; |
- _Remove.mergeRight(this.value) : mergedRight = true; |
-} |
- |
- |
-/** |
- * A container with information about split during insert. |
- */ |
-class _Split<K, N> { |
- final K key; |
- final N left; |
- final N right; |
- _Split(this.key, this.left, this.right); |
-} |