blob: e7edb1a4c07da7a834fc969466194a9db0f6911d [file] [log] [blame]
//===--- 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: