Files
swift-mirror/stdlib/public/core/Flatten.swift.gyb
Dave Abrahams ad43a596bd [stdlib] Retire the old lazy subsystem...
...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
2015-08-01 03:52:13 +00:00

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