#pragma once #include #include #include #include #include "types.h" // #include "robin_hood.h" #include "unordered_dense.h" template using aq_map = ankerl::unordered_dense::map; template using aq_set = ankerl::unordered_dense::set; // only works for 64 bit systems namespace hasher_consts{ constexpr size_t _FNV_offset_basis = 14695981039346656037ULL; constexpr size_t _FNV_prime = 1099511628211ULL; } inline size_t append_bytes(const unsigned char* _First) noexcept { size_t _Val = hasher_consts::_FNV_offset_basis; for (; *_First; ++_First) { _Val ^= static_cast(*_First); _Val *= hasher_consts::_FNV_prime; } return _Val; } inline size_t append_bytes(const astring_view& view) noexcept { return append_bytes(view.str); } #ifdef __SIZEOF_INT128__ union int128_struct { struct { uint64_t low, high; }__struct; __int128_t value = 0; __uint128_t uvalue; constexpr int128_struct() : value(0) {} constexpr int128_struct(const __int128_t &value) noexcept : value(value) {} constexpr int128_struct(const __uint128_t &value) noexcept : uvalue(value) {} operator __int128_t () const { return value; } operator __uint128_t () const { return uvalue; } operator __int128_t& () { return value; } operator __uint128_t& () { return uvalue; } }; #endif template struct hasher { template typename std::enable_if< i == sizeof...(Types), size_t>::type hashi(const std::tuple&) const { return 534235245539ULL; } template typename std::enable_if < i < sizeof ...(Types), size_t>::type hashi(const std::tuple& record) const { using current_type = typename std::decay>::type>::type; #ifdef __SIZEOF_INT128__ using _current_type = typename std::conditional_t< std::is_same_v || std::is_same_v, int128_struct, current_type>; #else #define _current_type current_type #endif return ankerl::unordered_dense::hash<_current_type>()(std::get(record)) ^ hashi(record); } size_t operator()(const std::tuple& record) const { return hashi(record); } }; template struct hasher{ size_t operator()(const std::tuple& record) const { return ankerl::unordered_dense::hash()(std::get<0>(record)); } }; namespace ankerl::unordered_dense{ template<> struct hash { size_t operator()(const astring_view& _Keyval) const noexcept { return ankerl::unordered_dense::hash()(_Keyval.rstr); //return append_bytes(_Keyval.str); } }; template<> struct hash { size_t operator() (const types::date_t& _Keyval) const noexcept { return ankerl::unordered_dense::hash()(*(unsigned int*)(&_Keyval)); } }; template<> struct hash { size_t operator() (const types::time_t& _Keyval) const noexcept { return ankerl::unordered_dense::hash()(_Keyval.ms) ^ ankerl::unordered_dense::hash()(_Keyval.seconds) ^ ankerl::unordered_dense::hash()(_Keyval.minutes) ^ ankerl::unordered_dense::hash()(_Keyval.hours) ; } }; template<> struct hash{ size_t operator() (const types::timestamp_t& _Keyval) const noexcept { return ankerl::unordered_dense::hash()(_Keyval.date) ^ ankerl::unordered_dense::hash()(_Keyval.time); } }; #ifdef __SIZEOF_INT128__ template<> struct hash{ size_t operator() (const int128_struct& _Keyval) const noexcept { return ankerl::unordered_dense::hash()(_Keyval.__struct.low) ^ ankerl::unordered_dense::hash()(_Keyval.__struct.high); } }; #endif template struct hash> : public hasher{ }; } template < typename ValueType = bool, int PerfectHashingThreshold = 12 > struct PerfectHashTable { // static int m_PerfectHashingThreshold = 12; using key_t = std::conditional_t>>; int n_cols, n_rows = 0; // char bits[32]; ValueType table[1 << PerfectHashingThreshold]; // PerfectHashTable(int n_cols, char* bits) { // this->n_cols = n_cols; // memcpy(this->bits, bits, 32); // } // template class VT> // PerfectHashTable(VT ... args) { // } template class VT> void construct(VT&... args) { ((this->n_cols = args.size), ...); static_assert( (sizeof...(Types) < PerfectHashingThreshold) && //(sizeof(Types) + ...) < PerfectHashingThreshold && (std::is_integral_v && ...), "Types must be integral and less than 12 wide in total." ); // this should be an attrib of VT. key_t* // this better be automatically determined by Threshould hash_values = static_cast( calloc(this->n_cols, sizeof(key_t)) ); //new short[this->n_cols] {0}; // use calloc/delete auto get_hash = [&hash_values](auto& arg, int idx) { uint32_t i = 0; if(idx > 0) for (auto& a : arg) { hash_values[i] = (hash_values[i] << arg.stats.bits) + (a - arg.stats.minima); ++i; } else for (auto& a : arg) { hash_values[i] = a - arg.stats.minima; ++i; } }; int idx = 0; (get_hash(args, idx++), ...); for (uint32_t i = 0; i < this->n_cols; ++i) { this->table[hash_values[i]] = true; // problem: random memory access } // delete[] hash_values; free(hash_values); } };