@@ -14,20 +14,56 @@ public struct Permutations<Base: Collection> {
14
14
/// The base collection to iterate over for permutations.
15
15
public let base : Base
16
16
17
+ @usableFromInline
17
18
internal let baseCount : Int
18
- internal let countToChoose : Int
19
19
20
+ /// The range of accepted sizes of permutations.
21
+ /// - Note: This may be empty if the attempted range entirely exceeds the
22
+ /// bounds of the size of the `base` collection.
23
+ @usableFromInline
24
+ internal let kRange : Range < Int >
25
+
26
+ /// Initializes a `Permutations` for all permutations of `base` of size `k`.
27
+ /// - Parameters:
28
+ /// - base: The collection to iterate over for permutations
29
+ /// - k: The expected size of each permutation, or `nil` (default) to
30
+ /// iterate over all permutations of the same size as the base collection.
31
+ @usableFromInline
20
32
internal init ( _ base: Base , k: Int ? = nil ) {
33
+ let kRange : ClosedRange < Int > ?
34
+ if let countToChoose = k {
35
+ kRange = countToChoose ... countToChoose
36
+ } else {
37
+ kRange = nil
38
+ }
39
+ self . init ( base, kRange: kRange)
40
+ }
41
+
42
+ /// Initializes a `Permutations` for all combinations of `base` of sizes
43
+ /// within a given range.
44
+ /// - Parameters:
45
+ /// - base: The collection to iterate over for permutations.
46
+ /// - kRange: The range of accepted sizes of permutations, or `nil` to
47
+ /// iterate over all permutations of the same size as the base collection.
48
+ @usableFromInline
49
+ internal init < R: RangeExpression > (
50
+ _ base: Base , kRange: R ?
51
+ ) where R. Bound == Int {
21
52
self . base = base
22
53
let baseCount = base. count
23
54
self . baseCount = baseCount
24
- self . countToChoose = k ?? baseCount
55
+ let upperBound = baseCount + 1
56
+ self . kRange = kRange? . relative ( to: 0 ..< . max)
57
+ . clamped ( to: 0 ..< upperBound) ??
58
+ baseCount ..< upperBound
25
59
}
26
60
61
+ /// The total number of permutations.
62
+ @inlinable
27
63
public var count : Int {
28
- return baseCount >= countToChoose
29
- ? stride ( from: baseCount, to: baseCount - countToChoose , by: - 1 ) . reduce ( 1 , * )
30
- : 0
64
+ return kRange . map {
65
+ stride ( from: baseCount, to: baseCount - $0 , by: - 1 ) . reduce ( 1 , * )
66
+ } . reduce ( 0 , + )
31
67
}
32
68
}
33
69
@@ -38,36 +74,30 @@ extension Permutations: Sequence {
38
74
internal var base : Base
39
75
40
76
@usableFromInline
41
- internal var indexes : [ Base . Index ]
42
- @usableFromInline
43
- internal var hasMorePermutations : Bool
77
+ internal let baseCount : Int
78
+
79
+ /// The current range of accepted sizes of permutations.
80
+ /// - Note: The range is contracted until empty while iterating over
81
+ /// permutations of different sizes. When the range is empty, iteration is
82
+ /// finished.
44
83
@usableFromInline
45
- internal var countToChoose : Int = 0
46
-
47
- /// `true` if we're generating permutations of the full collection.
84
+ internal var kRange : Range < Int >
85
+
86
+ /// Whether or not iteration is finished (`kRange` is empty)
48
87
@usableFromInline
49
- internal var permutesFullCollection : Bool {
50
- countToChoose == indexes . count
88
+ internal var isFinished : Bool {
89
+ return kRange . isEmpty
51
90
}
52
91
53
92
@usableFromInline
54
- internal init ( _ base: Base ) {
55
- self . base = base
56
- self . indexes = Array ( base. indices)
57
- self . countToChoose = self . indexes. count
58
- self . hasMorePermutations = true
59
- }
93
+ internal var indexes : [ Base . Index ]
60
94
61
95
@usableFromInline
62
- internal init ( _ base: Base , count: Int ) {
63
- self . base = base
64
- self . countToChoose = count
65
-
66
- // Produce exactly one empty permutation when `count == 0`.
67
- self . indexes = count == 0 ? [ ] : Array ( base. indices)
68
-
69
- // Can't produce any permutations when `count > base.count`.
70
- self . hasMorePermutations = count <= indexes. count
96
+ internal init ( _ permutations: Permutations ) {
97
+ self . base = permutations. base
98
+ self . baseCount = permutations. baseCount
99
+ self . kRange = permutations. kRange
100
+ self . indexes = Array ( permutations. base. indices)
71
101
}
72
102
73
103
/// Advances the `indexes` array such that the first `countToChoose`
@@ -83,6 +113,7 @@ extension Permutations: Sequence {
83
113
/// - Complexity: O(*n*), where *n* is the length of the collection.
84
114
@usableFromInline
85
115
internal mutating func nextState( ) -> Bool {
116
+ let countToChoose = self . kRange. lowerBound
86
117
let edge = countToChoose - 1
87
118
88
119
// Find first index greater than the one at `edge`.
@@ -113,31 +144,53 @@ extension Permutations: Sequence {
113
144
114
145
@inlinable
115
146
public mutating func next( ) -> [ Base . Element ] ? {
116
- if !hasMorePermutations { return nil }
147
+ guard !isFinished else { return nil }
148
+
149
+ /// Advances `kRange` by incrementing its `lowerBound` until the range is
150
+ /// empty, when iteration is finished.
151
+ func advanceKRange( ) {
152
+ if kRange. lowerBound < kRange. upperBound {
153
+ let advancedLowerBound = kRange. lowerBound + 1
154
+ kRange = advancedLowerBound ..< kRange. upperBound
155
+ indexes = Array ( base. indices)
156
+ }
157
+ }
158
+
159
+ let countToChoose = self . kRange. lowerBound
160
+ if countToChoose == 0 {
161
+ defer {
162
+ advanceKRange ( )
163
+ }
164
+ return [ ]
165
+ }
117
166
167
+ let permutesFullCollection = ( countToChoose == baseCount)
118
168
if permutesFullCollection {
119
169
// If we're permuting the full collection, each iteration is just a
120
170
// call to `nextPermutation` on `indexes`.
121
- defer { hasMorePermutations = indexes. nextPermutation ( ) }
171
+ defer {
172
+ let hasMorePermutations = indexes. nextPermutation ( )
173
+ if !hasMorePermutations {
174
+ advanceKRange ( )
175
+ }
176
+ }
122
177
return indexes. map { base [ $0] }
123
178
} else {
124
179
// Otherwise, return the items at the first `countToChoose` indices and
125
180
// advance the state.
126
- defer { hasMorePermutations = nextState ( ) }
181
+ defer {
182
+ let hasMorePermutations = nextState ( )
183
+ if !hasMorePermutations {
184
+ advanceKRange ( )
185
+ }
186
+ }
127
187
return indexes. prefix ( countToChoose) . map { base [ $0] }
128
188
}
129
189
}
130
190
}
131
191
132
- @usableFromInline
133
- internal var permutesFullCollection : Bool {
134
- baseCount == countToChoose
135
- }
136
-
137
192
public func makeIterator( ) -> Iterator {
138
- permutesFullCollection
139
- ? Iterator ( base)
140
- : Iterator ( base, count: countToChoose)
193
+ Iterator ( self )
141
194
}
142
195
}
143
196
@@ -196,6 +249,13 @@ where Self: BidirectionalCollection, Element: Comparable
196
249
//===----------------------------------------------------------------------===//
197
250
198
251
extension Collection {
252
+ @inlinable
253
+ public func permutations< R: RangeExpression > (
254
+ ofCount kRange: R
255
+ ) -> Permutations < Self > where R. Bound == Int {
256
+ return Permutations ( self , kRange: kRange)
257
+ }
258
+
199
259
/// Returns a collection of the permutations of this collection of the
200
260
/// specified length.
201
261
///
@@ -242,6 +302,7 @@ extension Collection {
242
302
/// of this entire collection.
243
303
///
244
304
/// - Complexity: O(1)
305
+ @inlinable
245
306
public func permutations( ofCount k: Int ? = nil ) -> Permutations < Self > {
246
307
precondition (
247
308
k ?? 0 >= 0 ,
0 commit comments