Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

making all collections const #282

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/src/iterable/built_iterable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ abstract class BuiltIterable<E> implements Iterable<E> {

/// Converts to a [BuiltSet].
BuiltSet<E> toBuiltSet();

const BuiltIterable();
}
33 changes: 24 additions & 9 deletions lib/src/list/built_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,27 @@ part of '../list.dart';
/// for the general properties of Built Collections.
abstract class BuiltList<E> implements Iterable<E>, BuiltIterable<E> {
final List<E> _list;
int? _hashCode;

/// Instantiates with elements from an [Iterable].
factory BuiltList([Iterable iterable = const []]) {
if (iterable is _BuiltList && iterable.hasExactElementType(E)) {
if ((iterable is _BuiltList && iterable.hasExactElementType(E)) ||
(iterable is _ConstBuiltList && iterable.hasExactElementType(E))) {
return iterable as BuiltList<E>;
} else {
return _BuiltList<E>.from(iterable);
}
}

const factory BuiltList.fromList([List<E> list]) =
_ConstBuiltList<E>.withSafeList;

/// Instantiates with elements from an [Iterable<E>].
///
/// `E` must not be `dynamic`.
factory BuiltList.of(Iterable<E> iterable) {
if (iterable is _BuiltList<E> && iterable.hasExactElementType(E)) {
return iterable;
if ((iterable is _BuiltList<E> && iterable.hasExactElementType(E)) ||
iterable is _ConstBuiltList<E> && iterable.hasExactElementType(E)) {
return iterable as BuiltList<E>;
} else {
return _BuiltList<E>.of(iterable);
}
Expand Down Expand Up @@ -61,10 +65,7 @@ abstract class BuiltList<E> implements Iterable<E>, BuiltIterable<E> {
/// A `BuiltList` is only equal to another `BuiltList` with equal elements in
/// the same order. Then, the `hashCode` is guaranteed to be the same.
@override
int get hashCode {
_hashCode ??= hashObjects(_list);
return _hashCode!;
}
int get hashCode => hashObjects(_list);

/// Deep equality.
///
Expand Down Expand Up @@ -234,11 +235,19 @@ abstract class BuiltList<E> implements Iterable<E>, BuiltIterable<E> {

// Internal.

BuiltList._(this._list);
const BuiltList._(this._list);
}

/// Default implementation of the public [BuiltList] interface.
class _BuiltList<E> extends BuiltList<E> {
int? _hashCode;

@override
int get hashCode {
_hashCode ??= super.hashCode;
return _hashCode!;
}

_BuiltList.withSafeList(List<E> list) : super._(list);

_BuiltList.from([Iterable iterable = const []])
Expand All @@ -265,6 +274,12 @@ class _BuiltList<E> extends BuiltList<E> {
bool hasExactElementType(Type type) => E == type;
}

/// An alternative implementation of BuiltList that supports a const constructor
class _ConstBuiltList<E> extends BuiltList<E> {
const _ConstBuiltList.withSafeList([List<E> list = const []]) : super._(list);
bool hasExactElementType(Type type) => E == type;
}

/// Extensions for [BuiltList] on [List].
extension BuiltListExtension<T> on List<T> {
/// Converts to a [BuiltList].
Expand Down
6 changes: 3 additions & 3 deletions lib/src/list/list_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ part of '../list.dart';
/// for the general properties of Built Collections.
class ListBuilder<E> {
late List<E> _list;
_BuiltList<E>? _listOwner;
BuiltList<E>? _listOwner;

/// Instantiates with elements from an [Iterable].
factory ListBuilder([Iterable iterable = const []]) {
Expand All @@ -38,7 +38,7 @@ class ListBuilder<E> {

/// Replaces all elements with elements from an [Iterable].
void replace(Iterable iterable) {
if (iterable is _BuiltList<E>) {
if (iterable is BuiltList<E>) {
_setOwner(iterable);
} else {
_setSafeList(List<E>.from(iterable));
Expand Down Expand Up @@ -258,7 +258,7 @@ class ListBuilder<E> {

ListBuilder._uninitialized();

void _setOwner(_BuiltList<E> listOwner) {
void _setOwner(BuiltList<E> listOwner) {
_list = listOwner._list;
_listOwner = listOwner;
}
Expand Down
79 changes: 56 additions & 23 deletions lib/src/list_multimap/built_list_multimap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,16 @@ part of '../list_multimap.dart';
abstract class BuiltListMultimap<K, V> {
final Map<K, BuiltList<V>> _map;

// Precomputed.
final BuiltList<V> _emptyList = BuiltList<V>();

// Cached.
int? _hashCode;
Iterable<K>? _keys;
Iterable<V>? _values;
const factory BuiltListMultimap.fromMap([Map<K, BuiltList<V>> map]) =
_ConstBuiltListMultimap.withSafeMap;

/// Instantiates with elements from a [Map], [ListMultimap] or
/// [BuiltListMultimap].
factory BuiltListMultimap([multimap = const {}]) {
if (multimap is _BuiltListMultimap &&
multimap.hasExactKeyAndValueTypes(K, V)) {
multimap.hasExactKeyAndValueTypes(K, V) ||
multimap is _ConstBuiltListMultimap &&
multimap.hasExactKeyAndValueTypes(K, V)) {
return multimap as BuiltListMultimap<K, V>;
} else if (multimap is Map) {
return _BuiltListMultimap<K, V>.copy(multimap.keys, (k) => multimap[k]);
Expand Down Expand Up @@ -72,11 +69,12 @@ abstract class BuiltListMultimap<K, V> {
/// to be the same.
@override
int get hashCode {
_hashCode ??= hashObjects(_map.keys
.map((key) => hash2(key.hashCode, _map[key].hashCode))
.toList(growable: false)
..sort());
return _hashCode!;
return hashObjects(
_map.keys
.map((key) => hash2(key.hashCode, _map[key].hashCode))
.toList(growable: false)
..sort(),
);
}

/// Deep equality.
Expand Down Expand Up @@ -109,7 +107,7 @@ abstract class BuiltListMultimap<K, V> {
/// As [ListMultimap], but results are [BuiltList]s and not mutable.
BuiltList<V> operator [](Object? key) {
var result = _map[key];
return result ?? _emptyList;
return result ?? BuiltList<V>();
}

/// As [ListMultimap.containsKey].
Expand Down Expand Up @@ -142,24 +140,18 @@ abstract class BuiltListMultimap<K, V> {

/// As [ListMultimap.keys], but result is stable; it always returns the same
/// instance.
Iterable<K> get keys {
_keys ??= _map.keys;
return _keys!;
}
Iterable<K> get keys => _map.keys;

/// As [ListMultimap.length].
int get length => _map.length;

/// As [ListMultimap.values], but result is stable; it always returns the
/// same instance.
Iterable<V> get values {
_values ??= _map.values.expand((x) => x);
return _values!;
}
Iterable<V> get values => _map.values.expand((x) => x);

// Internal.

BuiltListMultimap._(this._map);
const BuiltListMultimap._(this._map);
}

/// Default implementation of the public [BuiltListMultimap] interface.
Expand All @@ -177,5 +169,46 @@ class _BuiltListMultimap<K, V> extends BuiltListMultimap<K, V> {
}
}

// Precomputed.
final BuiltList<V> _emptyList = BuiltList<V>();

/// As [ListMultimap], but results are [BuiltList]s and not mutable.
@override
BuiltList<V> operator [](Object? key) {
var result = _map[key];
// Precomputed.
return result ?? _emptyList;
}

// Cached.
int? _hashCode;
Iterable<K>? _keys;
Iterable<V>? _values;

@override
Iterable<V> get values {
_values ??= super.values;
return _values!;
}

@override
Iterable<K> get keys {
_keys ??= super.keys;
return _keys!;
}

@override
int get hashCode {
_hashCode ??= super.hashCode;
return _hashCode!;
}

bool hasExactKeyAndValueTypes(Type key, Type value) => K == key && V == value;
}

class _ConstBuiltListMultimap<K, V> extends BuiltListMultimap<K, V> {
const _ConstBuiltListMultimap.withSafeMap(
[Map<K, BuiltList<V>> src = const {}])
: super._(src);
bool hasExactKeyAndValueTypes(Type key, Type value) => K == key && V == value;
}
6 changes: 3 additions & 3 deletions lib/src/list_multimap/list_multimap_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class ListMultimapBuilder<K, V> {
late Map<K, BuiltList<V>> _builtMap;
// Instance that _builtMap belongs to. If present, _builtMap must not be
// mutated.
_BuiltListMultimap<K, V>? _builtMapOwner;
BuiltListMultimap<K, V>? _builtMapOwner;
// ListBuilders for keys that are being changed.
late Map<K, ListBuilder<V>> _builderMap;

Expand Down Expand Up @@ -57,7 +57,7 @@ class ListMultimapBuilder<K, V> {
///
/// Any [ListBuilder]s associated with this collection are disconnected.
void replace(dynamic multimap) {
if (multimap is _BuiltListMultimap<K, V>) {
if (multimap is BuiltListMultimap<K, V>) {
_setOwner(multimap);
} else if (multimap is Map) {
_setWithCopyAndCheck(multimap.keys, (k) => multimap[k]);
Expand Down Expand Up @@ -178,7 +178,7 @@ class ListMultimapBuilder<K, V> {

ListMultimapBuilder._uninitialized();

void _setOwner(_BuiltListMultimap<K, V> builtListMultimap) {
void _setOwner(BuiltListMultimap<K, V> builtListMultimap) {
_builtMapOwner = builtListMultimap;
_builtMap = builtListMultimap._map;
_builderMap = <K, ListBuilder<V>>{};
Expand Down
62 changes: 39 additions & 23 deletions lib/src/map/built_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@ abstract class BuiltMap<K, V> {
final _MapFactory<K, V>? _mapFactory;
final Map<K, V> _map;

// Cached.
int? _hashCode;
Iterable<K>? _keys;
Iterable<V>? _values;

/// Instantiates with elements from a [Map] or [BuiltMap].
factory BuiltMap([map = const {}]) {
if (map is _BuiltMap && map.hasExactKeyAndValueTypes(K, V)) {
Expand All @@ -35,6 +30,9 @@ abstract class BuiltMap<K, V> {
}
}

const factory BuiltMap.fromMap([Map<K, V> map]) =
_ConstBuiltMap<K, V>.withSafeMap;

/// Instantiates with elements from a [Map].
factory BuiltMap.from(Map map) {
return _BuiltMap<K, V>.copyAndCheckTypes(map.keys, (k) => map[k]);
Expand All @@ -54,8 +52,7 @@ abstract class BuiltMap<K, V> {
/// Converts to a [MapBuilder] for modification.
///
/// The `BuiltMap` remains immutable and can continue to be used.
MapBuilder<K, V> toBuilder() =>
MapBuilder<K, V>._fromBuiltMap(this as _BuiltMap<K, V>);
MapBuilder<K, V> toBuilder() => MapBuilder<K, V>._fromBuiltMap(this);

/// Converts to a [MapBuilder], applies updates to it, and builds.
BuiltMap<K, V> rebuild(Function(MapBuilder<K, V>) updates) =>
Expand All @@ -82,13 +79,10 @@ abstract class BuiltMap<K, V> {
/// A `BuiltMap` is only equal to another `BuiltMap` with equal key/value
/// pairs in any order. Then, the `hashCode` is guaranteed to be the same.
@override
int get hashCode {
_hashCode ??= hashObjects(_map.keys
.map((key) => hash2(key.hashCode, _map[key].hashCode))
.toList(growable: false)
..sort());
return _hashCode!;
}
int get hashCode => hashObjects(_map.keys
.map((key) => hash2(key.hashCode, _map[key].hashCode))
.toList(growable: false)
..sort());

/// Deep equality.
///
Expand Down Expand Up @@ -132,20 +126,14 @@ abstract class BuiltMap<K, V> {
bool get isNotEmpty => _map.isNotEmpty;

/// As [Map.keys], but result is stable; it always returns the same instance.
Iterable<K> get keys {
_keys ??= _map.keys;
return _keys!;
}
Iterable<K> get keys => _map.keys;

/// As [Map.length].
int get length => _map.length;

/// As [Map.values], but result is stable; it always returns the same
/// instance.
Iterable<V> get values {
_values ??= _map.values;
return _values!;
}
Iterable<V> get values => _map.values;

/// As [Map.entries].
Iterable<MapEntry<K, V>> get entries => _map.entries;
Expand All @@ -156,11 +144,16 @@ abstract class BuiltMap<K, V> {

// Internal.

BuiltMap._(this._mapFactory, this._map);
const BuiltMap._(this._mapFactory, this._map);
}

/// Default implementation of the public [BuiltMap] interface.
class _BuiltMap<K, V> extends BuiltMap<K, V> {
// Cached.
int? _hashCode;
Iterable<K>? _keys;
Iterable<V>? _values;

_BuiltMap.withSafeMap(_MapFactory<K, V>? mapFactory, Map<K, V> map)
: super._(mapFactory, map);

Expand Down Expand Up @@ -196,9 +189,32 @@ class _BuiltMap<K, V> extends BuiltMap<K, V> {
}
}

@override
Iterable<V> get values {
_values ??= super.values;
return _values!;
}

@override
Iterable<K> get keys {
_keys ??= super.keys;
return _keys!;
}

@override
int get hashCode {
_hashCode ??= super.hashCode;
return _hashCode!;
}

bool hasExactKeyAndValueTypes(Type key, Type value) => K == key && V == value;
}

class _ConstBuiltMap<K, V> extends BuiltMap<K, V> {
const _ConstBuiltMap.withSafeMap([Map<K, V> map = const {}])
: super._(null, map);
}

/// Extensions for [BuiltMap] on [Map].
extension BuiltMapExtension<K, V> on Map<K, V> {
/// Converts to a [BuiltMap].
Expand Down
Loading