From 8541ec7f3cc6356dc76fa1fa29f0b70e43f5b8c5 Mon Sep 17 00:00:00 2001 From: rikbellens Date: Wed, 21 Feb 2024 10:26:36 +0100 Subject: [PATCH] refactor: keep sortedEntries iso sortedPairs in SortedMap --- lib/src/filteredmap.dart | 52 +++++++++++---------- lib/src/sortedmap.dart | 97 +++++++++++++++++++++++++++++----------- lib/src/treeset.dart | 2 - 3 files changed, 99 insertions(+), 52 deletions(-) diff --git a/lib/src/filteredmap.dart b/lib/src/filteredmap.dart index 07f5aa6..4543a9a 100644 --- a/lib/src/filteredmap.dart +++ b/lib/src/filteredmap.dart @@ -17,19 +17,18 @@ abstract class FilteredMap implements SortedMap { /// The interval within which no values were filtered out based on the /// filter's `limit` or `validInterval`. KeyValueInterval get completeInterval { - var keys = this.keys; var filterInterval = filter.validInterval; - if (filter.limit == null || keys.length < filter.limit!) { + if (filter.limit == null || length < filter.limit!) { return filterInterval; } if (filter.limit == 0) return KeyValueInterval(); if (filter.reversed) { return KeyValueInterval.fromPairs( - _pairForKey(keys.first)!, filterInterval.end); + ordering.indexFromMapEntry(entries.first), filterInterval.end); } else { return KeyValueInterval.fromPairs( - filterInterval.start, _pairForKey(keys.last)!); + filterInterval.start, ordering.indexFromMapEntry(entries.last)); } } } @@ -39,26 +38,29 @@ class _FilteredMap extends _SortedMap @override final Filter filter; - _FilteredMap._( - Filter filter, TreeSet? sortedPairs, TreeMap? map) + _FilteredMap._(Filter filter, + TreeSet<_MapEntryWithIndex>? sortedEntries, TreeMap? map) : filter = filter, - super._(filter.ordering, sortedPairs, map); + super._(filter.ordering, sortedEntries, map); @override FilteredMap clone() => _FilteredMap._( - filter, TreeSet()..addAll(_sortedPairs), TreeMap.from(_map)); + filter, + TreeSet(comparator: (a, b) => Comparable.compare(a.index, b.index)) + ..addAll(_sortedEntries), + TreeMap.from(_map)); @override - void _addPair(K key, V value) { + void _addEntry(K key, V value) { if (!filter.validInterval.containsPoint(ordering.mapKeyValue(key, value))) { remove(key); return; } - super._addPair(key, value); + super._addEntry(key, value); if (filter.limit != null && length > filter.limit!) { var toDel = filter.reversed - ? _sortedPairs.take(length - filter.limit!) - : _sortedPairs.skip(filter.limit!); + ? _sortedEntries.take(length - filter.limit!) + : _sortedEntries.skip(filter.limit!); toDel.toList().forEach((p) => remove(p.key)); } } @@ -86,15 +88,15 @@ class FilteredMapView extends MapBase @override V? operator [](Object? key) { - var k = _pairForKey(key)?.key as K?; + var k = _entryForKey(key)?.key; return k != null ? _baseMap[k] : null; } @override - Pair? _pairForKey(Object? key, [bool checked = true]) { + _MapEntryWithIndex? _entryForKey(Object? key, [bool checked = true]) { V value = _baseMap[key as K]!; - var p = ordering.mapKeyValue(key, value); - if (checked && !_containsPair(p)) return null; + var p = ordering.mapEntry(key, value); + if (checked && !_containsPair(p.index)) return null; return p; } @@ -102,8 +104,8 @@ class FilteredMapView extends MapBase KeyValueInterval get _effectiveInterval { var keys = this.keys; - return KeyValueInterval.fromPairs( - _pairForKey(keys.first, false)!, _pairForKey(keys.last, false)!); + return KeyValueInterval.fromPairs(_entryForKey(keys.first, false)!.index, + _entryForKey(keys.last, false)!.index); } @override @@ -111,11 +113,11 @@ class FilteredMapView extends MapBase @override K firstKeyAfter(K key, {K Function()? orElse}) => - _pairForKey(_baseMap.firstKeyAfter(key, orElse: orElse))!.key as K; + _entryForKey(_baseMap.firstKeyAfter(key, orElse: orElse))!.key; @override K lastKeyBefore(K key, {K Function()? orElse}) => - _pairForKey(_baseMap.lastKeyBefore(key, orElse: orElse))!.key as K; + _entryForKey(_baseMap.lastKeyBefore(key, orElse: orElse))!.key; @override Iterable get keys => _baseMap.subkeys( @@ -149,10 +151,12 @@ class FilteredMapView extends MapBase int get length { var b = _baseMap; if (b is _SortedMap) { - var e = (b._sortedPairs as AvlTreeSet) - .countUntil(filter.validInterval.end, inclusive: true); - var s = (b._sortedPairs as AvlTreeSet) - .countUntil(filter.validInterval.start, inclusive: false); + var e = (b._sortedEntries as AvlTreeSet<_MapEntryWithIndex>) + .countUntil(_MapEntryWithIndex.indexOnly(filter.validInterval.end), + inclusive: true); + var s = (b._sortedEntries as AvlTreeSet<_MapEntryWithIndex>) + .countUntil(_MapEntryWithIndex.indexOnly(filter.validInterval.start), + inclusive: false); var total = e - s; return filter.limit == null ? total : min(total, filter.limit!); } diff --git a/lib/src/sortedmap.dart b/lib/src/sortedmap.dart index 10f0c7f..92fe6aa 100644 --- a/lib/src/sortedmap.dart +++ b/lib/src/sortedmap.dart @@ -113,8 +113,41 @@ abstract class SortedMap implements Map { reversed: reversed)) ..addAll(this); - Pair? _pairForKey(K? key) => - containsKey(key) ? ordering.mapKeyValue(key!, this[key]) : null; + _MapEntryWithIndex? _entryForKey(K? key) => + containsKey(key) ? ordering.mapEntry(key!, this[key] as V) : null; +} + +class _MapEntryWithIndex implements MapEntry { + final K? _key; + + final V? _value; + + final Pair index; + + _MapEntryWithIndex.indexOnly(Pair pair) + : _key = null, + _value = null, + index = pair; + + _MapEntryWithIndex(K key, V value, this.index) + : _key = key, + _value = value; + + @override + V get value => _value as V; + + @override + K get key => _key as K; +} + +extension _OrderingX on Ordering { + _MapEntryWithIndex mapEntry(K key, V value) => + _MapEntryWithIndex(key, value, mapKeyValue(key, value)); + + Pair indexFromMapEntry(MapEntry entry) => + entry is _MapEntryWithIndex + ? entry.index + : mapKeyValue(entry.key, entry.value); } class _SortedMap extends MapBase @@ -122,22 +155,33 @@ class _SortedMap extends MapBase @override final Ordering ordering; - final TreeSet _sortedPairs; + final TreeSet<_MapEntryWithIndex> _sortedEntries; final TreeMap _map; - _SortedMap._(this.ordering, TreeSet? sortedPairs, TreeMap? map) - : _sortedPairs = sortedPairs ?? TreeSet(), + _SortedMap._(this.ordering, TreeSet<_MapEntryWithIndex>? sortedPairs, + TreeMap? map) + : _sortedEntries = sortedPairs ?? + TreeSet(comparator: (a, b) => Comparable.compare(a.index, b.index)), _map = map ?? TreeMap(); @override bool containsKey(Object? key) => _map.containsKey(key); @override - Iterable get keys => _sortedPairs.map((p) => p.key as K); + Iterable get keys => _sortedEntries.map((p) => p.key); + + @override + Iterable get values => _sortedEntries.map((p) => p.value); + + @override + Iterable> get entries => _sortedEntries; @override SortedMap clone() => _SortedMap._( - ordering, TreeSet()..addAll(_sortedPairs), TreeMap.from(_map)); + ordering, + TreeSet(comparator: (a, b) => Comparable.compare(a.index, b.index)) + ..addAll(_sortedEntries), + TreeMap.from(_map)); @override V? operator [](Object? key) => _map[key as K]; @@ -147,7 +191,7 @@ class _SortedMap extends MapBase if (other is _SortedMap && other.ordering == ordering && this is! FilteredMap) { - _sortedPairs.addAll(other._sortedPairs); + _sortedEntries.addAll(other._sortedEntries); _map.addAll(other._map); return; } @@ -156,29 +200,29 @@ class _SortedMap extends MapBase @override void operator []=(K key, V value) { - var pair = _pairForKey(key); - if (pair != null) _sortedPairs.remove(pair); - _addPair(key, value); + var entry = _entryForKey(key); + if (entry != null) _sortedEntries.remove(entry); + _addEntry(key, value); } @override bool get isEmpty => _map.isEmpty; - void _addPair(K key, V value) { + void _addEntry(K key, V value) { _map[key] = value; - _sortedPairs.add(ordering.mapKeyValue(key, value)); + _sortedEntries.add(ordering.mapEntry(key, value)); } @override void clear() { _map.clear(); - _sortedPairs.clear(); + _sortedEntries.clear(); } @override V? remove(Object? key) { if (!_map.containsKey(key)) return null; - _sortedPairs.remove(_pairForKey(key as K?)); + _sortedEntries.remove(_entryForKey(key as K?)); return _map.remove(key); } @@ -187,16 +231,16 @@ class _SortedMap extends MapBase if (!_map.containsKey(key)) { throw StateError('No such key $key in collection'); } - var pair = _pairForKey(key)!; - var it = _sortedPairs.fromIterator(pair, reversed: true); + var entry = _entryForKey(key)!; + var it = _sortedEntries.fromIterator(entry, reversed: true); bool hasMore; - while ((hasMore = it.moveNext()) && it.current == pair) {} + while ((hasMore = it.moveNext()) && it.current.index == entry.index) {} if (!hasMore) { if (orElse != null) return orElse(); throw StateError('No element.'); } - return it.current.key as K; + return it.current.key; } @override @@ -204,15 +248,15 @@ class _SortedMap extends MapBase if (!_map.containsKey(key)) { throw StateError('No such key $key in collection'); } - var pair = _pairForKey(key)!; - var it = _sortedPairs.fromIterator(pair); + var pair = _entryForKey(key)!; + var it = _sortedEntries.fromIterator(pair); bool hasMore; - while ((hasMore = it.moveNext()) && it.current == pair) {} + while ((hasMore = it.moveNext()) && it.current.index == pair.index) {} if (!hasMore) { if (orElse != null) return orElse(); throw StateError('No element.'); } - return it.current.key as K; + return it.current.key; } @override @@ -228,12 +272,13 @@ class _SortedMap extends MapBase Iterable _subkeys(Pair start, Pair end, int? limit, bool reversed) sync* { var from = reversed ? end : start; - var it = _sortedPairs.fromIterator(from, reversed: reversed); + var it = _sortedEntries.fromIterator(_MapEntryWithIndex.indexOnly(from), + reversed: reversed); var count = 0; while (it.moveNext() && (limit == null || count++ < limit)) { - var cmp = Comparable.compare(it.current, reversed ? start : end); + var cmp = Comparable.compare(it.current.index, reversed ? start : end); if ((reversed && cmp < 0) || (!reversed && cmp > 0)) return; - yield it.current.key as K; + yield it.current.key; } } } diff --git a/lib/src/treeset.dart b/lib/src/treeset.dart index 21c511f..6b01df7 100644 --- a/lib/src/treeset.dart +++ b/lib/src/treeset.dart @@ -1,8 +1,6 @@ import 'dart:collection'; import 'dart:math'; -import 'package:sortedmap/sortedmap.dart'; - abstract class TreeSet extends SetMixin implements Set { final Comparator comparator;