mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
...replacing it with the new, after passing API review! * The lazy free function has become a property. * Before we could extend protocols, we lacked a means for value types to share implementations, and each new lazy algorithm had to be added to each of up to four types: LazySequence, LazyForwardCollection, LazyBidirectionalCollection, and LazyRandomAccessCollection. These generic adapters hid the usual algorithms by defining their own versions that returned new lazy generic adapters. Now users can extend just one of two protocols to do the same thing: LazySequenceType or LazyCollectionType. * To avoid making the code duplication worse than it already was, the generic adapters mentioned above were used to add the lazy generic algorithms around simpler adapters such as MapSequence that just provided the basic requirements of SequenceType by applying a transformation to some base sequence, resulting in deeply nested generic types as shown here. Now, MapSequence is an instance of LazySequenceType (and is renamed LazyMapSequence), and thus transmits laziness to its algorithms automatically. * Documentation comments have been rewritten. * The .array property was retired * various renamings * A bunch of Gyb files were retired. Swift SVN r30902
304 lines
9.6 KiB
Plaintext
304 lines
9.6 KiB
Plaintext
//===--- Flatten.swift.gyb ------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// A flattened view of a base generator-of-sequences.
|
|
///
|
|
/// The elements generated are the concatenation of those in each
|
|
/// sequence generated by the base generator.
|
|
///
|
|
/// - Note: this is the `GeneratorType` used by `FlattenSequence`,
|
|
/// `FlattenCollection`, and `BidirectionalFlattenCollection`.
|
|
public struct FlattenGenerator<
|
|
Base : GeneratorType where Base.Element : SequenceType
|
|
> : GeneratorType, SequenceType {
|
|
|
|
/// Construct around a generator for the `base` sequence.
|
|
public init(_ base: Base) {
|
|
self._base = base
|
|
}
|
|
|
|
/// Advance to the next element and return it, or `nil` if no next
|
|
/// element exists.
|
|
///
|
|
/// - Requires: `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.Generator.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!.generate()
|
|
}
|
|
while true
|
|
}
|
|
|
|
internal var _base: Base
|
|
internal var _inner: Base.Element.Generator? = nil
|
|
}
|
|
|
|
/// A flattened view of a base sequence-of-sequences.
|
|
///
|
|
/// 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 : SequenceType where Base.Generator.Element : SequenceType
|
|
> : SequenceType {
|
|
|
|
/// Creates a concatenation of the elements of the elements of `base`.
|
|
///
|
|
/// - Complexity: O(1)
|
|
public init(_ base: Base) {
|
|
self._base = base
|
|
}
|
|
|
|
/// Return a *generator* over the elements of this *sequence*.
|
|
///
|
|
/// - Complexity: O(1).
|
|
public func generate() -> FlattenGenerator<Base.Generator> {
|
|
return FlattenGenerator(_base.generate())
|
|
}
|
|
|
|
internal var _base: Base
|
|
}
|
|
|
|
extension SequenceType where Generator.Element : SequenceType {
|
|
/// A concatenation of the elements of `self`.
|
|
public func flatten() -> FlattenSequence<Self> {
|
|
return FlattenSequence(self)
|
|
}
|
|
}
|
|
|
|
extension LazySequenceType
|
|
where Elements.Generator.Element == Generator.Element,
|
|
Generator.Element : SequenceType {
|
|
/// A concatenation of the elements of `self`.
|
|
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)sGenerator.Element : CollectionType'
|
|
% if traversal == 'Bidirectional':
|
|
% constraints += ''',
|
|
% %(Base)sIndex : BidirectionalIndexType,
|
|
% %(Base)sGenerator.Element.Index : BidirectionalIndexType'''
|
|
% Index = Collection + 'Index'
|
|
public struct ${Index}<
|
|
BaseElements: CollectionType where ${constraints % {'Base': 'BaseElements.'}}
|
|
> : ${traversal}IndexType {
|
|
/// Returns the next consecutive value after `self`.
|
|
///
|
|
/// - Requires: 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`.
|
|
///
|
|
/// - Requires: The previous value is representable.
|
|
public func predecessor() -> ${Index} {
|
|
var prevOuter = _outer
|
|
var prevInnerCollection = _innerCollection ?? _base[--prevOuter]
|
|
var prevInner = _inner ?? prevInnerCollection.endIndex
|
|
|
|
while prevInner == prevInnerCollection.startIndex {
|
|
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.Generator.Element.Index?,
|
|
_ innerCollection: BaseElements.Generator.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.Generator.Element.Index?
|
|
internal let _innerCollection: BaseElements.Generator.Element?
|
|
}
|
|
|
|
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`
|
|
///
|
|
/// - See also: `FlattenSequence`
|
|
public struct ${Collection}<
|
|
Base: CollectionType where ${constraints % {'Base': 'Base.'}}
|
|
> : CollectionType {
|
|
/// 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
|
|
}
|
|
|
|
/// Return a *generator* over the elements of this *sequence*.
|
|
///
|
|
/// - Complexity: O(1).
|
|
public func generate() -> FlattenGenerator<Base.Generator> {
|
|
return FlattenGenerator(_base.generate())
|
|
}
|
|
|
|
/// 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`.
|
|
///
|
|
/// - Requires: `position` is a valid position in `self` and
|
|
/// `position != endIndex`.
|
|
public subscript(
|
|
position: Index
|
|
) -> Base.Generator.Element.Generator.Element {
|
|
return position._innerCollection![position._inner!]
|
|
}
|
|
|
|
public func underestimateCount() -> Int {
|
|
// 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.
|
|
return 0
|
|
}
|
|
|
|
public func _copyToNativeArrayBuffer()
|
|
-> _ContiguousArrayBuffer<Base.Generator.Element.Generator.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 CollectionType where ${constraints % {'Base': ''}} {
|
|
/// A concatenation of the elements of `self`.
|
|
public func flatten() -> ${Collection}<Self> {
|
|
return ${Collection}(self)
|
|
}
|
|
}
|
|
|
|
extension LazyCollectionType
|
|
where ${constraints % {'Base': ''}},
|
|
${constraints % {'Base': 'Elements.'}},
|
|
Generator.Element == Elements.Generator.Element {
|
|
/// A concatenation of the elements of `self`.
|
|
public func flatten() -> LazyCollection<${Collection}<Elements>> {
|
|
return ${Collection}(elements).lazy
|
|
}
|
|
}
|
|
|
|
% end
|