Version 2.16.0-52.0.dev
Merge commit 'a98368c2506781c3552c2561f74b3efafd84386e' into 'dev'
diff --git a/sdk/lib/collection/hash_map.dart b/sdk/lib/collection/hash_map.dart
index 2d4f42c..9bc1661 100644
--- a/sdk/lib/collection/hash_map.dart
+++ b/sdk/lib/collection/hash_map.dart
@@ -18,6 +18,8 @@
/// A hash-table based implementation of [Map].
///
+/// The [HashMap] is unordered (the order of iteration is not guaranteed).
+///
/// The keys of a `HashMap` must have consistent [Object.==]
/// and [Object.hashCode] implementations. This means that the `==` operator
/// must define a stable equivalence relation on the keys (reflexive,
@@ -25,11 +27,94 @@
/// must be the same for objects that are considered equal by `==`.
///
/// Iterating the map's keys, values or entries (through [forEach])
-/// may happen in any order.
-/// The iteration order only changes when the map is modified.
-/// Values are iterated in the same order as their associated keys,
+/// may happen in any order. The iteration order only changes when the map is
+/// modified. Values are iterated in the same order as their associated keys,
/// so iterating the [keys] and [values] in parallel
/// will give matching key and value pairs.
+///
+/// **Notice:**
+/// Do not modify a map (add or remove keys) while an operation
+/// is being performed on that map, for example in functions
+/// called during a [forEach] or [putIfAbsent] call,
+/// or while iterating the map ([keys], [values] or [entries]).
+///
+/// Example:
+/// ```dart
+/// final Map<int, String> planets = HashMap(); // Is a HashMap
+/// ```
+/// To add data to a map, use [operator[]=], [addAll] or [addEntries].
+/// ```
+/// planets[3] = 'Earth';
+/// planets.addAll({4: 'Mars'});
+/// final gasGiants = {6: 'Jupiter', 5: 'Saturn'};
+/// planets.addEntries(gasGiants.entries);
+/// print(planets); // fx {5: Saturn, 6: Jupiter, 3: Earth, 4: Mars}
+/// ```
+/// To check if the map is empty, use [isEmpty] or [isNotEmpty].
+/// To find the number of map entries, use [length].
+/// ```
+/// final isEmpty = planets.isEmpty; // false
+/// final length = planets.length; // 4
+/// ```
+/// The [forEach] iterates through all entries of a map.
+/// ```
+/// planets.forEach((key, value) {
+/// print('$key \t $value');
+/// // 5 Saturn
+/// // 4 Mars
+/// // 3 Earth
+/// // 6 Jupiter
+/// });
+/// ```
+/// To check whether the map has an entry with a specific key, use [containsKey].
+/// ```
+/// final keyOneExists = planets.containsKey(4); // true
+/// final keyFiveExists = planets.containsKey(1); // false
+/// ```
+/// To check whether the map has an entry with a specific value,
+/// use [containsValue].
+/// ```
+/// final marsExists = planets.containsValue('Mars'); // true
+/// final venusExists = planets.containsValue('Venus'); // false
+/// ```
+/// To remove an entry with a specific key, use [remove].
+/// ```
+/// final removeValue = planets.remove(5);
+/// print(removeValue); // Jupiter
+/// print(planets); // fx {4: Mars, 3: Earth, 5: Saturn}
+/// ```
+/// To remove multiple entries at the same time, based on their keys and values,
+/// use [removeWhere].
+/// ```
+/// planets.removeWhere((key, value) => key == 5);
+/// print(planets); // fx {3: Earth, 4: Mars}
+/// ```
+/// To conditionally add or modify a value for a specific key, depending on
+/// whether there already is an entry with that key,
+/// use [putIfAbsent] or [update].
+/// ```
+/// planets.update(4, (v) => 'Saturn');
+/// planets.update(8, (v) => '', ifAbsent: () => 'Neptune');
+/// planets.putIfAbsent(4, () => 'Another Saturn');
+/// print(planets); // fx {4: Saturn, 8: Neptune, 3: Earth}
+/// ```
+/// To update the values of all keys, based on the existing key and value,
+/// use [updateAll].
+/// ```
+/// planets.updateAll((key, value) => 'X');
+/// print(planets); // fx {8: X, 3: X, 4: X}
+/// ```
+/// To remove all entries and empty the map, use [clear].
+/// ```
+/// planets.clear();
+/// print(planets); // {}
+/// print(planets.isEmpty); // true
+/// ```
+///
+/// **See also:**
+/// * [Map], the general interface of key/value pair collections.
+/// * [LinkedHashMap] iterates in key insertion order.
+/// * [SplayTreeMap] iterates the keys in sorted order.
abstract class HashMap<K, V> implements Map<K, V> {
/// Creates an unordered hash-table based [Map].
///
@@ -41,12 +126,12 @@
/// new keys. If [equals] is omitted, the key's own [Object.==] is used
/// instead.
///
- /// Similar, if [hashCode] is provided, it is used to produce a hash value
+ /// Similarly, if [hashCode] is provided, it is used to produce a hash value
/// for keys in order to place them in the map. If [hashCode] is omitted,
/// the key's own [Object.hashCode] is used.
///
/// The used `equals` and `hashCode` method should always be consistent,
- /// so that if `equals(a, b)` then `hashCode(a) == hashCode(b)`. The hash
+ /// so that if `equals(a, b)`, then `hashCode(a) == hashCode(b)`. The hash
/// of an object, or what it compares equal to, should not change while the
/// object is a key in the map. If it does change, the result is
/// unpredictable.
@@ -67,7 +152,7 @@
/// Example:
/// ```dart template:expression
/// HashMap<int,int>(equals: (int a, int b) => (b - a) % 5 == 0,
- /// hashCode: (int e) => e % 5)
+ /// hashCode: (int e) => e % 5);
/// ```
/// This example map does not need an `isValidKey` function to be passed.
/// The default function accepts precisely `int` values, which can safely be
@@ -90,9 +175,9 @@
/// Creates an unordered identity-based map.
///
/// Keys of this map are considered equal only to the same object,
- /// and does not use [Object.==] at all.
+ /// and do not use [Object.==] at all.
///
- /// Effectively a shorthand for:
+ /// Effectively shorthand for:
/// ```dart
/// HashMap<K, V>(equals: identical, hashCode: identityHashCode)
/// ```
@@ -102,6 +187,11 @@
///
/// The keys must all be instances of [K] and the values of [V].
/// The [other] map itself can have any type.
+ /// ```dart
+ /// final baseMap = {1: 'A', 2: 'B', 3: 'C'};
+ /// final fromBaseMap = HashMap<int, String>.from(baseMap);
+ /// print(fromBaseMap); // {1: A, 2: B, 3: C}
+ /// ```
factory HashMap.from(Map<dynamic, dynamic> other) {
HashMap<K, V> result = HashMap<K, V>();
other.forEach((dynamic k, dynamic v) {
@@ -111,6 +201,12 @@
}
/// Creates a [HashMap] that contains all key/value pairs of [other].
+ /// Example:
+ /// ```dart
+ /// final baseMap = <int, String>{1: 'A', 2: 'B', 3: 'C'};
+ /// final mapOf = HashMap<num, Object>.of(baseMap);
+ /// print(mapOf); // {1: A, 2: B, 3: C}
+ /// ```
factory HashMap.of(Map<K, V> other) => HashMap<K, V>()..addAll(other);
/// Creates a [HashMap] where the keys and values are computed from the
@@ -122,8 +218,15 @@
/// The keys of the key/value pairs do not need to be unique. The last
/// occurrence of a key will simply overwrite any previous value.
///
- /// If no values are specified for [key] and [value] the default is the
+ /// If no values are specified for [key] and [value], the default is the
/// identity function.
+ /// Example:
+ /// ```dart
+ /// final numbers = [11, 12, 13, 14];
+ /// final mapFromIterable = HashMap<int, int>.fromIterable(numbers,
+ /// key: (i) => i, value: (i) => i * i);
+ /// print(mapFromIterable); // {11: 121, 12: 144, 13: 169, 14: 196}
+ /// ```
factory HashMap.fromIterable(Iterable iterable,
{K Function(dynamic element)? key, V Function(dynamic element)? value}) {
HashMap<K, V> map = HashMap<K, V>();
@@ -140,6 +243,14 @@
/// overwrites the previous value.
///
/// It is an error if the two [Iterable]s don't have the same length.
+ /// Example:
+ /// ```dart
+ /// final keys = ['Mercury', 'Venus', 'Earth', 'Mars'];
+ /// final values = [0.06, 0.81, 1, 0.11];
+ /// final mapFromIterables = HashMap.fromIterables(keys, values);
+ /// print(mapFromIterables);
+ /// // {Earth: 1, Mercury: 0.06, Mars: 0.11, Venus: 0.81}
+ /// ```
factory HashMap.fromIterables(Iterable<K> keys, Iterable<V> values) {
HashMap<K, V> map = HashMap<K, V>();
MapBase._fillMapWithIterables(map, keys, values);
@@ -153,6 +264,13 @@
///
/// If multiple [entries] have the same key,
/// later occurrences overwrite the earlier ones.
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = [11, 12, 13, 14];
+ /// final map = HashMap.fromEntries(numbers.map((i) => MapEntry(i, i * i)));
+ /// print(map); // {11: 121, 12: 144, 13: 169, 14: 196}
+ /// ```
@Since("2.1")
factory HashMap.fromEntries(Iterable<MapEntry<K, V>> entries) =>
HashMap<K, V>()..addEntries(entries);
diff --git a/sdk/lib/collection/hash_set.dart b/sdk/lib/collection/hash_set.dart
index 1f94ffb..29ef55b 100644
--- a/sdk/lib/collection/hash_set.dart
+++ b/sdk/lib/collection/hash_set.dart
@@ -10,17 +10,91 @@
/// and hashCode implementations. This means that the equals operation
/// must define a stable equivalence relation on the elements (reflexive,
/// symmetric, transitive, and consistent over time), and that the hashCode
-/// must consistent with equality, so that the same for objects that are
+/// must be consistent with equality, so that it's the same for objects that are
/// considered equal.
///
/// Most simple operations on `HashSet` are done in (potentially amortized)
/// constant time: [add], [contains], [remove], and [length], provided the hash
/// codes of objects are well distributed.
///
-/// The iteration order of the set is not specified and depends on
-/// the hashcodes of the provided elements. However, the order is stable:
+/// **The iteration order of the set is not specified and depends on
+/// the hashcodes of the provided elements.** However, the order is stable:
/// multiple iterations over the same set produce the same order, as long as
/// the set is not modified.
+///
+/// **Note:**
+/// Do not modify a set (add or remove elements) while an operation
+/// is being performed on that set, for example in functions
+/// called during a [forEach] or [containsAll] call,
+/// or while iterating the set.
+///
+/// Do not modify elements in a way which changes their equality (and thus their
+/// hash code) while they are in the set. Some specialized kinds of sets may be
+/// more permissive with regards to equality, in which case they should document
+/// their different behavior and restrictions.
+///
+/// Example:
+/// ```dart
+/// final letters = HashSet<String>();
+/// ```
+/// To add data to a set, use [add] or [addAll].
+/// ```
+/// letters.add('A');
+/// letters.addAll({'B', 'C', 'D'});
+/// ```
+/// To check if the set is empty, use [isEmpty] or [isNotEmpty].
+/// To find the number of elements in the set, use [length].
+/// ```
+/// print(letters.isEmpty); // false
+/// print(letters.length); // 4
+/// print(letters); // fx {A, D, C, B}
+/// ```
+/// To check whether the set has an element with a specific value,
+/// use [contains].
+/// ```
+/// final bExists = letters.contains('B'); // true
+/// ```
+/// The [forEach] method calls a function with each element of the set.
+/// ```
+/// letters.forEach(print);
+/// // A
+/// // D
+/// // C
+/// // B
+/// ```
+/// To make a copy of the set, use [toSet].
+/// ```
+/// final anotherSet = letters.toSet();
+/// print(anotherSet); // fx {A, C, D, B}
+/// ```
+/// To remove an element, use [remove].
+/// ```
+/// final removedValue = letters.remove('A'); // true
+/// print(letters); // fx {B, C, D}
+/// ```
+/// To remove multiple elements at the same time, use [removeWhere] or
+/// [removeAll].
+/// ```
+/// letters.removeWhere((element) => element.startsWith('B'));
+/// print(letters); // fx {D, C}
+/// ```
+/// To removes all elements in this set that do not meet a condition,
+/// use [retainWhere].
+/// ```
+/// letters.retainWhere((element) => element.contains('C'));
+/// print(letters); // {C}
+/// ```
+/// To remove all elements and empty the set, use [clear].
+/// ```
+/// letters.clear();
+/// print(letters.isEmpty); // true
+/// print(letters); // {}
+/// ```
+/// **See also:**
+/// * [Set] is the general interface of collection where each object can
+/// occur only once.
+/// * [LinkedHashSet] objects stored based on insertion order.
+/// * [SplayTreeSet] iterates the objects in sorted order.
abstract class HashSet<E> implements Set<E> {
/// Create a hash set using the provided [equals] as equality.
///
@@ -31,7 +105,7 @@
/// the elements' intrinsic [Object.==] and [Object.hashCode].
///
/// If you supply one of [equals] and [hashCode],
- /// you should generally also to supply the other.
+ /// you should generally also supply the other.
///
/// Some [equals] or [hashCode] functions might not work for all objects.
/// If [isValidKey] is supplied, it's used to check a potential element
@@ -44,7 +118,7 @@
/// instance of [E], which means that:
/// ```dart template:expression
/// HashSet<int>(equals: (int e1, int e2) => (e1 - e2) % 5 == 0,
- /// hashCode: (int e) => e % 5)
+ /// hashCode: (int e) => e % 5);
/// ```
/// does not need an `isValidKey` argument because it defaults to only
/// accepting `int` values which are accepted by both `equals` and `hashCode`.
@@ -65,7 +139,7 @@
/// Creates an unordered identity-based set.
///
- /// Effectively a shorthand for:
+ /// Effectively shorthand for:
/// ```dart
/// HashSet<E>(equals: identical, hashCode: identityHashCode)
/// ```
@@ -86,6 +160,12 @@
/// Set<SubType> subSet =
/// HashSet<SubType>.from(superSet.whereType<SubType>());
/// ```
+ /// Example:
+ /// ```dart
+ /// final numbers = <num>[10, 20, 30];
+ /// final hashSetFrom = HashSet<int>.from(numbers);
+ /// print(hashSetFrom); // fx {20, 10, 30}
+ /// ```
factory HashSet.from(Iterable<dynamic> elements) {
HashSet<E> result = HashSet<E>();
for (final e in elements) {
@@ -96,15 +176,21 @@
/// Create a hash set containing all [elements].
///
- /// Creates a hash set as by `new HashSet<E>()` and adds all given [elements]
+ /// Creates a hash set as by `HashSet<E>()` and adds all given [elements]
/// to the set. The elements are added in order. If [elements] contains
/// two entries that are equal, but not identical, then the first one is
/// the one in the resulting set.
+ /// Example:
+ /// ```dart
+ /// final baseSet = <int>{1, 2, 3};
+ /// final hashSetOf = HashSet<num>.of(baseSet);
+ /// print(hashSetOf); // fx {3, 1, 2}
+ /// ```
factory HashSet.of(Iterable<E> elements) => HashSet<E>()..addAll(elements);
/// Provides an iterator that iterates over the elements of this set.
///
/// The order of iteration is unspecified,
- /// but consistent between changes to the set.
+ /// but is consistent between changes to the set.
Iterator<E> get iterator;
}
diff --git a/sdk/lib/collection/linked_hash_map.dart b/sdk/lib/collection/linked_hash_map.dart
index 646b581..be71118 100644
--- a/sdk/lib/collection/linked_hash_map.dart
+++ b/sdk/lib/collection/linked_hash_map.dart
@@ -4,7 +4,16 @@
part of dart.collection;
-/// A hash-table based implementation of [Map].
+/// An insertion-ordered [Map] with expected constant-time lookup.
+///
+/// A non-constant map literal, like `{"a": 42, "b": 7}`, is a `LinkedHashMap`.
+///
+/// The [keys], [values] and [entries] are iterated in key insertion order.
+///
+/// The map uses a hash-table to look up entries, so keys must have
+/// suitable implementations of [Object.operator==] and [Object.hashCode].
+/// If the hash codes are not well-distributed, the performance of map
+/// operations may suffer.
///
/// The insertion order of keys is remembered,
/// and keys are iterated in the order they were inserted into the map.
@@ -14,11 +23,93 @@
/// but removing the key and adding it again
/// will make it be last in the iteration order.
///
+/// **Notice:**
+/// Do not modify a map (add or remove keys) while an operation
+/// is being performed on that map, for example in functions
+/// called during a [forEach] or [putIfAbsent] call,
+/// or while iterating the map ([keys], [values] or [entries]).
+///
/// The keys of a `LinkedHashMap` must have consistent [Object.==]
/// and [Object.hashCode] implementations. This means that the `==` operator
/// must define a stable equivalence relation on the keys (reflexive,
/// symmetric, transitive, and consistent over time), and that `hashCode`
/// must be the same for objects that are considered equal by `==`.
+///
+/// Example:
+///
+/// ```dart
+/// final planetsByDiameter = {0.949: 'Venus'}; // A new LinkedHashMap
+/// ```
+/// To add data to a map, use [operator[]=], [addAll] or [addEntries].
+/// ```
+/// planetsByDiameter[1] = 'Earth';
+/// planetsByDiameter.addAll({0.532: 'Mars', 11.209: 'Jupiter'});
+/// ```
+/// To check if the map is empty, use [isEmpty] or [isNotEmpty].
+/// To find the number of map entries, use [length].
+/// ```
+/// print(planetsByDiameter.isEmpty); // false
+/// print(planetsByDiameter.length); // 4
+/// print(planetsByDiameter);
+/// // {0.949: Venus, 1.0: Earth, 0.532: Mars, 11.209: Jupiter}
+/// ```
+/// The [forEach] method calls a function for each key/value entry of the map.
+/// ```
+/// planetsByDiameter.forEach((key, value) {
+/// print('$key \t $value');
+/// // 0.949 Venus
+/// // 1.0 Earth
+/// // 0.532 Mars
+/// // 11.209 Jupiter
+/// });
+/// ```
+/// To check whether the map has an entry with a specific key, use [containsKey].
+/// ```
+/// final keyOneExists = planetsByDiameter.containsKey(1); // true
+/// final keyFiveExists = planetsByDiameter.containsKey(5); // false
+/// ```
+/// To check whether the map has an entry with a specific value,
+/// use [containsValue].
+/// ```
+/// final earthExists = planetsByDiameter.containsValue('Earth'); // true
+/// final saturnExists = planetsByDiameter.containsValue('Saturn'); // false
+/// ```
+/// To remove an entry with a specific key, use [remove].
+/// ```
+/// final removedValue = planetsByDiameter.remove(1);
+/// print(removedValue); // Earth
+/// print(planetsByDiameter); // {0.949: Venus, 0.532: Mars, 11.209: Jupiter}
+/// ```
+/// To remove multiple entries at the same time, based on their keys and values,
+/// use [removeWhere].
+/// ```
+/// planetsByDiameter.removeWhere((key, value) => key == 0.949);
+/// print(planetsByDiameter); // {0.532: Mars, 11.209: Jupiter}
+/// ```
+/// To conditionally add or modify a value for a specific key, depending on
+/// whether there already is an entry with that key,
+/// use [putIfAbsent] or [update].
+/// ```
+/// planetsByDiameter.update(0.949, (v) => 'Venus', ifAbsent: () => 'Venus');
+/// planetsByDiameter.putIfAbsent(0.532, () => "Another Mars if needed");
+/// print(planetsByDiameter); // {0.532: Mars, 11.209: Jupiter, 0.949: Venus}
+/// ```
+/// To update the values of all keys, based on the existing key and value,
+/// use [updateAll].
+/// ```
+/// planetsByDiameter.updateAll((key, value) => 'X');
+/// print(planetsByDiameter); // {0.532: X, 11.209: X, 0.949: X}
+/// ```
+/// To remove all entries and empty the map, use [clear].
+/// ```
+/// planetsByDiameter.clear();
+/// print(planetsByDiameter); // {}
+/// print(planetsByDiameter.isEmpty); // true
+/// ```
+/// **See also:**
+/// * [Map], the general interface of key/value pair collections.
+/// * [HashMap] is unordered (the order of iteration is not guaranteed).
+/// * [SplayTreeMap] iterates the keys in sorted order.
abstract class LinkedHashMap<K, V> implements Map<K, V> {
/// Creates an insertion-ordered hash-table based [Map].
///
@@ -26,7 +117,7 @@
/// new keys. If [equals] is omitted, the key's own [Object.==] is used
/// instead.
///
- /// Similar, if [hashCode] is provided, it is used to produce a hash value
+ /// Similarly, if [hashCode] is provided, it is used to produce a hash value
/// for keys in order to place them in the hash table. If it is omitted, the
/// key's own [Object.hashCode] is used.
///
@@ -35,7 +126,7 @@
/// of an object, or what it compares equal to, should not change while the
/// object is in the table. If it does change, the result is unpredictable.
///
- /// If you supply one of [equals] and [hashCode],
+ /// If you supply one of [equals] or [hashCode],
/// you should generally also supply the other.
///
/// Some [equals] or [hashCode] functions might not work for all objects.
@@ -73,7 +164,7 @@
/// Creates an insertion-ordered identity-based map.
///
- /// Effectively a shorthand for:
+ /// Effectively shorthand for:
/// ```dart template:expression
/// LinkedHashMap<K, V>(equals: identical,
/// hashCode: identityHashCode)
@@ -84,6 +175,12 @@
///
/// The keys must all be instances of [K] and the values to [V].
/// The [other] map itself can have any type.
+ /// Example:
+ /// ```dart
+ /// final baseMap = <num, Object>{1: 'A', 2: 'B', 3: 'C'};
+ /// final fromBaseMap = LinkedHashMap<int, String>.from(baseMap);
+ /// print(fromBaseMap); // {1: A, 2: B, 3: C}
+ /// ```
factory LinkedHashMap.from(Map<dynamic, dynamic> other) {
LinkedHashMap<K, V> result = LinkedHashMap<K, V>();
other.forEach((dynamic k, dynamic v) {
@@ -93,20 +190,33 @@
}
/// Creates a [LinkedHashMap] that contains all key value pairs of [other].
+ /// Example:
+ /// ```dart
+ /// final baseMap = <int, String> {3: 'A', 2: 'B', 1: 'C', 4: 'D'};
+ /// final mapOf = LinkedHashMap<num, Object>.of(baseMap);
+ /// print(mapOf); // {3: A, 2: B, 1: C, 4: D}
+ /// ```
factory LinkedHashMap.of(Map<K, V> other) =>
LinkedHashMap<K, V>()..addAll(other);
/// Creates a [LinkedHashMap] where the keys and values are computed from the
/// [iterable].
///
- /// For each element of the [iterable] this constructor computes a key/value
- /// pair, by applying [key] and [value] respectively.
+ /// For each element of the [iterable], this constructor computes a key/value
+ /// pair by applying [key] and [value] respectively.
///
/// The keys of the key/value pairs do not need to be unique. The last
/// occurrence of a key will simply overwrite any previous value.
///
- /// If no values are specified for [key] and [value] the default is the
- /// identity function.
+ /// If no values are specified for [key] and [value], the default is the
+ /// both default to the identity function.
+ /// Example:
+ /// ```dart
+ /// final numbers = [11, 12, 13, 14];
+ /// final mapFromIterable =
+ /// LinkedHashMap.fromIterable(numbers, key: (i) => i, value: (i) => i * i);
+ /// print(mapFromIterable); // {11: 121, 12: 144, 13: 169, 14: 196}
+ /// ```
factory LinkedHashMap.fromIterable(Iterable iterable,
{K Function(dynamic element)? key, V Function(dynamic element)? value}) {
LinkedHashMap<K, V> map = LinkedHashMap<K, V>();
@@ -123,6 +233,14 @@
/// overwrites the previous value.
///
/// It is an error if the two [Iterable]s don't have the same length.
+ /// Example:
+ /// ```dart
+ /// final values = [0.06, 0.81, 1, 0.11];
+ /// final keys = ['Mercury', 'Venus', 'Earth', 'Mars'];
+ /// final mapFromIterables = LinkedHashMap.fromIterables(keys, values);
+ /// print(mapFromIterables);
+ /// // {Mercury: 0.06, Venus: 0.81, Earth: 1, Mars: 0.11}
+ /// ```
factory LinkedHashMap.fromIterables(Iterable<K> keys, Iterable<V> values) {
LinkedHashMap<K, V> map = LinkedHashMap<K, V>();
MapBase._fillMapWithIterables(map, keys, values);
@@ -136,6 +254,12 @@
///
/// If multiple [entries] have the same key,
/// later occurrences overwrite the earlier ones.
+ /// Example:
+ /// ```dart
+ /// final numbers = [11, 12, 13, 14];
+ /// final map = LinkedHashMap.fromEntries(numbers.map((i) => MapEntry(i, i * i)));
+ /// print(map); // {11: 121, 12: 144, 13: 169, 14: 196}
+ /// ```
@Since("2.1")
factory LinkedHashMap.fromEntries(Iterable<MapEntry<K, V>> entries) =>
LinkedHashMap<K, V>()..addEntries(entries);
diff --git a/sdk/lib/collection/linked_hash_set.dart b/sdk/lib/collection/linked_hash_set.dart
index 66be66c..55349c9 100644
--- a/sdk/lib/collection/linked_hash_set.dart
+++ b/sdk/lib/collection/linked_hash_set.dart
@@ -6,7 +6,9 @@
/// A [LinkedHashSet] is a hash-table based [Set] implementation.
///
-/// The `LinkedHashSet` also keep track of the order that elements were inserted
+/// The default implementation of [Set] is [LinkedHashSet].
+///
+/// The `LinkedHashSet` also keeps track of the order that elements were inserted
/// in, and iteration happens in first-to-last insertion order.
///
/// The elements of a `LinkedHashSet` must have consistent [Object.==]
@@ -19,12 +21,88 @@
/// An element that was added after another will occur later in the iteration.
/// Adding an element that is already in the set
/// does not change its position in the iteration order,
-/// but removing an element and adding it again,
+/// but removing an element and adding it again
/// will make it the last element of an iteration.
///
/// Most simple operations on `HashSet` are done in (potentially amortized)
/// constant time: [add], [contains], [remove], and [length], provided the hash
-/// codes of objects are well distributed..
+/// codes of objects are well distributed.
+///
+/// **Note:**
+/// Do not modify a set (add or remove elements) while an operation
+/// is being performed on that set, for example in functions
+/// called during a [forEach] or [containsAll] call,
+/// or while iterating the set.
+///
+/// Do not modify elements in a way which changes their equality (and thus their
+/// hash code) while they are in the set. Some specialized kinds of sets may be
+/// more permissive with regards to equality, in which case they should document
+/// their different behavior and restrictions.
+///
+/// Example:
+/// ```dart
+/// final planets = <String>{}; // LinkedHashSet
+/// ```
+/// To add data to a set, use [add] or [addAll].
+/// ```
+/// final uranusAdded = planets.add('Uranus'); // true
+/// planets.addAll({'Venus', 'Mars', 'Earth', 'Jupiter'});
+/// print(planets); // {Uranus, Venus, Mars, Earth, Jupiter}
+/// ```
+/// To check if the set is empty, use [isEmpty] or [isNotEmpty].
+/// To find the number of elements in the set, use [length].
+/// ```
+/// print(planets.isEmpty); // false
+/// print(planets.length); // 5
+/// ```
+/// To check whether the set has an element with a specific value,
+/// use [contains].
+/// ```
+/// final marsExists = planets.contains('Mars'); // true
+/// ```
+/// The [forEach] method calls a function with each element of the set.
+/// ```
+/// planets.forEach(print);
+/// // Uranus
+/// // Venus
+/// // Mars
+/// // Earth
+/// // Jupiter
+/// ```
+///
+/// To make a copy of the set, use [toSet].
+/// ```
+/// final copySet = planets.toSet();
+/// print(copySet); // {Uranus, Venus, Mars, Earth, Jupiter}
+/// ```
+/// To remove an element, use [remove].
+/// ```
+/// final removedValue = planets.remove('Mars'); // Mars
+/// print(planets); // {Uranus, Venus, Earth, Jupiter}
+/// ```
+/// To remove multiple elements at the same time, use [removeWhere] or
+/// [removeAll].
+/// ```
+/// planets.removeWhere((element) => element.startsWith('E'));
+/// print(planets); // {Uranus, Venus, Jupiter}
+/// ```
+/// To removes all elements in this set that do not meet a condition,
+/// use [retainWhere].
+/// ```
+/// planets.retainWhere((element) => element.contains('Jupiter'));
+/// print(planets); // {Jupiter}
+/// ```
+/// To remove all elements and empty the set, use [clear].
+/// ```
+/// planets.clear();
+/// print(planets.isEmpty); // true
+/// print(planets); // {}
+/// ```
+/// **See also:**
+/// * [Set] is the general interface of collection where each object can
+/// occur only once.
+/// * [HashSet] the order of the objects in the iteration is not guaranteed.
+/// * [SplayTreeSet] iterates the objects in sorted order.
abstract class LinkedHashSet<E> implements Set<E> {
/// Create an insertion-ordered hash set using the provided
/// [equals] and [hashCode].
@@ -33,7 +111,7 @@
/// [hashCode] must be consistent with [equals].
///
/// If you supply one of [equals] and [hashCode],
- /// you should generally also to supply the other.
+ /// you should generally also supply the other.
///
/// Some [equals] or [hashCode] functions might not work for all objects.
/// If [isValidKey] is supplied, it's used to check a potential element
@@ -46,12 +124,12 @@
/// instance of [E], which means that:
/// ```dart template:expression
/// LinkedHashSet<int>(equals: (int e1, int e2) => (e1 - e2) % 5 == 0,
- /// hashCode: (int e) => e % 5)
+ /// hashCode: (int e) => e % 5);
/// ```
/// does not need an `isValidKey` argument, because it defaults to only
/// accepting `int` values which are accepted by both `equals` and `hashCode`.
///
- /// If neither `equals`, `hashCode`, nor `isValidKey` is provided,
+ /// If neither `equals`, `hashCode`, nor `isValidKey` are provided,
/// the default `isValidKey` instead accepts all values.
/// The default equality and hashcode operations are assumed to work on all
/// objects.
@@ -67,7 +145,7 @@
/// Creates an insertion-ordered identity-based set.
///
- /// Effectively a shorthand for:
+ /// Effectively shorthand for:
/// ```dart
/// LinkedHashSet<E>(equals: identical, hashCode: identityHashCode)
/// ```
@@ -75,7 +153,7 @@
/// Create a linked hash set containing all [elements].
///
- /// Creates a linked hash set as by `new LinkedHashSet<E>()` and adds each
+ /// Creates a linked hash set as by `LinkedHashSet<E>()` and adds each
/// element of `elements` to this set in the order they are iterated.
///
/// All the [elements] should be instances of [E].
@@ -86,6 +164,12 @@
/// Iterable<SuperType> tmp = superSet.where((e) => e is SubType);
/// Set<SubType> subSet = LinkedHashSet<SubType>.from(tmp);
/// ```
+ /// Example:
+ /// ```dart
+ /// final numbers = <num>[10, 20, 30];
+ /// final setFrom = LinkedHashSet<int>.from(numbers);
+ /// print(setFrom); // {10, 20, 30}
+ /// ```
factory LinkedHashSet.from(Iterable<dynamic> elements) {
LinkedHashSet<E> result = LinkedHashSet<E>();
for (final element in elements) {
@@ -96,8 +180,14 @@
/// Create a linked hash set from [elements].
///
- /// Creates a linked hash set as by `new LinkedHashSet<E>()` and adds each
+ /// Creates a linked hash set as by `LinkedHashSet<E>()` and adds each
/// element of `elements` to this set in the order they are iterated.
+ /// Example:
+ /// ```dart
+ /// final baseSet = <int>{1, 2, 3};
+ /// final setOf = LinkedHashSet<num>.of(baseSet);
+ /// print(setOf); // {1, 2, 3}
+ /// ```
factory LinkedHashSet.of(Iterable<E> elements) =>
LinkedHashSet<E>()..addAll(elements);
diff --git a/sdk/lib/collection/linked_list.dart b/sdk/lib/collection/linked_list.dart
index 3e77646..516deee 100644
--- a/sdk/lib/collection/linked_list.dart
+++ b/sdk/lib/collection/linked_list.dart
@@ -28,6 +28,56 @@
///
/// A `LinkedList` also allows constant time adding and removing at either end,
/// and a constant time length getter.
+///
+/// Example:
+/// ```dart
+/// class EntryItem extends LinkedListEntry<EntryItem> {
+/// final int id;
+/// final String text;
+/// EntryItem(this.id, this.text);
+///
+/// @override
+/// String toString() {
+/// return '$id : $text';
+/// }
+/// }
+///
+/// void main(){
+/// final linkedList = LinkedList<EntryItem>();
+/// linkedList.addAll(
+/// [EntryItem(1, 'A'), EntryItem(2, 'B'), EntryItem(3, 'C')]);
+/// print(linkedList.first); // 1 : A
+/// print(linkedList.last); // 3 : C
+///
+/// // Add new item after first item.
+/// linkedList.first.insertAfter(EntryItem(15, 'E'));
+/// // Add new item before last item.
+/// linkedList.last.insertBefore(EntryItem(10, 'D'));
+/// // Iterate items.
+/// for (var entry in linkedList) {
+/// print(entry);
+/// // 1 : A
+/// // 15 : E
+/// // 2 : B
+/// // 10 : D
+/// // 3 : C
+/// }
+///
+/// // Remove item using index from list.
+/// linkedList.elementAt(2).unlink();
+/// print(linkedList); // (1 : A, 15 : E, 10 : D, 3 : C)
+/// // Remove first item.
+/// linkedList.first.unlink();
+/// print(linkedList); // (15 : E, 10 : D, 3 : C)
+/// // Remove last item from list.
+/// linkedList.remove(linkedList.last);
+/// print(linkedList); // (15 : E, 10 : D)
+/// // Remove all items.
+/// linkedList.clear();
+/// print(linkedList.length); // 0
+/// print(linkedList.isEmpty); // true
+/// }
+/// ```
class LinkedList<E extends LinkedListEntry<E>> extends Iterable<E> {
int _modificationCount = 0;
int _length = 0;
@@ -47,7 +97,7 @@
_insertBefore(_first, entry, updateFirst: false);
}
- /// Add [entries] to the end of the linked list.
+ /// Adds [entries] to the end of the linked list.
void addAll(Iterable<E> entries) {
entries.forEach(add);
}
@@ -239,7 +289,7 @@
/// The successor of this element in its linked list.
///
- /// The value is `null` if there is no successor in the linked list,
+ /// The value is `null` if there is no successor in the linked list,
/// or if this entry is not currently in any list.
E? get next {
if (_list == null || identical(_list!.first, _next)) return null;
diff --git a/sdk/lib/collection/queue.dart b/sdk/lib/collection/queue.dart
index dcdecb4..7f1a6ce 100644
--- a/sdk/lib/collection/queue.dart
+++ b/sdk/lib/collection/queue.dart
@@ -9,12 +9,29 @@
/// an [Iterator].
///
/// It is generally not allowed to modify the queue (add or remove entries)
-/// while an operation on the queue is being performed, for example during a
+/// while an operation in the queue is being performed, for example during a
/// call to [forEach].
/// Modifying the queue while it is being iterated will most likely break the
/// iteration.
/// This goes both for using the [iterator] directly, or for iterating an
/// `Iterable` returned by a method like [map] or [where].
+///
+/// Example:
+/// ```dart
+/// final queue = Queue<int>(); // ListQueue() by default
+/// print(queue.runtimeType); // ListQueue
+///
+/// // Adding items to queue
+/// queue.addAll([1, 2, 3]);
+/// queue.addFirst(0);
+/// queue.addLast(10);
+/// print(queue); // {0, 1, 2, 3, 10}
+///
+/// // Removing items from queue
+/// queue.removeFirst();
+/// queue.removeLast();
+/// print(queue); // {1, 2, 3}
+/// ```
abstract class Queue<E> implements EfficientLengthIterable<E> {
/// Creates a queue.
factory Queue() = ListQueue<E>;
@@ -45,16 +62,16 @@
/// Any time the queue would produce an element that is not a [T],
/// the element access will throw.
///
- /// Any time a [T] value is attempted stored into the adapted queue,
- /// the store will throw unless the value is also an instance of [S].
+ /// When a [T] value is stored into the adapted queue,
+ /// the operation will throw unless the value is also an instance of [S].
///
/// If all accessed elements of [source] are actually instances of [T],
- /// and if all elements stored into the returned queue are actually instance
+ /// and if all elements stored into the returned queue are actually instances
/// of [S],
/// then the returned queue can be used as a `Queue<T>`.
///
/// Methods which accept `Object?` as argument, like [contains] and [remove],
- /// will pass the argument directly to the this queue's method
+ /// will pass the argument directly to this queue's method
/// without any checks.
static Queue<T> castFrom<S, T>(Queue<S> source) => CastQueue<S, T>(source);
@@ -65,8 +82,8 @@
/// that is not an instance of [R], the access will throw instead.
///
/// Elements added to the queue (e.g., by using [addFirst] or [addAll])
- /// must be instance of [R] to be valid arguments to the adding function,
- /// and they must be instances of [E] as well to be accepted by
+ /// must be instances of [R] to be valid arguments to the adding function,
+ /// and they must also be instances of [E] to be accepted by
/// this queue as well.
///
/// Methods which accept `Object?` as argument, like [contains] and [remove],
@@ -95,7 +112,7 @@
/// Adds [value] at the end of the queue.
void add(E value);
- /// Remove a single instance of [value] from the queue.
+ /// Removes a single instance of [value] from the queue.
///
/// Returns `true` if a value was removed, or `false` if the queue
/// contained no element equal to [value].
@@ -437,7 +454,7 @@
/// [DoubleLinkedQueueEntry.previousEntry()].
///
/// The [action] function can use methods on [DoubleLinkedQueueEntry] to
- /// remove the entry or it can insert elements before or after then entry.
+ /// remove the entry or it can insert elements before or after the entry.
/// If the current entry is removed, iteration continues with the entry that
/// was following the current entry when [action] was called. Any elements
/// inserted after the current element before it is removed will not be
@@ -509,6 +526,63 @@
/// amortized constant time add operations.
///
/// The structure is efficient for any queue or stack usage.
+///
+/// Example:
+/// ```dart
+/// final queue = ListQueue<int>();
+/// ```
+/// To add objects to a queue, use [add], [addAll], [addFirst] or[addLast].
+/// ```
+/// queue.add(5);
+/// queue.addFirst(0);
+/// queue.addLast(10);
+/// queue.addAll([1, 2, 3]);
+/// print(queue); // {0, 5, 10, 1, 2, 3}
+/// ```
+/// To check if the queue is empty, use [isEmpty] or [isNotEmpty].
+/// To find the number of queue entries, use [length].
+/// ```
+/// final isEmpty = queue.isEmpty; // false
+/// final queueSize = queue.length; // 6
+/// ```
+/// To get first or last item from queue, use [first] or [last].
+/// ```
+/// final first = queue.first; // 0
+/// final last = queue.last; // 3
+/// ```
+/// To get item value using index, use [elementAt].
+/// ```
+/// final itemAt = queue.elementAt(2); // 10
+/// ```
+/// To convert queue to list, call [toList].
+/// ```
+/// final numbers = queue.toList();
+/// print(numbers); // [0, 5, 10, 1, 2, 3]
+/// ```
+/// To remove item from queue, call [remove], [removeFirst] or [removeLast].
+/// ```
+/// queue.remove(10);
+/// queue.removeFirst();
+/// queue.removeLast();
+/// print(queue); // {5, 1, 2}
+/// ```
+/// To remove multiple elements at the same time, use [removeWhere].
+/// ```
+/// queue.removeWhere((element) => element == 1);
+/// print(queue); // {5, 2}
+/// ```
+/// To remove all elements in this queue that do not meet a condition,
+/// use [retainWhere].
+/// ```
+/// queue.retainWhere((element) => element < 4);
+/// print(queue); // {2}
+/// ```
+/// To remove all items and empty the set, use [clear].
+/// ```
+/// queue.clear();
+/// print(queue.isEmpty); // true
+/// print(queue); // {}
+/// ```
class ListQueue<E> extends ListIterable<E> implements Queue<E> {
static const int _INITIAL_CAPACITY = 8;
List<E?> _table;
@@ -548,6 +622,12 @@
/// Queue<SubType> subQueue =
/// ListQueue<SubType>.from(superQueue.whereType<SubType>());
/// ```
+ /// Example:
+ /// ```dart
+ /// final numbers = <num>[10, 20, 30];
+ /// final queue = ListQueue<int>.from(numbers);
+ /// print(queue); // {10, 20, 30}
+ /// ```
factory ListQueue.from(Iterable<dynamic> elements) {
if (elements is List<dynamic>) {
int length = elements.length;
@@ -575,6 +655,12 @@
///
/// The elements are added to the queue, as by [addLast], in the order given
/// by `elements.iterator`.
+ /// Example:
+ /// ```dart
+ /// final baseQueue = ListQueue.of([1.0, 2.0, 3.0]); // A ListQueue<double>
+ /// final numQueue = ListQueue<num>.of(baseQueue);
+ /// print(numQueue); // {1.0, 2.0, 3.0}
+ /// ```
factory ListQueue.of(Iterable<E> elements) =>
ListQueue<E>()..addAll(elements);
diff --git a/tools/VERSION b/tools/VERSION
index 717f643..5fade91 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 16
PATCH 0
-PRERELEASE 51
+PRERELEASE 52
PRERELEASE_PATCH 0
\ No newline at end of file