Files
swift-mirror/stdlib/public/core/Flatten.swift.gyb
2016-02-23 13:52:30 -08:00

350 lines
11 KiB
Swift

//===--- 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<Base.Iterator> {
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<Self> {
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<Elements>
> {
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 == <BaseElements> (
lhs: ${Index}<BaseElements>,
rhs: ${Index}<BaseElements>
) -> 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}<Base>
/// 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<Base.Iterator> {
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<Base.Iterator.Element.Iterator.Element> {
// 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}<Self> {
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}<Elements>> {
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<Base.Iterator> {
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