pub(crate) fn groupby_threaded_num<T, IntoSlice>(
    keys: Vec<IntoSlice>,
    group_size_hint: usize,
    n_partitions: u64,
) -> GroupTuples
where
    T: Send + Hash + Eq + Sync + Copy + AsU64,
    IntoSlice: AsRef<[T]> + Send + Sync,
{
    assert!(n_partitions.is_power_of_two());

    // We will create a hashtable in every thread.
    // We use the hash to partition the keys to the matching hashtable.
    // Every thread traverses all keys/hashes and ignores the ones that doesn't fall in that partition.
    POOL.install(|| {
        (0..n_partitions).into_par_iter().map(|thread_no| {
            let thread_no = thread_no as u64;

            let mut hash_tbl: PlHashMap<T, (u32, Vec<u32>)> =
                PlHashMap::with_capacity(HASHMAP_INIT_SIZE);

            let mut offset = 0;
            for keys in &keys {
                let keys = keys.as_ref();
                let len = keys.len() as u32;

                let mut cnt = 0;
                keys.iter().for_each(|k| {
                    let idx = cnt + offset;
                    cnt += 1;

                    if this_partition(k.as_u64(), thread_no, n_partitions) {
                        let entry = hash_tbl.entry(*k);

                        match entry {
                            Entry::Vacant(entry) => {
                                let mut tuples = Vec::with_capacity(group_size_hint);
                                tuples.push(idx);
                                entry.insert((idx, tuples));
                            }
                            Entry::Occupied(mut entry) => {
                                let v = entry.get_mut();
                                v.1.push(idx);
                            }
                        }
                    }
                });
                offset += len;
            }
            hash_tbl.into_iter().map(|(_k, v)| v).collect::<Vec<_>>()
        })
    })
    .flatten()
    .collect()
}
/// Determine group tuples over different threads. The hash of the key is used to determine the partitions.
/// Note that rehashing of the keys should be cheap and the keys small to allow efficient rehashing and improved cache locality.
///
/// Besides numeric values, we can also use this for pre hashed strings. The keys are simply a ptr to the str + precomputed hash.
/// The hash will be used to rehash, and the str will be used for equality.
Determine group tuples over different threads. The hash of the key is used to determine the partitions.
Note that rehashing of the keys should be cheap and the keys small to allow efficient rehashing and improved cache locality.

Besides numeric values, we can also use this for pre hashed strings. The keys are simply a ptr to the str + precomputed hash.
The hash will be used to rehash, and the str will be used for equality.
Determine group tuples over different threads . The hash of the key is used to determine the partitions . Note that rehashing of the keys should be cheap and the keys small to allow efficient rehashing and improved cache locality . Besides numeric values we can also use this for pre hashed strings . The keys are simply a ptr to the str + precomputed hash . The hash will be used to rehash and the str will be used for equality .
pub(crate) fn groupby_threaded_num<T, IntoSlice>(
    keys: Vec<IntoSlice>,
    group_size_hint: usize,
    n_partitions: u64,
) -> GroupTuples
where
    T: Send + Hash + Eq + Sync + Copy + AsU64,
    IntoSlice: AsRef<[T]> + Send + Sync,
{
    assert!(n_partitions.is_power_of_two());
    // We will create a hashtable in every thread.
    // We use the hash to partition the keys to the matching hashtable.
    // Every thread traverses all keys/hashes and ignores the ones that doesn't fall in that partition.
    POOL.install(|| {
        (0..n_partitions).into_par_iter().map(|thread_no| {
            let thread_no = thread_no as u64;
            let mut hash_tbl: PlHashMap<T, (u32, Vec<u32>)> =
                PlHashMap::with_capacity(HASHMAP_INIT_SIZE);
            let mut offset = 0;
            for keys in &keys {
                let keys = keys.as_ref();
                let len = keys.len() as u32;
                let mut cnt = 0;
                keys.iter().for_each(|k| {
                    let idx = cnt + offset;
                    cnt += 1;
                    if this_partition(k.as_u64(), thread_no, n_partitions) {
                        let entry = hash_tbl.entry(*k);
                        match entry {
                            Entry::Vacant(entry) => {
                                let mut tuples = Vec::with_capacity(group_size_hint);
                                tuples.push(idx);
                                entry.insert((idx, tuples));
                            }
                            Entry::Occupied(mut entry) => {
                                let v = entry.get_mut();
                                v.1.push(idx);
                            }
                        }
                    }
                });
                offset += len;
            }
            hash_tbl.into_iter().map(|(_k, v)| v).collect::<Vec<_>>()
        })
    })
    .flatten()
    .collect()
}
pub ( crate ) fn groupby_threaded_num < T , IntoSlice > ( keys : Vec < IntoSlice > , group_size_hint : usize , n_partitions : u64 , ) -> GroupTuples where T : Send + Hash + Eq + Sync + Copy + AsU64 , IntoSlice : AsRef < [ T ] > + Send + Sync , { assert ! ( n_partitions is_power_of_two ( ) ) ; // We will create a hashtable in every thread. // We use the hash to partition the keys to the matching hashtable. // Every thread traverses all keys/hashes and ignores the ones that doesn't fall in that partition. POOL . install ( | | { ( 0 .. n_partitions ) . into_par_iter ( ) . map ( | thread_no | { let thread_no = thread_no as u64 ; let mut hash_tbl : PlHashMap < T , ( u32 , Vec < u32 > ) > = PlHashMap :: with_capacity ( HASHMAP_INIT_SIZE ) ; let mut offset = 0 ; for keys in & keys { let keys = keys . as_ref ( ) ; let len = keys . len ( ) as u32 ; let mut cnt = 0 ; keys . iter ( ) . for_each ( | k | { let idx = cnt + offset ; cnt += 1 ; if this_partition ( k . as_u64 ( ) , thread_no , n_partitions ) { let entry = hash_tbl . entry ( * k ) ; match entry { Entry :: Vacant ( entry ) => { let mut tuples = Vec :: with_capacity ( group_size_hint ) ; tuples . push ( idx ) ; entry . insert ( ( idx , tuples ) ) ; } Entry :: Occupied ( mut entry ) => { let v = entry . get_mut ( ) ; v . 1 . push ( idx ) ; } } } } ) ; offset += len ; } hash_tbl . into_iter ( ) . map ( | ( _k , v ) | v ) . collect :: < Vec < _ > > ( ) } ) } ) . flatten ( ) . collect ( ) }
Determine group tuples over different threads.
Determine group tuples over different threads .
keys
Vec<IntoSlice>
group_size_hint
usize
n_partitions
u64
keys
Vec<IntoSlice>
group_size_hint
usize
n_partitions
u64