Skip to content

Commit

Permalink
perf: improve speed for forEach on SortedMap
Browse files Browse the repository at this point in the history
  • Loading branch information
rbellens committed Feb 21, 2024
1 parent c7cd055 commit 917d1e9
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 40 deletions.
7 changes: 7 additions & 0 deletions lib/src/sortedmap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,13 @@ class _SortedMap<K extends Comparable, V> extends MapBase<K, V>
_addEntry(key, value);
}

@override
void forEach(void Function(K key, V value) action) {
for (var e in entries) {
action(e.key, e.value);
}
}

@override
bool get isEmpty => _map.isEmpty;

Expand Down
98 changes: 58 additions & 40 deletions lib/src/treeset.dart
Original file line number Diff line number Diff line change
Expand Up @@ -349,21 +349,11 @@ class AvlNode<V> {
return left!.minimumNode;
}

Iterable<AvlNode<V>> get minimumPath sync* {
yield this;
if (left != null) yield* left!.minimumPath;
}

AvlNode<V> get maximumNode {
if (right == null) return this;
return right!.maximumNode;
}

Iterable<AvlNode<V>> get maximumPath sync* {
yield this;
if (right != null) yield* right!.maximumPath;
}

AvlNode<V> add(Comparator<V> comparator, V element) {
var compare = comparator(element, object);
if (compare == 0) {
Expand Down Expand Up @@ -611,29 +601,53 @@ class TreeIterator<V> extends BidirectionalIterator<V> {
}
}

class _Path<V> {
final AvlNode<V> node;
final _Path<V>? parent;

final AvlNode<V> root;

_Path(this.node, this.parent) : root = parent?.root ?? node;

factory _Path.from(Iterable<AvlNode<V>> nodes, [_Path<V>? parent]) {
if (nodes.isEmpty) return parent!;
return _Path.from(nodes.skip(1), _Path(nodes.first, parent));
}

factory _Path.minimum(AvlNode<V> node, [_Path<V>? parent]) {
if (node.left == null) return _Path(node, parent);
return _Path.minimum(node.left!, _Path(node, parent));
}

factory _Path.maximum(AvlNode<V> node, [_Path<V>? parent]) {
if (node.right == null) return _Path(node, parent);
return _Path.maximum(node.right!, _Path(node, parent));
}
}

class TreeCursor<V> extends BidirectionalIterator<V> {
final AvlTreeSet<V> tree;
final List<AvlNode<V>> _path = [];
_Path<V>? _path;
bool _lastMovedForward = true;

TreeCursor(this.tree);

bool get isOnNode => _path.isNotEmpty;
bool get isOnNode => _path != null;

void positionAfter(
V? anchor, {
bool inclusive = true,
}) {
_lastMovedForward = true;
_path.clear();
_path = null;
if (tree._root == null) return;
if (anchor == null) {
_path.addAll(tree._root!.minimumPath);
_path = _Path.minimum(tree._root!);
return;
}
var x = tree._root;
while (x != null) {
_path.add(x);
_path = _Path(x, _path);
var compare = tree.comparator(anchor, x.object);
if (compare == 0) {
if (!inclusive) moveNext();
Expand All @@ -644,7 +658,7 @@ class TreeCursor<V> extends BidirectionalIterator<V> {
x = x.right;
}
}
x = _path.last;
x = _path!.node;
var compare = tree.comparator(anchor, x.object);
if (compare > 0) {
moveNext();
Expand All @@ -656,15 +670,15 @@ class TreeCursor<V> extends BidirectionalIterator<V> {
bool inclusive = true,
}) {
_lastMovedForward = false;
_path.clear();
_path = null;
if (tree._root == null) return;
if (anchor == null) {
_path.addAll(tree._root!.maximumPath);
_path = _Path.maximum(tree._root!);
return;
}
var x = tree._root;
while (x != null) {
_path.add(x);
_path = _Path(x, _path);
var compare = tree.comparator(anchor, x.object);
if (compare == 0) {
if (!inclusive) movePrevious();
Expand All @@ -675,7 +689,7 @@ class TreeCursor<V> extends BidirectionalIterator<V> {
x = x.right;
}
}
x = _path.last;
x = _path!.node;
var compare = tree.comparator(anchor, x.object);
if (compare < 0) {
movePrevious();
Expand All @@ -684,65 +698,69 @@ class TreeCursor<V> extends BidirectionalIterator<V> {

@override
V get current {
if (_path.isEmpty) {
if (_path == null) {
throw StateError('TreeCursor not pointing to a value.');
}
return _path.last.object;
return _path!.node.object;
}

@override
bool moveNext() {
if (_path.isEmpty) {
if (_path == null) {
if (tree._root == null) return false;
if (_lastMovedForward) {
return false;
} else {
_path.addAll(tree._root!.minimumPath);
_path = _Path.minimum(tree._root!);
return true;
}
}
_lastMovedForward = true;

if (_path.first != tree._root) throw ConcurrentModificationError(tree);
var current = _path.last;
if (_path!.root != tree._root) throw ConcurrentModificationError(tree);
var current = _path!.node;
if (current.right != null) {
_path.addAll(current.right!.minimumPath);
_path = _Path.minimum(current.right!, _path);
return true;
}
var l = _path.removeLast();
while (_path.isNotEmpty && _path.last.right == l) {
l = _path.removeLast();
var l = _path!.node;
_path = _path!.parent;
while (_path != null && _path!.node.right == l) {
l = _path!.node;
_path = _path!.parent;
}
if (_path.isEmpty) {
if (_path == null) {
return false;
}
return true;
}

@override
bool movePrevious() {
if (_path.isEmpty) {
if (_path == null) {
if (tree._root == null) return false;
if (!_lastMovedForward) {
return false;
} else {
_path.addAll(tree._root!.maximumPath);
_path = _Path.maximum(tree._root!, _path);
return true;
}
}
_lastMovedForward = true;

if (_path.first != tree._root) throw ConcurrentModificationError(tree);
var current = _path.last;
if (_path!.root != tree._root) throw ConcurrentModificationError(tree);
var current = _path!.node;
if (current.left != null) {
_path.addAll(current.left!.maximumPath);
_path = _Path.maximum(current.left!, _path);
return true;
}
var l = _path.removeLast();
while (_path.isNotEmpty && _path.last.left == l) {
l = _path.removeLast();
var l = _path!.node;
_path = _path!.parent;
while (_path != null && _path!.node.left == l) {
l = _path!.node;
_path = _path!.parent;
}
if (_path.isEmpty) {
if (_path == null) {
return false;
}
return true;
Expand Down

0 comments on commit 917d1e9

Please sign in to comment.