From 9ef6e1b463bf697a97ec3cb6ebf1b84d865d2a8c Mon Sep 17 00:00:00 2001 From: rikbellens Date: Mon, 22 Apr 2024 21:11:59 +0200 Subject: [PATCH] perf: improve speed of addAll to empty map --- lib/src/sortedmap.dart | 6 +++++ lib/src/treemap.dart | 2 +- lib/src/treeset.dart | 56 ++++++++++++++++++++++++++++++++++++++++ test/sortedmap_test.dart | 1 - 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/lib/src/sortedmap.dart b/lib/src/sortedmap.dart index b24e9fe..5a5db24 100644 --- a/lib/src/sortedmap.dart +++ b/lib/src/sortedmap.dart @@ -209,6 +209,12 @@ class _SortedMap extends MapBase _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); } diff --git a/lib/src/treemap.dart b/lib/src/treemap.dart index aca43a3..9e08385 100644 --- a/lib/src/treemap.dart +++ b/lib/src/treemap.dart @@ -57,7 +57,7 @@ class TreeMap extends MapBase { if (other is TreeMap) { _tree.addAll(other._tree); } else { - super.addAll(other); + _tree.addAll(other.entries); } } } diff --git a/lib/src/treeset.dart b/lib/src/treeset.dart index 85b8a34..5aa44ba 100644 --- a/lib/src/treeset.dart +++ b/lib/src/treeset.dart @@ -387,12 +387,19 @@ class AvlTreeSet extends _BaseTreeSet { @override bool addAll(Iterable items) { + if (items.isEmpty) return false; if (_root == null && items is AvlTreeSet && 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; @@ -690,6 +697,55 @@ class AvlNode { height = max(left?.height ?? 0, right?.height ?? 0) + 1, length = (left?.length ?? 0) + (right?.length ?? 0) + 1; + factory AvlNode.fromOrderedList(List items) { + var depth = (log(items.length + 1) / ln2).ceil(); + var size = (1 << depth) - 1; + + var nulls = size - items.length; + + var l = items.cast(); + if (nulls > 0) { + var nonNulls = (size + 1) ~/ 2 - nulls; + + var spacing = nonNulls; + + var skip = 0; + var space = spacing; + l = List.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?>.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 get minimumNode { diff --git a/test/sortedmap_test.dart b/test/sortedmap_test.dart index 5c87935..2232d16 100644 --- a/test/sortedmap_test.dart +++ b/test/sortedmap_test.dart @@ -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);