Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@TellowKrinkle
Last active March 20, 2018 21:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TellowKrinkle/818c8d9ce467f272c889bdd503784d63 to your computer and use it in GitHub Desktop.
Save TellowKrinkle/818c8d9ce467f272c889bdd503784d63 to your computer and use it in GitHub Desktop.
LazyCompactMap
// 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)
}
}
}
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
}
)
}
}
// 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 { }
// 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)
}
}
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))")
}
// 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