From ac0ee98e11b8ef8106778901dc21e8a27925e1e5 Mon Sep 17 00:00:00 2001 From: rikbellens Date: Wed, 28 Feb 2024 12:11:44 +0100 Subject: [PATCH] refactor: use TreeSetView in FilteredMapView --- lib/src/filteredmap.dart | 37 ++++++++++------- lib/src/sortedmap.dart | 47 +++++++++++----------- lib/src/treeset.dart | 85 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 125 insertions(+), 44 deletions(-) diff --git a/lib/src/filteredmap.dart b/lib/src/filteredmap.dart index 9400d7c..db8943c 100644 --- a/lib/src/filteredmap.dart +++ b/lib/src/filteredmap.dart @@ -87,8 +87,8 @@ class FilteredMapView extends MapBase @override V? operator [](Object? key) { - var k = _entryForKey(key)?.key; - return k != null ? _baseMap[k] : null; + var e = _entryForKey(key); + return e?.value; } @override @@ -102,9 +102,8 @@ class FilteredMapView extends MapBase bool _containsPair(Pair pair) => _effectiveInterval.containsPoint(pair); KeyValueInterval get _effectiveInterval { - var keys = this.keys; - return KeyValueInterval.fromPairs(_entryForKey(keys.first, false)!.index, - _entryForKey(keys.last, false)!.index); + return KeyValueInterval.fromPairs(ordering.indexFromMapEntry(entries.first), + ordering.indexFromMapEntry(entries.last)); } @override @@ -125,6 +124,16 @@ class FilteredMapView extends MapBase limit: filter.limit, reversed: filter.reversed); + @override + Iterable get values => keys.map((k) => _baseMap[k]!); + + @override + Iterable> get entries => _baseMap.subentries( + start: filter.validInterval.start, + end: filter.validInterval.end, + limit: filter.limit, + reversed: filter.reversed); + /// Returns true when the [completeInterval] is within the complete interval /// of the base map. bool get isComplete { @@ -137,15 +146,6 @@ class FilteredMapView extends MapBase @override Ordering get ordering => _baseMap.ordering; - @override - Iterable subkeys( - {required Pair start, - required Pair end, - int? limit, - bool reversed = false}) { - throw UnimplementedError(); - } - @override int get length { var b = _baseMap; @@ -161,4 +161,13 @@ class FilteredMapView extends MapBase } return super.length; } + + @override + Iterable> subentries( + {required Pair start, + required Pair end, + int? limit, + bool reversed = false}) { + throw UnimplementedError(); + } } diff --git a/lib/src/sortedmap.dart b/lib/src/sortedmap.dart index bbd56e8..1abd8e4 100644 --- a/lib/src/sortedmap.dart +++ b/lib/src/sortedmap.dart @@ -86,11 +86,26 @@ abstract class SortedMap implements Map { /// Gets the keys within the desired bounds and limit. Iterable subkeys( + {required Pair start, + required Pair end, + int? limit, + bool reversed = false}) => + subentries(start: start, end: end, limit: limit, reversed: reversed) + .map((v) => v.key); + + /// Gets the entries within the desired bounds and limit. + Iterable> subentries( {required Pair start, required Pair end, int? limit, bool reversed = false}); + @override + Iterable get keys => entries.map((p) => p.key); + + @override + Iterable get values => entries.map((p) => p.value); + /// Creates a filtered view of this map. FilteredMapView filteredMapView( {required Pair start, @@ -169,12 +184,6 @@ class _SortedMap extends MapBase @override bool containsKey(Object? key) => _map.containsKey(key); - @override - Iterable get keys => _sortedEntries.map((p) => p.key); - - @override - Iterable get values => _sortedEntries.map((p) => p.value); - @override Iterable> get entries => _sortedEntries; @@ -268,26 +277,20 @@ class _SortedMap extends MapBase } @override - Iterable subkeys( + Iterable> subentries( {required Pair start, required Pair end, int? limit, bool reversed = false}) { - var it = _subkeys(start, end, limit, reversed); - if (reversed) return it.toList().reversed; - return it; - } - - Iterable _subkeys(Pair start, Pair end, int? limit, bool reversed) sync* { - var from = reversed ? end : start; - 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.index, reversed ? start : end); - if ((reversed && cmp < 0) || (!reversed && cmp > 0)) return; - yield it.current.key; - } + var v = TreeSetView<_MapEntryWithIndex>( + baseMap: _sortedEntries as AvlTreeSet<_MapEntryWithIndex>, + startAt: _MapEntryWithIndex.indexOnly(start), + startInclusive: true, + endAt: _MapEntryWithIndex.indexOnly(end), + endInclusive: true, + limit: limit, + limitFromStart: !reversed); + return v; } } diff --git a/lib/src/treeset.dart b/lib/src/treeset.dart index c29c7dd..153388a 100644 --- a/lib/src/treeset.dart +++ b/lib/src/treeset.dart @@ -22,6 +22,11 @@ abstract class TreeSet implements Set { BidirectionalIterator get reverseIterator; int indexOf(V element); + + @override + TreeSet toSet(); + + TreeSet get reversed; } abstract class _BaseTreeSet extends SetMixin implements TreeSet { @@ -72,8 +77,68 @@ abstract class _BaseTreeSet extends SetMixin implements TreeSet { throw IndexError.withLength(index, length, indexable: this, name: 'index'); } - return _avlTreeSet._root!.elementAt(index + _first!.index); + return _avlTreeSet._root! + .elementAt(index + _first!.index, null) + .node + .object; } + + @override + TreeSet get reversed => ReversedTreeSet(this); +} + +class ReversedTreeSet extends SetMixin implements TreeSet { + final TreeSet baseMap; + + ReversedTreeSet(this.baseMap); + + @override + bool add(V value) { + throw UnsupportedError('add is not supported on a ReversedTreeSet'); + } + + @override + bool contains(Object? element) => baseMap.contains(element); + + @override + bool remove(Object? value) { + throw UnsupportedError('remove is not supported on a ReversedTreeSet'); + } + + @override + int indexOf(V element) { + var index = baseMap.indexOf(element); + if (index == -1) return -1; + return baseMap.length - index - 1; + } + + @override + int get length => baseMap.length; + + @override + V? lookup(Object? element) => baseMap.lookup(element); + + @override + Comparator get comparator => baseMap.comparator; + + @override + BidirectionalIterator fromIterator(V anchor, + {bool reversed = false, bool inclusive = true}) { + return baseMap.fromIterator(anchor, + reversed: !reversed, inclusive: inclusive); + } + + @override + BidirectionalIterator get iterator => baseMap.reverseIterator; + + @override + BidirectionalIterator get reverseIterator => baseMap.iterator; + + @override + TreeSet toSet() => ReversedTreeSet(baseMap.toSet()); + + @override + TreeSet get reversed => baseMap; } class TreeSetView extends _BaseTreeSet { @@ -121,7 +186,9 @@ class TreeSetView extends _BaseTreeSet { if (limit != null && !limitFromStart) { var indexFromEnd = _endIndex! - v.index; - if (indexFromEnd < limit!) return null; + if (indexFromEnd >= limit!) { + return baseMap._root!.elementAt(_endIndex! - limit! + 1, v); + } } return v; } @@ -140,7 +207,9 @@ class TreeSetView extends _BaseTreeSet { if (limit != null && limitFromStart) { var indexFromStart = v.index - _startIndex!; - if (indexFromStart < limit!) return null; + if (indexFromStart >= limit!) { + return baseMap._root!.elementAt(_startIndex! + limit! - 1, v); + } } return v; } @@ -219,7 +288,7 @@ class AvlTreeSet extends _BaseTreeSet { throw IndexError.withLength(index, length, indexable: this, name: 'index'); } - return _root!.elementAt(index); + return _root!.elementAt(index, null).node.object; } @override @@ -766,15 +835,15 @@ class AvlNode { return this; } - V elementAt(int index) { + _Path elementAt(int index, _Path? parent) { var l = left?.length ?? 0; if (index < l) { - return left!.elementAt(index); + return left!.elementAt(index, _Path(this, parent)); } if (index == l) { - return this.object; + return _Path(this, parent); } - return right!.elementAt(index - l - 1); + return right!.elementAt(index - l - 1, _Path(this, parent)); } }