use super::noop::NoopConsumer; use super::{IntoParallelIterator, ParallelExtend, ParallelIterator}; use std::borrow::Cow; use std::collections::LinkedList; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::collections::{BinaryHeap, VecDeque}; use std::hash::{BuildHasher, Hash}; /// Performs a generic `par_extend` by collecting to a `LinkedList>` in /// parallel, then extending the collection sequentially. fn extend(collection: &mut C, par_iter: I, reserve: F) where I: IntoParallelIterator, F: FnOnce(&mut C, &LinkedList>), C: Extend, { let list = collect(par_iter); reserve(collection, &list); for vec in list { collection.extend(vec); } } pub(super) fn collect(par_iter: I) -> LinkedList> where I: IntoParallelIterator, { par_iter .into_par_iter() .fold(Vec::new, vec_push) .map(as_list) .reduce(LinkedList::new, list_append) } fn vec_push(mut vec: Vec, elem: T) -> Vec { vec.push(elem); vec } fn as_list(item: T) -> LinkedList { let mut list = LinkedList::new(); list.push_back(item); list } fn list_append(mut list1: LinkedList, mut list2: LinkedList) -> LinkedList { list1.append(&mut list2); list1 } /// Computes the total length of a `LinkedList>`. pub(super) fn len(list: &LinkedList>) -> usize { list.iter().map(Vec::len).sum() } fn no_reserve(_: &mut C, _: &LinkedList>) {} fn heap_reserve(heap: &mut BinaryHeap, list: &LinkedList>) { heap.reserve(len(list)); } /// Extends a binary heap with items from a parallel iterator. impl ParallelExtend for BinaryHeap where T: Ord + Send, { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { extend(self, par_iter, heap_reserve); } } /// Extends a binary heap with copied items from a parallel iterator. impl<'a, T> ParallelExtend<&'a T> for BinaryHeap where T: 'a + Copy + Ord + Send + Sync, { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { extend(self, par_iter, heap_reserve); } } /// Extends a B-tree map with items from a parallel iterator. impl ParallelExtend<(K, V)> for BTreeMap where K: Ord + Send, V: Send, { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { extend(self, par_iter, no_reserve); } } /// Extends a B-tree map with copied items from a parallel iterator. impl<'a, K: 'a, V: 'a> ParallelExtend<(&'a K, &'a V)> for BTreeMap where K: Copy + Ord + Send + Sync, V: Copy + Send + Sync, { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { extend(self, par_iter, no_reserve); } } /// Extends a B-tree set with items from a parallel iterator. impl ParallelExtend for BTreeSet where T: Ord + Send, { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { extend(self, par_iter, no_reserve); } } /// Extends a B-tree set with copied items from a parallel iterator. impl<'a, T> ParallelExtend<&'a T> for BTreeSet where T: 'a + Copy + Ord + Send + Sync, { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { extend(self, par_iter, no_reserve); } } fn map_reserve(map: &mut HashMap, list: &LinkedList>) where K: Eq + Hash, S: BuildHasher, { map.reserve(len(list)); } /// Extends a hash map with items from a parallel iterator. impl ParallelExtend<(K, V)> for HashMap where K: Eq + Hash + Send, V: Send, S: BuildHasher + Send, { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { // See the map_collect benchmarks in rayon-demo for different strategies. extend(self, par_iter, map_reserve); } } /// Extends a hash map with copied items from a parallel iterator. impl<'a, K: 'a, V: 'a, S> ParallelExtend<(&'a K, &'a V)> for HashMap where K: Copy + Eq + Hash + Send + Sync, V: Copy + Send + Sync, S: BuildHasher + Send, { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { extend(self, par_iter, map_reserve); } } fn set_reserve(set: &mut HashSet, list: &LinkedList>) where T: Eq + Hash, S: BuildHasher, { set.reserve(len(list)); } /// Extends a hash set with items from a parallel iterator. impl ParallelExtend for HashSet where T: Eq + Hash + Send, S: BuildHasher + Send, { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { extend(self, par_iter, set_reserve); } } /// Extends a hash set with copied items from a parallel iterator. impl<'a, T, S> ParallelExtend<&'a T> for HashSet where T: 'a + Copy + Eq + Hash + Send + Sync, S: BuildHasher + Send, { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { extend(self, par_iter, set_reserve); } } fn list_push_back(mut list: LinkedList, elem: T) -> LinkedList { list.push_back(elem); list } /// Extends a linked list with items from a parallel iterator. impl ParallelExtend for LinkedList where T: Send, { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { let mut list = par_iter .into_par_iter() .fold(LinkedList::new, list_push_back) .reduce(LinkedList::new, list_append); self.append(&mut list); } } /// Extends a linked list with copied items from a parallel iterator. impl<'a, T> ParallelExtend<&'a T> for LinkedList where T: 'a + Copy + Send + Sync, { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { self.par_extend(par_iter.into_par_iter().cloned()) } } fn string_push(mut string: String, ch: char) -> String { string.push(ch); string } /// Extends a string with characters from a parallel iterator. impl ParallelExtend for String { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { // This is like `extend`, but `Vec` is less efficient to deal // with than `String`, so instead collect to `LinkedList`. let list: LinkedList<_> = par_iter .into_par_iter() .fold(String::new, string_push) .map(as_list) .reduce(LinkedList::new, list_append); self.reserve(list.iter().map(String::len).sum()); self.extend(list) } } /// Extends a string with copied characters from a parallel iterator. impl<'a> ParallelExtend<&'a char> for String { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { self.par_extend(par_iter.into_par_iter().cloned()) } } fn string_reserve>(string: &mut String, list: &LinkedList>) { let len = list.iter().flatten().map(T::as_ref).map(str::len).sum(); string.reserve(len); } /// Extends a string with string slices from a parallel iterator. impl<'a> ParallelExtend<&'a str> for String { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { extend(self, par_iter, string_reserve); } } /// Extends a string with strings from a parallel iterator. impl ParallelExtend for String { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { extend(self, par_iter, string_reserve); } } /// Extends a string with string slices from a parallel iterator. impl<'a> ParallelExtend> for String { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator>, { extend(self, par_iter, string_reserve); } } fn deque_reserve(deque: &mut VecDeque, list: &LinkedList>) { deque.reserve(len(list)); } /// Extends a deque with items from a parallel iterator. impl ParallelExtend for VecDeque where T: Send, { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { extend(self, par_iter, deque_reserve); } } /// Extends a deque with copied items from a parallel iterator. impl<'a, T> ParallelExtend<&'a T> for VecDeque where T: 'a + Copy + Send + Sync, { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { extend(self, par_iter, deque_reserve); } } // See the `collect` module for the `Vec` implementation. // impl ParallelExtend for Vec /// Extends a vector with copied items from a parallel iterator. impl<'a, T> ParallelExtend<&'a T> for Vec where T: 'a + Copy + Send + Sync, { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { self.par_extend(par_iter.into_par_iter().cloned()) } } /// Collapses all unit items from a parallel iterator into one. impl ParallelExtend<()> for () { fn par_extend(&mut self, par_iter: I) where I: IntoParallelIterator, { par_iter.into_par_iter().drive_unindexed(NoopConsumer) } }