[CoreLib] Iterable.withIterator
Closes https://github.com/dart-lang/sdk/pull/59908 GitOrigin-RevId: bf05a5468020756e5a16b34134c9ec472b95576f Change-Id: Ie511e79c7cbc1e9230477913a54191730104f489 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/404341 Reviewed-by: Jake Macdonald <jakemac@google.com> Commit-Queue: Lasse Nielsen <lrn@google.com>
This commit is contained in:
committed by
Commit Queue
parent
57d877ff2e
commit
41a8e8147f
@@ -1,5 +1,11 @@
|
||||
## 3.8.0
|
||||
|
||||
### Libraries
|
||||
|
||||
#### `dart:core`
|
||||
|
||||
- Added `Iterable.withIterator` constructor.
|
||||
|
||||
## 3.7.0
|
||||
|
||||
### Language
|
||||
|
||||
@@ -127,6 +127,24 @@ abstract mixin class Iterable<E> {
|
||||
return _GeneratorIterable<E>(count, generator);
|
||||
}
|
||||
|
||||
/// Creates an [Iterable] from the [Iterator] factory.
|
||||
///
|
||||
/// The returned iterable creates a new iterator each time [iterator] is read,
|
||||
/// by calling the provided [iteratorFactory] function. The [iteratorFactory]
|
||||
/// function must return a new instance of `Iterator<E>` on each call.
|
||||
///
|
||||
/// This factory is useful when you need to create an iterable from a custom
|
||||
/// iterator, or when you want to ensure a fresh iteration state on each use.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// final numbers = Iterable.withIterator(() => [1, 2, 3].iterator);
|
||||
/// print(numbers.toList()); // [1, 2, 3]
|
||||
/// ```
|
||||
@Since("3.8")
|
||||
factory Iterable.withIterator(Iterator<E> Function() iteratorFactory) =
|
||||
_WithIteratorIterable<E>;
|
||||
|
||||
/// Creates an empty iterable.
|
||||
///
|
||||
/// The empty iterable has no elements, and iterating it always stops
|
||||
@@ -915,6 +933,20 @@ class _GeneratorIterable<E> extends ListIterable<E> {
|
||||
static int _id(int n) => n;
|
||||
}
|
||||
|
||||
/// Used internally by [Iterable.withIterator].
|
||||
///
|
||||
/// This class implements [Iterable] by delegating the iterator creation
|
||||
/// to the provided function.
|
||||
class _WithIteratorIterable<E> extends Iterable<E> {
|
||||
final Iterator<E> Function() _iteratorFactory;
|
||||
|
||||
/// Creates an iterable that gets its elements from iterators created by
|
||||
/// the provided factory function.
|
||||
_WithIteratorIterable(this._iteratorFactory);
|
||||
|
||||
Iterator<E> get iterator => _iteratorFactory();
|
||||
}
|
||||
|
||||
/// Convert elements of [iterable] to strings and store them in [parts].
|
||||
void _iterablePartsToStrings(Iterable<Object?> iterable, List<String> parts) {
|
||||
// This is the complicated part of [iterableToShortString].
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
void main() {
|
||||
testIteratorFactory();
|
||||
testIteratorEquality();
|
||||
}
|
||||
|
||||
void testIteratorFactory() {
|
||||
Iterator<Object?>? returnedIterator;
|
||||
Object? thrownError;
|
||||
int calls = 0;
|
||||
Iterator<T> f<T>() {
|
||||
calls++;
|
||||
if (thrownError case var error?) throw error;
|
||||
return returnedIterator as Iterator<T>;
|
||||
}
|
||||
|
||||
var ints = Iterable.withIterator(f<int>);
|
||||
var intIterator = <int>[].iterator;
|
||||
returnedIterator = intIterator;
|
||||
Expect.identical(intIterator, ints.iterator, "First iterator should match");
|
||||
Expect.equals(1, calls, "First call count");
|
||||
Expect.identical(intIterator, ints.iterator, "Second iterator should match");
|
||||
Expect.equals(2, calls, "Second call count");
|
||||
|
||||
var intIterator2 = <int>[].iterator;
|
||||
Expect.notIdentical(
|
||||
intIterator,
|
||||
intIterator2,
|
||||
"Different iterators should not be identical",
|
||||
);
|
||||
returnedIterator = intIterator2;
|
||||
Expect.identical(intIterator2, ints.iterator, "Third iterator should match");
|
||||
Expect.equals(3, calls, "Third call count");
|
||||
Expect.identical(intIterator2, ints.iterator, "Fourth iterator should match");
|
||||
Expect.equals(4, calls, "Fourth call count");
|
||||
|
||||
var error = StateError("quo");
|
||||
thrownError = error;
|
||||
Expect.identical(
|
||||
error,
|
||||
Expect.throws(() => ints.iterator),
|
||||
"Should throw first error",
|
||||
);
|
||||
Expect.equals(5, calls, "Fifth call count");
|
||||
Expect.identical(
|
||||
error,
|
||||
Expect.throws(() => ints.iterator),
|
||||
"Should throw second error",
|
||||
);
|
||||
Expect.equals(6, calls, "Sixth call count");
|
||||
|
||||
thrownError = null;
|
||||
Expect.identical(intIterator2, ints.iterator, "Fifth iterator should match");
|
||||
Expect.equals(7, calls, "Seventh call count");
|
||||
|
||||
var objectqs = Iterable.withIterator(f<Object?>);
|
||||
Expect.identical(
|
||||
intIterator2,
|
||||
objectqs.iterator,
|
||||
"Object iterator should match",
|
||||
);
|
||||
Expect.equals(8, calls, "Eighth call count");
|
||||
|
||||
var nulls = Iterable.withIterator(f<Null>);
|
||||
var nullIterator = <Null>[].iterator;
|
||||
returnedIterator = nullIterator;
|
||||
Expect.identical(nullIterator, nulls.iterator, "Null iterator should match");
|
||||
Expect.equals(9, calls, "Ninth call count");
|
||||
|
||||
var nevers = Iterable.withIterator(f<Never>);
|
||||
thrownError = error;
|
||||
Expect.identical(
|
||||
error,
|
||||
Expect.throws(() => nevers.iterator),
|
||||
"Should throw third error",
|
||||
);
|
||||
Expect.equals(10, calls, "Tenth call count");
|
||||
Expect.identical(
|
||||
error,
|
||||
Expect.throws(() => nevers.iterator),
|
||||
"Should throw fourth error",
|
||||
);
|
||||
Expect.equals(11, calls, "Eleventh call count");
|
||||
}
|
||||
|
||||
void testIteratorEquality() {
|
||||
var iterable1 = Iterable.withIterator(() => [1, 2, 3].iterator);
|
||||
var iterable2 = Iterable.withIterator(() => [1, 2, 3].iterator);
|
||||
Expect.listEquals(
|
||||
iterable1.toList(),
|
||||
iterable2.toList(),
|
||||
"Iterator contents should be equal",
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user