mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
350 lines
11 KiB
Swift
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
|