File: UnfoldSequence.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (131 lines) | stat: -rw-r--r-- 5,092 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

/// Returns a sequence formed from `first` and repeated lazy applications of
/// `next`.
///
/// The first element in the sequence is always `first`, and each successive
/// element is the result of invoking `next` with the previous element. The
/// sequence ends when `next` returns `nil`. If `next` never returns `nil`, the
/// sequence is infinite.
///
/// This function can be used to replace many cases that were previously handled
/// using C-style `for` loops.
///
/// Example:
///
///     // Walk the elements of a tree from a node up to the root
///     for node in sequence(first: leaf, next: { $0.parent }) {
///       // node is leaf, then leaf.parent, then leaf.parent.parent, etc.
///     }
///
///     // Iterate over all powers of two (ignoring overflow)
///     for value in sequence(first: 1, next: { $0 * 2 }) {
///       // value is 1, then 2, then 4, then 8, etc.
///     }
///
/// - Parameter first: The first element to be returned from the sequence.
/// - Parameter next: A closure that accepts the previous sequence element and
///   returns the next element.
/// - Returns: A sequence that starts with `first` and continues with every
///   value returned by passing the previous element to `next`.
@inlinable // generic-performance
public func sequence<T>(first: T, next: @escaping (T) -> T?) -> UnfoldFirstSequence<T> {
  // The trivial implementation where the state is the next value to return
  // has the downside of being unnecessarily eager (it evaluates `next` one
  // step in advance). We solve this by using a boolean value to disambiguate
  // between the first value (that's computed in advance) and the rest.
  return sequence(state: (first, true), next: { (state: inout (T?, Bool)) -> T? in
    switch state {
    case (let value, true):
      state.1 = false
      return value
    case (let value?, _):
      let nextValue = next(value)
      state.0 = nextValue
      return nextValue
    case (nil, _):
      return nil
    }
  })
}

/// Returns a sequence formed from repeated lazy applications of `next` to a
/// mutable `state`.
///
/// The elements of the sequence are obtained by invoking `next` with a mutable
/// state. The same state is passed to all invocations of `next`, so subsequent
/// calls will see any mutations made by previous calls. The sequence ends when
/// `next` returns `nil`. If `next` never returns `nil`, the sequence is
/// infinite.
///
/// This function can be used to replace many instances of `AnyIterator` that
/// wrap a closure.
///
/// Example:
///
///     // Interleave two sequences that yield the same element type
///     sequence(state: (false, seq1.makeIterator(), seq2.makeIterator()), next: { iters in
///       iters.0 = !iters.0
///       return iters.0 ? iters.1.next() : iters.2.next()
///     })
///
/// - Parameter state: The initial state that will be passed to the closure.
/// - Parameter next: A closure that accepts an `inout` state and returns the
///   next element of the sequence.
/// - Returns: A sequence that yields each successive value from `next`.
@inlinable // generic-performance
public func sequence<T, State>(state: State, next: @escaping (inout State) -> T?)
  -> UnfoldSequence<T, State> {
  return UnfoldSequence(_state: state, _next: next)
}

/// The return type of `sequence(first:next:)`.
public typealias UnfoldFirstSequence<T> = UnfoldSequence<T, (T?, Bool)>

/// A sequence whose elements are produced via repeated applications of a
/// closure to some mutable state.
///
/// The elements of the sequence are computed lazily and the sequence may
/// potentially be infinite in length.
///
/// Instances of `UnfoldSequence` are created with the functions
/// `sequence(first:next:)` and `sequence(state:next:)`.
@frozen // generic-performance
public struct UnfoldSequence<Element, State>: Sequence, IteratorProtocol {
  @usableFromInline // generic-performance
  internal var _state: State
  @usableFromInline // generic-performance
  internal let _next: (inout State) -> Element?
  @usableFromInline // generic-performance
  internal var _done = false

  @inlinable // generic-performance
  public mutating func next() -> Element? {
    guard !_done else { return nil }
    if let elt = _next(&_state) {
        return elt
    } else {
        _done = true
        return nil
    }
  }

  @inlinable // generic-performance
  internal init(_state: State, _next: @escaping (inout State) -> Element?) {
    self._state = _state
    self._next = _next
  }
}

extension UnfoldSequence: @unchecked Sendable
  where Element: Sendable, State: Sendable {}