blob: 73e6a3a97d2d5db846b74805d0b43f3e9e241e89 [file] [log] [blame]
//===-- PrefixWhile.swift.gyb - Lazy views for prefix(while:) -*- 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
//
//===----------------------------------------------------------------------===//
%{
from gyb_stdlib_support import (
TRAVERSALS,
collectionForTraversal
)
}%
//===--- Iterator & Sequence ----------------------------------------------===//
/// An iterator over the initial elements traversed by a base iterator that
/// satisfy a given predicate.
///
/// This is the associated iterator for the `LazyPrefixWhileSequence`,
/// `LazyPrefixWhileCollection`, and `LazyPrefixWhileBidirectionalCollection`
/// types.
public struct LazyPrefixWhileIterator<Base : IteratorProtocol> :
IteratorProtocol, Sequence {
public mutating func next() -> Base.Element? {
// Return elements from the base iterator until one fails the predicate.
if !_predicateHasFailed, let nextElement = _base.next() {
if _predicate(nextElement) {
return nextElement
} else {
_predicateHasFailed = true
}
}
return nil
}
internal init(_base: Base, predicate: @escaping (Base.Element) -> Bool) {
self._base = _base
self._predicate = predicate
}
internal var _predicateHasFailed = false
internal var _base: Base
internal let _predicate: (Base.Element) -> Bool
}
/// A sequence whose elements consist of the initial consecutive elements of
/// some base sequence that satisfy a given predicate.
public struct LazyPrefixWhileSequence<Base : Sequence> : LazySequenceProtocol {
public typealias Elements = LazyPrefixWhileSequence
public func makeIterator() -> LazyPrefixWhileIterator<Base.Iterator> {
return LazyPrefixWhileIterator(
_base: _base.makeIterator(), predicate: _predicate)
}
internal init(_base: Base, predicate: @escaping (Base.Element) -> Bool) {
self._base = _base
self._predicate = predicate
}
internal var _base: Base
internal let _predicate: (Base.Element) -> Bool
}
extension LazySequenceProtocol {
/// Returns a lazy sequence of the initial consecutive elements that satisfy
/// `predicate`.
///
/// - Parameter predicate: A closure that takes an element of the sequence as
/// its argument and returns `true` if the element should be included or
/// `false` otherwise. Once `predicate` returns `false` it will not be
/// called again.
public func prefix(
while predicate: @escaping (Elements.Element) -> Bool
) -> LazyPrefixWhileSequence<Self.Elements> {
return LazyPrefixWhileSequence(_base: self.elements, predicate: predicate)
}
}
//===--- Collections ------------------------------------------------------===//
/// A position in the base collection of a `LazyPrefixWhileCollection` or the
/// end of that collection.
public enum _LazyPrefixWhileIndexRepresentation<Base : Collection> {
case index(Base.Index)
case pastEnd
}
/// A position in a `LazyPrefixWhileCollection` or
/// `LazyPrefixWhileBidirectionalCollection` instance.
public struct LazyPrefixWhileIndex<Base : Collection> : Comparable {
/// The position corresponding to `self` in the underlying collection.
internal let _value: _LazyPrefixWhileIndexRepresentation<Base>
/// Creates a new index wrapper for `i`.
internal init(_ i: Base.Index) {
self._value = .index(i)
}
/// Creates a new index that can represent the `endIndex` of a
/// `LazyPrefixWhileCollection<Base>`. This is not the same as a wrapper
/// around `Base.endIndex`.
internal init(endOf: Base) {
self._value = .pastEnd
}
public static func == (
lhs: LazyPrefixWhileIndex, rhs: LazyPrefixWhileIndex
) -> Bool {
switch (lhs._value, rhs._value) {
case let (.index(l), .index(r)):
return l == r
case (.pastEnd, .pastEnd):
return true
default:
return false
}
}
public static func < (
lhs: LazyPrefixWhileIndex, rhs: LazyPrefixWhileIndex
) -> Bool {
switch (lhs._value, rhs._value) {
case let (.index(l), .index(r)):
return l < r
case (.index, .pastEnd):
return true
default:
return false
}
}
}
% for Traversal in ['Forward', 'Bidirectional']:
% Collection = collectionForTraversal(Traversal)
% Self = "LazyPrefixWhile" + Collection
/// A lazy `${Collection}` wrapper that includes the initial consecutive
/// elements of an underlying collection that satisfy a predicate.
///
/// - Note: The performance of accessing `endIndex`, `last`, any methods that
/// depend on `endIndex`, or moving an index depends on how many elements
/// satisfy the predicate at the start of the collection, and may not offer
/// the usual performance given by the `Collection` protocol. Be aware,
/// therefore, that general operations on `${Self}` instances may not have
/// the documented complexity.
public struct ${Self}<
Base : ${Collection}
> : LazyCollectionProtocol, ${Collection} {
public typealias Index = LazyPrefixWhileIndex<Base>
public var startIndex: Index {
return LazyPrefixWhileIndex(_base.startIndex)
}
public var endIndex: Index {
// If the first element of `_base` satisfies the predicate, there is at
// least one element in the lazy collection: Use the explicit `.pastEnd` index.
if let first = _base.first, _predicate(first) {
return LazyPrefixWhileIndex(endOf: _base)
}
// `_base` is either empty or `_predicate(_base.first!) == false`. In either
// case, the lazy collection is empty, so `endIndex == startIndex`.
return startIndex
}
public func index(after i: Index) -> Index {
_precondition(i != endIndex, "Can't advance past endIndex")
guard case .index(let i) = i._value else {
_preconditionFailure("Invalid index passed to index(after:)")
}
let nextIndex = _base.index(after: i)
guard nextIndex != _base.endIndex && _predicate(_base[nextIndex]) else {
return LazyPrefixWhileIndex(endOf: _base)
}
return LazyPrefixWhileIndex(nextIndex)
}
% if Traversal == 'Bidirectional':
public func index(before i: Index) -> Index {
switch i._value {
case .index(let i):
_precondition(i != _base.startIndex, "Can't move before startIndex")
return LazyPrefixWhileIndex(_base.index(before: i))
case .pastEnd:
// Look for the position of the last element in a non-empty
// prefix(while:) collection by searching forward for a predicate
// failure.
// Safe to assume that `_base.startIndex != _base.endIndex`; if they
// were equal, `_base.startIndex` would be used as the `endIndex` of
// this collection.
_sanityCheck(!_base.isEmpty)
var result = _base.startIndex
while true {
let next = _base.index(after: result)
if next == _base.endIndex || !_predicate(_base[next]) {
break
}
result = next
}
return LazyPrefixWhileIndex(result)
}
}
% end
public subscript(position: Index) -> Base.Element {
switch position._value {
case .index(let i):
return _base[i]
case .pastEnd:
_preconditionFailure("Index out of range")
}
}
public func makeIterator() -> LazyPrefixWhileIterator<Base.Iterator> {
return LazyPrefixWhileIterator(
_base: _base.makeIterator(), predicate: _predicate)
}
internal init(_base: Base, predicate: @escaping (Base.Element) -> Bool) {
self._base = _base
self._predicate = predicate
}
internal var _base: Base
internal let _predicate: (Base.Element) -> Bool
}
extension LazyCollectionProtocol
% if Collection != 'Collection':
where
Self : ${Collection},
Elements : ${Collection}
% end
{
/// Returns a lazy collection of the initial consecutive elements that
/// satisfy `predicate`.
///
/// - Parameter predicate: A closure that takes an element of the collection
/// as its argument and returns `true` if the element should be included
/// or `false` otherwise. Once `predicate` returns `false` it will not be
/// called again.
public func prefix(
while predicate: @escaping (Elements.Element) -> Bool
) -> LazyPrefixWhile${Collection}<Self.Elements> {
return LazyPrefixWhile${Collection}(
_base: self.elements, predicate: predicate)
}
}
% end
// ${'Local Variables'}:
// eval: (read-only-mode 1)
// End: