// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:collection';

import 'combined_iterator.dart';

/// A view of several iterables combined sequentially into a single iterable.
///
/// All methods and accessors treat the [CombinedIterableView] as if it were a
/// single concatenated iterable, but the underlying implementation is based on
/// lazily accessing individual iterable instances. This means that if the
/// underlying iterables change, the [CombinedIterableView] will reflect those
/// changes.
class CombinedIterableView<T> extends IterableBase<T> {
  /// The iterables that this combines.
  final Iterable<Iterable<T>> _iterables;

  /// Creates a combined view of [_iterables].
  const CombinedIterableView(this._iterables);

  @override
  Iterator<T> get iterator =>
      CombinedIterator<T>(_iterables.map((i) => i.iterator).iterator);

  // Special cased contains/isEmpty/length since many iterables have an
  // efficient implementation instead of running through the entire iterator.

  @override
  bool contains(Object? element) => _iterables.any((i) => i.contains(element));

  @override
  bool get isEmpty => _iterables.every((i) => i.isEmpty);

  @override
  int get length => _iterables.fold(0, (length, i) => length + i.length);
}
