Skip to content

Commit

Permalink
refactor: keep sortedEntries iso sortedPairs in SortedMap
Browse files Browse the repository at this point in the history
  • Loading branch information
rbellens committed Feb 21, 2024
1 parent 6c0217e commit 8541ec7
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 52 deletions.
52 changes: 28 additions & 24 deletions lib/src/filteredmap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,18 @@ abstract class FilteredMap<K extends Comparable, V> implements SortedMap<K, V> {
/// 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));
}
}
}
Expand All @@ -39,26 +38,29 @@ class _FilteredMap<K extends Comparable, V> extends _SortedMap<K, V>
@override
final Filter<K, V> filter;

_FilteredMap._(
Filter<K, V> filter, TreeSet<Pair>? sortedPairs, TreeMap<K, V>? map)
_FilteredMap._(Filter<K, V> filter,
TreeSet<_MapEntryWithIndex<K, V>>? sortedEntries, TreeMap<K, V>? map)
: filter = filter,
super._(filter.ordering, sortedPairs, map);
super._(filter.ordering, sortedEntries, map);

@override
FilteredMap<K, V> clone() => _FilteredMap<K, V>._(
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));
}
}
Expand Down Expand Up @@ -86,36 +88,36 @@ class FilteredMapView<K extends Comparable, V> extends MapBase<K, V>

@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<K, V>? _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;
}

bool _containsPair(Pair pair) => _effectiveInterval.containsPoint(pair);

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
SortedMap<K, V> clone() => FilteredMap(filter)..addAll(_baseMap);

@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<K> get keys => _baseMap.subkeys(
Expand Down Expand Up @@ -149,10 +151,12 @@ class FilteredMapView<K extends Comparable, V> extends MapBase<K, V>
int get length {
var b = _baseMap;
if (b is _SortedMap<K, V>) {
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<K, V>>)
.countUntil(_MapEntryWithIndex.indexOnly(filter.validInterval.end),
inclusive: true);
var s = (b._sortedEntries as AvlTreeSet<_MapEntryWithIndex<K, V>>)
.countUntil(_MapEntryWithIndex.indexOnly(filter.validInterval.start),
inclusive: false);
var total = e - s;
return filter.limit == null ? total : min(total, filter.limit!);
}
Expand Down
97 changes: 71 additions & 26 deletions lib/src/sortedmap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -113,31 +113,75 @@ abstract class SortedMap<K extends Comparable, V> implements Map<K, V> {
reversed: reversed))
..addAll(this);

Pair? _pairForKey(K? key) =>
containsKey(key) ? ordering.mapKeyValue(key!, this[key]) : null;
_MapEntryWithIndex<K, V>? _entryForKey(K? key) =>
containsKey(key) ? ordering.mapEntry(key!, this[key] as V) : null;
}

class _MapEntryWithIndex<K extends Comparable, V> implements MapEntry<K, V> {
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<K, V> mapEntry<K extends Comparable, V>(K key, V value) =>
_MapEntryWithIndex(key, value, mapKeyValue(key, value));

Pair indexFromMapEntry<K extends Comparable, V>(MapEntry<K, V> entry) =>
entry is _MapEntryWithIndex<K, V>
? entry.index
: mapKeyValue(entry.key, entry.value);
}

class _SortedMap<K extends Comparable, V> extends MapBase<K, V>
with SortedMap<K, V> {
@override
final Ordering ordering;

final TreeSet<Pair> _sortedPairs;
final TreeSet<_MapEntryWithIndex<K, V>> _sortedEntries;
final TreeMap<K, V> _map;

_SortedMap._(this.ordering, TreeSet<Pair>? sortedPairs, TreeMap<K, V>? map)
: _sortedPairs = sortedPairs ?? TreeSet(),
_SortedMap._(this.ordering, TreeSet<_MapEntryWithIndex<K, V>>? sortedPairs,
TreeMap<K, V>? 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<K> get keys => _sortedPairs.map<K>((p) => p.key as K);
Iterable<K> get keys => _sortedEntries.map<K>((p) => p.key);

@override
Iterable<V> get values => _sortedEntries.map<V>((p) => p.value);

@override
Iterable<MapEntry<K, V>> get entries => _sortedEntries;

@override
SortedMap<K, V> clone() => _SortedMap<K, V>._(
ordering, TreeSet()..addAll(_sortedPairs), TreeMap<K, V>.from(_map));
ordering,
TreeSet(comparator: (a, b) => Comparable.compare(a.index, b.index))
..addAll(_sortedEntries),
TreeMap<K, V>.from(_map));

@override
V? operator [](Object? key) => _map[key as K];
Expand All @@ -147,7 +191,7 @@ class _SortedMap<K extends Comparable, V> extends MapBase<K, V>
if (other is _SortedMap<K, V> &&
other.ordering == ordering &&
this is! FilteredMap) {
_sortedPairs.addAll(other._sortedPairs);
_sortedEntries.addAll(other._sortedEntries);
_map.addAll(other._map);
return;
}
Expand All @@ -156,29 +200,29 @@ class _SortedMap<K extends Comparable, V> extends MapBase<K, V>

@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);
}

Expand All @@ -187,32 +231,32 @@ class _SortedMap<K extends Comparable, V> extends MapBase<K, V>
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
K firstKeyAfter(K key, {K Function()? orElse}) {
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
Expand All @@ -228,12 +272,13 @@ class _SortedMap<K extends Comparable, V> extends MapBase<K, V>

Iterable<K> _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;
}
}
}
Expand Down
2 changes: 0 additions & 2 deletions lib/src/treeset.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import 'dart:collection';
import 'dart:math';

import 'package:sortedmap/sortedmap.dart';

abstract class TreeSet<V> extends SetMixin<V> implements Set<V> {
final Comparator<V> comparator;

Expand Down

0 comments on commit 8541ec7

Please sign in to comment.