@@ -84,21 +84,28 @@ pub mod internal {
84
84
}
85
85
86
86
/// The bipartite matching graph between actual and expected elements.
87
- pub ( crate ) struct MatchMatrix < const N : usize > ( Vec < [ MatcherResult ; N ] > ) ;
87
+ pub ( crate ) struct MatchMatrix {
88
+ graph : Vec < Vec < MatcherResult > > , // graph[actual_idx][expected_idx]
89
+ expected_len : usize ,
90
+ }
88
91
89
- impl < const N : usize > MatchMatrix < N > {
92
+ impl MatchMatrix {
90
93
pub ( crate ) fn generate <
91
94
' a ,
92
95
T : Debug + Copy + ' a ,
93
96
ContainerT : Debug + Copy + IntoIterator < Item = T > ,
94
97
> (
95
98
actual : ContainerT ,
96
- expected : & [ Box < dyn Matcher < T > + ' a > ; N ] ,
99
+ expected : & [ Box < dyn Matcher < T > + ' a > ] ,
97
100
) -> Self {
98
- let mut matrix = MatchMatrix ( vec ! [ [ MatcherResult :: NoMatch ; N ] ; count_elements( actual) ] ) ;
101
+ let expected_len = expected. len ( ) ;
102
+ let mut matrix = MatchMatrix {
103
+ graph : vec ! [ vec![ MatcherResult :: NoMatch ; expected_len] ; count_elements( actual) ] ,
104
+ expected_len,
105
+ } ;
99
106
for ( actual_idx, actual) in actual. into_iter ( ) . enumerate ( ) {
100
107
for ( expected_idx, expected) in expected. iter ( ) . enumerate ( ) {
101
- matrix. 0 [ actual_idx] [ expected_idx] = expected. matches ( actual) ;
108
+ matrix. graph [ actual_idx] [ expected_idx] = expected. matches ( actual) ;
102
109
}
103
110
}
104
111
matrix
@@ -137,28 +144,34 @@ pub mod internal {
137
144
// each expected matches at least one actual.
138
145
// This is a necessary condition but not sufficient. But it is faster
139
146
// than `find_best_match()`.
140
- fn find_unmatchable_elements ( & self ) -> UnmatchableElements < N > {
147
+ fn find_unmatchable_elements ( & self ) -> UnmatchableElements {
141
148
let unmatchable_actual =
142
- self . 0 . iter ( ) . map ( |row| row. iter ( ) . all ( |& e| e. is_no_match ( ) ) ) . collect ( ) ;
143
- let mut unmatchable_expected = [ false ; N ] ;
149
+ self . graph . iter ( ) . map ( |row| row. iter ( ) . all ( |& e| e. is_no_match ( ) ) ) . collect ( ) ;
150
+ let mut unmatchable_expected = vec ! [ false ; self . expected_len ] ;
144
151
for ( col_idx, expected) in unmatchable_expected. iter_mut ( ) . enumerate ( ) {
145
- * expected = self . 0 . iter ( ) . map ( |row| row[ col_idx] ) . all ( |e| e. is_no_match ( ) ) ;
152
+ * expected = self . graph . iter ( ) . map ( |row| row[ col_idx] ) . all ( |e| e. is_no_match ( ) ) ;
146
153
}
147
154
UnmatchableElements { unmatchable_actual, unmatchable_expected }
148
155
}
149
156
150
- fn find_unmatched_expected ( & self ) -> UnmatchableElements < N > {
151
- let mut unmatchable_expected = [ false ; N ] ;
157
+ fn find_unmatched_expected ( & self ) -> UnmatchableElements {
158
+ let mut unmatchable_expected = vec ! [ false ; self . expected_len ] ;
152
159
for ( col_idx, expected) in unmatchable_expected. iter_mut ( ) . enumerate ( ) {
153
- * expected = self . 0 . iter ( ) . map ( |row| row[ col_idx] ) . all ( |e| e. is_no_match ( ) ) ;
160
+ * expected = self . graph . iter ( ) . map ( |row| row[ col_idx] ) . all ( |e| e. is_no_match ( ) ) ;
161
+ }
162
+ UnmatchableElements {
163
+ unmatchable_actual : vec ! [ false ; self . expected_len] ,
164
+ unmatchable_expected,
154
165
}
155
- UnmatchableElements { unmatchable_actual : vec ! [ false ; N ] , unmatchable_expected }
156
166
}
157
167
158
- fn find_unmatched_actual ( & self ) -> UnmatchableElements < N > {
168
+ fn find_unmatched_actual ( & self ) -> UnmatchableElements {
159
169
let unmatchable_actual =
160
- self . 0 . iter ( ) . map ( |row| row. iter ( ) . all ( |e| e. is_no_match ( ) ) ) . collect ( ) ;
161
- UnmatchableElements { unmatchable_actual, unmatchable_expected : [ false ; N ] }
170
+ self . graph . iter ( ) . map ( |row| row. iter ( ) . all ( |e| e. is_no_match ( ) ) ) . collect ( ) ;
171
+ UnmatchableElements {
172
+ unmatchable_actual,
173
+ unmatchable_expected : vec ! [ false ; self . expected_len] ,
174
+ }
162
175
}
163
176
164
177
// Verifies that a full match exists.
@@ -170,16 +183,16 @@ pub mod internal {
170
183
// expected nodes. All edges have unit capacity.
171
184
//
172
185
// Neither the flow graph nor the residual flow graph are represented
173
- // explicitly. Instead, they are implied by the information in `self.0 ` and
174
- // the local `actual_match : [Option<usize>; N ]` whose elements are initialized
175
- // to `None`. This represents the initial state of the algorithm,
176
- // where the flow graph is empty, and the residual flow graph has the
177
- // following edges:
186
+ // explicitly. Instead, they are implied by the information in `self.graph ` and
187
+ // the local `actual_match : vec! [Option<usize>; self.expected_len ]` whose
188
+ // elements are initialized to `None`. This represents the initial state
189
+ // of the algorithm, where the flow graph is empty, and the residual
190
+ // flow graph has the following edges:
178
191
// - An edge from source to each actual element node
179
192
// - An edge from each expected element node to sink
180
193
// - An edge from each actual element node to each expected element node, if
181
194
// the actual element matches the expected element, i.e.
182
- // `matches!(self.0 [actual_id][expected_id], Matches)`
195
+ // `matches!(self.graph [actual_id][expected_id], Matches)`
183
196
//
184
197
// When the `try_augment(...)` method adds a flow, it sets `actual_match[l] =
185
198
// Some(r)` for some nodes l and r. This induces the following changes:
@@ -195,13 +208,13 @@ pub mod internal {
195
208
//
196
209
// It bears repeating that the flow graph and residual flow graph are
197
210
// never represented explicitly, but can be derived by looking at the
198
- // information in 'self.0 ' and in `actual_match`.
211
+ // information in 'self.graph ' and in `actual_match`.
199
212
//
200
- // As an optimization, there is a second local `expected_match: [Option<usize>;
201
- // N ]` which does not provide any new information. Instead, it enables
202
- // more efficient queries about edges entering or leaving the expected elements
203
- // nodes of the flow or residual flow graphs. The following invariants
204
- // are maintained:
213
+ // As an optimization, there is a second local `expected_match:
214
+ // vec![Option<usize>; self.expected_len ]` which does not provide any
215
+ // new information. Instead, it enables more efficient queries about
216
+ // edges entering or leaving the expected elements nodes of the flow or
217
+ // residual flow graphs. The following invariants are maintained:
205
218
//
206
219
// actual_match[a] == None or expected_match[actual_match[a].unwrap()] ==
207
220
// Some(a)
@@ -225,9 +238,9 @@ pub mod internal {
225
238
// "Introduction to Algorithms (Second ed.)", pp. 651-664.
226
239
// [2] "Ford-Fulkerson algorithm", Wikipedia,
227
240
// 'http://en.wikipedia.org/wiki/Ford%E2%80%93Fulkerson_algorithm'
228
- pub ( crate ) fn find_best_match ( & self ) -> BestMatch < N > {
229
- let mut actual_match = vec ! [ None ; self . 0 . len( ) ] ;
230
- let mut expected_match: [ Option < usize > ; N ] = [ None ; N ] ;
241
+ pub ( crate ) fn find_best_match ( & self ) -> BestMatch {
242
+ let mut actual_match = vec ! [ None ; self . graph . len( ) ] ;
243
+ let mut expected_match: Vec < Option < usize > > = vec ! [ None ; self . expected_len ] ;
231
244
// Searches the residual flow graph for a path from each actual node to
232
245
// the sink in the residual flow graph, and if one is found, add this path
233
246
// to the graph.
@@ -241,12 +254,12 @@ pub mod internal {
241
254
// need to visit the actual nodes more than once looking for
242
255
// augmented paths. The flow is known to be possible or impossible
243
256
// by looking at the node once.
244
- for actual_idx in 0 ..self . 0 . len ( ) {
257
+ for actual_idx in 0 ..self . graph . len ( ) {
245
258
assert ! ( actual_match[ actual_idx] . is_none( ) ) ;
246
- let mut seen = [ false ; N ] ;
259
+ let mut seen = vec ! [ false ; self . expected_len ] ;
247
260
self . try_augment ( actual_idx, & mut seen, & mut actual_match, & mut expected_match) ;
248
261
}
249
- BestMatch ( actual_match)
262
+ BestMatch :: new ( actual_match, self . expected_len )
250
263
}
251
264
252
265
// Perform a depth-first search from actual node `actual_idx` to the sink by
@@ -270,15 +283,15 @@ pub mod internal {
270
283
fn try_augment (
271
284
& self ,
272
285
actual_idx : usize ,
273
- seen : & mut [ bool ; N ] ,
286
+ seen : & mut Vec < bool > ,
274
287
actual_match : & mut [ Option < usize > ] ,
275
- expected_match : & mut [ Option < usize > ; N ] ,
288
+ expected_match : & mut Vec < Option < usize > > ,
276
289
) -> bool {
277
- for expected_idx in 0 ..N {
290
+ for expected_idx in 0 ..self . expected_len {
278
291
if seen[ expected_idx] {
279
292
continue ;
280
293
}
281
- if self . 0 [ actual_idx] [ expected_idx] . is_no_match ( ) {
294
+ if self . graph [ actual_idx] [ expected_idx] . is_no_match ( ) {
282
295
continue ;
283
296
}
284
297
// There is an edge between `actual_idx` and `expected_idx`.
@@ -317,15 +330,13 @@ pub mod internal {
317
330
318
331
/// The list of elements that do not match any element in the corresponding
319
332
/// set.
320
- /// These lists are represented as fixed sized bit set to avoid
321
- /// allocation.
322
- /// TODO(bjacotg) Use BitArr!(for N) once generic_const_exprs is stable.
323
- pub ( crate ) struct UnmatchableElements < const N : usize > {
333
+ /// TODO - Use BitVec.
334
+ pub ( crate ) struct UnmatchableElements {
324
335
unmatchable_actual : Vec < bool > ,
325
- unmatchable_expected : [ bool ; N ] ,
336
+ unmatchable_expected : Vec < bool > ,
326
337
}
327
338
328
- impl < const N : usize > UnmatchableElements < N > {
339
+ impl UnmatchableElements {
329
340
fn has_unmatchable_elements ( & self ) -> bool {
330
341
self . unmatchable_actual . iter ( ) . any ( |b| * b)
331
342
|| self . unmatchable_expected . iter ( ) . any ( |b| * b)
@@ -392,16 +403,23 @@ pub mod internal {
392
403
393
404
/// The representation of a match between actual and expected.
394
405
/// The value at idx represents to which expected the actual at idx is
395
- /// matched with. For example, `BestMatch([Some(0), None, Some(1)])`
396
- /// means:
406
+ /// matched with. For example, `BestMatch::new ([Some(0), None, Some(1)],
407
+ /// ..)` means:
397
408
/// * The 0th element in actual matches the 0th element in expected.
398
409
/// * The 1st element in actual does not match.
399
410
/// * The 2nd element in actual matches the 1st element in expected.
400
- pub ( crate ) struct BestMatch < const N : usize > ( Vec < Option < usize > > ) ;
411
+ pub ( crate ) struct BestMatch {
412
+ actual_match : Vec < Option < usize > > ,
413
+ expected_len : usize ,
414
+ }
415
+
416
+ impl BestMatch {
417
+ fn new ( actual_match : Vec < Option < usize > > , expected_len : usize ) -> BestMatch {
418
+ BestMatch { actual_match, expected_len }
419
+ }
401
420
402
- impl < const N : usize > BestMatch < N > {
403
421
pub ( crate ) fn is_full_match ( & self ) -> bool {
404
- self . 0 . iter ( ) . all ( |o| o. is_some ( ) )
422
+ self . actual_match . iter ( ) . all ( |o| o. is_some ( ) )
405
423
}
406
424
407
425
pub ( crate ) fn is_subset_match ( & self ) -> bool {
@@ -413,22 +431,24 @@ pub mod internal {
413
431
}
414
432
415
433
fn get_matches ( & self ) -> impl Iterator < Item = ( usize , usize ) > + ' _ {
416
- self . 0 . iter ( ) . enumerate ( ) . filter_map ( |( actual_idx, maybe_expected_idx) | {
434
+ self . actual_match . iter ( ) . enumerate ( ) . filter_map ( |( actual_idx, maybe_expected_idx) | {
417
435
maybe_expected_idx. map ( |expected_idx| ( actual_idx, expected_idx) )
418
436
} )
419
437
}
420
438
421
439
fn get_unmatched_actual ( & self ) -> impl Iterator < Item = usize > + ' _ {
422
- self . 0
440
+ self . actual_match
423
441
. iter ( )
424
442
. enumerate ( )
425
443
. filter ( |& ( _, o) | o. is_none ( ) )
426
444
. map ( |( actual_idx, _) | actual_idx)
427
445
}
428
446
429
447
fn get_unmatched_expected ( & self ) -> Vec < usize > {
430
- let matched_expected: HashSet < _ > = self . 0 . iter ( ) . flatten ( ) . collect ( ) ;
431
- ( 0 ..N ) . filter ( |expected_idx| !matched_expected. contains ( expected_idx) ) . collect ( )
448
+ let matched_expected: HashSet < _ > = self . actual_match . iter ( ) . flatten ( ) . collect ( ) ;
449
+ ( 0 ..self . expected_len )
450
+ . filter ( |expected_idx| !matched_expected. contains ( expected_idx) )
451
+ . collect ( )
432
452
}
433
453
434
454
pub ( crate ) fn get_explanation <
@@ -438,7 +458,7 @@ pub mod internal {
438
458
> (
439
459
& self ,
440
460
actual : ContainerT ,
441
- expected : & [ Box < dyn Matcher < T > + ' a > ; N ] ,
461
+ expected : & [ Box < dyn Matcher < T > + ' a > ] ,
442
462
requirements : Requirements ,
443
463
) -> Option < Description > {
444
464
let actual: Vec < _ > = actual. into_iter ( ) . collect ( ) ;
0 commit comments