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

feat: IListEmpty and friends #76

Merged
97 changes: 86 additions & 11 deletions lib/src/ilist/ilist.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,90 @@ import "l_add.dart";
import "l_add_all.dart";
import "l_flat.dart";

/// This is an [IList] which is always empty.
@immutable
class IListEmpty<T> // ignore: must_be_immutable
extends IList<T> {
/// Creates an empty list. In most cases, you should use `const IList.empty()`.
///
/// IMPORTANT: You must always use the `const` keyword.
/// It's always wrong to use an `IListEmpty()` which is not constant.
@literal
const IListEmpty._([this.config = const ConfigList()])
: super._gen();

@override
final ConfigList config;

/// An empty list is always flushed, by definition.
@override
bool get isFlushed => true;

/// Nothing happens when you flush a empty list, by definition.
@override
IListEmpty<T> get flush => this;

/// An empty list is always empty, by definition
@override
bool get isEmpty => true;

/// An empty list is always empty, by definition
@override
bool get isNotEmpty => false;

/// An empty list does not contain anything, by definition
@override
bool contains(covariant T? element) => false;

/// An empty list is always of length `0`, by definition
@override
int get length => 0;

/// An empty list has no first element, by definition
@override
Never get first => throw StateError("No element");

/// An empty list has no last element, by definition
@override
Never get last => throw StateError("No element");

/// An empty list has no single element, by definition
@override
Never get single => throw StateError("No element");

/// An empty list is always the reversed version of itself, by definition
@override
IListEmpty<T> get reversed => this;

/// An empty list is always the cleared version of itself, by definition
@override
IListEmpty<T> clear() => this;

@override
int get _counter => 0;

@override
L<T> get _l => LFlat<T>.unsafe([]);

/// Hash codes must be the same for objects that are equal to each other
/// according to operator ==.
@override
int? get _hashCode {
return isDeepEquals
? hash2(const ListEquality<dynamic>().hash([]), config.hashCode)
: hash2(identityHashCode(_l), config.hashCode);
}

@override
set _hashCode(int? value) {}

@override
bool same(IList<T>? other) =>
(other != null) &&
(other is IListEmpty) &&
(config == other.config);
}

/// This is an [IList] which can be made constant.
/// Note: Don't ever use it without the "const" keyword, because it will be unsafe.
///
Expand All @@ -34,15 +118,6 @@ class IListConst<T> // ignore: must_be_immutable
[this.config = const ConfigList()])
: super._gen();

/// Creates a empty constant list.
///
/// IMPORTANT: You must always use the `const` keyword.
/// It's always wrong to use an `IListConst.empty()` which is not constant.
@literal
const IListConst.empty([this.config = const ConfigList()])
: _list = const [],
super._gen();

final List<T> _list;

@override
Expand Down Expand Up @@ -200,9 +275,9 @@ abstract class IList<T> // ignore: must_be_immutable
IList.withConfig(iterable ?? const [], defaultConfig);

/// Create an empty [IList].
/// Use it with const: `const IList.empty()` (It's always an [IListConst]).
/// Use it with const: `const IList.empty()` (It's always an [IListEmpty]).
@literal
const factory IList.empty() = IListConst<T>.empty;
const factory IList.empty() = IListEmpty<T>._;

const IList._gen();

Expand Down
93 changes: 82 additions & 11 deletions lib/src/imap/imap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,86 @@ import "m_add_all.dart";
import "m_flat.dart";
import "m_replace.dart";

/// This is an [IMap] which is always empty.
@immutable
class IMapEmpty<K, V> // ignore: must_be_immutable
extends IMap<K, V> {
/// Creates an empty map. In most cases, you should use `const IMap.empty()`.
///
/// IMPORTANT: You must always use the `const` keyword.
/// It's always wrong to use an `IMapEmpty()` which is not constant.
@literal
const IMapEmpty._([this.config = const ConfigMap()])
: super._gen();

@override
final ConfigMap config;

/// An empty map is always flushed, by definition.
@override
bool get isFlushed => true;

/// Nothing happens when you flush a empty map, by definition.
@override
IMapEmpty<K, V> get flush => this;

/// An empty map is always empty, by definition
@override
bool get isEmpty => true;

/// An empty map is always empty, by definition
@override
bool get isNotEmpty => false;

/// An empty map does not contain anything, by definition
@override
bool contains(K key, V value) => false;

/// An empty map does not contain anything, by definition
@override
bool containsKey(K? key) => false;

/// An empty map does not contain anything, by definition
@override
bool containsValue(V? value) => false;

/// An empty map does not contain anything, by definition
@override
bool containsEntry(MapEntry<K, V> entry) => false;

/// An empty map is always of length `0`, by definition
@override
int get length => 0;

/// An empty map is always the cleared version of itself, by definition
@override
IMapEmpty<K, V> clear() => this;

@override
int get _counter => 0;

@override
M<K, V> get _m => MFlat<K, V>.unsafe({});

/// Hash codes must be the same for objects that are equal to each other
/// according to operator ==.
@override
int? get _hashCode {
return isDeepEquals
? hash2(const MapEquality<dynamic, dynamic>().hash({}), config.hashCode)
: hash2(identityHashCode(_m), config.hashCode);
}

@override
set _hashCode(int? value) {}

@override
bool same(IMap<K, V>? other) =>
(other != null) &&
(other is IMapEmpty) &&
(config == other.config);
}

/// This is an [IMap] which can be made constant.
/// Note: Don't ever use it without the "const" keyword, because it will be unsafe.
///
Expand All @@ -35,15 +115,6 @@ class IMapConst<K, V> // ignore: must_be_immutable
[this.config = const ConfigMap()])
: super._gen();

/// Creates a empty constant map.
///
/// IMPORTANT: You must always use the `const` keyword.
/// It's always wrong to use an `IMapConst.empty()` which is not constant.
@literal
const IMapConst.empty([this.config = const ConfigMap()])
: _map = const {},
super._gen();

final Map<K, V> _map;

@override
Expand Down Expand Up @@ -182,9 +253,9 @@ abstract class IMap<K, V> // ignore: must_be_immutable
IMap.withConfig(map, defaultConfig);

/// Create an empty [IMap].
/// Use it with const: `const IMap.empty()` (It's always an [IMapConst]).
/// Use it with const: `const IMap.empty()` (It's always an [IMapEmpty]).
@literal
const factory IMap.empty() = IMapConst<K, V>.empty;
const factory IMap.empty() = IMapEmpty<K, V>._;

const IMap._gen();

Expand Down
93 changes: 82 additions & 11 deletions lib/src/iset/iset.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,86 @@ import "s_add.dart";
import "s_add_all.dart";
import "s_flat.dart";

/// This is an [ISet] which is always empty.
@immutable
class ISetEmpty<T> // ignore: must_be_immutable
extends ISet<T> {
/// Creates an empty set. In most cases, you should use `const ISet.empty()`.
///
/// IMPORTANT: You must always use the `const` keyword.
/// It's always wrong to use an `ISetEmpty()` which is not constant.
@literal
const ISetEmpty._([this.config = const ConfigSet()])
: super._gen();

@override
final ConfigSet config;

/// An empty set is always flushed, by definition.
@override
bool get isFlushed => true;

/// Nothing happens when you flush a empty set, by definition.
@override
ISetEmpty<T> get flush => this;

/// An empty set is always empty, by definition
@override
bool get isEmpty => true;

/// An empty set is always empty, by definition
@override
bool get isNotEmpty => false;

/// An empty set does not contain anything, by definition
@override
bool contains(covariant T? element) => false;

/// An empty set is always of length `0`, by definition
@override
int get length => 0;

/// An empty set has no first element, by definition
@override
Never get first => throw StateError("No element");

/// An empty set has no last element, by definition
@override
Never get last => throw StateError("No element");

/// An empty set has no single element, by definition
@override
Never get single => throw StateError("No element");

/// An empty set is always the cleared version of itself, by definition
@override
ISetEmpty<T> clear() => this;

@override
int get _counter => 0;

@override
S<T> get _s => SFlat<T>.unsafe({});

/// Hash codes must be the same for objects that are equal to each other
/// according to operator ==.
@override
int? get _hashCode {
return isDeepEquals
? hash2(const SetEquality<dynamic>().hash({}), config.hashCode)
: hash2(identityHashCode(_s), config.hashCode);
}

@override
set _hashCode(int? value) {}

@override
bool same(ISet<T>? other) =>
(other != null) &&
(other is ISetEmpty) &&
(config == other.config);
}

/// This is an [ISet] which can be made constant.
/// Note: Don't ever use it without the "const" keyword, because it will be unsafe.
///
Expand All @@ -37,15 +117,6 @@ class ISetConst<T> // ignore: must_be_immutable
[this.config = const ConfigSet()])
: super._gen();

/// Creates a empty constant set.
///
/// IMPORTANT: You must always use the `const` keyword.
/// It's always wrong to use an `ISetConst.empty()` which is not constant.
@literal
const ISetConst.empty([this.config = const ConfigSet()])
: _set = const {},
super._gen();

final Set<T> _set;

@override
Expand Down Expand Up @@ -197,9 +268,9 @@ abstract class ISet<T> // ignore: must_be_immutable
ISet.withConfig(iterable, defaultConfig);

/// Create an empty [ISet].
/// Use it with const: `const ISet.empty()` (It's always an [ISetConst]).
/// Use it with const: `const ISet.empty()` (It's always an [ISetEmpty]).
@literal
const factory ISet.empty() = ISetConst<T>.empty;
const factory ISet.empty() = ISetEmpty<T>._;

const ISet._gen();

Expand Down
Loading