Skip to content

Commit

Permalink
perf: improve speed of addAll to empty map
Browse files Browse the repository at this point in the history
  • Loading branch information
rbellens committed Apr 22, 2024
1 parent 76b025d commit 9ef6e1b
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 2 deletions.
6 changes: 6 additions & 0 deletions lib/src/sortedmap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,12 @@ class _SortedMap<K extends Comparable, V> extends MapBase<K, V>
_map.addAll(other._map);
return;
}
if (this is! FilteredMap) {
_sortedEntries
.addAll(other.entries.map((e) => ordering.mapEntry(e.key, e.value)));
_map.addAll(other);
return;
}
super.addAll(other);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/src/treemap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class TreeMap<K extends Comparable, V> extends MapBase<K, V> {
if (other is TreeMap<K, V>) {
_tree.addAll(other._tree);
} else {
super.addAll(other);
_tree.addAll(other.entries);
}
}
}
56 changes: 56 additions & 0 deletions lib/src/treeset.dart
Original file line number Diff line number Diff line change
Expand Up @@ -387,12 +387,19 @@ class AvlTreeSet<V> extends _BaseTreeSet<V> {

@override
bool addAll(Iterable<V> items) {
if (items.isEmpty) return false;
if (_root == null &&
items is AvlTreeSet<V> &&
identical((items as dynamic).comparator, comparator)) {
_root = items._root;
return _root != null;
}
if (_root == null) {
//
var l = items.toList()..sort(comparator);
_root = AvlNode.fromOrderedList(l);
return true;
}
var modified = false;
for (var ele in items) {
modified = add(ele) ? true : modified;
Expand Down Expand Up @@ -690,6 +697,55 @@ class AvlNode<V> {
height = max(left?.height ?? 0, right?.height ?? 0) + 1,
length = (left?.length ?? 0) + (right?.length ?? 0) + 1;

factory AvlNode.fromOrderedList(List<V> items) {
var depth = (log(items.length + 1) / ln2).ceil();
var size = (1 << depth) - 1;

var nulls = size - items.length;

var l = items.cast<V?>();
if (nulls > 0) {
var nonNulls = (size + 1) ~/ 2 - nulls;

var spacing = nonNulls;

var skip = 0;
var space = spacing;
l = List<V?>.generate(size, (index) {
if (index % 2 == 0) {
if (space >= spacing) {
space -= spacing;
skip++;
return null;
} else {
space += nulls - 1;
}
}
return items[index - skip];
});
}

var k = List<AvlNode<V>?>.generate(
(size + 1) >> 1,
(index) => l[index * 2] == null
? null
: AvlNode(
object: l[index * 2]!,
));

var skip = 2;
while (k.length > 1) {
skip *= 2;
k = List.generate(k.length >> 1, (index) {
return AvlNode(
object: l[(skip ~/ 2) - 1 + index * skip]!,
left: k[index * 2],
right: k[index * 2 + 1]);
});
}
return k.single!;
}

int get balanceFactor => (right?.height ?? 0) - (left?.height ?? 0);

AvlNode<V> get minimumNode {
Expand Down
1 change: 0 additions & 1 deletion test/sortedmap_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ void main() {
map.addAll({'b': 1, 'e': 2, 'a': 3, 'c': 4});

var keys = map.keys.toList();

expect(keys.indexOf('a'), 0);
expect(keys.indexOf('b'), 1);
expect(keys.indexOf('c'), 2);
Expand Down

0 comments on commit 9ef6e1b

Please sign in to comment.