Skip to content

Commit 249fbb9

Browse files
committed
Reduce the genericity of extend closures
Most of these closures only need to be generic in the item type, but when created in the context of some `I` generic iterator, they inherit that genericity. This affects both type length and code duplication.
1 parent d2c1424 commit 249fbb9

File tree

3 files changed

+118
-103
lines changed

3 files changed

+118
-103
lines changed

src/iter/collect/mod.rs

+4-19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use super::{IndexedParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator};
2-
use std::collections::LinkedList;
32
use std::slice;
43
use std::sync::atomic::{AtomicUsize, Ordering};
54

@@ -138,24 +137,10 @@ where
138137
}
139138
None => {
140139
// This works like `extend`, but `Vec::append` is more efficient.
141-
let list: LinkedList<_> = par_iter
142-
.fold(Vec::new, |mut vec, elem| {
143-
vec.push(elem);
144-
vec
145-
})
146-
.map(|vec| {
147-
let mut list = LinkedList::new();
148-
list.push_back(vec);
149-
list
150-
})
151-
.reduce(LinkedList::new, |mut list1, mut list2| {
152-
list1.append(&mut list2);
153-
list1
154-
});
155-
156-
self.reserve(list.iter().map(Vec::len).sum());
157-
for mut vec in list {
158-
self.append(&mut vec);
140+
let list = super::extend::collect(par_iter);
141+
self.reserve(super::extend::len(&list));
142+
for ref mut vec in list {
143+
self.append(vec);
159144
}
160145
}
161146
}

src/iter/extend.rs

+95-84
Original file line numberDiff line numberDiff line change
@@ -14,41 +14,49 @@ where
1414
F: FnOnce(&mut C, &LinkedList<Vec<I::Item>>),
1515
C: Extend<I::Item>,
1616
{
17-
let list = par_iter
18-
.into_par_iter()
19-
.fold(Vec::new, |mut vec, elem| {
20-
vec.push(elem);
21-
vec
22-
})
23-
.map(|vec| {
24-
let mut list = LinkedList::new();
25-
list.push_back(vec);
26-
list
27-
})
28-
.reduce(LinkedList::new, |mut list1, mut list2| {
29-
list1.append(&mut list2);
30-
list1
31-
});
32-
17+
let list = collect(par_iter);
3318
reserve(collection, &list);
3419
for vec in list {
3520
collection.extend(vec);
3621
}
3722
}
3823

24+
pub(super) fn collect<I>(par_iter: I) -> LinkedList<Vec<I::Item>>
25+
where
26+
I: IntoParallelIterator,
27+
{
28+
par_iter
29+
.into_par_iter()
30+
.fold(Vec::new, vec_push)
31+
.map(as_list)
32+
.reduce(LinkedList::new, list_append)
33+
}
34+
35+
fn vec_push<T>(mut vec: Vec<T>, elem: T) -> Vec<T> {
36+
vec.push(elem);
37+
vec
38+
}
39+
40+
fn as_list<T>(item: T) -> LinkedList<T> {
41+
let mut list = LinkedList::new();
42+
list.push_back(item);
43+
list
44+
}
45+
46+
fn list_append<T>(mut list1: LinkedList<T>, ref mut list2: LinkedList<T>) -> LinkedList<T> {
47+
list1.append(list2);
48+
list1
49+
}
50+
3951
/// Compute the total length of a `LinkedList<Vec<_>>`.
40-
fn len<T>(list: &LinkedList<Vec<T>>) -> usize {
52+
pub(super) fn len<T>(list: &LinkedList<Vec<T>>) -> usize {
4153
list.iter().map(Vec::len).sum()
4254
}
4355

44-
/// Compute the total string length of a `LinkedList<Vec<AsRef<str>>>`.
45-
fn str_len<T>(list: &LinkedList<Vec<T>>) -> usize
46-
where
47-
T: AsRef<str>,
48-
{
49-
list.iter()
50-
.flat_map(|vec| vec.iter().map(|s| s.as_ref().len()))
51-
.sum()
56+
fn no_reserve<C, T>(_: &mut C, _: &LinkedList<Vec<T>>) {}
57+
58+
fn heap_reserve<T: Ord, U>(heap: &mut BinaryHeap<T>, list: &LinkedList<Vec<U>>) {
59+
heap.reserve(len(list));
5260
}
5361

5462
/// Extend a binary heap with items from a parallel iterator.
@@ -60,7 +68,7 @@ where
6068
where
6169
I: IntoParallelIterator<Item = T>,
6270
{
63-
extend(self, par_iter, |heap, list| heap.reserve(len(list)));
71+
extend(self, par_iter, heap_reserve);
6472
}
6573
}
6674

@@ -73,7 +81,7 @@ where
7381
where
7482
I: IntoParallelIterator<Item = &'a T>,
7583
{
76-
extend(self, par_iter, |heap, list| heap.reserve(len(list)));
84+
extend(self, par_iter, heap_reserve);
7785
}
7886
}
7987

@@ -87,12 +95,12 @@ where
8795
where
8896
I: IntoParallelIterator<Item = (K, V)>,
8997
{
90-
extend(self, par_iter, |_, _| {});
98+
extend(self, par_iter, no_reserve);
9199
}
92100
}
93101

94102
/// Extend a B-tree map with copied items from a parallel iterator.
95-
impl<'a, K, V> ParallelExtend<(&'a K, &'a V)> for BTreeMap<K, V>
103+
impl<'a, K: 'a, V: 'a> ParallelExtend<(&'a K, &'a V)> for BTreeMap<K, V>
96104
where
97105
K: Copy + Ord + Send + Sync,
98106
V: Copy + Send + Sync,
@@ -101,7 +109,7 @@ where
101109
where
102110
I: IntoParallelIterator<Item = (&'a K, &'a V)>,
103111
{
104-
extend(self, par_iter, |_, _| {});
112+
extend(self, par_iter, no_reserve);
105113
}
106114
}
107115

@@ -114,7 +122,7 @@ where
114122
where
115123
I: IntoParallelIterator<Item = T>,
116124
{
117-
extend(self, par_iter, |_, _| {});
125+
extend(self, par_iter, no_reserve);
118126
}
119127
}
120128

@@ -127,10 +135,18 @@ where
127135
where
128136
I: IntoParallelIterator<Item = &'a T>,
129137
{
130-
extend(self, par_iter, |_, _| {});
138+
extend(self, par_iter, no_reserve);
131139
}
132140
}
133141

142+
fn map_reserve<K, V, S, U>(map: &mut HashMap<K, V, S>, list: &LinkedList<Vec<U>>)
143+
where
144+
K: Eq + Hash,
145+
S: BuildHasher,
146+
{
147+
map.reserve(len(list));
148+
}
149+
134150
/// Extend a hash map with items from a parallel iterator.
135151
impl<K, V, S> ParallelExtend<(K, V)> for HashMap<K, V, S>
136152
where
@@ -143,12 +159,12 @@ where
143159
I: IntoParallelIterator<Item = (K, V)>,
144160
{
145161
// See the map_collect benchmarks in rayon-demo for different strategies.
146-
extend(self, par_iter, |map, list| map.reserve(len(list)));
162+
extend(self, par_iter, map_reserve);
147163
}
148164
}
149165

150166
/// Extend a hash map with copied items from a parallel iterator.
151-
impl<'a, K, V, S> ParallelExtend<(&'a K, &'a V)> for HashMap<K, V, S>
167+
impl<'a, K: 'a, V: 'a, S> ParallelExtend<(&'a K, &'a V)> for HashMap<K, V, S>
152168
where
153169
K: Copy + Eq + Hash + Send + Sync,
154170
V: Copy + Send + Sync,
@@ -158,10 +174,18 @@ where
158174
where
159175
I: IntoParallelIterator<Item = (&'a K, &'a V)>,
160176
{
161-
extend(self, par_iter, |map, list| map.reserve(len(list)));
177+
extend(self, par_iter, map_reserve);
162178
}
163179
}
164180

181+
fn set_reserve<T, S, U>(set: &mut HashSet<T, S>, list: &LinkedList<Vec<U>>)
182+
where
183+
T: Eq + Hash,
184+
S: BuildHasher,
185+
{
186+
set.reserve(len(list));
187+
}
188+
165189
/// Extend a hash set with items from a parallel iterator.
166190
impl<T, S> ParallelExtend<T> for HashSet<T, S>
167191
where
@@ -172,7 +196,7 @@ where
172196
where
173197
I: IntoParallelIterator<Item = T>,
174198
{
175-
extend(self, par_iter, |set, list| set.reserve(len(list)));
199+
extend(self, par_iter, set_reserve);
176200
}
177201
}
178202

@@ -186,10 +210,15 @@ where
186210
where
187211
I: IntoParallelIterator<Item = &'a T>,
188212
{
189-
extend(self, par_iter, |set, list| set.reserve(len(list)));
213+
extend(self, par_iter, set_reserve);
190214
}
191215
}
192216

217+
fn list_push_back<T>(mut list: LinkedList<T>, elem: T) -> LinkedList<T> {
218+
list.push_back(elem);
219+
list
220+
}
221+
193222
/// Extend a linked list with items from a parallel iterator.
194223
impl<T> ParallelExtend<T> for LinkedList<T>
195224
where
@@ -201,14 +230,8 @@ where
201230
{
202231
let mut list = par_iter
203232
.into_par_iter()
204-
.fold(LinkedList::new, |mut list, elem| {
205-
list.push_back(elem);
206-
list
207-
})
208-
.reduce(LinkedList::new, |mut list1, mut list2| {
209-
list1.append(&mut list2);
210-
list1
211-
});
233+
.fold(LinkedList::new, list_push_back)
234+
.reduce(LinkedList::new, list_append);
212235
self.append(&mut list);
213236
}
214237
}
@@ -226,6 +249,11 @@ where
226249
}
227250
}
228251

252+
fn string_push(mut string: String, ch: char) -> String {
253+
string.push(ch);
254+
string
255+
}
256+
229257
/// Extend a string with characters from a parallel iterator.
230258
impl ParallelExtend<char> for String {
231259
fn par_extend<I>(&mut self, par_iter: I)
@@ -236,19 +264,9 @@ impl ParallelExtend<char> for String {
236264
// with than `String`, so instead collect to `LinkedList<String>`.
237265
let list: LinkedList<_> = par_iter
238266
.into_par_iter()
239-
.fold(String::new, |mut string, ch| {
240-
string.push(ch);
241-
string
242-
})
243-
.map(|vec| {
244-
let mut list = LinkedList::new();
245-
list.push_back(vec);
246-
list
247-
})
248-
.reduce(LinkedList::new, |mut list1, mut list2| {
249-
list1.append(&mut list2);
250-
list1
251-
});
267+
.fold(String::new, string_push)
268+
.map(as_list)
269+
.reduce(LinkedList::new, list_append);
252270

253271
self.reserve(list.iter().map(String::len).sum());
254272
self.extend(list)
@@ -265,13 +283,23 @@ impl<'a> ParallelExtend<&'a char> for String {
265283
}
266284
}
267285

286+
fn string_reserve<T: AsRef<str>>(string: &mut String, list: &LinkedList<Vec<T>>) {
287+
let len = list
288+
.iter()
289+
.flat_map(|vec| vec)
290+
.map(T::as_ref)
291+
.map(str::len)
292+
.sum();
293+
string.reserve(len);
294+
}
295+
268296
/// Extend a string with string slices from a parallel iterator.
269297
impl<'a> ParallelExtend<&'a str> for String {
270298
fn par_extend<I>(&mut self, par_iter: I)
271299
where
272300
I: IntoParallelIterator<Item = &'a str>,
273301
{
274-
extend(self, par_iter, |string, list| string.reserve(str_len(list)));
302+
extend(self, par_iter, string_reserve);
275303
}
276304
}
277305

@@ -281,7 +309,7 @@ impl ParallelExtend<String> for String {
281309
where
282310
I: IntoParallelIterator<Item = String>,
283311
{
284-
extend(self, par_iter, |string, list| string.reserve(str_len(list)));
312+
extend(self, par_iter, string_reserve);
285313
}
286314
}
287315

@@ -291,31 +319,14 @@ impl<'a> ParallelExtend<Cow<'a, str>> for String {
291319
where
292320
I: IntoParallelIterator<Item = Cow<'a, str>>,
293321
{
294-
// This is like `extend`, but `Extend<Cow<'a, str>> for String`
295-
// wasn't added until Rust 1.19, so we can't use it directly yet.
296-
let list = par_iter
297-
.into_par_iter()
298-
.fold(Vec::new, |mut vec, elem| {
299-
vec.push(elem);
300-
vec
301-
})
302-
.map(|vec| {
303-
let mut list = LinkedList::new();
304-
list.push_back(vec);
305-
list
306-
})
307-
.reduce(LinkedList::new, |mut list1, mut list2| {
308-
list1.append(&mut list2);
309-
list1
310-
});
311-
312-
self.reserve(str_len(&list));
313-
for vec in list {
314-
self.extend(vec.iter().map(|cow| &**cow));
315-
}
322+
extend(self, par_iter, string_reserve);
316323
}
317324
}
318325

326+
fn deque_reserve<T, U>(deque: &mut VecDeque<T>, list: &LinkedList<Vec<U>>) {
327+
deque.reserve(len(list));
328+
}
329+
319330
/// Extend a deque with items from a parallel iterator.
320331
impl<T> ParallelExtend<T> for VecDeque<T>
321332
where
@@ -325,7 +336,7 @@ where
325336
where
326337
I: IntoParallelIterator<Item = T>,
327338
{
328-
extend(self, par_iter, |deque, list| deque.reserve(len(list)));
339+
extend(self, par_iter, deque_reserve);
329340
}
330341
}
331342

@@ -338,7 +349,7 @@ where
338349
where
339350
I: IntoParallelIterator<Item = &'a T>,
340351
{
341-
extend(self, par_iter, |deque, list| deque.reserve(len(list)));
352+
extend(self, par_iter, deque_reserve);
342353
}
343354
}
344355

0 commit comments

Comments
 (0)