Permalink
Switch branches/tags
4.1-dont-hardcode-numbers-in-objc-block-sil 5.0-dont-hardcode-numbers-in-objc-block-sil Character-test-patch Compare-types-with-equal-equal SR-2545 TensorFlowLite UnicodeEncoding add-swift-libcxx-and-swift-clang-tools-extra add-test-for-asan-compiler-crash anotherdayanothercommit asyncawait bananaphone builtin-int128 cherr42 codable_test_comment_fix core-team-resolution-2017-05-10 dabrahams-append-contentsOf-replaceRange dcci-build-script-backend demangledmepatatino distributed-test dwa-where-clause-cleanup empty-collection-debugPrecondition external-swift-stdlib _fastCStringContents fix-macos-build-runtime fixmeSC generic-typealias-1-lldb gsb-superclass gyb-nested-expand hoist-to-stringprotocol hoist-to-stringprotocol.1 inhibit-implicit-conversions inline-ASCII-grapheme-fastpaths is-swift-bit-5 latest-emacs-fix-fix marcrasi-const-evaluator-part-1 marcrasi-const-evaluator-part-2 marcrasi-const-evaluator-part-3 marcrasi-last-irgen-attrs marcrasi-static-assert master-llvm-swift5-transition master-next master move-debugging-executables-into-its-own-section no-6-figure-benchmarks owned_fix patatinomio pr-66bbf1369684fc75517cfe6a12718d3cdf6a09d6 pr-94ee6e6c6e2d268f47f17dead77e4feb169c24e6 preservesugar rdar-43033749-fix-batch-mode-no-diags-swift-5.0-branch readme-add-tf-gpu remotemirrorsfixmacho remove-narrow-perf-hack revert-12818-cover-model revert-12843-force-on-named-lazy-member-loading revert-13168-large_type_lldb_workaround revert-13438-re-cover-model revert-13597-master revert-14840-concat_thin revert-14846-rdar-37790062-alt revert-15421-disable_autolinkextract revert-15602-deserialize-clang-importer-witness-tables-4.2 revert-16072-disable_failing_test revert-16149-rdar39629937-master revert-16188-assert-metadata-mangled-name-roundtrip revert-17271-DIOptWritePR revert-17370-raj-cp-allargs revert-17668-master revert-18066-sr8022-workaround revert-18156-generalized-accessors revert-18226-42480588 revert-18315-fix-argument-convention revert-18500-swift-syntax-dependency revert-18624-unbreak_unified_linux_builds revert-19006-error-bridging-integer-type revert-19050-revert-19006-error-bridging-integer-type revert-19097-fluctuation-of-the-pupil revert-19130-run-remote-run revert-19138-revert-19130-run-remote-run revert-19202-rework-type-checking-designated-protocol revert-19253-serialize-generic-typealias revert-19300-explicit-implicit-conversion revert-19447-fix-req-diagnstics-not-to-print-special-names revert-19500-updateValue-but-not-the-key revert-19689-keep-sourcekitd-response-alive-while-variant-lives revert-20129-make-nsobject-hashvalue-final revert-20187-another-42247881 revert-20191-revert-20190-rdar45708367 revert-20444-rdar-45659733-5.0 revert-20561-multi-payload-xi revert-20846-swift-5.0-default-to-gold-linker revert-20956-irgen-invariant-load revert-21199-14 rst-to-markdown runtime-fix-swift-error-box-comparison rxwei-patch-1 sequence=collection shahmishal-patch-1 shahmishal/swift-4.2-branch-update shahmishal/test-swift-4.2-branch silgen-tests-should-build-modules silgen-transform-null-context-3.0 stable static-rangereplaceable-plus stdlib-BidirectionalCollection.removeLast stdlib-default-RangeReplaceableCollection.SubSequence-3.0 stdlib-indexing stdlib-manual stdlib-swift4-build substring-views substring swift-2.2-branch swift-2.2-with-migration-attributes swift-2.3-branch swift-3.0-branch swift-3.0-preview-1-branch swift-3.0-preview-2-branch swift-3.0-preview-3-branch swift-3.0-preview-4-branch swift-3.0-preview-5-branch swift-3.0-preview-5-speculative swift-3.0.1-preview-2-branch swift-3.1-branch swift-4.0-branch-04-18-2017 swift-4.0-branch-06-02-2017 swift-4.0-branch-06-23-2017 swift-4.0-branch-07-11-2017 swift-4.0-branch-10-10-2017 swift-4.0-branch swift-4.1-branch swift-4.2-branch-03-26-2018 swift-4.2-branch-04-20-2018 swift-4.2-branch-04-30-2018 swift-4.2-branch-06-11-2018 swift-4.2-branch swift-4.2-xcode-10-beta-5 swift-5.0-branch-10-15-2018 swift-5.0-branch-11-16-2018 swift-5.0-branch-12-12-2018 swift-5.0-branch swift-master-xcode-10-beta-5 swiftstringview-specialization tensorflow-merge tensorflow the-runtime-stands-alone-5 typelist-existential unicode-rethink unioc update-checkout-swift-5
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
273 lines (243 sloc) 8.79 KB
//===-- PrefixWhile.swift - 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
//
//===----------------------------------------------------------------------===//
/// A sequence whose elements consist of the initial consecutive elements of
/// some base sequence that satisfy a given predicate.
@_fixed_layout // lazy-performance
public struct LazyPrefixWhileSequence<Base: Sequence> {
public typealias Element = Base.Element
@inlinable // lazy-performance
internal init(_base: Base, predicate: @escaping (Element) -> Bool) {
self._base = _base
self._predicate = predicate
}
@usableFromInline // lazy-performance
internal var _base: Base
@usableFromInline // lazy-performance
internal let _predicate: (Element) -> Bool
}
extension LazyPrefixWhileSequence {
/// 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.
@_fixed_layout // lazy-performance
public struct Iterator {
public typealias Element = Base.Element
@usableFromInline // lazy-performance
internal var _predicateHasFailed = false
@usableFromInline // lazy-performance
internal var _base: Base.Iterator
@usableFromInline // lazy-performance
internal let _predicate: (Element) -> Bool
@inlinable // lazy-performance
internal init(_base: Base.Iterator, predicate: @escaping (Element) -> Bool) {
self._base = _base
self._predicate = predicate
}
}
}
extension LazyPrefixWhileSequence.Iterator: IteratorProtocol, Sequence {
@inlinable // lazy-performance
public mutating func next() -> 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
}
}
extension LazyPrefixWhileSequence: Sequence {
@inlinable // lazy-performance
public __consuming func makeIterator() -> Iterator {
return Iterator(_base: _base.makeIterator(), predicate: _predicate)
}
}
extension LazyPrefixWhileSequence: LazySequenceProtocol {
public typealias Elements = LazyPrefixWhileSequence
}
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.
@inlinable // lazy-performance
public __consuming func prefix(
while predicate: @escaping (Elements.Element) -> Bool
) -> LazyPrefixWhileSequence<Self.Elements> {
return LazyPrefixWhileSequence(_base: self.elements, predicate: predicate)
}
}
/// 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 typealias LazyPrefixWhileCollection<T: Collection> = LazyPrefixWhileSequence<T>
extension LazyPrefixWhileCollection {
/// A position in the base collection of a `LazyPrefixWhileCollection` or the
/// end of that collection.
@_frozen // lazy-performance
@usableFromInline
internal enum _IndexRepresentation {
case index(Base.Index)
case pastEnd
}
/// A position in a `LazyPrefixWhileCollection` or
/// `LazyPrefixWhileBidirectionalCollection` instance.
@_fixed_layout // lazy-performance
public struct Index {
/// The position corresponding to `self` in the underlying collection.
@usableFromInline // lazy-performance
internal let _value: _IndexRepresentation
/// Creates a new index wrapper for `i`.
@inlinable // lazy-performance
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`.
@inlinable // lazy-performance
internal init(endOf: Base) {
self._value = .pastEnd
}
}
}
// FIXME: should work on the typealias
extension LazyPrefixWhileSequence.Index: Comparable where Base: Collection {
@inlinable // lazy-performance
public static func == (
lhs: LazyPrefixWhileCollection<Base>.Index,
rhs: LazyPrefixWhileCollection<Base>.Index
) -> Bool {
switch (lhs._value, rhs._value) {
case let (.index(l), .index(r)):
return l == r
case (.pastEnd, .pastEnd):
return true
case (.pastEnd, .index), (.index, .pastEnd):
return false
}
}
@inlinable // lazy-performance
public static func < (
lhs: LazyPrefixWhileCollection<Base>.Index,
rhs: LazyPrefixWhileCollection<Base>.Index
) -> Bool {
switch (lhs._value, rhs._value) {
case let (.index(l), .index(r)):
return l < r
case (.index, .pastEnd):
return true
case (.pastEnd, _):
return false
}
}
}
// FIXME: should work on the typealias
extension LazyPrefixWhileSequence.Index: Hashable where Base.Index: Hashable, Base: Collection {
/// Hashes the essential components of this value by feeding them into the
/// given hasher.
///
/// - Parameter hasher: The hasher to use when combining the components
/// of this instance.
@inlinable
public func hash(into hasher: inout Hasher) {
switch _value {
case .index(let value):
hasher.combine(value)
case .pastEnd:
hasher.combine(Int.max)
}
}
}
extension LazyPrefixWhileCollection: Collection {
public typealias SubSequence = Slice<LazyPrefixWhileCollection<Base>>
@inlinable // lazy-performance
public var startIndex: Index {
return Index(_base.startIndex)
}
@inlinable // lazy-performance
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 Index(endOf: _base)
}
// `_base` is either empty or `_predicate(_base.first!) == false`. In either
// case, the lazy collection is empty, so `endIndex == startIndex`.
return startIndex
}
@inlinable // lazy-performance
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 Index(endOf: _base)
}
return Index(nextIndex)
}
@inlinable // lazy-performance
public subscript(position: Index) -> Element {
switch position._value {
case .index(let i):
return _base[i]
case .pastEnd:
_preconditionFailure("Index out of range")
}
}
}
extension LazyPrefixWhileCollection: LazyCollectionProtocol { }
extension LazyPrefixWhileCollection: BidirectionalCollection
where Base: BidirectionalCollection {
@inlinable // lazy-performance
public func index(before i: Index) -> Index {
switch i._value {
case .index(let i):
_precondition(i != _base.startIndex, "Can't move before startIndex")
return Index(_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.
_internalInvariant(!_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 Index(result)
}
}
}