//===--- Flatten.swift.gyb ------------------------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// /// An iterator that produces the elements contained in each segment /// produced by some `Base` Iterator. /// /// The elements traversed are the concatenation of those in each /// segment produced by the base iterator. /// /// - Note: This is the `IteratorProtocol` used by `FlattenSequence`, /// `FlattenCollection`, and `BidirectionalFlattenCollection`. public struct FlattenIterator< Base : IteratorProtocol where Base.Element : Sequence > : IteratorProtocol, Sequence { /// Construct around a `base` iterator. internal init(_ base: Base) { self._base = base } /// Advance to the next element and return it, or `nil` if no next /// element exists. /// /// - Precondition: `next()` has not been applied to a copy of `self` /// since the copy was made, and no preceding call to `self.next()` /// has returned `nil`. public mutating func next() -> Base.Element.Iterator.Element? { repeat { if _fastPath(_inner != nil) { let ret = _inner!.next() if _fastPath(ret != nil) { return ret } } let s = _base.next() if _slowPath(s == nil) { return nil } _inner = s!.makeIterator() } while true } internal var _base: Base internal var _inner: Base.Element.Iterator? } /// A sequence consisting of all the elements contained in each segment /// contained in some `Base` sequence. /// /// The elements of this view are a concatenation of the elements of /// each sequence in the base. /// /// The `flatten` property is always lazy, but does not implicitly /// confer laziness on algorithms applied to its result. In other /// words, for ordinary sequences `s`: /// /// * `s.flatten()` does not create new storage /// * `s.flatten().map(f)` maps eagerly and returns a new array /// * `s.lazy.flatten().map(f)` maps lazily and returns a `LazyMapSequence` /// /// - See also: `FlattenCollection` public struct FlattenSequence< Base : Sequence where Base.Iterator.Element : Sequence > : Sequence { /// Creates a concatenation of the elements of the elements of `base`. /// /// - Complexity: O(1) internal init(_ base: Base) { self._base = base } /// Returns an iterator over the elements of this sequence. /// /// - Complexity: O(1). public func makeIterator() -> FlattenIterator { return FlattenIterator(_base.makeIterator()) } internal var _base: Base } extension Sequence where Iterator.Element : Sequence { /// A concatenation of the elements of `self`. @warn_unused_result public func flatten() -> FlattenSequence { return FlattenSequence(self) } } extension LazySequenceProtocol where Elements.Iterator.Element == Iterator.Element, Iterator.Element : Sequence { /// A concatenation of the elements of `self`. @warn_unused_result public func flatten() -> LazySequence< FlattenSequence > { return FlattenSequence(elements).lazy } } % for traversal in ('Forward', 'Bidirectional'): % t = '' if traversal == 'Forward' else traversal % Collection = 'Flatten%sCollection' % t % constraints = '%(Base)sIterator.Element : Collection' % if traversal == 'Bidirectional': % constraints += ''', % %(Base)sIndex : BidirectionalIndex, % %(Base)sIterator.Element.Index : BidirectionalIndex''' % Index = Collection + 'Index' /// A position in a `${Collection}`. public struct ${Index}< BaseElements: Collection where ${constraints % {'Base': 'BaseElements.'}} > : ${traversal}Index { /// Returns the next consecutive value after `self`. /// /// - Precondition: The next value is representable. public func successor() -> ${Index} { let nextInner = _inner!.successor() if _fastPath(nextInner != _innerCollection!.endIndex) { return ${Index}(_base, _outer, nextInner, _innerCollection) } for nextOuter in _outer.successor()..<_base.endIndex { let nextInnerCollection = _base[nextOuter] if !nextInnerCollection.isEmpty { return ${Index}( _base, nextOuter, nextInnerCollection.startIndex, nextInnerCollection) } } return ${Index}(_endIndexOfFlattened: _base) } % if traversal == 'Bidirectional': /// Returns the previous consecutive value before `self`. /// /// - Precondition: The previous value is representable. public func predecessor() -> ${Index} { var prevOuter = _outer var prevInnerCollection : BaseElements.Iterator.Element if let ic = _innerCollection { prevInnerCollection = ic } else { prevOuter._predecessorInPlace() prevInnerCollection = _base[prevOuter] } var prevInner = _inner ?? prevInnerCollection.endIndex while prevInner == prevInnerCollection.startIndex { prevOuter._predecessorInPlace() prevInnerCollection = _base[prevOuter] prevInner = prevInnerCollection.endIndex } return ${Index}( _base, prevOuter, prevInner.predecessor(), prevInnerCollection) } % end /// Construct the `startIndex` for a flattened view of `base`. internal init(_startIndexOfFlattened base: BaseElements) { for outer in base.indices { let innerCollection = base[outer] if !innerCollection.isEmpty { self._base = base self._outer = outer self._innerCollection = innerCollection self._inner = innerCollection.startIndex return } } self = ${Index}(_endIndexOfFlattened: base) } /// Construct the `endIndex` for a flattened view of `base`. internal init(_endIndexOfFlattened _base: BaseElements) { self._base = _base self._outer = _base.endIndex self._inner = nil self._innerCollection = nil } internal init( _ _base: BaseElements, _ outer: BaseElements.Index, _ inner: BaseElements.Iterator.Element.Index?, _ innerCollection: BaseElements.Iterator.Element?) { self._base = _base self._outer = outer self._inner = inner self._innerCollection = innerCollection } internal let _base: BaseElements internal let _outer: BaseElements.Index internal let _inner: BaseElements.Iterator.Element.Index? internal let _innerCollection: BaseElements.Iterator.Element? } @warn_unused_result public func == ( lhs: ${Index}, rhs: ${Index} ) -> Bool { return lhs._outer == rhs._outer && lhs._inner == rhs._inner } /// A flattened view of a base collection-of-collections. /// /// The elements of this view are a concatenation of the elements of /// each collection in the base. /// /// The `flatten` property is always lazy, but does not implicitly /// confer laziness on algorithms applied to its result. In other /// words, for ordinary collections `c`: /// /// * `c.flatten()` does not create new storage /// * `c.flatten().map(f)` maps eagerly and returns a new array /// * `c.lazy.flatten().map(f)` maps lazily and returns a `LazyMapCollection` /// /// - Note: The performance of accessing `startIndex`, `first`, any methods /// that depend on `startIndex`, or of advancing a `${Collection}Index` /// depends on how many empty subcollections are found in the base /// collection, and may not offer the usual performance given by /// `CollectionType` or `${traversal}IndexType`. Be aware, therefore, that /// general operations on `${Collection}` instances may not have the /// documented complexity. /// /// - See also: `FlattenSequence` public struct ${Collection}< Base: Collection where ${constraints % {'Base': 'Base.'}} > : Collection { /// A type that represents a valid position in the collection. /// /// Valid indices consist of the position of every element and a /// "past the end" position that's not valid for use as a subscript. public typealias Index = ${Index} /// Creates a flattened view of `base`. public init(_ base: Base) { self._base = base } /// Returns an iterator over the elements of this sequence. /// /// - Complexity: O(1). public func makeIterator() -> FlattenIterator { return FlattenIterator(_base.makeIterator()) } /// The position of the first element in a non-empty collection. /// /// In an empty collection, `startIndex == endIndex`. public var startIndex: Index { return ${Index}(_startIndexOfFlattened: _base) } /// The collection's "past the end" position. /// /// `endIndex` is not a valid argument to `subscript`, and is always /// reachable from `startIndex` by zero or more applications of /// `successor()`. public var endIndex: Index { return ${Index}(_endIndexOfFlattened: _base) } /// Access the element at `position`. /// /// - Precondition: `position` is a valid position in `self` and /// `position != endIndex`. public subscript( position: Index ) -> Base.Iterator.Element.Iterator.Element { return position._innerCollection![position._inner!] } // To return any estimate of the number of elements, we have to start // evaluating the collections. That is a bad default for `flatMap()`, so // just return zero. public var underestimatedCount: Int { return 0 } public func _copyToNativeArrayBuffer() -> _ContiguousArrayBuffer { // The default implementation of `_copyToNativeArrayBuffer` queries the // `count` property, which materializes every inner collection. This is a // bad default for `flatMap()`. So we treat `self` as a sequence and only // rely on underestimated count. return _copySequenceToNativeArrayBuffer(self) } internal var _base: Base } extension Collection where ${constraints % {'Base': ''}} { /// A concatenation of the elements of `self`. @warn_unused_result public func flatten() -> ${Collection} { return ${Collection}(self) } } extension LazyCollectionProtocol where ${constraints % {'Base': ''}}, ${constraints % {'Base': 'Elements.'}}, Iterator.Element == Elements.Iterator.Element { /// A concatenation of the elements of `self`. @warn_unused_result public func flatten() -> LazyCollection<${Collection}> { return ${Collection}(elements).lazy } } % end @available(*, unavailable, renamed="FlattenIterator") public struct FlattenGenerator< Base : IteratorProtocol where Base.Element : Sequence > {} extension FlattenSequence { @available(*, unavailable, renamed="iterator") public func generate() -> FlattenIterator { fatalError("unavailable function can't be called") } } % for traversal in ('Forward', 'Bidirectional'): % t = '' if traversal == 'Forward' else traversal % Collection = 'Flatten%sCollection' % t extension ${Collection} { @available(*, unavailable, message="Please use underestimatedCount property instead.") public func underestimateCount() -> Int { fatalError("unavailable function can't be called") } } %end