97 HashTable(
int block_size = 16*1024,
int init_hash_size = 32*1024);
125 T*
Get(
int p1,
int p2,
int p3,
int p4 = -1 );
150 int GetId(
int p1,
int p2,
int p3,
int p4 = -1);
173 T*
Find(
int p1,
int p2,
int p3,
int p4 = -1);
183 const T*
Find(
int p1,
int p2)
const;
196 const T*
Find(
int p1,
int p2,
int p3,
int p4 = -1)
const;
224 int FindId(
int p1,
int p2,
int p3,
int p4 = -1)
const;
290 void Reparent(
int id,
int new_p1,
int new_p2,
int new_p3,
int new_p4 = -1);
372 inline int Hash(
size_t p1,
size_t p2)
const
373 {
return (984120265ul*p1 + 125965121ul*p2) &
mask; }
385 inline int Hash(
size_t p1,
size_t p2,
size_t p3)
const
386 {
return (984120265ul*p1 + 125965121ul*p2 + 495698413ul*p3) &
mask; }
429 inline void Insert(
int idx,
int id, T &item);
473 uint64_t buf_[2] = {0, 0};
478 void init(uint64_t seed = 0);
479 void append(
const uint8_t *vs, uint64_t bytes);
485 void add_block(uint64_t k1, uint64_t k2);
488 void finalize(uint64_t k1,
int num);
492 void finalize(uint64_t k1, uint64_t k2,
int num);
498 template <
class T,
class V>
503 hash.
init(0xfebd1fe69813c14full);
504 hash.
append(
reinterpret_cast<const uint8_t *
>(&v.first),
sizeof(T));
505 hash.
append(
reinterpret_cast<const uint8_t *
>(&v.second),
sizeof(V));
514 template <
class T,
size_t N>
519 hash.
init(0xfebd1fe69813c14full);
520 for (
size_t i = 0; i < N; ++i)
522 hash.
append(
reinterpret_cast<const uint8_t *
>(&v[i]),
sizeof(T));
537 void HashBuffer(
const void *buffer,
size_t num_bytes);
540 template <
typename int_type_const_iter>
542 int_type_const_iter end);
545 template <
typename double_const_iter>
547 double_const_iter end);
563 template <
typename int_type>
570 template <
typename int_type,
size_t num_
ints>
577 template <
typename int_type_container>
590 template <
size_t num_
doubles>
597 template <
typename double_container>
613 mask = init_hash_size-1;
614 MFEM_VERIFY(!(init_hash_size &
mask),
"init_size must be a power of two.");
616 table =
new int[init_hash_size];
617 for (
int i = 0; i < init_hash_size; i++)
625 :
Base(other), mask(other.mask)
642inline void sort3(
int &
a,
int &
b,
int &c)
644 if (
a >
b) { std::swap(
a,
b); }
645 if (
a > c) { std::swap(
a, c); }
646 if (
b > c) { std::swap(
b, c); }
649inline void sort4(
int &
a,
int &
b,
int &c,
int &d)
651 if (
a >
b) { std::swap(
a,
b); }
652 if (
a > c) { std::swap(
a, c); }
653 if (
a > d) { std::swap(
a, d); }
657inline void sort4_ext(
int &
a,
int &
b,
int &c,
int &d)
674 return &(Base::At(GetId(p1, p2)));
680 return &(Base::At(GetId(p1, p2, p3, p4)));
687 if (p1 > p2) { std::swap(p1, p2); }
688 int idx = Hash(p1, p2);
689 int id = SearchList(table[idx], p1, p2);
690 if (
id >= 0) {
return id; }
696 new_id = unused.Last();
701 new_id = Base::Append();
703 T& item = Base::At(new_id);
708 Insert(idx, new_id, item);
718 internal::sort4_ext(p1, p2, p3, p4);
719 int idx = Hash(p1, p2, p3);
720 int id = SearchList(table[idx], p1, p2, p3);
721 if (
id >= 0) {
return id; }
727 new_id = unused.Last();
732 new_id = Base::Append();
734 T& item = Base::At(new_id);
740 Insert(idx, new_id, item);
749 int id = FindId(p1, p2);
750 return (
id >= 0) ? &(Base::At(
id)) : NULL;
756 int id = FindId(p1, p2, p3, p4);
757 return (
id >= 0) ? &(Base::At(
id)) : NULL;
763 int id = FindId(p1, p2);
764 return (
id >= 0) ? &(Base::At(
id)) : NULL;
770 int id = FindId(p1, p2, p3, p4);
771 return (
id >= 0) ? &(Base::At(
id)) : NULL;
777 if (p1 > p2) { std::swap(p1, p2); }
778 return SearchList(table[Hash(p1, p2)], p1, p2);
784 internal::sort4_ext(p1, p2, p3, p4);
785 return SearchList(table[Hash(p1, p2, p3)], p1, p2, p3);
793 const T& item = Base::At(
id);
794 if (item.p1 == p1 && item.p2 == p2) {
return id; }
805 const T& item = Base::At(
id);
806 if (item.p1 == p1 && item.p2 == p2 && item.p3 == p3) {
return id; }
815 const int fill_factor = 2;
818 if (Base::Size() > (mask+1) * fill_factor)
830 int new_table_size = 2*(mask+1);
831 table =
new int[new_table_size];
832 for (
int i = 0; i < new_table_size; i++) { table[i] = -1; }
833 mask = new_table_size-1;
835#if defined(MFEM_DEBUG) && !defined(MFEM_USE_MPI)
836 mfem::out << _MFEM_FUNC_NAME <<
": rehashing to size " << new_table_size
841 for (
iterator it = begin(); it != end(); ++it)
843 Insert(Hash(*it), it.index(), *it);
851 item.next = table[idx];
859 int* p_id = table + idx;
862 T& item = Base::At(*p_id);
870 MFEM_ABORT(
"HashTable<>::Unlink: item not found!");
876 T& item = Base::At(
id);
877 Unlink(Hash(item),
id);
886 for (
int i = 0; i <= mask; i++) { table[i] = -1; }
894 while (
id >= Base::Size())
896 Base::At(Base::Append()).next = -2;
899 T& item = Base::At(
id);
906 Insert(Hash(p1, p2),
id, item);
915 for (
int i = 0; i < Base::Size(); i++)
917 if (Base::At(i).next == -2) { unused.Append(i); }
924 T& item = Base::At(
id);
925 Unlink(Hash(item),
id);
927 if (new_p1 > new_p2) { std::swap(new_p1, new_p2); }
932 int new_idx = Hash(new_p1, new_p2);
933 Insert(new_idx,
id, item);
938 int new_p1,
int new_p2,
int new_p3,
int new_p4)
940 T& item = Base::At(
id);
941 Unlink(Hash(item),
id);
943 internal::sort4_ext(new_p1, new_p2, new_p3, new_p4);
949 int new_idx = Hash(new_p1, new_p2, new_p3);
950 Insert(new_idx,
id, item);
956 return (mask+1) *
sizeof(int) + Base::MemoryUsage() + unused.MemoryUsage();
962 mfem::out << Base::MemoryUsage() <<
" + " << (mask+1) *
sizeof(
int)
963 <<
" + " << unused.MemoryUsage();
973 const T& item = Base::At(
id);
983 int table_size = mask+1;
984 mfem::out <<
"Hash table size: " << table_size <<
"\n";
985 mfem::out <<
"Item count: " << Size() <<
"\n";
986 mfem::out <<
"BlockArray size: " << Base::Size() <<
"\n";
991 for (
int i = 0; i < H; i++) { hist[i] = 0; }
993 for (
int i = 0; i < table_size; i++)
996 if (bs >= H) { bs = H-1; }
1001 for (
int i = 0; i < H; i++)
1004 << hist[i] <<
" bins" << std::endl;
1009template <
typename int_type_const_iter>
1011 int_type_const_iter end)
1023 typename std::remove_reference<
decltype(*begin)>::type
1025 "invalid iterator type");
1028 if (
hash_data ==
nullptr) {
return *
this; }
1030 constexpr int max_buffer_bytes = 64*1024;
1031 unsigned char buffer[max_buffer_bytes];
1032 int buffer_counter = 0;
1033 while (begin != end)
1035 int byte_counter = 0;
1037 buffer[buffer_counter] = (k >= 0) ? 0 : (k = -k, 128);
1041 buffer[buffer_counter + byte_counter] = (
unsigned char)(k % 256);
1044 buffer[buffer_counter] |= byte_counter;
1045 buffer_counter += (byte_counter + 1);
1050 buffer_counter + (1 +
sizeof(*begin)) > max_buffer_bytes)
1059template <
typename double_const_iter>
1061 double_const_iter end)
1066 std::is_same<
decltype(*begin),
const real_t &>::value,
1067 "invalid iterator type");
1070 if (
hash_data ==
nullptr) {
return *
this; }
1072 constexpr int max_buffer_bytes = 64*1024;
1073 unsigned char buffer[max_buffer_bytes];
1074 int buffer_counter = 0;
1075 while (begin != end)
1077 auto k =
reinterpret_cast<const uint64_t &
>(*begin);
1078 for (
int i = 0; i != 7; i++)
1080 buffer[buffer_counter++] = (
unsigned char)(k & 255); k >>= 8;
1082 buffer[buffer_counter++] = (
unsigned char)k;
1086 if (begin == end || buffer_counter + 8 > max_buffer_bytes)
int Size() const
Return the logical size of the array.
void Copy(Array ©) const
Create a copy of the internal array to the provided copy.
T & At(int index)
Access item of the array.
const_iterator cbegin() const
int Size() const
Return the number of items actually stored.
Hash function for data sequences.
HashFunction()
Default constructor: initialize the hash function.
HashFunction & AppendInts(const int_type(&ints)[num_ints])
Add a sequence of integers for hashing, given as a fixed-size c-array.
HashFunction & AppendDoubles(const real_t(&doubles)[num_doubles])
Add a sequence of doubles for hashing, given as a fixed-size c-array.
HashFunction & AppendDoubles(const double_container &doubles)
Add a sequence of doubles for hashing, given as a container.
HashFunction & EncodeAndHashInts(int_type_const_iter begin, int_type_const_iter end)
Integer encoding method; result is independent of endianness and type.
HashFunction & EncodeAndHashDoubles(double_const_iter begin, double_const_iter end)
Double encoding method: encode in little-endian byte-order.
std::string GetHash() const
Return the hash string for the current sequence and reset (clear) the sequence.
~HashFunction()
Destructor.
HashFunction & AppendBytes(const void *seq, size_t num_bytes)
Add a sequence of bytes for hashing.
HashFunction & AppendDoubles(const real_t *doubles, size_t num_doubles)
Add a sequence of doubles for hashing, given as a c-array.
HashFunction & AppendInts(const int_type *ints, size_t num_ints)
Add a sequence of integers for hashing, given as a c-array.
HashFunction & AppendInts(const int_type_container &ints)
Add a sequence of integers for hashing, given as a container.
void HashBuffer(const void *buffer, size_t num_bytes)
Add a sequence of bytes for hashing.
Base::const_iterator base
const_iterator(const base &it)
const_iterator & operator++()
void Reparent(int id, int new_p1, int new_p2, int new_p3, int new_p4=-1)
Change the key associated with an item.
const_iterator end() const
T * Get(int p1, int p2)
Item accessor with key (or parents) the pair p1, p2. Default construct an item of type T if no value ...
void PrintMemoryDetail() const
Write details of the memory usage to the mfem output stream.
int Hash(const Hashed4 &item) const
Hash function for items of type T that inherit from Hashed4.
void DeleteAll()
Remove all items.
T * Find(int p1, int p2)
Item accessor with key (or parents) the pair p1, p2. Return NULL if no value corresponds to the reque...
bool IdExists(int id) const
Return true if item id exists in (is used by) the container.
int Hash(size_t p1, size_t p2, size_t p3) const
hash function for Hashed4 items.
HashTable(int block_size=16 *1024, int init_hash_size=32 *1024)
Main constructor of the HashTable class.
void Reparent(int id, int new_p1, int new_p2)
Change the key associated with an item.
T * Get(int p1, int p2, int p3, int p4=-1)
Item accessor with key (or parents) the quadruplet p1, p2, p3, p4. The key p4 is optional....
int Hash(size_t p1, size_t p2) const
hash function for Hashed2 items.
const_iterator begin() const
void Insert(int idx, int id, T &item)
Insert the item id into bin idx.
int FindId(int p1, int p2, int p3, int p4=-1) const
Find the "id" of an item, this "id" corresponding to the index of the item in the underlying BlockArr...
int SearchList(int id, int p1, int p2) const
Search the index of the item associated to the key (p1,p2) starting from the item with index id.
int GetId(int p1, int p2)
Get the "id" of the item whose parents are p1, p2, this "id" corresponding to the index of the item i...
void CheckRehash()
Check table fill factor and resize if necessary.
int NumIds() const
Return the total number of ids (used and unused) in the HashTable.
const T * Find(int p1, int p2, int p3, int p4=-1) const
Item const accessor with key (or parents) the quadruplet p1, p2, p3, p4. The key p4 is optional....
int SearchList(int id, int p1, int p2, int p3) const
Search the index of the item associated to the key (p1,p2,p3,(p4)) starting from the item with index ...
int Hash(const Hashed2 &item) const
Hash function for items of type T that inherit from Hashed2.
int GetId(int p1, int p2, int p3, int p4=-1)
Get the "id" of an item, this "id" corresponding to the index of the item in the underlying BlockArra...
void Delete(int id)
Remove an item from the hash table.
HashTable(const HashTable &other)
Deep copy.
int BinSize(int idx) const
Return the size of the bin idx.
int FindId(int p1, int p2) const
Find the "id" of an item whose parents are p1, p2. Return -1 if it does not exist.
void DoRehash()
Double the size of the hash table (i.e., double the number of bins) and reinsert all items into the n...
T * Find(int p1, int p2, int p3, int p4=-1)
Item accessor with key (or parents) the quadruplet p1, p2, p3, p4. The key p4 is optional....
void Alloc(int id, int p1, int p2)
Allocate an item at id. Enlarge the underlying BlockArray if necessary.
const_iterator cend() const
int Size() const
Return the number of elements currently stored in the HashTable.
void Unlink(int idx, int id)
Unlink an item id from the linked list of bin idx.
const T * Find(int p1, int p2) const
Item const accessor with key (or parents) the pair p1, p2. Return NULL if no value corresponds to the...
void UpdateUnused()
Reinitialize the internal list of unallocated items.
const_iterator cbegin() const
int NumFreeIds() const
Return the number of free/unused ids in the HashTable.
void PrintStats() const
Print a histogram of bin sizes for debugging purposes.
HashTable & operator=(const HashTable &)=delete
Copy assignment not supported.
std::size_t MemoryUsage() const
Return total size of allocated memory (tables plus items), in bytes.
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Helper class for hashing std::array. Usable in place of std::hash<std::array<T,N>>
size_t operator()(const std::array< T, N > &v) const noexcept
streaming implementation for murmurhash3 128 (x64). Constructs the hash in 3 stages: init,...
void init(uint64_t seed=0)
resets this hasher back to an initial seed
void append(const uint8_t *vs, uint64_t bytes)
Helper class for hashing std::pair. Usable in place of std::hash<std::pair<T,U>>
size_t operator()(const std::pair< T, V > &v) const noexcept