| //===--- Filter.swift.gyb -------------------------------------*- swift -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| %{ |
| from gyb_stdlib_support import ( |
| collectionForTraversal, |
| sliceTypeName |
| ) |
| }% |
| |
| /// An iterator over the elements traversed by some base iterator that also |
| /// satisfy a given predicate. |
| /// |
| /// - Note: This is the associated `Iterator` of `LazyFilterSequence` |
| /// and `LazyFilterCollection`. |
| public struct LazyFilterIterator< |
| Base : IteratorProtocol |
| > : 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. |
| public mutating func next() -> Base.Element? { |
| while let n = _base.next() { |
| if _predicate(n) { |
| return n |
| } |
| } |
| return nil |
| } |
| |
| /// Creates an instance that produces the elements `x` of `base` |
| /// for which `isIncluded(x) == true`. |
| internal init( |
| _base: Base, |
| _ isIncluded: @escaping (Base.Element) -> Bool |
| ) { |
| self._base = _base |
| self._predicate = isIncluded |
| } |
| |
| /// The underlying iterator whose elements are being filtered. |
| public var base: Base { return _base } |
| |
| internal var _base: Base |
| |
| /// The predicate used to determine which elements produced by |
| /// `base` are also produced by `self`. |
| internal let _predicate: (Base.Element) -> Bool |
| } |
| |
| /// 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 `LazyFilterSequence`. |
| public struct LazyFilterSequence<Base : Sequence> |
| : LazySequenceProtocol { |
| |
| /// Returns an iterator over the elements of this sequence. |
| /// |
| /// - Complexity: O(1). |
| public func makeIterator() -> LazyFilterIterator<Base.Iterator> { |
| return LazyFilterIterator( |
| _base: base.makeIterator(), _include) |
| } |
| |
| /// Creates an instance consisting of the elements `x` of `base` for |
| /// which `isIncluded(x) == true`. |
| public // @testable |
| init( |
| _base base: Base, |
| _ isIncluded: @escaping (Base.Iterator.Element) -> Bool |
| ) { |
| self.base = base |
| self._include = isIncluded |
| } |
| |
| /// The underlying sequence whose elements are being filtered |
| public let base: Base |
| |
| /// The predicate used to determine which elements of `base` are |
| /// also elements of `self`. |
| internal let _include: (Base.Iterator.Element) -> Bool |
| } |
| |
| /// The `Index` used for subscripting a `LazyFilterCollection`. |
| /// |
| /// The positions of a `LazyFilterIndex` correspond to those positions |
| /// `p` in its underlying collection `c` such that `c[p]` |
| /// satisfies the predicate with which the `LazyFilterIndex` was |
| /// initialized. |
| /// |
| /// - Note: The performance of advancing a `LazyFilterIndex` |
| /// depends on how sparsely the filtering predicate is satisfied, |
| /// and may not offer the usual performance given by models of |
| /// `Collection`. |
| public struct LazyFilterIndex<Base : Collection> { |
| |
| /// The position corresponding to `self` in the underlying collection. |
| public let base: Base.Index |
| } |
| |
| extension LazyFilterIndex : Comparable { |
| public static func == ( |
| lhs: LazyFilterIndex<Base>, |
| rhs: LazyFilterIndex<Base> |
| ) -> Bool { |
| return lhs.base == rhs.base |
| } |
| |
| public static func != ( |
| lhs: LazyFilterIndex<Base>, |
| rhs: LazyFilterIndex<Base> |
| ) -> Bool { |
| return lhs.base != rhs.base |
| } |
| |
| public static func < ( |
| lhs: LazyFilterIndex<Base>, |
| rhs: LazyFilterIndex<Base> |
| ) -> Bool { |
| return lhs.base < rhs.base |
| } |
| |
| public static func <= ( |
| lhs: LazyFilterIndex<Base>, |
| rhs: LazyFilterIndex<Base> |
| ) -> Bool { |
| return lhs.base <= rhs.base |
| } |
| |
| public static func >= ( |
| lhs: LazyFilterIndex<Base>, |
| rhs: LazyFilterIndex<Base> |
| ) -> Bool { |
| return lhs.base >= rhs.base |
| } |
| |
| public static func > ( |
| lhs: LazyFilterIndex<Base>, |
| rhs: LazyFilterIndex<Base> |
| ) -> Bool { |
| return lhs.base > rhs.base |
| } |
| } |
| |
| // FIXME(ABI)(compiler limitation): `LazyFilter*Collection` types should be |
| // collapsed into one `LazyFilterCollection` using conditional conformances. |
| // Maybe even combined with `LazyFilterSequence`. |
| |
| % for Traversal in ['Forward', 'Bidirectional']: |
| % Self = "LazyFilter" + collectionForTraversal(Traversal) |
| % Slice = sliceTypeName(traversal=Traversal, mutable=False, rangeReplaceable=False) |
| |
| /// 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 a `LazyFilterIndex` 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 `LazyFilterCollection` instances may not have the |
| /// documented complexity. |
| public struct ${Self}< |
| Base : ${collectionForTraversal(Traversal)} |
| > : LazyCollectionProtocol, ${collectionForTraversal(Traversal)} { |
| |
| /// 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 = LazyFilterIndex<Base> |
| |
| public typealias IndexDistance = Base.IndexDistance |
| |
| /// Creates an instance containing the elements of `base` that |
| /// satisfy `isIncluded`. |
| public // @testable |
| init( |
| _base: Base, |
| _ isIncluded: @escaping (Base.Iterator.Element) -> Bool |
| ) { |
| self._base = _base |
| self._predicate = isIncluded |
| } |
| |
| /// 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. |
| public var startIndex: Index { |
| var index = _base.startIndex |
| while index != _base.endIndex && !_predicate(_base[index]) { |
| _base.formIndex(after: &index) |
| } |
| return LazyFilterIndex(base: 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:)`. |
| public var endIndex: Index { |
| return LazyFilterIndex(base: _base.endIndex) |
| } |
| |
| // TODO: swift-3-indexing-model - add docs |
| public func index(after i: Index) -> Index { |
| var i = i |
| formIndex(after: &i) |
| return i |
| } |
| |
| public func formIndex(after i: inout Index) { |
| // TODO: swift-3-indexing-model: _failEarlyRangeCheck i? |
| var index = i.base |
| _precondition(index != _base.endIndex, "can't advance past endIndex") |
| repeat { |
| _base.formIndex(after: &index) |
| } while index != _base.endIndex && !_predicate(_base[index]) |
| i = LazyFilterIndex(base: index) |
| } |
| |
| % if Traversal == 'Bidirectional': |
| public func index(before i: Index) -> Index { |
| var i = i |
| formIndex(before: &i) |
| return i |
| } |
| |
| public func formIndex(before i: inout Index) { |
| // TODO: swift-3-indexing-model: _failEarlyRangeCheck i? |
| var index = i.base |
| _precondition(index != _base.startIndex, "can't retreat before startIndex") |
| repeat { |
| _base.formIndex(before: &index) |
| } while !_predicate(_base[index]) |
| i = LazyFilterIndex(base: index) |
| } |
| % end |
| |
| /// Accesses the element at `position`. |
| /// |
| /// - Precondition: `position` is a valid position in `self` and |
| /// `position != endIndex`. |
| public subscript(position: Index) -> Base.Iterator.Element { |
| return _base[position.base] |
| } |
| |
| public subscript(bounds: Range<Index>) -> ${Slice}<${Self}<Base>> { |
| return ${Slice}(base: self, bounds: bounds) |
| } |
| |
| // FIXME(ABI)(compiler limitation): we actually want to add: |
| // |
| // typealias SubSequence = ${Self}<Base.SubSequence> |
| // |
| // so that all slicing optimizations of the base collection can kick in. |
| // |
| // We can't do that right now though, because that would force a lot of |
| // constraints on `Base.SubSequence`, limiting the possible contexts where |
| // the `.lazy.filter` API can be used. |
| |
| /// Returns an iterator over the elements of this sequence. |
| /// |
| /// - Complexity: O(1). |
| public func makeIterator() -> LazyFilterIterator<Base.Iterator> { |
| return LazyFilterIterator( |
| _base: _base.makeIterator(), _predicate) |
| } |
| |
| var _base: Base |
| let _predicate: (Base.Iterator.Element) -> Bool |
| } |
| |
| % end |
| |
| extension LazySequenceProtocol { |
| /// 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. |
| public func filter( |
| _ isIncluded: @escaping (Elements.Iterator.Element) -> Bool |
| ) -> LazyFilterSequence<Self.Elements> { |
| return LazyFilterSequence( |
| _base: self.elements, isIncluded) |
| } |
| } |
| |
| % for Traversal in ['Forward', 'Bidirectional']: |
| |
| extension LazyCollectionProtocol |
| where |
| Self : ${collectionForTraversal(Traversal)}, |
| Elements : ${collectionForTraversal(Traversal)} |
| { |
| /// 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. |
| public func filter( |
| _ isIncluded: @escaping (Elements.Iterator.Element) -> Bool |
| ) -> LazyFilter${collectionForTraversal(Traversal)}<Self.Elements> { |
| return LazyFilter${collectionForTraversal(Traversal)}( |
| _base: self.elements, isIncluded) |
| } |
| } |
| |
| % end |
| |
| @available(*, unavailable, renamed: "LazyFilterIterator") |
| public struct LazyFilterGenerator<Base : IteratorProtocol> {} |
| |
| extension LazyFilterIterator { |
| @available(*, unavailable, message: "use '.lazy.filter' on the sequence") |
| public init( |
| _ base: Base, |
| whereElementsSatisfy predicate: (Base.Element) -> Bool |
| ) { |
| Builtin.unreachable() |
| } |
| } |
| |
| extension LazyFilterSequence { |
| @available(*, unavailable, message: "use '.lazy.filter' on the sequence") |
| public init( |
| _ base: Base, |
| whereElementsSatisfy predicate: (Base.Iterator.Element) -> Bool |
| ) { |
| Builtin.unreachable() |
| } |
| |
| @available(*, unavailable, renamed: "makeIterator()") |
| public func generate() -> LazyFilterIterator<Base.Iterator> { |
| Builtin.unreachable() |
| } |
| } |
| |
| extension LazyFilterCollection { |
| @available(*, unavailable, message: "use '.lazy.filter' on the collection") |
| public init( |
| _ base: Base, |
| whereElementsSatisfy predicate: (Base.Iterator.Element) -> Bool |
| ) { |
| Builtin.unreachable() |
| } |
| |
| @available(*, unavailable, renamed: "makeIterator()") |
| public func generate() -> LazyFilterIterator<Base.Iterator> { |
| Builtin.unreachable() |
| } |
| } |
| |
| // ${'Local Variables'}: |
| // eval: (read-only-mode 1) |
| // End: |