@@ -84,21 +84,28 @@ pub mod internal {
8484 }
8585
8686 /// 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+ }
8891
89- impl < const N : usize > MatchMatrix < N > {
92+ impl MatchMatrix {
9093 pub ( crate ) fn generate <
9194 ' a ,
9295 T : Debug + Copy + ' a ,
9396 ContainerT : Debug + Copy + IntoIterator < Item = T > ,
9497 > (
9598 actual : ContainerT ,
96- expected : & [ Box < dyn Matcher < T > + ' a > ; N ] ,
99+ expected : & [ Box < dyn Matcher < T > + ' a > ] ,
97100 ) -> 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+ } ;
99106 for ( actual_idx, actual) in actual. into_iter ( ) . enumerate ( ) {
100107 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) ;
102109 }
103110 }
104111 matrix
@@ -137,28 +144,34 @@ pub mod internal {
137144 // each expected matches at least one actual.
138145 // This is a necessary condition but not sufficient. But it is faster
139146 // than `find_best_match()`.
140- fn find_unmatchable_elements ( & self ) -> UnmatchableElements < N > {
147+ fn find_unmatchable_elements ( & self ) -> UnmatchableElements {
141148 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 ] ;
144151 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 ( ) ) ;
146153 }
147154 UnmatchableElements { unmatchable_actual, unmatchable_expected }
148155 }
149156
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 ] ;
152159 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,
154165 }
155- UnmatchableElements { unmatchable_actual : vec ! [ false ; N ] , unmatchable_expected }
156166 }
157167
158- fn find_unmatched_actual ( & self ) -> UnmatchableElements < N > {
168+ fn find_unmatched_actual ( & self ) -> UnmatchableElements {
159169 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+ }
162175 }
163176
164177 // Verifies that a full match exists.
@@ -170,16 +183,16 @@ pub mod internal {
170183 // expected nodes. All edges have unit capacity.
171184 //
172185 // 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:
178191 // - An edge from source to each actual element node
179192 // - An edge from each expected element node to sink
180193 // - An edge from each actual element node to each expected element node, if
181194 // 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)`
183196 //
184197 // When the `try_augment(...)` method adds a flow, it sets `actual_match[l] =
185198 // Some(r)` for some nodes l and r. This induces the following changes:
@@ -195,13 +208,13 @@ pub mod internal {
195208 //
196209 // It bears repeating that the flow graph and residual flow graph are
197210 // 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`.
199212 //
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:
205218 //
206219 // actual_match[a] == None or expected_match[actual_match[a].unwrap()] ==
207220 // Some(a)
@@ -225,9 +238,9 @@ pub mod internal {
225238 // "Introduction to Algorithms (Second ed.)", pp. 651-664.
226239 // [2] "Ford-Fulkerson algorithm", Wikipedia,
227240 // '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 ] ;
231244 // Searches the residual flow graph for a path from each actual node to
232245 // the sink in the residual flow graph, and if one is found, add this path
233246 // to the graph.
@@ -241,12 +254,12 @@ pub mod internal {
241254 // need to visit the actual nodes more than once looking for
242255 // augmented paths. The flow is known to be possible or impossible
243256 // by looking at the node once.
244- for actual_idx in 0 ..self . 0 . len ( ) {
257+ for actual_idx in 0 ..self . graph . len ( ) {
245258 assert ! ( actual_match[ actual_idx] . is_none( ) ) ;
246- let mut seen = [ false ; N ] ;
259+ let mut seen = vec ! [ false ; self . expected_len ] ;
247260 self . try_augment ( actual_idx, & mut seen, & mut actual_match, & mut expected_match) ;
248261 }
249- BestMatch ( actual_match)
262+ BestMatch :: new ( actual_match, self . expected_len )
250263 }
251264
252265 // Perform a depth-first search from actual node `actual_idx` to the sink by
@@ -270,15 +283,15 @@ pub mod internal {
270283 fn try_augment (
271284 & self ,
272285 actual_idx : usize ,
273- seen : & mut [ bool ; N ] ,
286+ seen : & mut Vec < bool > ,
274287 actual_match : & mut [ Option < usize > ] ,
275- expected_match : & mut [ Option < usize > ; N ] ,
288+ expected_match : & mut Vec < Option < usize > > ,
276289 ) -> bool {
277- for expected_idx in 0 ..N {
290+ for expected_idx in 0 ..self . expected_len {
278291 if seen[ expected_idx] {
279292 continue ;
280293 }
281- if self . 0 [ actual_idx] [ expected_idx] . is_no_match ( ) {
294+ if self . graph [ actual_idx] [ expected_idx] . is_no_match ( ) {
282295 continue ;
283296 }
284297 // There is an edge between `actual_idx` and `expected_idx`.
@@ -317,15 +330,13 @@ pub mod internal {
317330
318331 /// The list of elements that do not match any element in the corresponding
319332 /// 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 {
324335 unmatchable_actual : Vec < bool > ,
325- unmatchable_expected : [ bool ; N ] ,
336+ unmatchable_expected : Vec < bool > ,
326337 }
327338
328- impl < const N : usize > UnmatchableElements < N > {
339+ impl UnmatchableElements {
329340 fn has_unmatchable_elements ( & self ) -> bool {
330341 self . unmatchable_actual . iter ( ) . any ( |b| * b)
331342 || self . unmatchable_expected . iter ( ) . any ( |b| * b)
@@ -392,16 +403,23 @@ pub mod internal {
392403
393404 /// The representation of a match between actual and expected.
394405 /// 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:
397408 /// * The 0th element in actual matches the 0th element in expected.
398409 /// * The 1st element in actual does not match.
399410 /// * 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+ }
401420
402- impl < const N : usize > BestMatch < N > {
403421 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 ( ) )
405423 }
406424
407425 pub ( crate ) fn is_subset_match ( & self ) -> bool {
@@ -413,22 +431,24 @@ pub mod internal {
413431 }
414432
415433 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) | {
417435 maybe_expected_idx. map ( |expected_idx| ( actual_idx, expected_idx) )
418436 } )
419437 }
420438
421439 fn get_unmatched_actual ( & self ) -> impl Iterator < Item = usize > + ' _ {
422- self . 0
440+ self . actual_match
423441 . iter ( )
424442 . enumerate ( )
425443 . filter ( |& ( _, o) | o. is_none ( ) )
426444 . map ( |( actual_idx, _) | actual_idx)
427445 }
428446
429447 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 ( )
432452 }
433453
434454 pub ( crate ) fn get_explanation <
@@ -438,7 +458,7 @@ pub mod internal {
438458 > (
439459 & self ,
440460 actual : ContainerT ,
441- expected : & [ Box < dyn Matcher < T > + ' a > ; N ] ,
461+ expected : & [ Box < dyn Matcher < T > + ' a > ] ,
442462 requirements : Requirements ,
443463 ) -> Option < Description > {
444464 let actual: Vec < _ > = actual. into_iter ( ) . collect ( ) ;
0 commit comments