@@ -2,19 +2,23 @@ use std::cmp::Ordering;
2
2
use std:: iter:: Fuse ;
3
3
use std:: fmt;
4
4
5
+ use either:: Either ;
6
+
5
7
use super :: adaptors:: { PutBack , put_back} ;
6
8
use crate :: either_or_both:: EitherOrBoth ;
9
+ use crate :: size_hint:: { self , SizeHint } ;
7
10
#[ cfg( doc) ]
8
11
use crate :: Itertools ;
9
12
10
13
/// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order.
11
14
///
12
15
/// [`IntoIterator`] enabled version of [`Itertools::merge_join_by`].
13
- pub fn merge_join_by < I , J , F > ( left : I , right : J , cmp_fn : F )
16
+ pub fn merge_join_by < I , J , F , T > ( left : I , right : J , cmp_fn : F )
14
17
-> MergeJoinBy < I :: IntoIter , J :: IntoIter , F >
15
18
where I : IntoIterator ,
16
19
J : IntoIterator ,
17
- F : FnMut ( & I :: Item , & J :: Item ) -> Ordering
20
+ F : FnMut ( & I :: Item , & J :: Item ) -> T ,
21
+ T : OrderingOrBool < I :: Item , J :: Item > ,
18
22
{
19
23
MergeJoinBy {
20
24
left : put_back ( left. into_iter ( ) . fuse ( ) ) ,
@@ -30,7 +34,66 @@ pub fn merge_join_by<I, J, F>(left: I, right: J, cmp_fn: F)
30
34
pub struct MergeJoinBy < I : Iterator , J : Iterator , F > {
31
35
left : PutBack < Fuse < I > > ,
32
36
right : PutBack < Fuse < J > > ,
33
- cmp_fn : F
37
+ cmp_fn : F ,
38
+ }
39
+
40
+ pub trait OrderingOrBool < L , R > {
41
+ type MergeResult ;
42
+ fn left ( left : L ) -> Self :: MergeResult ;
43
+ fn right ( right : R ) -> Self :: MergeResult ;
44
+ // "merge" never returns (Some(...), Some(...), ...) so Option<Either<I::Item, J::Item>>
45
+ // is appealing but it is always followed by two put_backs, so we think the compiler is
46
+ // smart enough to optimize it. Or we could move put_backs into "merge".
47
+ fn merge ( self , left : L , right : R ) -> ( Option < L > , Option < R > , Self :: MergeResult ) ;
48
+ fn size_hint ( left : SizeHint , right : SizeHint ) -> SizeHint ;
49
+ }
50
+
51
+ impl < L , R > OrderingOrBool < L , R > for Ordering {
52
+ type MergeResult = EitherOrBoth < L , R > ;
53
+ fn left ( left : L ) -> Self :: MergeResult {
54
+ EitherOrBoth :: Left ( left)
55
+ }
56
+ fn right ( right : R ) -> Self :: MergeResult {
57
+ EitherOrBoth :: Right ( right)
58
+ }
59
+ fn merge ( self , left : L , right : R ) -> ( Option < L > , Option < R > , Self :: MergeResult ) {
60
+ match self {
61
+ Ordering :: Equal => ( None , None , EitherOrBoth :: Both ( left, right) ) ,
62
+ Ordering :: Less => ( None , Some ( right) , EitherOrBoth :: Left ( left) ) ,
63
+ Ordering :: Greater => ( Some ( left) , None , EitherOrBoth :: Right ( right) ) ,
64
+ }
65
+ }
66
+ fn size_hint ( left : SizeHint , right : SizeHint ) -> SizeHint {
67
+ let ( a_lower, a_upper) = left;
68
+ let ( b_lower, b_upper) = right;
69
+ let lower = :: std:: cmp:: max ( a_lower, b_lower) ;
70
+ let upper = match ( a_upper, b_upper) {
71
+ ( Some ( x) , Some ( y) ) => x. checked_add ( y) ,
72
+ _ => None ,
73
+ } ;
74
+ ( lower, upper)
75
+ }
76
+ }
77
+
78
+ impl < L , R > OrderingOrBool < L , R > for bool {
79
+ type MergeResult = Either < L , R > ;
80
+ fn left ( left : L ) -> Self :: MergeResult {
81
+ Either :: Left ( left)
82
+ }
83
+ fn right ( right : R ) -> Self :: MergeResult {
84
+ Either :: Right ( right)
85
+ }
86
+ fn merge ( self , left : L , right : R ) -> ( Option < L > , Option < R > , Self :: MergeResult ) {
87
+ if self {
88
+ ( None , Some ( right) , Either :: Left ( left) )
89
+ } else {
90
+ ( Some ( left) , None , Either :: Right ( right) )
91
+ }
92
+ }
93
+ fn size_hint ( left : SizeHint , right : SizeHint ) -> SizeHint {
94
+ // Not ExactSizeIterator because size may be larger than usize
95
+ size_hint:: add ( left, right)
96
+ }
34
97
}
35
98
36
99
impl < I , J , F > Clone for MergeJoinBy < I , J , F >
@@ -52,49 +115,34 @@ impl<I, J, F> fmt::Debug for MergeJoinBy<I, J, F>
52
115
debug_fmt_fields ! ( MergeJoinBy , left, right) ;
53
116
}
54
117
55
- impl < I , J , F > Iterator for MergeJoinBy < I , J , F >
118
+ impl < I , J , F , T > Iterator for MergeJoinBy < I , J , F >
56
119
where I : Iterator ,
57
120
J : Iterator ,
58
- F : FnMut ( & I :: Item , & J :: Item ) -> Ordering
121
+ F : FnMut ( & I :: Item , & J :: Item ) -> T ,
122
+ T : OrderingOrBool < I :: Item , J :: Item > ,
59
123
{
60
- type Item = EitherOrBoth < I :: Item , J :: Item > ;
124
+ type Item = T :: MergeResult ;
61
125
62
126
fn next ( & mut self ) -> Option < Self :: Item > {
63
127
match ( self . left . next ( ) , self . right . next ( ) ) {
64
128
( None , None ) => None ,
65
- ( Some ( left) , None ) =>
66
- Some ( EitherOrBoth :: Left ( left) ) ,
67
- ( None , Some ( right) ) =>
68
- Some ( EitherOrBoth :: Right ( right) ) ,
129
+ ( Some ( left) , None ) => Some ( T :: left ( left) ) ,
130
+ ( None , Some ( right) ) => Some ( T :: right ( right) ) ,
69
131
( Some ( left) , Some ( right) ) => {
70
- match ( self . cmp_fn ) ( & left, & right) {
71
- Ordering :: Equal =>
72
- Some ( EitherOrBoth :: Both ( left, right) ) ,
73
- Ordering :: Less => {
74
- self . right . put_back ( right) ;
75
- Some ( EitherOrBoth :: Left ( left) )
76
- } ,
77
- Ordering :: Greater => {
78
- self . left . put_back ( left) ;
79
- Some ( EitherOrBoth :: Right ( right) )
80
- }
132
+ let ( left, right, next) = ( self . cmp_fn ) ( & left, & right) . merge ( left, right) ;
133
+ if let Some ( left) = left {
134
+ self . left . put_back ( left) ;
135
+ }
136
+ if let Some ( right) = right {
137
+ self . right . put_back ( right) ;
81
138
}
139
+ Some ( next)
82
140
}
83
141
}
84
142
}
85
143
86
- fn size_hint ( & self ) -> ( usize , Option < usize > ) {
87
- let ( a_lower, a_upper) = self . left . size_hint ( ) ;
88
- let ( b_lower, b_upper) = self . right . size_hint ( ) ;
89
-
90
- let lower = :: std:: cmp:: max ( a_lower, b_lower) ;
91
-
92
- let upper = match ( a_upper, b_upper) {
93
- ( Some ( x) , Some ( y) ) => x. checked_add ( y) ,
94
- _ => None ,
95
- } ;
96
-
97
- ( lower, upper)
144
+ fn size_hint ( & self ) -> SizeHint {
145
+ T :: size_hint ( self . left . size_hint ( ) , self . right . size_hint ( ) )
98
146
}
99
147
100
148
fn count ( mut self ) -> usize {
@@ -106,10 +154,12 @@ impl<I, J, F> Iterator for MergeJoinBy<I, J, F>
106
154
( None , Some ( _right) ) => break count + 1 + self . right . into_parts ( ) . 1 . count ( ) ,
107
155
( Some ( left) , Some ( right) ) => {
108
156
count += 1 ;
109
- match ( self . cmp_fn ) ( & left, & right) {
110
- Ordering :: Equal => { }
111
- Ordering :: Less => self . right . put_back ( right) ,
112
- Ordering :: Greater => self . left . put_back ( left) ,
157
+ let ( left, right, _) = ( self . cmp_fn ) ( & left, & right) . merge ( left, right) ;
158
+ if let Some ( left) = left {
159
+ self . left . put_back ( left) ;
160
+ }
161
+ if let Some ( right) = right {
162
+ self . right . put_back ( right) ;
113
163
}
114
164
}
115
165
}
@@ -122,27 +172,24 @@ impl<I, J, F> Iterator for MergeJoinBy<I, J, F>
122
172
match ( self . left . next ( ) , self . right . next ( ) ) {
123
173
( None , None ) => break previous_element,
124
174
( Some ( left) , None ) => {
125
- break Some ( EitherOrBoth :: Left (
175
+ break Some ( T :: left (
126
176
self . left . into_parts ( ) . 1 . last ( ) . unwrap_or ( left) ,
127
177
) )
128
178
}
129
179
( None , Some ( right) ) => {
130
- break Some ( EitherOrBoth :: Right (
180
+ break Some ( T :: right (
131
181
self . right . into_parts ( ) . 1 . last ( ) . unwrap_or ( right) ,
132
182
) )
133
183
}
134
184
( Some ( left) , Some ( right) ) => {
135
- previous_element = match ( self . cmp_fn ) ( & left, & right) {
136
- Ordering :: Equal => Some ( EitherOrBoth :: Both ( left, right) ) ,
137
- Ordering :: Less => {
138
- self . right . put_back ( right) ;
139
- Some ( EitherOrBoth :: Left ( left) )
140
- }
141
- Ordering :: Greater => {
142
- self . left . put_back ( left) ;
143
- Some ( EitherOrBoth :: Right ( right) )
144
- }
185
+ let ( left, right, elem) = ( self . cmp_fn ) ( & left, & right) . merge ( left, right) ;
186
+ if let Some ( left) = left {
187
+ self . left . put_back ( left) ;
188
+ }
189
+ if let Some ( right) = right {
190
+ self . right . put_back ( right) ;
145
191
}
192
+ previous_element = Some ( elem) ;
146
193
}
147
194
}
148
195
}
@@ -156,13 +203,17 @@ impl<I, J, F> Iterator for MergeJoinBy<I, J, F>
156
203
n -= 1 ;
157
204
match ( self . left . next ( ) , self . right . next ( ) ) {
158
205
( None , None ) => break None ,
159
- ( Some ( _left) , None ) => break self . left . nth ( n) . map ( EitherOrBoth :: Left ) ,
160
- ( None , Some ( _right) ) => break self . right . nth ( n) . map ( EitherOrBoth :: Right ) ,
161
- ( Some ( left) , Some ( right) ) => match ( self . cmp_fn ) ( & left, & right) {
162
- Ordering :: Equal => { }
163
- Ordering :: Less => self . right . put_back ( right) ,
164
- Ordering :: Greater => self . left . put_back ( left) ,
165
- } ,
206
+ ( Some ( _left) , None ) => break self . left . nth ( n) . map ( T :: left) ,
207
+ ( None , Some ( _right) ) => break self . right . nth ( n) . map ( T :: right) ,
208
+ ( Some ( left) , Some ( right) ) => {
209
+ let ( left, right, _) = ( self . cmp_fn ) ( & left, & right) . merge ( left, right) ;
210
+ if let Some ( left) = left {
211
+ self . left . put_back ( left) ;
212
+ }
213
+ if let Some ( right) = right {
214
+ self . right . put_back ( right) ;
215
+ }
216
+ }
166
217
}
167
218
}
168
219
}
0 commit comments