Last active
March 20, 2018 21:45
-
-
Save TellowKrinkle/818c8d9ce467f272c889bdd503784d63 to your computer and use it in GitHub Desktop.
LazyCompactMap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Note: This is just a copy of the swift stdlib Filter.swift with everything renamed | |
//===--- Filter.swift -----------------------------------------*- swift -*-===// | |
// | |
// This source file is part of the Swift.org open source project | |
// | |
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors | |
// Licensed under Apache License v2.0 with Runtime Library Exception | |
// | |
// See https://swift.org/LICENSE.txt for license information | |
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | |
// | |
//===----------------------------------------------------------------------===// | |
/// A sequence whose elements consist of the elements of some base | |
/// sequence that also satisfy a given predicate. | |
/// | |
/// - Note: `s.lazy.filter { ... }`, for an arbitrary sequence `s`, | |
/// is a `LazyFilterSequence2`. | |
@_fixed_layout // FIXME(sil-serialize-all) | |
public struct LazyFilterSequence2<Base: Sequence> { | |
@_versioned // FIXME(sil-serialize-all) | |
internal var _base: Base | |
/// The predicate used to determine which elements produced by | |
/// `base` are also produced by `self`. | |
@_versioned // FIXME(sil-serialize-all) | |
internal let _predicate: (Base.Element) -> Bool | |
/// Creates an instance consisting of the elements `x` of `base` for | |
/// which `isIncluded(x) == true`. | |
@_inlineable // FIXME(sil-serialize-all) | |
public // @testable | |
init(_base base: Base, _ isIncluded: @escaping (Base.Element) -> Bool) { | |
self._base = base | |
self._predicate = isIncluded | |
} | |
} | |
extension LazyFilterSequence2 { | |
/// An iterator over the elements traversed by some base iterator that also | |
/// satisfy a given predicate. | |
/// | |
/// - Note: This is the associated `Iterator` of `LazyFilterSequence2` | |
/// and `LazyFilterCollection2`. | |
@_fixed_layout // FIXME(sil-serialize-all) | |
public struct Iterator { | |
/// The underlying iterator whose elements are being filtered. | |
public var base: Base.Iterator { return _base } | |
@_versioned // FIXME(sil-serialize-all) | |
internal var _base: Base.Iterator | |
@_versioned // FIXME(sil-serialize-all) | |
internal let _predicate: (Base.Element) -> Bool | |
/// Creates an instance that produces the elements `x` of `base` | |
/// for which `isIncluded(x) == true`. | |
@_inlineable // FIXME(sil-serialize-all) | |
@_versioned // FIXME(sil-serialize-all) | |
internal init(_base: Base.Iterator, _ isIncluded: @escaping (Base.Element) -> Bool) { | |
self._base = _base | |
self._predicate = isIncluded | |
} | |
} | |
} | |
extension LazyFilterSequence2.Iterator: IteratorProtocol, Sequence { | |
public typealias Element = Base.Element | |
/// Advances to the next element and returns it, or `nil` if no next element | |
/// exists. | |
/// | |
/// Once `nil` has been returned, all subsequent calls return `nil`. | |
/// | |
/// - Precondition: `next()` has not been applied to a copy of `self` | |
/// since the copy was made. | |
@_inlineable // FIXME(sil-serialize-all) | |
public mutating func next() -> Element? { | |
while let n = _base.next() { | |
if _predicate(n) { | |
return n | |
} | |
} | |
return nil | |
} | |
} | |
extension LazyFilterSequence2: LazySequenceProtocol { | |
public typealias Element = Base.Element | |
/// Returns an iterator over the elements of this sequence. | |
/// | |
/// - Complexity: O(1). | |
@_inlineable // FIXME(sil-serialize-all) | |
public func makeIterator() -> Iterator { | |
return Iterator(_base: _base.makeIterator(), _predicate) | |
} | |
@_inlineable | |
public func _customContainsEquatableElement(_ element: Element) -> Bool? { | |
// optimization to check the element first matches the predicate | |
guard _predicate(element) else { return false } | |
return _base._customContainsEquatableElement(element) | |
} | |
} | |
/// A lazy `Collection` wrapper that includes the elements of an | |
/// underlying collection that satisfy a predicate. | |
/// | |
/// - Note: The performance of accessing `startIndex`, `first`, any methods | |
/// that depend on `startIndex`, or of advancing an index depends | |
/// on how sparsely the filtering predicate is satisfied, and may not offer | |
/// the usual performance given by `Collection`. Be aware, therefore, that | |
/// general operations on `LazyFilterCollection2` instances may not have the | |
/// documented complexity. | |
@_fixed_layout // FIXME(sil-serialize-all) | |
public struct LazyFilterCollection2<Base : Collection> { | |
@_versioned // FIXME(sil-serialize-all) | |
internal var _base: Base | |
@_versioned // FIXME(sil-serialize-all) | |
internal let _predicate: (Base.Element) -> Bool | |
/// Creates an instance containing the elements of `base` that | |
/// satisfy `isIncluded`. | |
@_inlineable // FIXME(sil-serialize-all) | |
public // @testable | |
init(_base: Base, _ isIncluded: @escaping (Base.Element) -> Bool) { | |
self._base = _base | |
self._predicate = isIncluded | |
} | |
} | |
extension LazyFilterCollection2 : LazySequenceProtocol { | |
public typealias Element = Base.Element | |
public typealias Iterator = LazyFilterSequence2<Base>.Iterator | |
public typealias SubSequence = LazyFilterCollection2<Base.SubSequence> | |
// Any estimate of the number of elements that pass `_predicate` requires | |
// iterating the collection and evaluating each element, which can be costly, | |
// is unexpected, and usually doesn't pay for itself in saving time through | |
// preventing intermediate reallocations. (SR-4164) | |
@_inlineable // FIXME(sil-serialize-all) | |
public var underestimatedCount: Int { return 0 } | |
/// Returns an iterator over the elements of this sequence. | |
/// | |
/// - Complexity: O(1). | |
@_inlineable // FIXME(sil-serialize-all) | |
public func makeIterator() -> Iterator { | |
return Iterator(_base: _base.makeIterator(), _predicate) | |
} | |
@_inlineable | |
public func _customContainsEquatableElement(_ element: Element) -> Bool? { | |
guard _predicate(element) else { return false } | |
return _base._customContainsEquatableElement(element) | |
} | |
} | |
extension LazyFilterCollection2 : LazyCollectionProtocol { | |
/// 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 = Base.Index | |
/// The position of the first element in a non-empty collection. | |
/// | |
/// In an empty collection, `startIndex == endIndex`. | |
/// | |
/// - Complexity: O(*n*), where *n* is the ratio between unfiltered and | |
/// filtered collection counts. | |
@_inlineable // FIXME(sil-serialize-all) | |
public var startIndex: Index { | |
var index = _base.startIndex | |
while index != _base.endIndex && !_predicate(_base[index]) { | |
_base.formIndex(after: &index) | |
} | |
return index | |
} | |
/// The collection's "past the end" position---that is, the position one | |
/// greater than the last valid subscript argument. | |
/// | |
/// `endIndex` is always reachable from `startIndex` by zero or more | |
/// applications of `index(after:)`. | |
@_inlineable // FIXME(sil-serialize-all) | |
public var endIndex: Index { | |
return _base.endIndex | |
} | |
// TODO: swift-3-indexing-model - add docs | |
@_inlineable // FIXME(sil-serialize-all) | |
public func index(after i: Index) -> Index { | |
var i = i | |
formIndex(after: &i) | |
return i | |
} | |
@_inlineable // FIXME(sil-serialize-all) | |
public func formIndex(after i: inout Index) { | |
// TODO: swift-3-indexing-model: _failEarlyRangeCheck i? | |
var index = i | |
_precondition(index != _base.endIndex, "Can't advance past endIndex") | |
repeat { | |
_base.formIndex(after: &index) | |
} while index != _base.endIndex && !_predicate(_base[index]) | |
i = index | |
} | |
@inline(__always) | |
@_inlineable // FIXME(sil-serialize-all) | |
@_versioned // FIXME(sil-serialize-all) | |
internal func _advanceIndex(_ i: inout Index, step: Int) { | |
repeat { | |
_base.formIndex(&i, offsetBy: step) | |
} while i != _base.endIndex && !_predicate(_base[i]) | |
} | |
@inline(__always) | |
@_inlineable // FIXME(sil-serialize-all) | |
@_versioned // FIXME(sil-serialize-all) | |
internal func _ensureBidirectional(step: Int) { | |
// FIXME: This seems to be the best way of checking whether _base is | |
// forward only without adding an extra protocol requirement. | |
// index(_:offsetBy:limitedBy:) is chosen becuase it is supposed to return | |
// nil when the resulting index lands outside the collection boundaries, | |
// and therefore likely does not trap in these cases. | |
if step < 0 { | |
_ = _base.index( | |
_base.endIndex, offsetBy: step, limitedBy: _base.startIndex) | |
} | |
} | |
@_inlineable // FIXME(sil-serialize-all) | |
public func distance(from start: Index, to end: Index) -> Int { | |
// The following line makes sure that distance(from:to:) is invoked on the | |
// _base at least once, to trigger a _precondition in forward only | |
// collections. | |
_ = _base.distance(from: start, to: end) | |
var _start: Index | |
let _end: Index | |
let step: Int | |
if start > end { | |
_start = end | |
_end = start | |
step = -1 | |
} | |
else { | |
_start = start | |
_end = end | |
step = 1 | |
} | |
var count = 0 | |
while _start != _end { | |
count += step | |
formIndex(after: &_start) | |
} | |
return count | |
} | |
@_inlineable // FIXME(sil-serialize-all) | |
public func index(_ i: Index, offsetBy n: Int) -> Index { | |
var i = i | |
let step = n.signum() | |
// The following line makes sure that index(_:offsetBy:) is invoked on the | |
// _base at least once, to trigger a _precondition in forward only | |
// collections. | |
_ensureBidirectional(step: step) | |
for _ in 0 ..< abs(numericCast(n)) { | |
_advanceIndex(&i, step: step) | |
} | |
return i | |
} | |
@_inlineable // FIXME(sil-serialize-all) | |
public func formIndex(_ i: inout Index, offsetBy n: Int) { | |
i = index(i, offsetBy: n) | |
} | |
@_inlineable // FIXME(sil-serialize-all) | |
public func index( | |
_ i: Index, offsetBy n: Int, limitedBy limit: Index | |
) -> Index? { | |
var i = i | |
let step = n.signum() | |
// The following line makes sure that index(_:offsetBy:limitedBy:) is | |
// invoked on the _base at least once, to trigger a _precondition in | |
// forward only collections. | |
_ensureBidirectional(step: step) | |
for _ in 0 ..< abs(numericCast(n)) { | |
if i == limit { | |
return nil | |
} | |
_advanceIndex(&i, step: step) | |
} | |
return i | |
} | |
@_inlineable // FIXME(sil-serialize-all) | |
public func formIndex( | |
_ i: inout Index, offsetBy n: Int, limitedBy limit: Index | |
) -> Bool { | |
if let advancedIndex = index(i, offsetBy: n, limitedBy: limit) { | |
i = advancedIndex | |
return true | |
} | |
i = limit | |
return false | |
} | |
/// Accesses the element at `position`. | |
/// | |
/// - Precondition: `position` is a valid position in `self` and | |
/// `position != endIndex`. | |
@_inlineable // FIXME(sil-serialize-all) | |
public subscript(position: Index) -> Element { | |
return _base[position] | |
} | |
@_inlineable // FIXME(sil-serialize-all) | |
public subscript(bounds: Range<Index>) -> SubSequence { | |
return SubSequence(_base: _base[bounds], _predicate) | |
} | |
} | |
extension LazyFilterCollection2 : BidirectionalCollection | |
where Base : BidirectionalCollection { | |
@_inlineable // FIXME(sil-serialize-all) | |
public func index(before i: Index) -> Index { | |
var i = i | |
formIndex(before: &i) | |
return i | |
} | |
@_inlineable // FIXME(sil-serialize-all) | |
public func formIndex(before i: inout Index) { | |
// TODO: swift-3-indexing-model: _failEarlyRangeCheck i? | |
var index = i | |
_precondition(index != _base.startIndex, "Can't retreat before startIndex") | |
repeat { | |
_base.formIndex(before: &index) | |
} while !_predicate(_base[index]) | |
i = index | |
} | |
} | |
extension LazySequenceProtocol2 { | |
/// Returns the elements of `self` that satisfy `isIncluded`. | |
/// | |
/// - Note: The elements of the result are computed on-demand, as | |
/// the result is used. No buffering storage is allocated and each | |
/// traversal step invokes `predicate` on one or more underlying | |
/// elements. | |
@_inlineable // FIXME(sil-serialize-all) | |
public func filter( | |
_ isIncluded: @escaping (Elements.Element) -> Bool | |
) -> LazyFilterSequence2<Self.Elements> { | |
return LazyFilterSequence2(_base: self.elements, isIncluded) | |
} | |
} | |
extension LazyCollectionProtocol2 { | |
/// Returns the elements of `self` that satisfy `predicate`. | |
/// | |
/// - Note: The elements of the result are computed on-demand, as | |
/// the result is used. No buffering storage is allocated and each | |
/// traversal step invokes `predicate` on one or more underlying | |
/// elements. | |
@_inlineable // FIXME(sil-serialize-all) | |
public func filter( | |
_ isIncluded: @escaping (Elements.Element) -> Bool | |
) -> LazyFilterCollection2<Self.Elements> { | |
return LazyFilterCollection2(_base: self.elements, isIncluded) | |
} | |
} | |
extension LazyFilterSequence2 { | |
public func filter( | |
_ isIncluded: @escaping (Element) -> Bool | |
) -> LazyFilterSequence2<Base> { | |
return LazyFilterSequence2(_base: _base) { | |
isIncluded($0) && self._predicate($0) | |
} | |
} | |
} | |
extension LazyFilterCollection2 { | |
public func filter( | |
_ isIncluded: @escaping (Element) -> Bool | |
) -> LazyFilterCollection2<Base> { | |
return LazyFilterCollection2(_base: _base) { | |
isIncluded($0) && self._predicate($0) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extension LazySequenceProtocol2 { | |
public func flatMap<SegmentOfResult>( | |
_ transform: @escaping (Elements.Element) -> SegmentOfResult | |
) -> LazySequence<FlattenSequence<LazyMapSequence2<Elements, SegmentOfResult>>> { | |
return self.map(transform).lazy.joined() | |
} | |
} | |
extension LazyCollectionProtocol2 { | |
public func flatMap<SegmentOfResult>( | |
_ transform: @escaping (Elements.Element) -> SegmentOfResult | |
) -> LazyCollection<FlattenCollection<LazyMapCollection2<Elements, SegmentOfResult>>> { | |
return self.map(transform).lazy.joined() | |
} | |
} | |
public struct LazyCompactMapSequence2<Base: Sequence, Element> { | |
public typealias Elements = LazyCompactMapSequence2 | |
internal var _base: Base | |
internal let _transform: (Base.Element) -> Element? | |
internal init(_base: Base, transform: @escaping (Base.Element) -> Element?) { | |
self._base = _base | |
self._transform = transform | |
} | |
} | |
extension LazyCompactMapSequence2 { | |
public struct Iterator { | |
internal var _base: Base.Iterator | |
internal let _transform: (Base.Element) -> Element? | |
public var base : Base.Iterator { return _base } | |
internal init( | |
_base: Base.Iterator, | |
_transform: @escaping (Base.Element) -> Element? | |
) { | |
self._base = _base | |
self._transform = _transform | |
} | |
} | |
} | |
extension LazyCompactMapSequence2.Iterator : IteratorProtocol, Sequence { | |
public mutating func next() -> Element? { | |
while let n = _base.next() { | |
if let transformed = _transform(n) { | |
return transformed | |
} | |
} | |
return nil | |
} | |
} | |
extension LazyCompactMapSequence2: LazySequenceProtocol2 { | |
public func makeIterator() -> Iterator { | |
return Iterator(_base: _base.makeIterator(), _transform: _transform) | |
} | |
} | |
public struct LazyCompactMapCollection2<Base: Collection, Element> { | |
internal var _base: Base | |
internal let _transform: (Base.Element) -> Element? | |
internal init(_base: Base, transform: @escaping (Base.Element) -> Element?) { | |
self._base = _base | |
self._transform = transform | |
} | |
} | |
extension LazyCompactMapCollection2: LazySequenceProtocol2 { | |
public typealias Iterator = LazyCompactMapSequence2<Base, Element>.Iterator | |
public func makeIterator() -> Iterator { | |
return Iterator(_base: _base.makeIterator(), _transform: _transform) | |
} | |
} | |
extension LazyCompactMapCollection2: LazyCollectionProtocol2 { | |
public typealias Index = Base.Index | |
public var startIndex: Index { | |
var index = _base.startIndex | |
while index != _base.endIndex && _transform(_base[index]) == nil { | |
_base.formIndex(after: &index) | |
} | |
return index | |
} | |
public var endIndex: Index { return _base.endIndex } | |
public func index(after i: Index) -> Index { | |
var i = i | |
formIndex(after: &i) | |
return i | |
} | |
public func formIndex(after i: inout Index) { | |
_precondition(i != _base.endIndex, "Can't advance past endIndex") | |
repeat { | |
_base.formIndex(after: &i) | |
} while i != _base.endIndex && _transform(_base[i]) == nil | |
} | |
public func distance(from start: Index, to end: Index) -> Int { | |
_ = _base.distance(from: start, to: end) | |
var _start: Index | |
let _end: Index | |
let step: Int | |
if start > end { | |
_start = end | |
_end = start | |
step = -1 | |
} | |
else { | |
_start = start | |
_end = end | |
step = 1 | |
} | |
var count = 0 | |
while _start != _end { | |
count += step | |
formIndex(after: &_start) | |
} | |
return count | |
} | |
public subscript(position: Base.Index) -> Element { | |
return _transform(_base[position])! | |
} | |
} | |
extension LazySequenceProtocol2 { | |
public func compactMap<U>(_ transform: @escaping (Element) -> U?) -> LazyCompactMapSequence2<Self.Elements, U> { | |
return LazyCompactMapSequence2(_base: self.elements, transform: transform) | |
} | |
} | |
extension LazyCollectionProtocol2 { | |
public func compactMap<U>(_ transform: @escaping (Element) -> U?) -> LazyCompactMapCollection2<Self.Elements, U> { | |
return LazyCompactMapCollection2(_base: self.elements, transform: transform) | |
} | |
} | |
extension LazyMapSequence2 { | |
public func compactMap<U>(_ transform: @escaping (Element) -> U?) -> LazyCompactMapSequence2<Base, U> { | |
let mytransform = self._transform | |
return LazyCompactMapSequence2<Base, U>( | |
_base: self._base, | |
transform: { transform(mytransform($0)) } | |
) | |
} | |
public func filter(_ isIncluded: @escaping (Element) -> Bool) -> LazyCompactMapSequence2<Base, Element> { | |
let mytransform = self._transform | |
return LazyCompactMapSequence2<Base, Element>( | |
_base: self._base, | |
transform: { | |
let transformed = mytransform($0) | |
return isIncluded(transformed) ? transformed : nil | |
} | |
) | |
} | |
} | |
extension LazyFilterSequence2 { | |
public func compactMap<U>(_ transform: @escaping (Base.Element) -> U?) -> LazyCompactMapSequence2<Base, U> { | |
let mypredicate = self._predicate | |
return LazyCompactMapSequence2<Base, U>( | |
_base: self._base, | |
transform: { mypredicate($0) ? transform($0) : nil } | |
) | |
} | |
public func map<U>(_ transform: @escaping (Base.Element) -> U) -> LazyCompactMapSequence2<Base, U> { | |
let mypredicate = self._predicate | |
return LazyCompactMapSequence2<Base, U>( | |
_base: self._base, | |
transform: { mypredicate($0) ? transform($0) : nil } | |
) | |
} | |
} | |
extension LazyCompactMapSequence2 { | |
public func compactMap<U>(_ transform: @escaping (Element) -> U?) -> LazyCompactMapSequence2<Base, U> { | |
let mytransform = self._transform | |
return LazyCompactMapSequence2<Base, U>( | |
_base: self._base, | |
transform: { | |
guard let halfTransformed = mytransform($0) else { return nil } | |
return transform(halfTransformed) | |
} | |
) | |
} | |
public func map<U>(_ transform: @escaping (Element) -> U) -> LazyCompactMapSequence2<Base, U> { | |
let mytransform = self._transform | |
return LazyCompactMapSequence2<Base, U>( | |
_base: self._base, | |
transform: { | |
guard let halfTransformed = mytransform($0) else { return nil } | |
return transform(halfTransformed) | |
} | |
) | |
} | |
public func filter(_ isIncluded: @escaping (Element) -> Bool) -> LazyCompactMapSequence2<Base, Element> { | |
let mytransform = self._transform | |
return LazyCompactMapSequence2<Base, Element>( | |
_base: self._base, | |
transform: { | |
guard let halfTransformed = mytransform($0), isIncluded(halfTransformed) else { return nil } | |
return halfTransformed | |
} | |
) | |
} | |
} | |
extension LazyMapCollection2 { | |
public func compactMap<U>(_ transform: @escaping (Element) -> U?) -> LazyCompactMapCollection2<Base, U> { | |
let mytransform = self._transform | |
return LazyCompactMapCollection2<Base, U>( | |
_base: self._base, | |
transform: { transform(mytransform($0)) } | |
) | |
} | |
public func filter(_ isIncluded: @escaping (Element) -> Bool) -> LazyCompactMapCollection2<Base, Element> { | |
let mytransform = self._transform | |
return LazyCompactMapCollection2<Base, Element>( | |
_base: self._base, | |
transform: { | |
let transformed = mytransform($0) | |
return isIncluded(transformed) ? transformed : nil | |
} | |
) | |
} | |
} | |
extension LazyFilterCollection2 { | |
public func compactMap<U>(_ transform: @escaping (Base.Element) -> U?) -> LazyCompactMapCollection2<Base, U> { | |
let mypredicate = self._predicate | |
return LazyCompactMapCollection2<Base, U>( | |
_base: self._base, | |
transform: { mypredicate($0) ? transform($0) : nil } | |
) | |
} | |
public func map<U>(_ transform: @escaping (Base.Element) -> U) -> LazyCompactMapCollection2<Base, U> { | |
let mypredicate = self._predicate | |
return LazyCompactMapCollection2<Base, U>( | |
_base: self._base, | |
transform: { mypredicate($0) ? transform($0) : nil } | |
) | |
} | |
} | |
extension LazyCompactMapCollection2 { | |
public func compactMap<U>(_ transform: @escaping (Element) -> U?) -> LazyCompactMapCollection2<Base, U> { | |
let mytransform = self._transform | |
return LazyCompactMapCollection2<Base, U>( | |
_base: self._base, | |
transform: { | |
guard let halfTransformed = mytransform($0) else { return nil } | |
return transform(halfTransformed) | |
} | |
) | |
} | |
public func map<U>(_ transform: @escaping (Element) -> U) -> LazyCompactMapCollection2<Base, U> { | |
let mytransform = self._transform | |
return LazyCompactMapCollection2<Base, U>( | |
_base: self._base, | |
transform: { | |
guard let halfTransformed = mytransform($0) else { return nil } | |
return transform(halfTransformed) | |
} | |
) | |
} | |
public func filter(_ isIncluded: @escaping (Element) -> Bool) -> LazyCompactMapCollection2<Base, Element> { | |
let mytransform = self._transform | |
return LazyCompactMapCollection2<Base, Element>( | |
_base: self._base, | |
transform: { | |
guard let halfTransformed = mytransform($0), isIncluded(halfTransformed) else { return nil } | |
return halfTransformed | |
} | |
) | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Note: This is just a copy of the swift stdlib LazyCollection.swift with everything renamed | |
//===--- LazyCollection.swift ---------------------------------*- swift -*-===// | |
// | |
// This source file is part of the Swift.org open source project | |
// | |
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors | |
// Licensed under Apache License v2.0 with Runtime Library Exception | |
// | |
// See https://swift.org/LICENSE.txt for license information | |
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | |
// | |
//===----------------------------------------------------------------------===// | |
/// A collection on which normally-eager operations such as `map` and | |
/// `filter` are implemented lazily. | |
/// | |
/// Please see `LazySequenceProtocol` for background; `LazyCollectionProtocol2` | |
/// is an analogous component, but for collections. | |
/// | |
/// To add new lazy collection operations, extend this protocol with | |
/// methods that return lazy wrappers that are themselves | |
/// `LazyCollectionProtocol2`s. | |
public protocol LazyCollectionProtocol2: Collection, LazySequenceProtocol2 { | |
/// A `Collection` that can contain the same elements as this one, | |
/// possibly with a simpler type. | |
/// | |
/// - See also: `elements` | |
associatedtype Elements : Collection = Self | |
} | |
extension LazyCollectionProtocol2 { | |
// Lazy things are already lazy | |
@_inlineable // FIXME(sil-serialize-all) | |
public var lazy2: LazyCollection2<Elements> { | |
return elements.lazy2 | |
} | |
} | |
extension LazyCollectionProtocol2 where Elements: LazyCollectionProtocol2 { | |
// Lazy things are already lazy | |
@_inlineable // FIXME(sil-serialize-all) | |
public var lazy2: Elements { | |
return elements | |
} | |
} | |
/// A collection containing the same elements as a `Base` collection, | |
/// but on which some operations such as `map` and `filter` are | |
/// implemented lazily. | |
/// | |
/// - See also: `LazySequenceProtocol`, `LazyCollection` | |
@_fixed_layout | |
public struct LazyCollection2<Base : Collection> { | |
/// Creates an instance with `base` as its underlying Collection | |
/// instance. | |
@_inlineable | |
@_versioned | |
internal init(_base: Base) { | |
self._base = _base | |
} | |
@_versioned | |
internal var _base: Base | |
} | |
extension LazyCollection2: LazyCollectionProtocol2 { | |
/// The type of the underlying collection. | |
public typealias Elements = Base | |
/// The underlying collection. | |
@_inlineable | |
public var elements: Elements { return _base } | |
} | |
/// Forward implementations to the base collection, to pick up any | |
/// optimizations it might implement. | |
extension LazyCollection2 : Sequence { | |
public typealias Iterator = Base.Iterator | |
/// Returns an iterator over the elements of this sequence. | |
/// | |
/// - Complexity: O(1). | |
@_inlineable | |
public func makeIterator() -> Iterator { | |
return _base.makeIterator() | |
} | |
/// A value less than or equal to the number of elements in the sequence, | |
/// calculated nondestructively. | |
/// | |
/// - Complexity: O(1) if the collection conforms to | |
/// `RandomAccessCollection`; otherwise, O(*n*), where *n* is the length | |
/// of the collection. | |
@_inlineable | |
public var underestimatedCount: Int { return _base.underestimatedCount } | |
@_inlineable | |
public func _copyToContiguousArray() | |
-> ContiguousArray<Base.Iterator.Element> { | |
return _base._copyToContiguousArray() | |
} | |
@_inlineable | |
public func _copyContents( | |
initializing buf: UnsafeMutableBufferPointer<Iterator.Element> | |
) -> (Iterator,UnsafeMutableBufferPointer<Iterator.Element>.Index) { | |
return _base._copyContents(initializing: buf) | |
} | |
@_inlineable | |
public func _customContainsEquatableElement( | |
_ element: Base.Iterator.Element | |
) -> Bool? { | |
return _base._customContainsEquatableElement(element) | |
} | |
} | |
extension LazyCollection2 : 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 Element = Base.Element | |
public typealias Index = Base.Index | |
public typealias Indices = Base.Indices | |
/// The position of the first element in a non-empty collection. | |
/// | |
/// In an empty collection, `startIndex == endIndex`. | |
@_inlineable | |
public var startIndex: Index { return _base.startIndex } | |
/// The collection's "past the end" position---that is, the position one | |
/// greater than the last valid subscript argument. | |
/// | |
/// `endIndex` is always reachable from `startIndex` by zero or more | |
/// applications of `index(after:)`. | |
@_inlineable | |
public var endIndex: Index { return _base.endIndex } | |
@_inlineable | |
public var indices: Indices { return _base.indices } | |
// TODO: swift-3-indexing-model - add docs | |
@_inlineable | |
public func index(after i: Index) -> Index { | |
return _base.index(after: i) | |
} | |
/// Accesses the element at `position`. | |
/// | |
/// - Precondition: `position` is a valid position in `self` and | |
/// `position != endIndex`. | |
@_inlineable | |
public subscript(position: Index) -> Element { | |
return _base[position] | |
} | |
/// A Boolean value indicating whether the collection is empty. | |
@_inlineable | |
public var isEmpty: Bool { | |
return _base.isEmpty | |
} | |
/// Returns the number of elements. | |
/// | |
/// To check whether a collection is empty, use its `isEmpty` property | |
/// instead of comparing `count` to zero. Unless the collection guarantees | |
/// random-access performance, calculating `count` can be an O(*n*) | |
/// operation. | |
/// | |
/// - Complexity: O(1) if `Self` conforms to `RandomAccessCollection`; | |
/// O(*n*) otherwise. | |
@_inlineable | |
public var count: Int { | |
return _base.count | |
} | |
// The following requirement enables dispatching for index(of:) when | |
// the element type is Equatable. | |
/// Returns `Optional(Optional(index))` if an element was found; | |
/// `nil` otherwise. | |
/// | |
/// - Complexity: O(*n*) | |
@_inlineable | |
public func _customIndexOfEquatableElement( | |
_ element: Element | |
) -> Index?? { | |
return _base._customIndexOfEquatableElement(element) | |
} | |
/// Returns the first element of `self`, or `nil` if `self` is empty. | |
@_inlineable | |
public var first: Element? { | |
return _base.first | |
} | |
// TODO: swift-3-indexing-model - add docs | |
@_inlineable | |
public func index(_ i: Index, offsetBy n: Int) -> Index { | |
return _base.index(i, offsetBy: n) | |
} | |
// TODO: swift-3-indexing-model - add docs | |
@_inlineable | |
public func index( | |
_ i: Index, offsetBy n: Int, limitedBy limit: Index | |
) -> Index? { | |
return _base.index(i, offsetBy: n, limitedBy: limit) | |
} | |
// TODO: swift-3-indexing-model - add docs | |
@_inlineable | |
public func distance(from start: Index, to end: Index) -> Int { | |
return _base.distance(from:start, to: end) | |
} | |
} | |
extension LazyCollection2 : BidirectionalCollection | |
where Base : BidirectionalCollection { | |
@_inlineable | |
public func index(before i: Index) -> Index { | |
return _base.index(before: i) | |
} | |
@_inlineable | |
public var last: Element? { | |
return _base.last | |
} | |
} | |
extension LazyCollection2 : RandomAccessCollection | |
where Base : RandomAccessCollection {} | |
/// Augment `self` with lazy methods such as `map`, `filter`, etc. | |
extension Collection { | |
/// A view onto this collection that provides lazy implementations of | |
/// normally eager operations, such as `map` and `filter`. | |
/// | |
/// Use the `lazy` property when chaining operations to prevent | |
/// intermediate operations from allocating storage, or when you only | |
/// need a part of the final collection to avoid unnecessary computation. | |
@_inlineable | |
public var lazy2: LazyCollection2<Self> { | |
return LazyCollection2(_base: self) | |
} | |
} | |
extension Slice: LazySequenceProtocol2 where Base: LazySequenceProtocol2 { } | |
extension Slice: LazyCollectionProtocol2 where Base: LazyCollectionProtocol2 { } | |
extension ReversedCollection: LazySequenceProtocol2 where Base: LazySequenceProtocol2 { } | |
extension ReversedCollection: LazyCollectionProtocol2 where Base: LazyCollectionProtocol2 { } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Note: This is just a copy of the swift stdlib LazySequence.swift with everything renamed | |
//===--- LazySequence.swift -----------------------------------------------===// | |
// | |
// This source file is part of the Swift.org open source project | |
// | |
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors | |
// Licensed under Apache License v2.0 with Runtime Library Exception | |
// | |
// See https://swift.org/LICENSE.txt for license information | |
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | |
// | |
//===----------------------------------------------------------------------===// | |
/// A sequence on which normally-eager operations such as `map` and | |
/// `filter` are implemented lazily. | |
/// | |
/// Lazy sequences can be used to avoid needless storage allocation | |
/// and computation, because they use an underlying sequence for | |
/// storage and compute their elements on demand. For example, | |
/// | |
/// [1, 2, 3].lazy.map { $0 * 2 } | |
/// | |
/// is a sequence containing { `2`, `4`, `6` }. Each time an element | |
/// of the lazy sequence is accessed, an element of the underlying | |
/// array is accessed and transformed by the closure. | |
/// | |
/// Sequence operations taking closure arguments, such as `map` and | |
/// `filter`, are normally eager: they use the closure immediately and | |
/// return a new array. Using the `lazy` property gives the standard | |
/// library explicit permission to store the closure and the sequence | |
/// in the result, and defer computation until it is needed. | |
/// | |
/// To add new lazy sequence operations, extend this protocol with | |
/// methods that return lazy wrappers that are themselves | |
/// `LazySequenceProtocol2`s. For example, given an eager `scan` | |
/// method defined as follows | |
/// | |
/// extension Sequence { | |
/// /// Returns an array containing the results of | |
/// /// | |
/// /// p.reduce(initial, nextPartialResult) | |
/// /// | |
/// /// for each prefix `p` of `self`, in order from shortest to | |
/// /// longest. For example: | |
/// /// | |
/// /// (1..<6).scan(0, +) // [0, 1, 3, 6, 10, 15] | |
/// /// | |
/// /// - Complexity: O(n) | |
/// func scan<ResultElement>( | |
/// _ initial: ResultElement, | |
/// _ nextPartialResult: (ResultElement, Element) -> ResultElement | |
/// ) -> [ResultElement] { | |
/// var result = [initial] | |
/// for x in self { | |
/// result.append(nextPartialResult(result.last!, x)) | |
/// } | |
/// return result | |
/// } | |
/// } | |
/// | |
/// we can build a sequence that lazily computes the elements in the | |
/// result of `scan`: | |
/// | |
/// struct LazyScanIterator<Base : IteratorProtocol, ResultElement> | |
/// : IteratorProtocol { | |
/// mutating func next() -> ResultElement? { | |
/// return nextElement.map { result in | |
/// nextElement = base.next().map { nextPartialResult(result, $0) } | |
/// return result | |
/// } | |
/// } | |
/// private var nextElement: ResultElement? // The next result of next(). | |
/// private var base: Base // The underlying iterator. | |
/// private let nextPartialResult: (ResultElement, Base.Element) -> ResultElement | |
/// } | |
/// | |
/// struct LazyScanSequence<Base: Sequence, ResultElement> | |
/// : LazySequenceProtocol2 // Chained operations on self are lazy, too | |
/// { | |
/// func makeIterator() -> LazyScanIterator<Base.Iterator, ResultElement> { | |
/// return LazyScanIterator( | |
/// nextElement: initial, base: base.makeIterator(), nextPartialResult) | |
/// } | |
/// private let initial: ResultElement | |
/// private let base: Base | |
/// private let nextPartialResult: | |
/// (ResultElement, Base.Element) -> ResultElement | |
/// } | |
/// | |
/// and finally, we can give all lazy sequences a lazy `scan` method: | |
/// | |
/// extension LazySequenceProtocol2 { | |
/// /// Returns a sequence containing the results of | |
/// /// | |
/// /// p.reduce(initial, nextPartialResult) | |
/// /// | |
/// /// for each prefix `p` of `self`, in order from shortest to | |
/// /// longest. For example: | |
/// /// | |
/// /// Array((1..<6).lazy.scan(0, +)) // [0, 1, 3, 6, 10, 15] | |
/// /// | |
/// /// - Complexity: O(1) | |
/// func scan<ResultElement>( | |
/// _ initial: ResultElement, | |
/// _ nextPartialResult: (ResultElement, Element) -> ResultElement | |
/// ) -> LazyScanSequence<Self, ResultElement> { | |
/// return LazyScanSequence( | |
/// initial: initial, base: self, nextPartialResult) | |
/// } | |
/// } | |
/// | |
/// - See also: `LazySequence`, `LazyCollectionProtocol`, `LazyCollection` | |
/// | |
/// - Note: The explicit permission to implement further operations | |
/// lazily applies only in contexts where the sequence is statically | |
/// known to conform to `LazySequenceProtocol2`. Thus, side-effects such | |
/// as the accumulation of `result` below are never unexpectedly | |
/// dropped or deferred: | |
/// | |
/// extension Sequence where Element == Int { | |
/// func sum() -> Int { | |
/// var result = 0 | |
/// _ = self.map { result += $0 } | |
/// return result | |
/// } | |
/// } | |
/// | |
/// [We don't recommend that you use `map` this way, because it | |
/// creates and discards an array. `sum` would be better implemented | |
/// using `reduce`]. | |
public protocol LazySequenceProtocol2 : Sequence { | |
/// A `Sequence` that can contain the same elements as this one, | |
/// possibly with a simpler type. | |
/// | |
/// - See also: `elements` | |
associatedtype Elements : Sequence = Self | |
where Elements.Iterator.Element == Iterator.Element | |
/// A sequence containing the same elements as this one, possibly with | |
/// a simpler type. | |
/// | |
/// When implementing lazy operations, wrapping `elements` instead | |
/// of `self` can prevent result types from growing an extra | |
/// `LazySequence` layer. For example, | |
/// | |
/// _prext_ example needed | |
/// | |
/// Note: this property need not be implemented by conforming types, | |
/// it has a default implementation in a protocol extension that | |
/// just returns `self`. | |
var elements: Elements { get } | |
} | |
/// When there's no special associated `Elements` type, the `elements` | |
/// property is provided. | |
extension LazySequenceProtocol2 where Elements == Self { | |
/// Identical to `self`. | |
@_inlineable // FIXME(sil-serialize-all) | |
public var elements: Self { return self } | |
} | |
extension LazySequenceProtocol2 { | |
@_inlineable // FIXME(sil-serialize-all) | |
public var lazy2: LazySequence2<Elements> { | |
return elements.lazy2 | |
} | |
} | |
extension LazySequenceProtocol2 where Elements: LazySequenceProtocol2 { | |
@_inlineable // FIXME(sil-serialize-all) | |
public var lazy2: Elements { | |
return elements | |
} | |
} | |
/// A sequence containing the same elements as a `Base` sequence, but | |
/// on which some operations such as `map` and `filter` are | |
/// implemented lazily. | |
/// | |
/// - See also: `LazySequenceProtocol2` | |
@_fixed_layout // FIXME(sil-serialize-all) | |
public struct LazySequence2<Base : Sequence>: _SequenceWrapper { | |
public var _base: Base | |
/// Creates a sequence that has the same elements as `base`, but on | |
/// which some operations such as `map` and `filter` are implemented | |
/// lazily. | |
@_inlineable // FIXME(sil-serialize-all) | |
@_versioned // FIXME(sil-serialize-all) | |
internal init(_base: Base) { | |
self._base = _base | |
} | |
} | |
extension LazySequence2: LazySequenceProtocol2 { | |
public typealias Elements = Base | |
/// The `Base` (presumably non-lazy) sequence from which `self` was created. | |
@_inlineable // FIXME(sil-serialize-all) | |
public var elements: Elements { return _base } | |
} | |
extension Sequence { | |
/// A sequence containing the same elements as this sequence, | |
/// but on which some operations, such as `map` and `filter`, are | |
/// implemented lazily. | |
@_inlineable // FIXME(sil-serialize-all) | |
public var lazy2: LazySequence2<Self> { | |
return LazySequence2(_base: self) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Dispatch | |
func benchmark<T>(_ function: () -> T) -> (T, time: Double) { | |
let start = DispatchTime.now() | |
let result = function() | |
let end = DispatchTime.now() | |
return (result, Double(end.uptimeNanoseconds - start.uptimeNanoseconds) / 1_000_000_000) | |
} | |
do { | |
let count = 10000000 | |
let stdlibLazyPart1 = (0..<count).lazy.map({ $0 * $0 }).filter({ $0 % 3 == 0 }) | |
let stdlibLazyPart2 = stdlibLazyPart1.map({ $0 &+ 7 }).filter({ $0 % 5 > 2 }).map(Double.init) | |
let stdlibLazyPart3 = stdlibLazyPart2.map({ $0 * $0 }).map({ $0.significand }).filter({ $0 > 1.1 }) | |
let stdlibLazy = stdlibLazyPart3.map({ $0 * 1000 }).map(Int.init) | |
let newLazyPart1 = (0..<count).lazy2.map({ $0 * $0 }).filter({ $0 % 3 == 0 }) | |
let newLazyPart2 = newLazyPart1.map({ $0 + 7 }).filter({ $0 % 5 > 2 }).map(Double.init) | |
let newLazyPart3 = newLazyPart2.map({ $0 * $0 }).map({ $0.significand }).filter({ $0 > 1.1 }) | |
let newLazy = newLazyPart3.map({ $0 * 1000 }).map(Int.init) | |
func filterFunc(_ num: Int) -> Int? { | |
let a = num * num | |
guard a % 3 == 0 else { return nil } | |
let b = a + 7 | |
guard b % 5 > 2 else { return nil } | |
let c = Double(b) | |
let d = c * c | |
let e = d.significand | |
guard e > 1.1 else { return nil } | |
let f = e * 1000 | |
return Int(f) | |
} | |
// Due to a bug in the swift 4.1+ optimizer this takes way longer, | |
// But it runs as fast as newCompactMap when compiled with the swift 4.0.3 compiler | |
let stdlibCompactMap = (0..<count).lazy.compactMap(filterFunc) | |
let newCompactMap = (0..<count).lazy2.compactMap(filterFunc) | |
let (stdlibLazyResult, stdlibLazyTime) = benchmark { stdlibLazy.reduce(0, +) } | |
let (newLazyResult, newLazyTime) = benchmark { newLazy.reduce(0, +) } | |
let (stdlibCompactMapResult, stdlibCompactMapTime) = benchmark { stdlibCompactMap.reduce(0, +) } | |
let (newCompactMapResult, newCompactMapTime) = benchmark { newCompactMap.reduce(0, +) } | |
let (manualLoopResult, manualLoopTime) = benchmark { () -> Int in | |
var total = 0 | |
for item in 0..<count { | |
if let item = filterFunc(item) { | |
total += item | |
} | |
} | |
return total | |
} | |
print(""" | |
Current Lazy: \(stdlibLazyResult), time: \(stdlibLazyTime)s | |
New Lazy: \(newLazyResult), time: \(newLazyTime)s | |
Current CompactMap: \(stdlibCompactMapResult), time: \(stdlibCompactMapTime)s | |
New CompactMap: \(newCompactMapResult), time: \(newCompactMapTime)s | |
Manual Loop: \(manualLoopResult), time: \(manualLoopTime)s | |
""") | |
print("\nType of Current Lazy:\n\(type(of: stdlibLazy))") | |
print("\nType of New Lazy:\n\(type(of: newLazy))") | |
print("\nType of Current CompactMap:\n\(type(of: stdlibCompactMap))") | |
print("\nType of New CompactMap:\n\(type(of: newCompactMap))") | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Note: This is just a copy of the swift stdlib Map.swift with everything renamed | |
//===--- Map.swift - Lazily map over a Sequence ---------------*- swift -*-===// | |
// | |
// This source file is part of the Swift.org open source project | |
// | |
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors | |
// Licensed under Apache License v2.0 with Runtime Library Exception | |
// | |
// See https://swift.org/LICENSE.txt for license information | |
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | |
// | |
//===----------------------------------------------------------------------===// | |
/// A `Sequence` whose elements consist of those in a `Base` | |
/// `Sequence` passed through a transform function returning `Element`. | |
/// These elements are computed lazily, each time they're read, by | |
/// calling the transform function on a base element. | |
@_fixed_layout | |
public struct LazyMapSequence2<Base : Sequence, Element> { | |
public typealias Elements = LazyMapSequence2 | |
@_versioned | |
internal var _base: Base | |
@_versioned | |
internal let _transform: (Base.Element) -> Element | |
/// Creates an instance with elements `transform(x)` for each element | |
/// `x` of base. | |
@_inlineable | |
@_versioned | |
internal init(_base: Base, transform: @escaping (Base.Element) -> Element) { | |
self._base = _base | |
self._transform = transform | |
} | |
} | |
extension LazyMapSequence2 { | |
@_fixed_layout | |
public struct Iterator { | |
@_versioned | |
internal var _base: Base.Iterator | |
@_versioned | |
internal let _transform: (Base.Element) -> Element | |
@_inlineable | |
public var base: Base.Iterator { return _base } | |
@_inlineable | |
@_versioned | |
internal init( | |
_base: Base.Iterator, | |
_transform: @escaping (Base.Element) -> Element | |
) { | |
self._base = _base | |
self._transform = _transform | |
} | |
} | |
} | |
extension LazyMapSequence2.Iterator: IteratorProtocol, Sequence { | |
/// Advances to the next element and returns it, or `nil` if no next element | |
/// exists. | |
/// | |
/// Once `nil` has been returned, all subsequent calls return `nil`. | |
/// | |
/// - Precondition: `next()` has not been applied to a copy of `self` | |
/// since the copy was made. | |
@_inlineable | |
public mutating func next() -> Element? { | |
return _base.next().map(_transform) | |
} | |
} | |
extension LazyMapSequence2: LazySequenceProtocol2 { | |
/// Returns an iterator over the elements of this sequence. | |
/// | |
/// - Complexity: O(1). | |
@_inlineable | |
public func makeIterator() -> Iterator { | |
return Iterator(_base: _base.makeIterator(), _transform: _transform) | |
} | |
/// A value less than or equal to the number of elements in the sequence, | |
/// calculated nondestructively. | |
/// | |
/// The default implementation returns 0. If you provide your own | |
/// implementation, make sure to compute the value nondestructively. | |
/// | |
/// - Complexity: O(1), except if the sequence also conforms to `Collection`. | |
/// In this case, see the documentation of `Collection.underestimatedCount`. | |
@_inlineable | |
public var underestimatedCount: Int { | |
return _base.underestimatedCount | |
} | |
} | |
/// A `Collection` whose elements consist of those in a `Base` | |
/// `Collection` passed through a transform function returning `Element`. | |
/// These elements are computed lazily, each time they're read, by | |
/// calling the transform function on a base element. | |
@_fixed_layout | |
public struct LazyMapCollection2<Base: Collection, Element> { | |
@_versioned | |
internal var _base: Base | |
@_versioned | |
internal let _transform: (Base.Element) -> Element | |
/// Create an instance with elements `transform(x)` for each element | |
/// `x` of base. | |
@_inlineable | |
@_versioned | |
internal init(_base: Base, transform: @escaping (Base.Element) -> Element) { | |
self._base = _base | |
self._transform = transform | |
} | |
} | |
extension LazyMapCollection2: Sequence { | |
public typealias Iterator = LazyMapSequence2<Base,Element>.Iterator | |
/// Returns an iterator over the elements of this sequence. | |
/// | |
/// - Complexity: O(1). | |
@_inlineable | |
public func makeIterator() -> Iterator { | |
return Iterator(_base: _base.makeIterator(), _transform: _transform) | |
} | |
/// A value less than or equal to the number of elements in the sequence, | |
/// calculated nondestructively. | |
/// | |
/// - Complexity: O(1) if the collection conforms to | |
/// `RandomAccessCollection`; otherwise, O(*n*), where *n* is the length | |
/// of the collection. | |
@_inlineable | |
public var underestimatedCount: Int { | |
return _base.underestimatedCount | |
} | |
} | |
extension LazyMapCollection2: LazyCollectionProtocol2 { | |
public typealias Index = Base.Index | |
public typealias Indices = Base.Indices | |
public typealias SubSequence = LazyMapCollection2<Base.SubSequence, Element> | |
@_inlineable | |
public var startIndex: Base.Index { return _base.startIndex } | |
@_inlineable | |
public var endIndex: Base.Index { return _base.endIndex } | |
@_inlineable | |
public func index(after i: Index) -> Index { return _base.index(after: i) } | |
@_inlineable | |
public func formIndex(after i: inout Index) { _base.formIndex(after: &i) } | |
/// Accesses the element at `position`. | |
/// | |
/// - Precondition: `position` is a valid position in `self` and | |
/// `position != endIndex`. | |
@_inlineable | |
public subscript(position: Base.Index) -> Element { | |
return _transform(_base[position]) | |
} | |
@_inlineable | |
public subscript(bounds: Range<Base.Index>) -> SubSequence { | |
return SubSequence(_base: _base[bounds], transform: _transform) | |
} | |
@_inlineable | |
public var indices: Indices { | |
return _base.indices | |
} | |
/// A Boolean value indicating whether the collection is empty. | |
@_inlineable | |
public var isEmpty: Bool { return _base.isEmpty } | |
/// The number of elements in the collection. | |
/// | |
/// To check whether the collection is empty, use its `isEmpty` property | |
/// instead of comparing `count` to zero. Unless the collection guarantees | |
/// random-access performance, calculating `count` can be an O(*n*) | |
/// operation. | |
/// | |
/// - Complexity: O(1) if `Index` conforms to `RandomAccessIndex`; O(*n*) | |
/// otherwise. | |
@_inlineable | |
public var count: Int { | |
return _base.count | |
} | |
@_inlineable | |
public var first: Element? { return _base.first.map(_transform) } | |
@_inlineable | |
public func index(_ i: Index, offsetBy n: Int) -> Index { | |
return _base.index(i, offsetBy: n) | |
} | |
@_inlineable | |
public func index( | |
_ i: Index, offsetBy n: Int, limitedBy limit: Index | |
) -> Index? { | |
return _base.index(i, offsetBy: n, limitedBy: limit) | |
} | |
@_inlineable | |
public func distance(from start: Index, to end: Index) -> Int { | |
return _base.distance(from: start, to: end) | |
} | |
} | |
extension LazyMapCollection2 : BidirectionalCollection | |
where Base : BidirectionalCollection { | |
/// A value less than or equal to the number of elements in the collection. | |
/// | |
/// - Complexity: O(1) if the collection conforms to | |
/// `RandomAccessCollection`; otherwise, O(*n*), where *n* is the length | |
/// of the collection. | |
@_inlineable | |
public func index(before i: Index) -> Index { return _base.index(before: i) } | |
@_inlineable | |
public func formIndex(before i: inout Index) { | |
_base.formIndex(before: &i) | |
} | |
@_inlineable | |
public var last: Element? { return _base.last.map(_transform) } | |
} | |
extension LazyMapCollection2 : RandomAccessCollection | |
where Base : RandomAccessCollection { } | |
//===--- Support for s.lazy -----------------------------------------------===// | |
extension LazySequenceProtocol2 { | |
/// Returns a `LazyMapSequence2` over this `Sequence`. The elements of | |
/// the result are computed lazily, each time they are read, by | |
/// calling `transform` function on a base element. | |
@_inlineable | |
public func map<U>( | |
_ transform: @escaping (Elements.Element) -> U | |
) -> LazyMapSequence2<Self.Elements, U> { | |
return LazyMapSequence2(_base: self.elements, transform: transform) | |
} | |
} | |
extension LazyCollectionProtocol2 { | |
/// Returns a `LazyMapCollection2` over this `Collection`. The elements of | |
/// the result are computed lazily, each time they are read, by | |
/// calling `transform` function on a base element. | |
@_inlineable | |
public func map<U>( | |
_ transform: @escaping (Elements.Element) -> U | |
) -> LazyMapCollection2<Self.Elements, U> { | |
return LazyMapCollection2(_base: self.elements, transform: transform) | |
} | |
} | |
extension LazyMapCollection2 { | |
// This overload is needed to re-enable Swift 3 source compatibility related | |
// to a bugfix in ranking behavior of the constraint solver. | |
@available(swift, obsoleted: 4.0) | |
public static func + < | |
Other : LazyCollectionProtocol2 | |
>(lhs: LazyMapCollection2, rhs: Other) -> [Element] | |
where Other.Element == Element { | |
var result: [Element] = [] | |
result.reserveCapacity(numericCast(lhs.count + rhs.count)) | |
result.append(contentsOf: lhs) | |
result.append(contentsOf: rhs) | |
return result | |
} | |
} | |
extension LazyMapSequence2 { | |
@_inlineable | |
public func map<ElementOfResult>( | |
_ transform: @escaping (Element) -> ElementOfResult | |
) -> LazyMapSequence2<Base, ElementOfResult> { | |
return LazyMapSequence2<Base, ElementOfResult>( | |
_base: _base, | |
transform: {transform(self._transform($0))}) | |
} | |
} | |
extension LazyMapCollection2 { | |
@_inlineable | |
public func map<ElementOfResult>( | |
_ transform: @escaping (Element) -> ElementOfResult | |
) -> LazyMapCollection2<Base, ElementOfResult> { | |
return LazyMapCollection2<Base, ElementOfResult>( | |
_base: _base, | |
transform: {transform(self._transform($0))}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment