-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Zip.swift
155 lines (142 loc) · 5.4 KB
/
Zip.swift
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
/// Creates a sequence of pairs built out of two underlying sequences.
///
/// In the `Zip2Sequence` instance returned by this function, the elements of
/// the *i*th pair are the *i*th elements of each underlying sequence. The
/// following example uses the `zip(_:_:)` function to iterate over an array
/// of strings and a countable range at the same time:
///
/// let words = ["one", "two", "three", "four"]
/// let numbers = 1...4
///
/// for (word, number) in zip(words, numbers) {
/// print("\(word): \(number)")
/// }
/// // Prints "one: 1"
/// // Prints "two: 2
/// // Prints "three: 3"
/// // Prints "four: 4"
///
/// If the two sequences passed to `zip(_:_:)` are different lengths, the
/// resulting sequence is the same length as the shorter sequence. In this
/// example, the resulting array is the same length as `words`:
///
/// let naturalNumbers = 1...Int.max
/// let zipped = Array(zip(words, naturalNumbers))
/// // zipped == [("one", 1), ("two", 2), ("three", 3), ("four", 4)]
///
/// - Parameters:
/// - sequence1: The first sequence or collection to zip.
/// - sequence2: The second sequence or collection to zip.
/// - Returns: A sequence of tuple pairs, where the elements of each pair are
/// corresponding elements of `sequence1` and `sequence2`.
@inlinable // generic-performance
public func zip<Sequence1, Sequence2>(
_ sequence1: Sequence1, _ sequence2: Sequence2
) -> Zip2Sequence<Sequence1, Sequence2> {
return Zip2Sequence(sequence1, sequence2)
}
/// A sequence of pairs built out of two underlying sequences.
///
/// In a `Zip2Sequence` instance, the elements of the *i*th pair are the *i*th
/// elements of each underlying sequence. To create a `Zip2Sequence` instance,
/// use the `zip(_:_:)` function.
///
/// The following example uses the `zip(_:_:)` function to iterate over an
/// array of strings and a countable range at the same time:
///
/// let words = ["one", "two", "three", "four"]
/// let numbers = 1...4
///
/// for (word, number) in zip(words, numbers) {
/// print("\(word): \(number)")
/// }
/// // Prints "one: 1"
/// // Prints "two: 2
/// // Prints "three: 3"
/// // Prints "four: 4"
@frozen // generic-performance
public struct Zip2Sequence<Sequence1: Sequence, Sequence2: Sequence> {
@usableFromInline // generic-performance
internal let _sequence1: Sequence1
@usableFromInline // generic-performance
internal let _sequence2: Sequence2
/// Creates an instance that makes pairs of elements from `sequence1` and
/// `sequence2`.
@inlinable // generic-performance
internal init(_ sequence1: Sequence1, _ sequence2: Sequence2) {
(_sequence1, _sequence2) = (sequence1, sequence2)
}
}
extension Zip2Sequence {
/// An iterator for `Zip2Sequence`.
@frozen // generic-performance
public struct Iterator {
@usableFromInline // generic-performance
internal var _baseStream1: Sequence1.Iterator
@usableFromInline // generic-performance
internal var _baseStream2: Sequence2.Iterator
@usableFromInline // generic-performance
internal var _reachedEnd: Bool = false
/// Creates an instance around a pair of underlying iterators.
@inlinable // generic-performance
internal init(
_ iterator1: Sequence1.Iterator,
_ iterator2: Sequence2.Iterator
) {
(_baseStream1, _baseStream2) = (iterator1, iterator2)
}
}
}
extension Zip2Sequence.Iterator: IteratorProtocol {
/// The type of element returned by `next()`.
public typealias Element = (Sequence1.Element, Sequence2.Element)
/// 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`.
@inlinable // generic-performance
public mutating func next() -> Element? {
// The next() function needs to track if it has reached the end. If we
// didn't, and the first sequence is longer than the second, then when we
// have already exhausted the second sequence, on every subsequent call to
// next() we would consume and discard one additional element from the
// first sequence, even though next() had already returned nil.
if _reachedEnd {
return nil
}
guard let element1 = _baseStream1.next(),
let element2 = _baseStream2.next() else {
_reachedEnd = true
return nil
}
return (element1, element2)
}
}
extension Zip2Sequence: Sequence {
public typealias Element = (Sequence1.Element, Sequence2.Element)
/// Returns an iterator over the elements of this sequence.
@inlinable // generic-performance
public __consuming func makeIterator() -> Iterator {
return Iterator(
_sequence1.makeIterator(),
_sequence2.makeIterator())
}
@inlinable // generic-performance
public var underestimatedCount: Int {
return Swift.min(
_sequence1.underestimatedCount,
_sequence2.underestimatedCount
)
}
}