build(rust): vendor rnix parser crate
This commit was merged in pull request #57.
This commit is contained in:
6
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/mod.rs
vendored
Normal file
6
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/mod.rs
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#[cfg(feature = "rayon")]
|
||||
pub(crate) mod rayon;
|
||||
#[cfg(feature = "rkyv")]
|
||||
mod rkyv;
|
||||
#[cfg(feature = "serde")]
|
||||
mod serde;
|
||||
27
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/helpers.rs
vendored
Normal file
27
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/helpers.rs
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
use alloc::collections::LinkedList;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
|
||||
/// Helper for collecting parallel iterators to an intermediary
|
||||
#[allow(clippy::linkedlist)] // yes, we need linked list here for efficient appending!
|
||||
pub(super) fn collect<I: IntoParallelIterator>(iter: I) -> (LinkedList<Vec<I::Item>>, usize) {
|
||||
let list = iter
|
||||
.into_par_iter()
|
||||
.fold(Vec::new, |mut vec, elem| {
|
||||
vec.push(elem);
|
||||
vec
|
||||
})
|
||||
.map(|vec| {
|
||||
let mut list = LinkedList::new();
|
||||
list.push_back(vec);
|
||||
list
|
||||
})
|
||||
.reduce(LinkedList::new, |mut list1, mut list2| {
|
||||
list1.append(&mut list2);
|
||||
list1
|
||||
});
|
||||
|
||||
let len = list.iter().map(Vec::len).sum();
|
||||
(list, len)
|
||||
}
|
||||
721
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/map.rs
vendored
Normal file
721
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/map.rs
vendored
Normal file
@@ -0,0 +1,721 @@
|
||||
//! Rayon extensions for `HashMap`.
|
||||
|
||||
use super::raw::{RawIntoParIter, RawParDrain, RawParIter};
|
||||
use crate::hash_map::HashMap;
|
||||
use crate::raw::{Allocator, Global};
|
||||
use core::fmt;
|
||||
use core::hash::{BuildHasher, Hash};
|
||||
use core::marker::PhantomData;
|
||||
use rayon::iter::plumbing::UnindexedConsumer;
|
||||
use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator};
|
||||
|
||||
/// Parallel iterator over shared references to entries in a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_iter`] method on [`HashMap`]
|
||||
/// (provided by the [`IntoParallelRefIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_iter`]: /hashbrown/struct.HashMap.html#method.par_iter
|
||||
/// [`HashMap`]: /hashbrown/struct.HashMap.html
|
||||
/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html
|
||||
pub struct ParIter<'a, K, V> {
|
||||
inner: RawParIter<(K, V)>,
|
||||
marker: PhantomData<(&'a K, &'a V)>,
|
||||
}
|
||||
|
||||
impl<'a, K: Sync, V: Sync> ParallelIterator for ParIter<'a, K, V> {
|
||||
type Item = (&'a K, &'a V);
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner
|
||||
.map(|x| unsafe {
|
||||
let r = x.as_ref();
|
||||
(&r.0, &r.1)
|
||||
})
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Clone for ParIter<'_, K, V> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: self.inner.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: fmt::Debug + Eq + Hash, V: fmt::Debug> fmt::Debug for ParIter<'_, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let iter = unsafe { self.inner.iter() }.map(|x| unsafe {
|
||||
let r = x.as_ref();
|
||||
(&r.0, &r.1)
|
||||
});
|
||||
f.debug_list().entries(iter).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over shared references to keys in a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_keys`] method on [`HashMap`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_keys`]: /hashbrown/struct.HashMap.html#method.par_keys
|
||||
/// [`HashMap`]: /hashbrown/struct.HashMap.html
|
||||
pub struct ParKeys<'a, K, V> {
|
||||
inner: RawParIter<(K, V)>,
|
||||
marker: PhantomData<(&'a K, &'a V)>,
|
||||
}
|
||||
|
||||
impl<'a, K: Sync, V: Sync> ParallelIterator for ParKeys<'a, K, V> {
|
||||
type Item = &'a K;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner
|
||||
.map(|x| unsafe { &x.as_ref().0 })
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Clone for ParKeys<'_, K, V> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: self.inner.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: fmt::Debug + Eq + Hash, V> fmt::Debug for ParKeys<'_, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().0 });
|
||||
f.debug_list().entries(iter).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over shared references to values in a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_values`] method on [`HashMap`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_values`]: /hashbrown/struct.HashMap.html#method.par_values
|
||||
/// [`HashMap`]: /hashbrown/struct.HashMap.html
|
||||
pub struct ParValues<'a, K, V> {
|
||||
inner: RawParIter<(K, V)>,
|
||||
marker: PhantomData<(&'a K, &'a V)>,
|
||||
}
|
||||
|
||||
impl<'a, K: Sync, V: Sync> ParallelIterator for ParValues<'a, K, V> {
|
||||
type Item = &'a V;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner
|
||||
.map(|x| unsafe { &x.as_ref().1 })
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Clone for ParValues<'_, K, V> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: self.inner.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Eq + Hash, V: fmt::Debug> fmt::Debug for ParValues<'_, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().1 });
|
||||
f.debug_list().entries(iter).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over mutable references to entries in a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_iter_mut`] method on [`HashMap`]
|
||||
/// (provided by the [`IntoParallelRefMutIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_iter_mut`]: /hashbrown/struct.HashMap.html#method.par_iter_mut
|
||||
/// [`HashMap`]: /hashbrown/struct.HashMap.html
|
||||
/// [`IntoParallelRefMutIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefMutIterator.html
|
||||
pub struct ParIterMut<'a, K, V> {
|
||||
inner: RawParIter<(K, V)>,
|
||||
marker: PhantomData<(&'a K, &'a mut V)>,
|
||||
}
|
||||
|
||||
impl<'a, K: Sync, V: Send> ParallelIterator for ParIterMut<'a, K, V> {
|
||||
type Item = (&'a K, &'a mut V);
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner
|
||||
.map(|x| unsafe {
|
||||
let r = x.as_mut();
|
||||
(&r.0, &mut r.1)
|
||||
})
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: fmt::Debug + Eq + Hash, V: fmt::Debug> fmt::Debug for ParIterMut<'_, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ParIter {
|
||||
inner: self.inner.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over mutable references to values in a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_values_mut`] method on [`HashMap`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_values_mut`]: /hashbrown/struct.HashMap.html#method.par_values_mut
|
||||
/// [`HashMap`]: /hashbrown/struct.HashMap.html
|
||||
pub struct ParValuesMut<'a, K, V> {
|
||||
inner: RawParIter<(K, V)>,
|
||||
marker: PhantomData<(&'a K, &'a mut V)>,
|
||||
}
|
||||
|
||||
impl<'a, K: Sync, V: Send> ParallelIterator for ParValuesMut<'a, K, V> {
|
||||
type Item = &'a mut V;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner
|
||||
.map(|x| unsafe { &mut x.as_mut().1 })
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Eq + Hash, V: fmt::Debug> fmt::Debug for ParValuesMut<'_, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ParValues {
|
||||
inner: self.inner.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over entries of a consumed map.
|
||||
///
|
||||
/// This iterator is created by the [`into_par_iter`] method on [`HashMap`]
|
||||
/// (provided by the [`IntoParallelIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`into_par_iter`]: /hashbrown/struct.HashMap.html#method.into_par_iter
|
||||
/// [`HashMap`]: /hashbrown/struct.HashMap.html
|
||||
/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html
|
||||
pub struct IntoParIter<K, V, A: Allocator = Global> {
|
||||
inner: RawIntoParIter<(K, V), A>,
|
||||
}
|
||||
|
||||
impl<K: Send, V: Send, A: Allocator + Send> ParallelIterator for IntoParIter<K, V, A> {
|
||||
type Item = (K, V);
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: fmt::Debug + Eq + Hash, V: fmt::Debug, A: Allocator> fmt::Debug for IntoParIter<K, V, A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ParIter {
|
||||
inner: unsafe { self.inner.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel draining iterator over entries of a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_drain`] method on [`HashMap`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_drain`]: /hashbrown/struct.HashMap.html#method.par_drain
|
||||
/// [`HashMap`]: /hashbrown/struct.HashMap.html
|
||||
pub struct ParDrain<'a, K, V, A: Allocator = Global> {
|
||||
inner: RawParDrain<'a, (K, V), A>,
|
||||
}
|
||||
|
||||
impl<K: Send, V: Send, A: Allocator + Sync> ParallelIterator for ParDrain<'_, K, V, A> {
|
||||
type Item = (K, V);
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: fmt::Debug + Eq + Hash, V: fmt::Debug, A: Allocator> fmt::Debug for ParDrain<'_, K, V, A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ParIter {
|
||||
inner: unsafe { self.inner.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Sync, V: Sync, S, A: Allocator> HashMap<K, V, S, A> {
|
||||
/// Visits (potentially in parallel) immutably borrowed keys in an arbitrary order.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_keys(&self) -> ParKeys<'_, K, V> {
|
||||
ParKeys {
|
||||
inner: unsafe { self.table.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Visits (potentially in parallel) immutably borrowed values in an arbitrary order.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_values(&self) -> ParValues<'_, K, V> {
|
||||
ParValues {
|
||||
inner: unsafe { self.table.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Send, V: Send, S, A: Allocator> HashMap<K, V, S, A> {
|
||||
/// Visits (potentially in parallel) mutably borrowed values in an arbitrary order.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V> {
|
||||
ParValuesMut {
|
||||
inner: unsafe { self.table.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes (potentially in parallel) all values in an arbitrary order,
|
||||
/// while preserving the map's allocated memory for reuse.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_drain(&mut self) -> ParDrain<'_, K, V, A> {
|
||||
ParDrain {
|
||||
inner: self.table.par_drain(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, S, A> HashMap<K, V, S, A>
|
||||
where
|
||||
K: Eq + Hash + Sync,
|
||||
V: PartialEq + Sync,
|
||||
S: BuildHasher + Sync,
|
||||
A: Allocator + Sync,
|
||||
{
|
||||
/// Returns `true` if the map is equal to another,
|
||||
/// i.e. both maps contain the same keys mapped to the same values.
|
||||
///
|
||||
/// This method runs in a potentially parallel fashion.
|
||||
pub fn par_eq(&self, other: &Self) -> bool {
|
||||
self.len() == other.len()
|
||||
&& self
|
||||
.into_par_iter()
|
||||
.all(|(key, value)| other.get(key).map_or(false, |v| *value == *v))
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Send, V: Send, S, A: Allocator + Send> IntoParallelIterator for HashMap<K, V, S, A> {
|
||||
type Item = (K, V);
|
||||
type Iter = IntoParIter<K, V, A>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
IntoParIter {
|
||||
inner: self.table.into_par_iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Sync, V: Sync, S, A: Allocator> IntoParallelIterator for &'a HashMap<K, V, S, A> {
|
||||
type Item = (&'a K, &'a V);
|
||||
type Iter = ParIter<'a, K, V>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
ParIter {
|
||||
inner: unsafe { self.table.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Sync, V: Send, S, A: Allocator> IntoParallelIterator for &'a mut HashMap<K, V, S, A> {
|
||||
type Item = (&'a K, &'a mut V);
|
||||
type Iter = ParIterMut<'a, K, V>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
ParIterMut {
|
||||
inner: unsafe { self.table.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect (key, value) pairs from a parallel iterator into a
|
||||
/// hashmap. If multiple pairs correspond to the same key, then the
|
||||
/// ones produced earlier in the parallel iterator will be
|
||||
/// overwritten, just as with a sequential iterator.
|
||||
impl<K, V, S> FromParallelIterator<(K, V)> for HashMap<K, V, S, Global>
|
||||
where
|
||||
K: Eq + Hash + Send,
|
||||
V: Send,
|
||||
S: BuildHasher + Default,
|
||||
{
|
||||
fn from_par_iter<P>(par_iter: P) -> Self
|
||||
where
|
||||
P: IntoParallelIterator<Item = (K, V)>,
|
||||
{
|
||||
let mut map = HashMap::default();
|
||||
map.par_extend(par_iter);
|
||||
map
|
||||
}
|
||||
}
|
||||
|
||||
/// Extend a hash map with items from a parallel iterator.
|
||||
impl<K, V, S, A> ParallelExtend<(K, V)> for HashMap<K, V, S, A>
|
||||
where
|
||||
K: Eq + Hash + Send,
|
||||
V: Send,
|
||||
S: BuildHasher,
|
||||
A: Allocator,
|
||||
{
|
||||
fn par_extend<I>(&mut self, par_iter: I)
|
||||
where
|
||||
I: IntoParallelIterator<Item = (K, V)>,
|
||||
{
|
||||
extend(self, par_iter);
|
||||
}
|
||||
}
|
||||
|
||||
/// Extend a hash map with copied items from a parallel iterator.
|
||||
impl<'a, K, V, S, A> ParallelExtend<(&'a K, &'a V)> for HashMap<K, V, S, A>
|
||||
where
|
||||
K: Copy + Eq + Hash + Sync,
|
||||
V: Copy + Sync,
|
||||
S: BuildHasher,
|
||||
A: Allocator,
|
||||
{
|
||||
fn par_extend<I>(&mut self, par_iter: I)
|
||||
where
|
||||
I: IntoParallelIterator<Item = (&'a K, &'a V)>,
|
||||
{
|
||||
extend(self, par_iter);
|
||||
}
|
||||
}
|
||||
|
||||
// This is equal to the normal `HashMap` -- no custom advantage.
|
||||
fn extend<K, V, S, A, I>(map: &mut HashMap<K, V, S, A>, par_iter: I)
|
||||
where
|
||||
K: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
I: IntoParallelIterator,
|
||||
A: Allocator,
|
||||
HashMap<K, V, S, A>: Extend<I::Item>,
|
||||
{
|
||||
let (list, len) = super::helpers::collect(par_iter);
|
||||
|
||||
// Keys may be already present or show multiple times in the iterator.
|
||||
// Reserve the entire length if the map is empty.
|
||||
// Otherwise reserve half the length (rounded up), so the map
|
||||
// will only resize twice in the worst case.
|
||||
let reserve = if map.is_empty() { len } else { (len + 1) / 2 };
|
||||
map.reserve(reserve);
|
||||
for vec in list {
|
||||
map.extend(vec);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_par_map {
|
||||
use alloc::vec::Vec;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::hash_map::HashMap;
|
||||
|
||||
struct Dropable<'a> {
|
||||
k: usize,
|
||||
counter: &'a AtomicUsize,
|
||||
}
|
||||
|
||||
impl Dropable<'_> {
|
||||
fn new(k: usize, counter: &AtomicUsize) -> Dropable<'_> {
|
||||
counter.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
Dropable { k, counter }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Dropable<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.counter.fetch_sub(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Dropable<'_> {
|
||||
fn clone(&self) -> Self {
|
||||
Dropable::new(self.k, self.counter)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Dropable<'_> {
|
||||
fn hash<H>(&self, state: &mut H)
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
self.k.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Dropable<'_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.k == other.k
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Dropable<'_> {}
|
||||
|
||||
#[test]
|
||||
fn test_into_iter_drops() {
|
||||
let key = AtomicUsize::new(0);
|
||||
let value = AtomicUsize::new(0);
|
||||
|
||||
let hm = {
|
||||
let mut hm = HashMap::new();
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 0);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 0);
|
||||
|
||||
for i in 0..100 {
|
||||
let d1 = Dropable::new(i, &key);
|
||||
let d2 = Dropable::new(i + 100, &value);
|
||||
hm.insert(d1, d2);
|
||||
}
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 100);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 100);
|
||||
|
||||
hm
|
||||
};
|
||||
|
||||
// By the way, ensure that cloning doesn't screw up the dropping.
|
||||
drop(hm.clone());
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 100);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 100);
|
||||
|
||||
// Ensure that dropping the iterator does not leak anything.
|
||||
drop(hm.clone().into_par_iter());
|
||||
|
||||
{
|
||||
assert_eq!(key.load(Ordering::Relaxed), 100);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 100);
|
||||
|
||||
// retain only half
|
||||
let _v: Vec<_> = hm.into_par_iter().filter(|(key, _)| key.k < 50).collect();
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 50);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 50);
|
||||
};
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 0);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_drain_drops() {
|
||||
let key = AtomicUsize::new(0);
|
||||
let value = AtomicUsize::new(0);
|
||||
|
||||
let mut hm = {
|
||||
let mut hm = HashMap::new();
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 0);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 0);
|
||||
|
||||
for i in 0..100 {
|
||||
let d1 = Dropable::new(i, &key);
|
||||
let d2 = Dropable::new(i + 100, &value);
|
||||
hm.insert(d1, d2);
|
||||
}
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 100);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 100);
|
||||
|
||||
hm
|
||||
};
|
||||
|
||||
// By the way, ensure that cloning doesn't screw up the dropping.
|
||||
drop(hm.clone());
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 100);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 100);
|
||||
|
||||
// Ensure that dropping the drain iterator does not leak anything.
|
||||
drop(hm.clone().par_drain());
|
||||
|
||||
{
|
||||
assert_eq!(key.load(Ordering::Relaxed), 100);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 100);
|
||||
|
||||
// retain only half
|
||||
let _v: Vec<_> = hm.drain().filter(|(key, _)| key.k < 50).collect();
|
||||
assert!(hm.is_empty());
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 50);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 50);
|
||||
};
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 0);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_iter() {
|
||||
let mut m: HashMap<isize, bool> = HashMap::new();
|
||||
assert_eq!(m.par_drain().count(), 0);
|
||||
assert_eq!(m.par_keys().count(), 0);
|
||||
assert_eq!(m.par_values().count(), 0);
|
||||
assert_eq!(m.par_values_mut().count(), 0);
|
||||
assert_eq!(m.par_iter().count(), 0);
|
||||
assert_eq!(m.par_iter_mut().count(), 0);
|
||||
assert_eq!(m.len(), 0);
|
||||
assert!(m.is_empty());
|
||||
assert_eq!(m.into_par_iter().count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterate() {
|
||||
let mut m = HashMap::with_capacity(4);
|
||||
for i in 0..32 {
|
||||
assert!(m.insert(i, i * 2).is_none());
|
||||
}
|
||||
assert_eq!(m.len(), 32);
|
||||
|
||||
let observed = AtomicUsize::new(0);
|
||||
|
||||
m.par_iter().for_each(|(k, v)| {
|
||||
assert_eq!(*v, *k * 2);
|
||||
observed.fetch_or(1 << *k, Ordering::Relaxed);
|
||||
});
|
||||
assert_eq!(observed.into_inner(), 0xFFFF_FFFF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keys() {
|
||||
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
|
||||
let map: HashMap<_, _> = vec.into_par_iter().collect();
|
||||
let keys: Vec<_> = map.par_keys().cloned().collect();
|
||||
assert_eq!(keys.len(), 3);
|
||||
assert!(keys.contains(&1));
|
||||
assert!(keys.contains(&2));
|
||||
assert!(keys.contains(&3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_values() {
|
||||
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
|
||||
let map: HashMap<_, _> = vec.into_par_iter().collect();
|
||||
let values: Vec<_> = map.par_values().cloned().collect();
|
||||
assert_eq!(values.len(), 3);
|
||||
assert!(values.contains(&'a'));
|
||||
assert!(values.contains(&'b'));
|
||||
assert!(values.contains(&'c'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_values_mut() {
|
||||
let vec = vec![(1, 1), (2, 2), (3, 3)];
|
||||
let mut map: HashMap<_, _> = vec.into_par_iter().collect();
|
||||
map.par_values_mut().for_each(|value| *value *= 2);
|
||||
let values: Vec<_> = map.par_values().cloned().collect();
|
||||
assert_eq!(values.len(), 3);
|
||||
assert!(values.contains(&2));
|
||||
assert!(values.contains(&4));
|
||||
assert!(values.contains(&6));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eq() {
|
||||
let mut m1 = HashMap::new();
|
||||
m1.insert(1, 2);
|
||||
m1.insert(2, 3);
|
||||
m1.insert(3, 4);
|
||||
|
||||
let mut m2 = HashMap::new();
|
||||
m2.insert(1, 2);
|
||||
m2.insert(2, 3);
|
||||
|
||||
assert!(!m1.par_eq(&m2));
|
||||
|
||||
m2.insert(3, 4);
|
||||
|
||||
assert!(m1.par_eq(&m2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_iter() {
|
||||
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
|
||||
|
||||
let map: HashMap<_, _> = xs.par_iter().cloned().collect();
|
||||
|
||||
for &(k, v) in &xs {
|
||||
assert_eq!(map.get(&k), Some(&v));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extend_ref() {
|
||||
let mut a = HashMap::new();
|
||||
a.insert(1, "one");
|
||||
let mut b = HashMap::new();
|
||||
b.insert(2, "two");
|
||||
b.insert(3, "three");
|
||||
|
||||
a.par_extend(&b);
|
||||
|
||||
assert_eq!(a.len(), 3);
|
||||
assert_eq!(a[&1], "one");
|
||||
assert_eq!(a[&2], "two");
|
||||
assert_eq!(a[&3], "three");
|
||||
}
|
||||
}
|
||||
5
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/mod.rs
vendored
Normal file
5
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/mod.rs
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
mod helpers;
|
||||
pub(crate) mod map;
|
||||
pub(crate) mod raw;
|
||||
pub(crate) mod set;
|
||||
pub(crate) mod table;
|
||||
230
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/raw.rs
vendored
Normal file
230
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/raw.rs
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
use crate::raw::Bucket;
|
||||
use crate::raw::{Allocator, Global, RawIter, RawIterRange, RawTable};
|
||||
use crate::scopeguard::guard;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem;
|
||||
use core::ptr::NonNull;
|
||||
use rayon::iter::{
|
||||
plumbing::{self, Folder, UnindexedConsumer, UnindexedProducer},
|
||||
ParallelIterator,
|
||||
};
|
||||
|
||||
/// Parallel iterator which returns a raw pointer to every full bucket in the table.
|
||||
pub struct RawParIter<T> {
|
||||
iter: RawIterRange<T>,
|
||||
}
|
||||
|
||||
impl<T> RawParIter<T> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub(super) unsafe fn iter(&self) -> RawIterRange<T> {
|
||||
self.iter.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for RawParIter<T> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
iter: self.iter.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<RawIter<T>> for RawParIter<T> {
|
||||
fn from(it: RawIter<T>) -> Self {
|
||||
RawParIter { iter: it.iter }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ParallelIterator for RawParIter<T> {
|
||||
type Item = Bucket<T>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
let producer = ParIterProducer { iter: self.iter };
|
||||
plumbing::bridge_unindexed(producer, consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Producer which returns a `Bucket<T>` for every element.
|
||||
struct ParIterProducer<T> {
|
||||
iter: RawIterRange<T>,
|
||||
}
|
||||
|
||||
impl<T> UnindexedProducer for ParIterProducer<T> {
|
||||
type Item = Bucket<T>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn split(self) -> (Self, Option<Self>) {
|
||||
let (left, right) = self.iter.split();
|
||||
let left = ParIterProducer { iter: left };
|
||||
let right = right.map(|right| ParIterProducer { iter: right });
|
||||
(left, right)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn fold_with<F>(self, folder: F) -> F
|
||||
where
|
||||
F: Folder<Self::Item>,
|
||||
{
|
||||
folder.consume_iter(self.iter)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator which consumes a table and returns elements.
|
||||
pub struct RawIntoParIter<T, A: Allocator = Global> {
|
||||
table: RawTable<T, A>,
|
||||
}
|
||||
|
||||
impl<T, A: Allocator> RawIntoParIter<T, A> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub(super) unsafe fn par_iter(&self) -> RawParIter<T> {
|
||||
self.table.par_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator + Send> ParallelIterator for RawIntoParIter<T, A> {
|
||||
type Item = T;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
let iter = unsafe { self.table.iter().iter };
|
||||
let _guard = guard(self.table.into_allocation(), |alloc| {
|
||||
if let Some((ptr, layout, ref alloc)) = *alloc {
|
||||
unsafe {
|
||||
alloc.deallocate(ptr, layout);
|
||||
}
|
||||
}
|
||||
});
|
||||
let producer = ParDrainProducer { iter };
|
||||
plumbing::bridge_unindexed(producer, consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator which consumes elements without freeing the table storage.
|
||||
pub struct RawParDrain<'a, T, A: Allocator = Global> {
|
||||
// We don't use a &'a mut RawTable<T> because we want RawParDrain to be
|
||||
// covariant over T.
|
||||
table: NonNull<RawTable<T, A>>,
|
||||
marker: PhantomData<&'a RawTable<T, A>>,
|
||||
}
|
||||
|
||||
unsafe impl<T: Send, A: Allocator> Send for RawParDrain<'_, T, A> {}
|
||||
|
||||
impl<T, A: Allocator> RawParDrain<'_, T, A> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub(super) unsafe fn par_iter(&self) -> RawParIter<T> {
|
||||
self.table.as_ref().par_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator> ParallelIterator for RawParDrain<'_, T, A> {
|
||||
type Item = T;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
let _guard = guard(self.table, |table| unsafe {
|
||||
table.as_mut().clear_no_drop();
|
||||
});
|
||||
let iter = unsafe { self.table.as_ref().iter().iter };
|
||||
mem::forget(self);
|
||||
let producer = ParDrainProducer { iter };
|
||||
plumbing::bridge_unindexed(producer, consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A: Allocator> Drop for RawParDrain<'_, T, A> {
|
||||
fn drop(&mut self) {
|
||||
// If drive_unindexed is not called then simply clear the table.
|
||||
unsafe {
|
||||
self.table.as_mut().clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Producer which will consume all elements in the range, even if it is dropped
|
||||
/// halfway through.
|
||||
struct ParDrainProducer<T> {
|
||||
iter: RawIterRange<T>,
|
||||
}
|
||||
|
||||
impl<T: Send> UnindexedProducer for ParDrainProducer<T> {
|
||||
type Item = T;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn split(self) -> (Self, Option<Self>) {
|
||||
let (left, right) = self.iter.clone().split();
|
||||
mem::forget(self);
|
||||
let left = ParDrainProducer { iter: left };
|
||||
let right = right.map(|right| ParDrainProducer { iter: right });
|
||||
(left, right)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn fold_with<F>(mut self, mut folder: F) -> F
|
||||
where
|
||||
F: Folder<Self::Item>,
|
||||
{
|
||||
// Make sure to modify the iterator in-place so that any remaining
|
||||
// elements are processed in our Drop impl.
|
||||
for item in &mut self.iter {
|
||||
folder = folder.consume(unsafe { item.read() });
|
||||
if folder.full() {
|
||||
return folder;
|
||||
}
|
||||
}
|
||||
|
||||
// If we processed all elements then we don't need to run the drop.
|
||||
mem::forget(self);
|
||||
folder
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for ParDrainProducer<T> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drop(&mut self) {
|
||||
// Drop all remaining elements
|
||||
if mem::needs_drop::<T>() {
|
||||
for item in &mut self.iter {
|
||||
unsafe {
|
||||
item.drop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A: Allocator> RawTable<T, A> {
|
||||
/// Returns a parallel iterator over the elements in a `RawTable`.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub unsafe fn par_iter(&self) -> RawParIter<T> {
|
||||
RawParIter {
|
||||
iter: self.iter().iter,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a parallel iterator over the elements in a `RawTable`.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn into_par_iter(self) -> RawIntoParIter<T, A> {
|
||||
RawIntoParIter { table: self }
|
||||
}
|
||||
|
||||
/// Returns a parallel iterator which consumes all elements of a `RawTable`
|
||||
/// without freeing its memory allocation.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_drain(&mut self) -> RawParDrain<'_, T, A> {
|
||||
RawParDrain {
|
||||
table: NonNull::from(self),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
659
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/set.rs
vendored
Normal file
659
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/set.rs
vendored
Normal file
@@ -0,0 +1,659 @@
|
||||
//! Rayon extensions for `HashSet`.
|
||||
|
||||
use super::map;
|
||||
use crate::hash_set::HashSet;
|
||||
use crate::raw::{Allocator, Global};
|
||||
use core::hash::{BuildHasher, Hash};
|
||||
use rayon::iter::plumbing::UnindexedConsumer;
|
||||
use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator};
|
||||
|
||||
/// Parallel iterator over elements of a consumed set.
|
||||
///
|
||||
/// This iterator is created by the [`into_par_iter`] method on [`HashSet`]
|
||||
/// (provided by the [`IntoParallelIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`into_par_iter`]: /hashbrown/struct.HashSet.html#method.into_par_iter
|
||||
/// [`HashSet`]: /hashbrown/struct.HashSet.html
|
||||
/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html
|
||||
pub struct IntoParIter<T, A: Allocator = Global> {
|
||||
inner: map::IntoParIter<T, (), A>,
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator + Send> ParallelIterator for IntoParIter<T, A> {
|
||||
type Item = T;
|
||||
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner.map(|(k, _)| k).drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel draining iterator over entries of a set.
|
||||
///
|
||||
/// This iterator is created by the [`par_drain`] method on [`HashSet`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_drain`]: /hashbrown/struct.HashSet.html#method.par_drain
|
||||
/// [`HashSet`]: /hashbrown/struct.HashSet.html
|
||||
pub struct ParDrain<'a, T, A: Allocator = Global> {
|
||||
inner: map::ParDrain<'a, T, (), A>,
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator + Send + Sync> ParallelIterator for ParDrain<'_, T, A> {
|
||||
type Item = T;
|
||||
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner.map(|(k, _)| k).drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over shared references to elements in a set.
|
||||
///
|
||||
/// This iterator is created by the [`par_iter`] method on [`HashSet`]
|
||||
/// (provided by the [`IntoParallelRefIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_iter`]: /hashbrown/struct.HashSet.html#method.par_iter
|
||||
/// [`HashSet`]: /hashbrown/struct.HashSet.html
|
||||
/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html
|
||||
pub struct ParIter<'a, T> {
|
||||
inner: map::ParKeys<'a, T, ()>,
|
||||
}
|
||||
|
||||
impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over shared references to elements in the difference of
|
||||
/// sets.
|
||||
///
|
||||
/// This iterator is created by the [`par_difference`] method on [`HashSet`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_difference`]: /hashbrown/struct.HashSet.html#method.par_difference
|
||||
/// [`HashSet`]: /hashbrown/struct.HashSet.html
|
||||
pub struct ParDifference<'a, T, S, A: Allocator = Global> {
|
||||
a: &'a HashSet<T, S, A>,
|
||||
b: &'a HashSet<T, S, A>,
|
||||
}
|
||||
|
||||
impl<'a, T, S, A> ParallelIterator for ParDifference<'a, T, S, A>
|
||||
where
|
||||
T: Eq + Hash + Sync,
|
||||
S: BuildHasher + Sync,
|
||||
A: Allocator + Sync,
|
||||
{
|
||||
type Item = &'a T;
|
||||
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.a
|
||||
.into_par_iter()
|
||||
.filter(|&x| !self.b.contains(x))
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over shared references to elements in the symmetric
|
||||
/// difference of sets.
|
||||
///
|
||||
/// This iterator is created by the [`par_symmetric_difference`] method on
|
||||
/// [`HashSet`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_symmetric_difference`]: /hashbrown/struct.HashSet.html#method.par_symmetric_difference
|
||||
/// [`HashSet`]: /hashbrown/struct.HashSet.html
|
||||
pub struct ParSymmetricDifference<'a, T, S, A: Allocator = Global> {
|
||||
a: &'a HashSet<T, S, A>,
|
||||
b: &'a HashSet<T, S, A>,
|
||||
}
|
||||
|
||||
impl<'a, T, S, A> ParallelIterator for ParSymmetricDifference<'a, T, S, A>
|
||||
where
|
||||
T: Eq + Hash + Sync,
|
||||
S: BuildHasher + Sync,
|
||||
A: Allocator + Sync,
|
||||
{
|
||||
type Item = &'a T;
|
||||
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.a
|
||||
.par_difference(self.b)
|
||||
.chain(self.b.par_difference(self.a))
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over shared references to elements in the intersection of
|
||||
/// sets.
|
||||
///
|
||||
/// This iterator is created by the [`par_intersection`] method on [`HashSet`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_intersection`]: /hashbrown/struct.HashSet.html#method.par_intersection
|
||||
/// [`HashSet`]: /hashbrown/struct.HashSet.html
|
||||
pub struct ParIntersection<'a, T, S, A: Allocator = Global> {
|
||||
a: &'a HashSet<T, S, A>,
|
||||
b: &'a HashSet<T, S, A>,
|
||||
}
|
||||
|
||||
impl<'a, T, S, A> ParallelIterator for ParIntersection<'a, T, S, A>
|
||||
where
|
||||
T: Eq + Hash + Sync,
|
||||
S: BuildHasher + Sync,
|
||||
A: Allocator + Sync,
|
||||
{
|
||||
type Item = &'a T;
|
||||
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.a
|
||||
.into_par_iter()
|
||||
.filter(|&x| self.b.contains(x))
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over shared references to elements in the union of sets.
|
||||
///
|
||||
/// This iterator is created by the [`par_union`] method on [`HashSet`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_union`]: /hashbrown/struct.HashSet.html#method.par_union
|
||||
/// [`HashSet`]: /hashbrown/struct.HashSet.html
|
||||
pub struct ParUnion<'a, T, S, A: Allocator = Global> {
|
||||
a: &'a HashSet<T, S, A>,
|
||||
b: &'a HashSet<T, S, A>,
|
||||
}
|
||||
|
||||
impl<'a, T, S, A> ParallelIterator for ParUnion<'a, T, S, A>
|
||||
where
|
||||
T: Eq + Hash + Sync,
|
||||
S: BuildHasher + Sync,
|
||||
A: Allocator + Sync,
|
||||
{
|
||||
type Item = &'a T;
|
||||
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
// We'll iterate one set in full, and only the remaining difference from the other.
|
||||
// Use the smaller set for the difference in order to reduce hash lookups.
|
||||
let (smaller, larger) = if self.a.len() <= self.b.len() {
|
||||
(self.a, self.b)
|
||||
} else {
|
||||
(self.b, self.a)
|
||||
};
|
||||
larger
|
||||
.into_par_iter()
|
||||
.chain(smaller.par_difference(larger))
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, A> HashSet<T, S, A>
|
||||
where
|
||||
T: Eq + Hash + Sync,
|
||||
S: BuildHasher + Sync,
|
||||
A: Allocator + Sync,
|
||||
{
|
||||
/// Visits (potentially in parallel) the values representing the union,
|
||||
/// i.e. all the values in `self` or `other`, without duplicates.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_union<'a>(&'a self, other: &'a Self) -> ParUnion<'a, T, S, A> {
|
||||
ParUnion { a: self, b: other }
|
||||
}
|
||||
|
||||
/// Visits (potentially in parallel) the values representing the difference,
|
||||
/// i.e. the values that are in `self` but not in `other`.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_difference<'a>(&'a self, other: &'a Self) -> ParDifference<'a, T, S, A> {
|
||||
ParDifference { a: self, b: other }
|
||||
}
|
||||
|
||||
/// Visits (potentially in parallel) the values representing the symmetric
|
||||
/// difference, i.e. the values that are in `self` or in `other` but not in both.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_symmetric_difference<'a>(
|
||||
&'a self,
|
||||
other: &'a Self,
|
||||
) -> ParSymmetricDifference<'a, T, S, A> {
|
||||
ParSymmetricDifference { a: self, b: other }
|
||||
}
|
||||
|
||||
/// Visits (potentially in parallel) the values representing the
|
||||
/// intersection, i.e. the values that are both in `self` and `other`.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_intersection<'a>(&'a self, other: &'a Self) -> ParIntersection<'a, T, S, A> {
|
||||
ParIntersection { a: self, b: other }
|
||||
}
|
||||
|
||||
/// Returns `true` if `self` has no elements in common with `other`.
|
||||
/// This is equivalent to checking for an empty intersection.
|
||||
///
|
||||
/// This method runs in a potentially parallel fashion.
|
||||
pub fn par_is_disjoint(&self, other: &Self) -> bool {
|
||||
self.into_par_iter().all(|x| !other.contains(x))
|
||||
}
|
||||
|
||||
/// Returns `true` if the set is a subset of another,
|
||||
/// i.e. `other` contains at least all the values in `self`.
|
||||
///
|
||||
/// This method runs in a potentially parallel fashion.
|
||||
pub fn par_is_subset(&self, other: &Self) -> bool {
|
||||
if self.len() <= other.len() {
|
||||
self.into_par_iter().all(|x| other.contains(x))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the set is a superset of another,
|
||||
/// i.e. `self` contains at least all the values in `other`.
|
||||
///
|
||||
/// This method runs in a potentially parallel fashion.
|
||||
pub fn par_is_superset(&self, other: &Self) -> bool {
|
||||
other.par_is_subset(self)
|
||||
}
|
||||
|
||||
/// Returns `true` if the set is equal to another,
|
||||
/// i.e. both sets contain the same values.
|
||||
///
|
||||
/// This method runs in a potentially parallel fashion.
|
||||
pub fn par_eq(&self, other: &Self) -> bool {
|
||||
self.len() == other.len() && self.par_is_subset(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, A> HashSet<T, S, A>
|
||||
where
|
||||
T: Eq + Hash + Send,
|
||||
A: Allocator + Send,
|
||||
{
|
||||
/// Consumes (potentially in parallel) all values in an arbitrary order,
|
||||
/// while preserving the set's allocated memory for reuse.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_drain(&mut self) -> ParDrain<'_, T, A> {
|
||||
ParDrain {
|
||||
inner: self.map.par_drain(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send, S, A: Allocator + Send> IntoParallelIterator for HashSet<T, S, A> {
|
||||
type Item = T;
|
||||
type Iter = IntoParIter<T, A>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
IntoParIter {
|
||||
inner: self.map.into_par_iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Sync, S, A: Allocator> IntoParallelIterator for &'a HashSet<T, S, A> {
|
||||
type Item = &'a T;
|
||||
type Iter = ParIter<'a, T>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
ParIter {
|
||||
inner: self.map.par_keys(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect values from a parallel iterator into a hashset.
|
||||
impl<T, S> FromParallelIterator<T> for HashSet<T, S, Global>
|
||||
where
|
||||
T: Eq + Hash + Send,
|
||||
S: BuildHasher + Default,
|
||||
{
|
||||
fn from_par_iter<P>(par_iter: P) -> Self
|
||||
where
|
||||
P: IntoParallelIterator<Item = T>,
|
||||
{
|
||||
let mut set = HashSet::default();
|
||||
set.par_extend(par_iter);
|
||||
set
|
||||
}
|
||||
}
|
||||
|
||||
/// Extend a hash set with items from a parallel iterator.
|
||||
impl<T, S> ParallelExtend<T> for HashSet<T, S, Global>
|
||||
where
|
||||
T: Eq + Hash + Send,
|
||||
S: BuildHasher,
|
||||
{
|
||||
fn par_extend<I>(&mut self, par_iter: I)
|
||||
where
|
||||
I: IntoParallelIterator<Item = T>,
|
||||
{
|
||||
extend(self, par_iter);
|
||||
}
|
||||
}
|
||||
|
||||
/// Extend a hash set with copied items from a parallel iterator.
|
||||
impl<'a, T, S> ParallelExtend<&'a T> for HashSet<T, S, Global>
|
||||
where
|
||||
T: 'a + Copy + Eq + Hash + Sync,
|
||||
S: BuildHasher,
|
||||
{
|
||||
fn par_extend<I>(&mut self, par_iter: I)
|
||||
where
|
||||
I: IntoParallelIterator<Item = &'a T>,
|
||||
{
|
||||
extend(self, par_iter);
|
||||
}
|
||||
}
|
||||
|
||||
// This is equal to the normal `HashSet` -- no custom advantage.
|
||||
fn extend<T, S, I, A>(set: &mut HashSet<T, S, A>, par_iter: I)
|
||||
where
|
||||
T: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
A: Allocator,
|
||||
I: IntoParallelIterator,
|
||||
HashSet<T, S, A>: Extend<I::Item>,
|
||||
{
|
||||
let (list, len) = super::helpers::collect(par_iter);
|
||||
|
||||
// Values may be already present or show multiple times in the iterator.
|
||||
// Reserve the entire length if the set is empty.
|
||||
// Otherwise reserve half the length (rounded up), so the set
|
||||
// will only resize twice in the worst case.
|
||||
let reserve = if set.is_empty() { len } else { (len + 1) / 2 };
|
||||
set.reserve(reserve);
|
||||
for vec in list {
|
||||
set.extend(vec);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_par_set {
|
||||
use alloc::vec::Vec;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::hash_set::HashSet;
|
||||
|
||||
#[test]
|
||||
fn test_disjoint() {
|
||||
let mut xs = HashSet::new();
|
||||
let mut ys = HashSet::new();
|
||||
assert!(xs.par_is_disjoint(&ys));
|
||||
assert!(ys.par_is_disjoint(&xs));
|
||||
assert!(xs.insert(5));
|
||||
assert!(ys.insert(11));
|
||||
assert!(xs.par_is_disjoint(&ys));
|
||||
assert!(ys.par_is_disjoint(&xs));
|
||||
assert!(xs.insert(7));
|
||||
assert!(xs.insert(19));
|
||||
assert!(xs.insert(4));
|
||||
assert!(ys.insert(2));
|
||||
assert!(ys.insert(-11));
|
||||
assert!(xs.par_is_disjoint(&ys));
|
||||
assert!(ys.par_is_disjoint(&xs));
|
||||
assert!(ys.insert(7));
|
||||
assert!(!xs.par_is_disjoint(&ys));
|
||||
assert!(!ys.par_is_disjoint(&xs));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_subset_and_superset() {
|
||||
let mut a = HashSet::new();
|
||||
assert!(a.insert(0));
|
||||
assert!(a.insert(5));
|
||||
assert!(a.insert(11));
|
||||
assert!(a.insert(7));
|
||||
|
||||
let mut b = HashSet::new();
|
||||
assert!(b.insert(0));
|
||||
assert!(b.insert(7));
|
||||
assert!(b.insert(19));
|
||||
assert!(b.insert(250));
|
||||
assert!(b.insert(11));
|
||||
assert!(b.insert(200));
|
||||
|
||||
assert!(!a.par_is_subset(&b));
|
||||
assert!(!a.par_is_superset(&b));
|
||||
assert!(!b.par_is_subset(&a));
|
||||
assert!(!b.par_is_superset(&a));
|
||||
|
||||
assert!(b.insert(5));
|
||||
|
||||
assert!(a.par_is_subset(&b));
|
||||
assert!(!a.par_is_superset(&b));
|
||||
assert!(!b.par_is_subset(&a));
|
||||
assert!(b.par_is_superset(&a));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterate() {
|
||||
let mut a = HashSet::new();
|
||||
for i in 0..32 {
|
||||
assert!(a.insert(i));
|
||||
}
|
||||
let observed = AtomicUsize::new(0);
|
||||
a.par_iter().for_each(|k| {
|
||||
observed.fetch_or(1 << *k, Ordering::Relaxed);
|
||||
});
|
||||
assert_eq!(observed.into_inner(), 0xFFFF_FFFF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_intersection() {
|
||||
let mut a = HashSet::new();
|
||||
let mut b = HashSet::new();
|
||||
|
||||
assert!(a.insert(11));
|
||||
assert!(a.insert(1));
|
||||
assert!(a.insert(3));
|
||||
assert!(a.insert(77));
|
||||
assert!(a.insert(103));
|
||||
assert!(a.insert(5));
|
||||
assert!(a.insert(-5));
|
||||
|
||||
assert!(b.insert(2));
|
||||
assert!(b.insert(11));
|
||||
assert!(b.insert(77));
|
||||
assert!(b.insert(-9));
|
||||
assert!(b.insert(-42));
|
||||
assert!(b.insert(5));
|
||||
assert!(b.insert(3));
|
||||
|
||||
let expected = [3, 5, 11, 77];
|
||||
let i = a
|
||||
.par_intersection(&b)
|
||||
.map(|x| {
|
||||
assert!(expected.contains(x));
|
||||
1
|
||||
})
|
||||
.sum::<usize>();
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_difference() {
|
||||
let mut a = HashSet::new();
|
||||
let mut b = HashSet::new();
|
||||
|
||||
assert!(a.insert(1));
|
||||
assert!(a.insert(3));
|
||||
assert!(a.insert(5));
|
||||
assert!(a.insert(9));
|
||||
assert!(a.insert(11));
|
||||
|
||||
assert!(b.insert(3));
|
||||
assert!(b.insert(9));
|
||||
|
||||
let expected = [1, 5, 11];
|
||||
let i = a
|
||||
.par_difference(&b)
|
||||
.map(|x| {
|
||||
assert!(expected.contains(x));
|
||||
1
|
||||
})
|
||||
.sum::<usize>();
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_symmetric_difference() {
|
||||
let mut a = HashSet::new();
|
||||
let mut b = HashSet::new();
|
||||
|
||||
assert!(a.insert(1));
|
||||
assert!(a.insert(3));
|
||||
assert!(a.insert(5));
|
||||
assert!(a.insert(9));
|
||||
assert!(a.insert(11));
|
||||
|
||||
assert!(b.insert(-2));
|
||||
assert!(b.insert(3));
|
||||
assert!(b.insert(9));
|
||||
assert!(b.insert(14));
|
||||
assert!(b.insert(22));
|
||||
|
||||
let expected = [-2, 1, 5, 11, 14, 22];
|
||||
let i = a
|
||||
.par_symmetric_difference(&b)
|
||||
.map(|x| {
|
||||
assert!(expected.contains(x));
|
||||
1
|
||||
})
|
||||
.sum::<usize>();
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_union() {
|
||||
let mut a = HashSet::new();
|
||||
let mut b = HashSet::new();
|
||||
|
||||
assert!(a.insert(1));
|
||||
assert!(a.insert(3));
|
||||
assert!(a.insert(5));
|
||||
assert!(a.insert(9));
|
||||
assert!(a.insert(11));
|
||||
assert!(a.insert(16));
|
||||
assert!(a.insert(19));
|
||||
assert!(a.insert(24));
|
||||
|
||||
assert!(b.insert(-2));
|
||||
assert!(b.insert(1));
|
||||
assert!(b.insert(5));
|
||||
assert!(b.insert(9));
|
||||
assert!(b.insert(13));
|
||||
assert!(b.insert(19));
|
||||
|
||||
let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24];
|
||||
let i = a
|
||||
.par_union(&b)
|
||||
.map(|x| {
|
||||
assert!(expected.contains(x));
|
||||
1
|
||||
})
|
||||
.sum::<usize>();
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_iter() {
|
||||
let xs = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
|
||||
let set: HashSet<_> = xs.par_iter().cloned().collect();
|
||||
|
||||
for x in &xs {
|
||||
assert!(set.contains(x));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_move_iter() {
|
||||
let hs = {
|
||||
let mut hs = HashSet::new();
|
||||
|
||||
hs.insert('a');
|
||||
hs.insert('b');
|
||||
|
||||
hs
|
||||
};
|
||||
|
||||
let v = hs.into_par_iter().collect::<Vec<char>>();
|
||||
assert!(v == ['a', 'b'] || v == ['b', 'a']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eq() {
|
||||
// These constants once happened to expose a bug in insert().
|
||||
// I'm keeping them around to prevent a regression.
|
||||
let mut s1 = HashSet::new();
|
||||
|
||||
s1.insert(1);
|
||||
s1.insert(2);
|
||||
s1.insert(3);
|
||||
|
||||
let mut s2 = HashSet::new();
|
||||
|
||||
s2.insert(1);
|
||||
s2.insert(2);
|
||||
|
||||
assert!(!s1.par_eq(&s2));
|
||||
|
||||
s2.insert(3);
|
||||
|
||||
assert!(s1.par_eq(&s2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extend_ref() {
|
||||
let mut a = HashSet::new();
|
||||
a.insert(1);
|
||||
|
||||
a.par_extend(&[2, 3, 4][..]);
|
||||
|
||||
assert_eq!(a.len(), 4);
|
||||
assert!(a.contains(&1));
|
||||
assert!(a.contains(&2));
|
||||
assert!(a.contains(&3));
|
||||
assert!(a.contains(&4));
|
||||
|
||||
let mut b = HashSet::new();
|
||||
b.insert(5);
|
||||
b.insert(6);
|
||||
|
||||
a.par_extend(&b);
|
||||
|
||||
assert_eq!(a.len(), 6);
|
||||
assert!(a.contains(&1));
|
||||
assert!(a.contains(&2));
|
||||
assert!(a.contains(&3));
|
||||
assert!(a.contains(&4));
|
||||
assert!(a.contains(&5));
|
||||
assert!(a.contains(&6));
|
||||
}
|
||||
}
|
||||
252
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/table.rs
vendored
Normal file
252
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/table.rs
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
//! Rayon extensions for `HashTable`.
|
||||
|
||||
use super::raw::{RawIntoParIter, RawParDrain, RawParIter};
|
||||
use crate::hash_table::HashTable;
|
||||
use crate::raw::{Allocator, Global};
|
||||
use core::fmt;
|
||||
use core::marker::PhantomData;
|
||||
use rayon::iter::plumbing::UnindexedConsumer;
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
|
||||
/// Parallel iterator over shared references to entries in a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_iter`] method on [`HashTable`]
|
||||
/// (provided by the [`IntoParallelRefIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_iter`]: /hashbrown/struct.HashTable.html#method.par_iter
|
||||
/// [`HashTable`]: /hashbrown/struct.HashTable.html
|
||||
/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html
|
||||
pub struct ParIter<'a, T> {
|
||||
inner: RawParIter<T>,
|
||||
marker: PhantomData<&'a T>,
|
||||
}
|
||||
|
||||
impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner
|
||||
.map(|x| unsafe { x.as_ref() })
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for ParIter<'_, T> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: self.inner.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug> fmt::Debug for ParIter<'_, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let iter = unsafe { self.inner.iter() }.map(|x| unsafe { x.as_ref() });
|
||||
f.debug_list().entries(iter).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over mutable references to entries in a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_iter_mut`] method on [`HashTable`]
|
||||
/// (provided by the [`IntoParallelRefMutIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_iter_mut`]: /hashbrown/struct.HashTable.html#method.par_iter_mut
|
||||
/// [`HashTable`]: /hashbrown/struct.HashTable.html
|
||||
/// [`IntoParallelRefMutIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefMutIterator.html
|
||||
pub struct ParIterMut<'a, T> {
|
||||
inner: RawParIter<T>,
|
||||
marker: PhantomData<&'a mut T>,
|
||||
}
|
||||
|
||||
impl<'a, T: Send> ParallelIterator for ParIterMut<'a, T> {
|
||||
type Item = &'a mut T;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner
|
||||
.map(|x| unsafe { x.as_mut() })
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug> fmt::Debug for ParIterMut<'_, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ParIter {
|
||||
inner: self.inner.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over entries of a consumed map.
|
||||
///
|
||||
/// This iterator is created by the [`into_par_iter`] method on [`HashTable`]
|
||||
/// (provided by the [`IntoParallelIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`into_par_iter`]: /hashbrown/struct.HashTable.html#method.into_par_iter
|
||||
/// [`HashTable`]: /hashbrown/struct.HashTable.html
|
||||
/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html
|
||||
pub struct IntoParIter<T, A: Allocator = Global> {
|
||||
inner: RawIntoParIter<T, A>,
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator + Send> ParallelIterator for IntoParIter<T, A> {
|
||||
type Item = T;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoParIter<T, A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ParIter {
|
||||
inner: unsafe { self.inner.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel draining iterator over entries of a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_drain`] method on [`HashTable`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_drain`]: /hashbrown/struct.HashTable.html#method.par_drain
|
||||
/// [`HashTable`]: /hashbrown/struct.HashTable.html
|
||||
pub struct ParDrain<'a, T, A: Allocator = Global> {
|
||||
inner: RawParDrain<'a, T, A>,
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator + Sync> ParallelIterator for ParDrain<'_, T, A> {
|
||||
type Item = T;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug, A: Allocator> fmt::Debug for ParDrain<'_, T, A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ParIter {
|
||||
inner: unsafe { self.inner.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator> HashTable<T, A> {
|
||||
/// Consumes (potentially in parallel) all values in an arbitrary order,
|
||||
/// while preserving the map's allocated memory for reuse.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_drain(&mut self) -> ParDrain<'_, T, A> {
|
||||
ParDrain {
|
||||
inner: self.raw.par_drain(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator + Send> IntoParallelIterator for HashTable<T, A> {
|
||||
type Item = T;
|
||||
type Iter = IntoParIter<T, A>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
IntoParIter {
|
||||
inner: self.raw.into_par_iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Sync, A: Allocator> IntoParallelIterator for &'a HashTable<T, A> {
|
||||
type Item = &'a T;
|
||||
type Iter = ParIter<'a, T>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
ParIter {
|
||||
inner: unsafe { self.raw.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Send, A: Allocator> IntoParallelIterator for &'a mut HashTable<T, A> {
|
||||
type Item = &'a mut T;
|
||||
type Iter = ParIterMut<'a, T>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
ParIterMut {
|
||||
inner: unsafe { self.raw.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_par_table {
|
||||
use alloc::vec::Vec;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::{
|
||||
hash_map::{make_hash, DefaultHashBuilder},
|
||||
hash_table::HashTable,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_iterate() {
|
||||
let hasher = DefaultHashBuilder::default();
|
||||
let mut a = HashTable::new();
|
||||
for i in 0..32 {
|
||||
a.insert_unique(make_hash(&hasher, &i), i, |x| make_hash(&hasher, x));
|
||||
}
|
||||
let observed = AtomicUsize::new(0);
|
||||
a.par_iter().for_each(|k| {
|
||||
observed.fetch_or(1 << *k, Ordering::Relaxed);
|
||||
});
|
||||
assert_eq!(observed.into_inner(), 0xFFFF_FFFF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_move_iter() {
|
||||
let hasher = DefaultHashBuilder::default();
|
||||
let hs = {
|
||||
let mut hs = HashTable::new();
|
||||
|
||||
hs.insert_unique(make_hash(&hasher, &'a'), 'a', |x| make_hash(&hasher, x));
|
||||
hs.insert_unique(make_hash(&hasher, &'b'), 'b', |x| make_hash(&hasher, x));
|
||||
|
||||
hs
|
||||
};
|
||||
|
||||
let v = hs.into_par_iter().collect::<Vec<char>>();
|
||||
assert!(v == ['a', 'b'] || v == ['b', 'a']);
|
||||
}
|
||||
}
|
||||
125
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_map.rs
vendored
Normal file
125
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_map.rs
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
use crate::HashMap;
|
||||
use core::{
|
||||
borrow::Borrow,
|
||||
hash::{BuildHasher, Hash},
|
||||
};
|
||||
use rkyv::{
|
||||
collections::hash_map::{ArchivedHashMap, HashMapResolver},
|
||||
ser::{ScratchSpace, Serializer},
|
||||
Archive, Deserialize, Fallible, Serialize,
|
||||
};
|
||||
|
||||
impl<K: Archive + Hash + Eq, V: Archive, S> Archive for HashMap<K, V, S>
|
||||
where
|
||||
K::Archived: Hash + Eq,
|
||||
{
|
||||
type Archived = ArchivedHashMap<K::Archived, V::Archived>;
|
||||
type Resolver = HashMapResolver;
|
||||
|
||||
#[inline]
|
||||
unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) {
|
||||
ArchivedHashMap::resolve_from_len(self.len(), pos, resolver, out);
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, S, RandomState> Serialize<S> for HashMap<K, V, RandomState>
|
||||
where
|
||||
K: Serialize<S> + Hash + Eq,
|
||||
K::Archived: Hash + Eq,
|
||||
V: Serialize<S>,
|
||||
S: Serializer + ScratchSpace + ?Sized,
|
||||
{
|
||||
#[inline]
|
||||
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
|
||||
unsafe { ArchivedHashMap::serialize_from_iter(self.iter(), serializer) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Archive + Hash + Eq, V: Archive, D: Fallible + ?Sized, S: Default + BuildHasher>
|
||||
Deserialize<HashMap<K, V, S>, D> for ArchivedHashMap<K::Archived, V::Archived>
|
||||
where
|
||||
K::Archived: Deserialize<K, D> + Hash + Eq,
|
||||
V::Archived: Deserialize<V, D>,
|
||||
{
|
||||
#[inline]
|
||||
fn deserialize(&self, deserializer: &mut D) -> Result<HashMap<K, V, S>, D::Error> {
|
||||
let mut result = HashMap::with_capacity_and_hasher(self.len(), S::default());
|
||||
for (k, v) in self.iter() {
|
||||
result.insert(k.deserialize(deserializer)?, v.deserialize(deserializer)?);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq + Borrow<AK>, V, AK: Hash + Eq, AV: PartialEq<V>, S: BuildHasher>
|
||||
PartialEq<HashMap<K, V, S>> for ArchivedHashMap<AK, AV>
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &HashMap<K, V, S>) -> bool {
|
||||
if self.len() != other.len() {
|
||||
false
|
||||
} else {
|
||||
self.iter()
|
||||
.all(|(key, value)| other.get(key).map_or(false, |v| value.eq(v)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq + Borrow<AK>, V, AK: Hash + Eq, AV: PartialEq<V>>
|
||||
PartialEq<ArchivedHashMap<AK, AV>> for HashMap<K, V>
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &ArchivedHashMap<AK, AV>) -> bool {
|
||||
other.eq(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::HashMap;
|
||||
use alloc::string::String;
|
||||
use rkyv::{
|
||||
archived_root, check_archived_root,
|
||||
ser::{serializers::AllocSerializer, Serializer},
|
||||
Deserialize, Infallible,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn index_map() {
|
||||
let mut value = HashMap::new();
|
||||
value.insert(String::from("foo"), 10);
|
||||
value.insert(String::from("bar"), 20);
|
||||
value.insert(String::from("baz"), 40);
|
||||
value.insert(String::from("bat"), 80);
|
||||
|
||||
let mut serializer = AllocSerializer::<4096>::default();
|
||||
serializer.serialize_value(&value).unwrap();
|
||||
let result = serializer.into_serializer().into_inner();
|
||||
let archived = unsafe { archived_root::<HashMap<String, i32>>(result.as_ref()) };
|
||||
|
||||
assert_eq!(value.len(), archived.len());
|
||||
for (k, v) in value.iter() {
|
||||
let (ak, av) = archived.get_key_value(k.as_str()).unwrap();
|
||||
assert_eq!(k, ak);
|
||||
assert_eq!(v, av);
|
||||
}
|
||||
|
||||
let deserialized: HashMap<String, i32> = archived.deserialize(&mut Infallible).unwrap();
|
||||
assert_eq!(value, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_index_map() {
|
||||
let mut value = HashMap::new();
|
||||
value.insert(String::from("foo"), 10);
|
||||
value.insert(String::from("bar"), 20);
|
||||
value.insert(String::from("baz"), 40);
|
||||
value.insert(String::from("bat"), 80);
|
||||
|
||||
let mut serializer = AllocSerializer::<4096>::default();
|
||||
serializer.serialize_value(&value).unwrap();
|
||||
let result = serializer.into_serializer().into_inner();
|
||||
check_archived_root::<HashMap<String, i32>>(result.as_ref())
|
||||
.expect("failed to validate archived index map");
|
||||
}
|
||||
}
|
||||
123
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_set.rs
vendored
Normal file
123
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_set.rs
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
use crate::HashSet;
|
||||
use core::{
|
||||
borrow::Borrow,
|
||||
hash::{BuildHasher, Hash},
|
||||
};
|
||||
use rkyv::{
|
||||
collections::hash_set::{ArchivedHashSet, HashSetResolver},
|
||||
ser::{ScratchSpace, Serializer},
|
||||
Archive, Deserialize, Fallible, Serialize,
|
||||
};
|
||||
|
||||
impl<K: Archive + Hash + Eq, S> Archive for HashSet<K, S>
|
||||
where
|
||||
K::Archived: Hash + Eq,
|
||||
{
|
||||
type Archived = ArchivedHashSet<K::Archived>;
|
||||
type Resolver = HashSetResolver;
|
||||
|
||||
#[inline]
|
||||
unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) {
|
||||
ArchivedHashSet::<K::Archived>::resolve_from_len(self.len(), pos, resolver, out);
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, S, RS> Serialize<S> for HashSet<K, RS>
|
||||
where
|
||||
K::Archived: Hash + Eq,
|
||||
K: Serialize<S> + Hash + Eq,
|
||||
S: ScratchSpace + Serializer + ?Sized,
|
||||
{
|
||||
#[inline]
|
||||
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
|
||||
unsafe { ArchivedHashSet::serialize_from_iter(self.iter(), serializer) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, D, S> Deserialize<HashSet<K, S>, D> for ArchivedHashSet<K::Archived>
|
||||
where
|
||||
K: Archive + Hash + Eq,
|
||||
K::Archived: Deserialize<K, D> + Hash + Eq,
|
||||
D: Fallible + ?Sized,
|
||||
S: Default + BuildHasher,
|
||||
{
|
||||
#[inline]
|
||||
fn deserialize(&self, deserializer: &mut D) -> Result<HashSet<K, S>, D::Error> {
|
||||
let mut result = HashSet::with_hasher(S::default());
|
||||
for k in self.iter() {
|
||||
result.insert(k.deserialize(deserializer)?);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq + Borrow<AK>, AK: Hash + Eq, S: BuildHasher> PartialEq<HashSet<K, S>>
|
||||
for ArchivedHashSet<AK>
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &HashSet<K, S>) -> bool {
|
||||
if self.len() != other.len() {
|
||||
false
|
||||
} else {
|
||||
self.iter().all(|key| other.get(key).is_some())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq + Borrow<AK>, AK: Hash + Eq, S: BuildHasher> PartialEq<ArchivedHashSet<AK>>
|
||||
for HashSet<K, S>
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &ArchivedHashSet<AK>) -> bool {
|
||||
other.eq(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::HashSet;
|
||||
use alloc::string::String;
|
||||
use rkyv::{
|
||||
archived_root, check_archived_root,
|
||||
ser::{serializers::AllocSerializer, Serializer},
|
||||
Deserialize, Infallible,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn index_set() {
|
||||
let mut value = HashSet::new();
|
||||
value.insert(String::from("foo"));
|
||||
value.insert(String::from("bar"));
|
||||
value.insert(String::from("baz"));
|
||||
value.insert(String::from("bat"));
|
||||
|
||||
let mut serializer = AllocSerializer::<4096>::default();
|
||||
serializer.serialize_value(&value).unwrap();
|
||||
let result = serializer.into_serializer().into_inner();
|
||||
let archived = unsafe { archived_root::<HashSet<String>>(result.as_ref()) };
|
||||
|
||||
assert_eq!(value.len(), archived.len());
|
||||
for k in value.iter() {
|
||||
let ak = archived.get(k.as_str()).unwrap();
|
||||
assert_eq!(k, ak);
|
||||
}
|
||||
|
||||
let deserialized: HashSet<String> = archived.deserialize(&mut Infallible).unwrap();
|
||||
assert_eq!(value, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_index_set() {
|
||||
let mut value = HashSet::new();
|
||||
value.insert(String::from("foo"));
|
||||
value.insert(String::from("bar"));
|
||||
value.insert(String::from("baz"));
|
||||
value.insert(String::from("bat"));
|
||||
|
||||
let mut serializer = AllocSerializer::<4096>::default();
|
||||
serializer.serialize_value(&value).unwrap();
|
||||
let result = serializer.into_serializer().into_inner();
|
||||
check_archived_root::<HashSet<String>>(result.as_ref())
|
||||
.expect("failed to validate archived index set");
|
||||
}
|
||||
}
|
||||
2
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/mod.rs
vendored
Normal file
2
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/mod.rs
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
mod hash_map;
|
||||
mod hash_set;
|
||||
220
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/serde.rs
vendored
Normal file
220
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/serde.rs
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
mod size_hint {
|
||||
use core::cmp;
|
||||
|
||||
/// This presumably exists to prevent denial of service attacks.
|
||||
///
|
||||
/// Original discussion: https://github.com/serde-rs/serde/issues/1114.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub(super) fn cautious(hint: Option<usize>) -> usize {
|
||||
cmp::min(hint.unwrap_or(0), 4096)
|
||||
}
|
||||
}
|
||||
|
||||
mod map {
|
||||
use crate::raw::Allocator;
|
||||
use core::fmt;
|
||||
use core::hash::{BuildHasher, Hash};
|
||||
use core::marker::PhantomData;
|
||||
use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
|
||||
use serde::ser::{Serialize, Serializer};
|
||||
|
||||
use crate::hash_map::HashMap;
|
||||
|
||||
use super::size_hint;
|
||||
|
||||
impl<K, V, H, A> Serialize for HashMap<K, V, H, A>
|
||||
where
|
||||
K: Serialize + Eq + Hash,
|
||||
V: Serialize,
|
||||
H: BuildHasher,
|
||||
A: Allocator,
|
||||
{
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_map(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, K, V, S, A> Deserialize<'de> for HashMap<K, V, S, A>
|
||||
where
|
||||
K: Deserialize<'de> + Eq + Hash,
|
||||
V: Deserialize<'de>,
|
||||
S: BuildHasher + Default,
|
||||
A: Allocator + Default,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct MapVisitor<K, V, S, A>
|
||||
where
|
||||
A: Allocator,
|
||||
{
|
||||
marker: PhantomData<HashMap<K, V, S, A>>,
|
||||
}
|
||||
|
||||
impl<'de, K, V, S, A> Visitor<'de> for MapVisitor<K, V, S, A>
|
||||
where
|
||||
K: Deserialize<'de> + Eq + Hash,
|
||||
V: Deserialize<'de>,
|
||||
S: BuildHasher + Default,
|
||||
A: Allocator + Default,
|
||||
{
|
||||
type Value = HashMap<K, V, S, A>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a map")
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
{
|
||||
let mut values = HashMap::with_capacity_and_hasher_in(
|
||||
size_hint::cautious(map.size_hint()),
|
||||
S::default(),
|
||||
A::default(),
|
||||
);
|
||||
|
||||
while let Some((key, value)) = map.next_entry()? {
|
||||
values.insert(key, value);
|
||||
}
|
||||
|
||||
Ok(values)
|
||||
}
|
||||
}
|
||||
|
||||
let visitor = MapVisitor {
|
||||
marker: PhantomData,
|
||||
};
|
||||
deserializer.deserialize_map(visitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod set {
|
||||
use crate::raw::Allocator;
|
||||
use core::fmt;
|
||||
use core::hash::{BuildHasher, Hash};
|
||||
use core::marker::PhantomData;
|
||||
use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor};
|
||||
use serde::ser::{Serialize, Serializer};
|
||||
|
||||
use crate::hash_set::HashSet;
|
||||
|
||||
use super::size_hint;
|
||||
|
||||
impl<T, H, A> Serialize for HashSet<T, H, A>
|
||||
where
|
||||
T: Serialize + Eq + Hash,
|
||||
H: BuildHasher,
|
||||
A: Allocator,
|
||||
{
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_seq(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T, S, A> Deserialize<'de> for HashSet<T, S, A>
|
||||
where
|
||||
T: Deserialize<'de> + Eq + Hash,
|
||||
S: BuildHasher + Default,
|
||||
A: Allocator + Default,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct SeqVisitor<T, S, A>
|
||||
where
|
||||
A: Allocator,
|
||||
{
|
||||
marker: PhantomData<HashSet<T, S, A>>,
|
||||
}
|
||||
|
||||
impl<'de, T, S, A> Visitor<'de> for SeqVisitor<T, S, A>
|
||||
where
|
||||
T: Deserialize<'de> + Eq + Hash,
|
||||
S: BuildHasher + Default,
|
||||
A: Allocator + Default,
|
||||
{
|
||||
type Value = HashSet<T, S, A>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a sequence")
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn visit_seq<M>(self, mut seq: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: SeqAccess<'de>,
|
||||
{
|
||||
let mut values = HashSet::with_capacity_and_hasher_in(
|
||||
size_hint::cautious(seq.size_hint()),
|
||||
S::default(),
|
||||
A::default(),
|
||||
);
|
||||
|
||||
while let Some(value) = seq.next_element()? {
|
||||
values.insert(value);
|
||||
}
|
||||
|
||||
Ok(values)
|
||||
}
|
||||
}
|
||||
|
||||
let visitor = SeqVisitor {
|
||||
marker: PhantomData,
|
||||
};
|
||||
deserializer.deserialize_seq(visitor)
|
||||
}
|
||||
|
||||
#[allow(clippy::missing_errors_doc)]
|
||||
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct SeqInPlaceVisitor<'a, T, S, A>(&'a mut HashSet<T, S, A>)
|
||||
where
|
||||
A: Allocator;
|
||||
|
||||
impl<'a, 'de, T, S, A> Visitor<'de> for SeqInPlaceVisitor<'a, T, S, A>
|
||||
where
|
||||
T: Deserialize<'de> + Eq + Hash,
|
||||
S: BuildHasher + Default,
|
||||
A: Allocator,
|
||||
{
|
||||
type Value = ();
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a sequence")
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn visit_seq<M>(self, mut seq: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: SeqAccess<'de>,
|
||||
{
|
||||
self.0.clear();
|
||||
self.0.reserve(size_hint::cautious(seq.size_hint()));
|
||||
|
||||
while let Some(value) = seq.next_element()? {
|
||||
self.0.insert(value);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_seq(SeqInPlaceVisitor(place))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user