blob: d11d19823d92e94cade3f1925a88fec48bb464bc [file] [log] [blame]
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
part of quiver.iterables;
Iterable generate(initial(), next(o)) => new GeneratingIterable(initial, next);
/**
* An Iterable who's first value is [object] and who's subsequent values are
* generated by passing the current value to the [next] function.
*
* The class is useful for creating lazy iterables from object hierarchies and
* graphs.
*
* It's important that for the given initial value and next function that the
* sequence of items eventually terminates. Otherwise calling methods that
* expect a finite sequence, like `length` or `last`, will cause an infinite
* loop.
*
* Example:
*
* class Node {
* Node parent;
*
* /**
* * An iterable of node and all ancestors up to the root.
* */
* Iterable<Node> ancestors =
* new GeneratingIterable<Node>(() => this, (n) => n.parent);
*
* /**
* * An iterable of the root and the path of nodes to this. The reverse
* * of ancestors.
* */
* Iterable<Node> path = ancestors.toList().reversed();
* }
*
*/
class GeneratingIterable<T> extends IterableBase<T> {
final initial;
final next;
GeneratingIterable(T this.initial(), T this.next(T o));
@override
Iterator<T> get iterator => new _GeneratingIterator(initial(), next);
}
class _GeneratingIterator<T> implements Iterator<T> {
final next;
T object;
bool started = false;
_GeneratingIterator(T this.object, T this.next(T o));
@override
T get current => started ? object : null;
@override
bool moveNext() {
if (object == null) return false;
if (started) {
object = next(object);
} else {
started = true;
}
return object != null;
}
}