@ -166,8 +166,10 @@ public:
template < typename . . . Keys_t >
inline void hashtable_push_all ( Keys_t & . . . keys , uint32_t len ) {
# pragma omp simd
for ( uint32_t i = 0 ; i < len ; + + i )
reversemap [ i ] = ankerl : : unordered_dense : : set < Key , Hash > : : hashtable_push ( keys [ i ] . . . ) ;
# pragma omp simd
for ( uint32_t i = 0 ; i < len ; + + i )
+ + ht_base [ reversemap [ i ] ] ;
}
@ -182,10 +184,12 @@ public:
auto vecs = static_cast < vector_type < uint32_t > * > ( malloc ( sizeof ( vector_type < uint32_t > ) * len ) ) ;
vecs [ 0 ] . init_from ( ht_base [ 0 ] , mapbase ) ;
# pragma omp simd
for ( uint32_t i = 1 ; i < len ; + + i ) {
vecs [ i ] . init_from ( ht_base [ i ] , mapbase + ht_base [ i - 1 ] ) ;
ht_base [ i ] + = ht_base [ i - 1 ] ;
}
# pragma omp simd
for ( uint32_t i = 0 ; i < sz ; + + i ) {
auto id = reversemap [ i ] ;
mapbase [ - - ht_base [ id ] ] = i ;
@ -194,11 +198,18 @@ public:
}
} ;
template < class . . . Ty >
struct HashTableComponents {
uint32_t size ;
std : : vector < std : : tuple < Ty . . . > > * keys ;
vector_type < uint32_t > * values ;
uint32_t * offsets ;
} ;
template <
typename ValueType = uint32_t ,
int PerfectHashingThreshold = 12
>
int PerfectHashingThreshold = 1 8
> // default < 1M table size
struct PerfectHashTable {
using key_t = std : : conditional_t < PerfectHashingThreshold < = 8 , uint8_t ,
std : : conditional_t < PerfectHashingThreshold < = 16 , uint16_t ,
@ -207,7 +218,7 @@ struct PerfectHashTable {
> > > ;
constexpr static uint32_t tbl_sz = 1 < < PerfectHashingThreshold ;
template < typename . . . Types , template < typename > class VT >
static vector_type < uint32_t > *
static HashTableComponents< Types . . . > // vector_type<uint32_t>*
construct ( VT < Types > & . . . args ) { // construct a hash set
// AQTmr();
int n_cols , n_rows = 0 ;
@ -216,7 +227,7 @@ struct PerfectHashTable {
static_assert (
( sizeof . . . ( Types ) < PerfectHashingThreshold ) & &
( std : : is_integral_v < Types > & & . . . ) ,
" Types must be integral and less than 12 wide in total."
" Types must be integral and less than \" PerfectHashingThreshold \" wide in total."
) ;
key_t *
hash_values = static_cast < key_t * > (
@ -241,9 +252,10 @@ struct PerfectHashTable {
} ;
int idx = 0 ;
( get_hash ( args , idx + + ) , . . . ) ;
uint32_t cnt [ tbl_sz ] ;
uint32_t * cnt_ext = static_cast < uint32_t * > (
calloc ( tbl_sz , sizeof ( uint32_t ) )
) , * cnt = cnt_ext + 1 ;
uint32_t n_grps = 0 ;
memset ( cnt , 0 , tbl_sz * sizeof ( tbl_sz ) ) ;
# pragma omp simd
for ( uint32_t i = 0 ; i < n_cols ; + + i ) {
+ + cnt [ hash_values [ i ] ] ;
@ -256,6 +268,24 @@ struct PerfectHashTable {
grp_ids [ i ] = n_grps + + ;
}
}
std : : vector < std : : tuple < Types . . . > > * keys = new std : : vector < std : : tuple < Types . . . > > ( n_grps ) ; // Memory leak here, cleanup after module is done.
const char bits [ ] = { 0 , args . stats . bits . . . } ;
auto decode = [ ] < typename Ret > ( auto & val , const char prev , const char curr ) - > Ret {
val > > = prev ;
const auto mask = ( 1 < < curr ) - 1 ;
return val & mask ;
} ;
# pragma omp simd
for ( ValueType i = 0 ; i < n_grps ; + + i ) {
int idx2 = 1 ;
ValueType curr_val = grp_ids [ i ] ;
keys [ i ] = std : : make_tuple ( (
decode . template operator ( ) < Types > (
curr_val , bits [ idx2 - 1 ] , bits [ idx2 + + ]
) , . . . )
) ; // require C++20 for the calls to be executed sequentially.
}
uint32_t * idxs = static_cast < uint32_t * > (
malloc ( n_cols * sizeof ( uint32_t ) )
) ;
@ -281,7 +311,47 @@ struct PerfectHashTable {
idxs_vec [ i ] . container = idxs_ptr [ i ] ;
idxs_vec [ i ] . size = cnt [ i ] ;
}
free ( hash_values ) ;
return idxs_vec ;
GC : : gc_handle - > reg ( hash_values ) ;
# pragma omp simd
for ( int i = 1 ; i < n_grps ; + + i )
cnt [ i ] + = cnt [ i - 1 ] ;
cnt_ext [ 0 ] = 0 ;
return { . size = n_grps , . keys = keys , . values = idxs_vec , . offset = cnt_ext } ;
}
} ;
template < class >
class ColRef ;
template <
class Key ,
class Hash ,
int PerfectHashingThreshold = 18
>
class HashTableFactory {
public :
template < class . . . Ty >
static HashTableComponents < Ty . . . >
get ( ColRef < Ty > & . . . cols ) {
// To use Perfect Hash Table
if constexpr ( ( std : : is_integral_v < Ty > & & . . . ) ) {
if ( ( cols . stats . bits + . . . ) < = PerfectHashingThreshold ) {
return PerfectHashTable <
uint32_t ,
PerfectHashingThreshold
> : : construct ( cols . . . ) ;
}
}
// Fallback to regular hash table
int n_rows = 0 ;
( ( n_rows = cols . size ) , . . . ) ;
AQHashTable < Key , Hash > ht { n_rows } ;
ht . template hashtable_push_all < decays < decltype ( cols ) > . . . > ( cols . . . , n_rows ) ;
auto vals = ht . ht_postproc ( n_rows ) ;
return { . size = ht . size ( ) , . keys = ht . values ( ) , . values = vals , . offset = ht . ht_base } ;
}
} ;