blob: c4774c51ea4d04e782c7cccb180a30b7dc0e361d [file] [log] [blame]
//===--- DropWhile.swift.gyb - Lazy views for drop(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 elements traversed by a base iterator that follow the
/// initial consecutive elements that satisfy a given predicate.
///
/// This is the associated iterator for the `LazyDropWhileSequence`,
/// `LazyDropWhileCollection`, and `LazyDropWhileBidirectionalCollection`
/// types.
public struct LazyDropWhileIterator<Base : IteratorProtocol> :
IteratorProtocol, Sequence {
public mutating func next() -> Base.Element? {
// Once the predicate has failed for the first time, the base iterator
// can be used for the rest of the elements.
if _predicateHasFailed {
return _base.next()
}
// Retrieve and discard elements from the base iterator until one fails
// the predicate.
while let nextElement = _base.next() {
if !_predicate(nextElement) {
_predicateHasFailed = true
return nextElement
}
}
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 elements that follow the initial
/// consecutive elements of some base sequence that satisfy a given predicate.
public struct LazyDropWhileSequence<Base : Sequence> : LazySequenceProtocol {
public typealias Elements = LazyDropWhileSequence
/// Returns an iterator over the elements of this sequence.
///
/// - Complexity: O(1).
public func makeIterator() -> LazyDropWhileIterator<Base.Iterator> {
return LazyDropWhileIterator(
_base: _base.makeIterator(), predicate: _predicate)
}
/// Create an instance with elements `transform(x)` for each element
/// `x` of base.
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 that skips any initial 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 skipped or
/// `false` otherwise. Once `predicate` returns `false` it will not be
/// called again.
public func drop(
while predicate: @escaping (Elements.Element) -> Bool
) -> LazyDropWhileSequence<Self.Elements> {
return LazyDropWhileSequence(_base: self.elements, predicate: predicate)
}
}
//===--- Collections ------------------------------------------------------===//
/// A position in a `LazyDropWhileCollection` or
/// `LazyDropWhileBidirectionalCollection` instance.
public struct LazyDropWhileIndex<Base : Collection> : Comparable {
/// The position corresponding to `self` in the underlying collection.
public let base: Base.Index
public static func == (
lhs: LazyDropWhileIndex, rhs: LazyDropWhileIndex
) -> Bool {
return lhs.base == rhs.base
}
public static func < (
lhs: LazyDropWhileIndex, rhs: LazyDropWhileIndex
) -> Bool {
return lhs.base < rhs.base
}
}
% for Traversal in ['Forward', 'Bidirectional']:
% Collection = collectionForTraversal(Traversal)
% Self = "LazyDropWhile" + Collection
/// A lazy `${Collection}` wrapper that includes the elements of an underlying
/// collection after any initial consecutive elements that satisfy a
/// predicate.
///
/// - Note: The performance of accessing `startIndex`, `first`, or any methods
/// that depend on `startIndex` 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} {
// FIXME(compiler limitation): should be inferable.
public typealias Index = LazyDropWhileIndex<Base>
public var startIndex: Index {
var index = _base.startIndex
while index != _base.endIndex && _predicate(_base[index]) {
_base.formIndex(after: &index)
}
return LazyDropWhileIndex(base: index)
}
public var endIndex: Index {
return LazyDropWhileIndex(base: _base.endIndex)
}
public func index(after i: Index) -> Index {
_precondition(i.base < _base.endIndex, "Can't advance past endIndex")
return LazyDropWhileIndex(base: _base.index(after: i.base))
}
% if Traversal == 'Bidirectional':
public func index(before i: Index) -> Index {
_precondition(i > startIndex, "Can't move before startIndex")
return LazyDropWhileIndex(base: _base.index(before: i.base))
}
% end
public subscript(position: Index) -> Base.Element {
return _base[position.base]
}
public func makeIterator() -> LazyDropWhileIterator<Base.Iterator> {
return LazyDropWhileIterator(
_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 that skips any initial 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 skipped or
/// `false` otherwise. Once `predicate` returns `false` it will not be
/// called again.
public func drop(
while predicate: @escaping (Elements.Element) -> Bool
) -> LazyDropWhile${Collection}<Self.Elements> {
return LazyDropWhile${Collection}(
_base: self.elements, predicate: predicate)
}
}
% end
// ${'Local Variables'}:
// eval: (read-only-mode 1)
// End: