blob: 53441e1d3429babcc9f5d45291eb1e5f4946c44f [file] [log] [blame]
// Copyright 2013 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;
/**
* Returns the result of merging an [Iterable] of [Iterable]s, according to
* the order specified by the [compare] function. This function assumes the
* provided iterables are already sorted according to the provided [compare]
* function. It will not check for this condition or sort the iterables.
*
* The compare function must act as a [Comparator]. If [compare] is omitted,
* [Comparable.compare] is used.
*
* If any of the [iterables] contain null elements, an exception will be
* thrown.
*/
Iterable merge(Iterable<Iterable> iterables,
[Comparator compare = Comparable.compare]) =>
(iterables.isEmpty) ? const [] : new _Merge(iterables, compare);
class _Merge extends IterableBase {
final Iterable<Iterable> _iterables;
final Comparator _compare;
_Merge(this._iterables, this._compare);
Iterator get iterator => new _MergeIterator(
_iterables.map((i) => i.iterator).toList(growable: false), _compare);
String toString() => this.toList().toString();
}
/// Like [Iterator] but one element ahead.
class _IteratorPeeker {
final Iterator _iterator;
bool _hasCurrent;
_IteratorPeeker(Iterator iterator)
: _iterator = iterator,
_hasCurrent = iterator.moveNext();
moveNext() {
_hasCurrent = _iterator.moveNext();
}
get current => _iterator.current;
}
class _MergeIterator implements Iterator {
final List<_IteratorPeeker> _peekers;
final Comparator _compare;
var _current;
_MergeIterator(List<Iterator> iterators, this._compare)
: _peekers = iterators.map((i) => new _IteratorPeeker(i)).toList();
bool moveNext() {
// Pick the peeker that's peeking at the puniest piece
_IteratorPeeker minIter = null;
for (var p in _peekers) {
if (p._hasCurrent) {
if (minIter == null || _compare(p.current, minIter.current) < 0) {
minIter = p;
}
}
}
if (minIter == null) {
return false;
}
_current = minIter.current;
minIter.moveNext();
return true;
}
get current => _current;
}