15 #include "../config/config.hpp" 18 #include <type_traits> 94 HashTable(
int block_size = 16*1024,
int init_hash_size = 32*1024);
109 T*
Get(
int p1,
int p2);
122 T*
Get(
int p1,
int p2,
int p3,
int p4 = -1 );
134 int GetId(
int p1,
int p2);
147 int GetId(
int p1,
int p2,
int p3,
int p4 = -1);
158 T*
Find(
int p1,
int p2);
171 T*
Find(
int p1,
int p2,
int p3,
int p4 = -1);
181 const T*
Find(
int p1,
int p2)
const;
194 const T*
Find(
int p1,
int p2,
int p3,
int p4 = -1)
const;
206 int FindId(
int p1,
int p2)
const;
219 int FindId(
int p1,
int p2,
int p3,
int p4 = -1)
const;
256 void Alloc(
int id,
int p1,
int p2);
272 void Reparent(
int id,
int new_p1,
int new_p2);
285 void Reparent(
int id,
int new_p1,
int new_p2,
int new_p3,
int new_p4 = -1);
337 iterator
end() {
return iterator(); }
340 const_iterator
cend()
const {
return const_iterator(); }
365 inline int Hash(
size_t p1,
size_t p2)
const 366 {
return (984120265ul*p1 + 125965121ul*p2) &
mask; }
378 inline int Hash(
size_t p1,
size_t p2,
size_t p3)
const 379 {
return (984120265ul*p1 + 125965121ul*p2 + 495698413ul*p3) &
mask; }
411 int SearchList(
int id,
int p1,
int p2,
int p3)
const;
422 inline void Insert(
int idx,
int id, T &item);
430 void Unlink(
int idx,
int id);
462 void HashBuffer(
const void *buffer,
size_t num_bytes);
465 template <
typename int_type_const_iter>
467 int_type_const_iter end);
470 template <
typename double_const_iter>
472 double_const_iter end);
488 template <
typename int_type>
495 template <
typename int_type,
size_t num_
ints>
502 template <
typename int_type_container>
515 template <
size_t num_
doubles>
522 template <
typename double_container>
538 mask = init_hash_size-1;
539 MFEM_VERIFY(!(init_hash_size & mask),
"init_size must be a power of two.");
541 table =
new int[init_hash_size];
542 for (
int i = 0; i < init_hash_size; i++)
550 :
Base(other), mask(other.mask)
553 table =
new int[size];
554 memcpy(table, other.
table, size*
sizeof(
int));
567 inline void sort3(
int &
a,
int &
b,
int &c)
569 if (
a >
b) { std::swap(
a,
b); }
570 if (
a > c) { std::swap(
a, c); }
571 if (
b > c) { std::swap(
b, c); }
574 inline void sort4(
int &
a,
int &
b,
int &c,
int &d)
576 if (
a >
b) { std::swap(
a,
b); }
577 if (
a > c) { std::swap(
a, c); }
578 if (
a > d) { std::swap(
a, d); }
582 inline void sort4_ext(
int &
a,
int &
b,
int &c,
int &d)
599 return &(Base::At(GetId(p1, p2)));
605 return &(Base::At(GetId(p1, p2, p3, p4)));
612 if (p1 > p2) { std::swap(p1, p2); }
613 int idx = Hash(p1, p2);
614 int id = SearchList(table[idx], p1, p2);
615 if (
id >= 0) {
return id; }
621 new_id = unused.Last();
626 new_id = Base::Append();
628 T& item = Base::At(new_id);
633 Insert(idx, new_id, item);
643 internal::sort4_ext(p1, p2, p3, p4);
644 int idx = Hash(p1, p2, p3);
645 int id = SearchList(table[idx], p1, p2, p3);
646 if (
id >= 0) {
return id; }
652 new_id = unused.Last();
657 new_id = Base::Append();
659 T& item = Base::At(new_id);
665 Insert(idx, new_id, item);
674 int id = FindId(p1, p2);
675 return (
id >= 0) ? &(Base::At(
id)) : NULL;
681 int id = FindId(p1, p2, p3, p4);
682 return (
id >= 0) ? &(Base::At(
id)) : NULL;
688 int id = FindId(p1, p2);
689 return (
id >= 0) ? &(Base::At(
id)) : NULL;
695 int id = FindId(p1, p2, p3, p4);
696 return (
id >= 0) ? &(Base::At(
id)) : NULL;
702 if (p1 > p2) { std::swap(p1, p2); }
703 return SearchList(table[Hash(p1, p2)], p1, p2);
709 internal::sort4_ext(p1, p2, p3, p4);
710 return SearchList(table[Hash(p1, p2, p3)], p1, p2, p3);
718 const T& item = Base::At(
id);
719 if (item.p1 == p1 && item.p2 == p2) {
return id; }
730 const T& item = Base::At(
id);
731 if (item.p1 == p1 && item.p2 == p2 && item.p3 == p3) {
return id; }
740 const int fill_factor = 2;
743 if (Base::Size() > (mask+1) * fill_factor)
755 int new_table_size = 2*(mask+1);
756 table =
new int[new_table_size];
757 for (
int i = 0; i < new_table_size; i++) { table[i] = -1; }
758 mask = new_table_size-1;
760 #if defined(MFEM_DEBUG) && !defined(MFEM_USE_MPI) 761 mfem::out << _MFEM_FUNC_NAME <<
": rehashing to size " << new_table_size
766 for (iterator it = begin(); it != end(); ++it)
768 Insert(Hash(*it), it.index(), *it);
776 item.next = table[idx];
784 int* p_id = table + idx;
787 T& item = Base::At(*p_id);
795 MFEM_ABORT(
"HashTable<>::Unlink: item not found!");
801 T& item = Base::At(
id);
802 Unlink(Hash(item),
id);
811 for (
int i = 0; i <= mask; i++) { table[i] = -1; }
819 while (
id >= Base::Size())
821 Base::At(Base::Append()).next = -2;
824 T& item = Base::At(
id);
831 Insert(Hash(p1, p2),
id, item);
840 for (
int i = 0; i < Base::Size(); i++)
842 if (Base::At(i).next == -2) { unused.Append(i); }
849 T& item = Base::At(
id);
850 Unlink(Hash(item),
id);
852 if (new_p1 > new_p2) { std::swap(new_p1, new_p2); }
857 int new_idx = Hash(new_p1, new_p2);
858 Insert(new_idx,
id, item);
863 int new_p1,
int new_p2,
int new_p3,
int new_p4)
865 T& item = Base::At(
id);
866 Unlink(Hash(item),
id);
868 internal::sort4_ext(new_p1, new_p2, new_p3, new_p4);
874 int new_idx = Hash(new_p1, new_p2, new_p3);
875 Insert(new_idx,
id, item);
881 return (mask+1) *
sizeof(int) + Base::MemoryUsage() + unused.
MemoryUsage();
887 mfem::out << Base::MemoryUsage() <<
" + " << (mask+1) *
sizeof(
int)
888 <<
" + " << unused.MemoryUsage();
898 const T& item = Base::At(
id);
908 int table_size = mask+1;
909 mfem::out <<
"Hash table size: " << table_size <<
"\n";
910 mfem::out <<
"Item count: " << Size() <<
"\n";
911 mfem::out <<
"BlockArray size: " << Base::Size() <<
"\n";
916 for (
int i = 0; i < H; i++) { hist[i] = 0; }
918 for (
int i = 0; i < table_size; i++)
921 if (bs >= H) { bs = H-1; }
926 for (
int i = 0; i < H; i++)
929 << hist[i] <<
" bins" << std::endl;
934 template <
typename int_type_const_iter>
935 HashFunction &HashFunction::EncodeAndHashInts(int_type_const_iter begin,
936 int_type_const_iter end)
948 typename std::remove_reference<decltype(*begin)>::type
950 "invalid iterator type");
953 if (hash_data ==
nullptr) {
return *
this; }
955 constexpr
int max_buffer_bytes = 64*1024;
956 unsigned char buffer[max_buffer_bytes];
957 int buffer_counter = 0;
960 int byte_counter = 0;
962 buffer[buffer_counter] = (k >= 0) ? 0 : (k = -k, 128);
966 buffer[buffer_counter + byte_counter] = (
unsigned char)(k % 256);
969 buffer[buffer_counter] |= byte_counter;
970 buffer_counter += (byte_counter + 1);
975 buffer_counter + (1 +
sizeof(*begin)) > max_buffer_bytes)
977 HashBuffer(buffer, buffer_counter);
984 template <
typename double_const_iter>
985 HashFunction &HashFunction::EncodeAndHashDoubles(double_const_iter begin,
986 double_const_iter end)
991 std::is_same<decltype(*begin),
const double &>::value,
992 "invalid iterator type");
995 if (hash_data ==
nullptr) {
return *
this; }
997 constexpr
int max_buffer_bytes = 64*1024;
998 unsigned char buffer[max_buffer_bytes];
999 int buffer_counter = 0;
1000 while (begin != end)
1002 auto k =
reinterpret_cast<const uint64_t &
>(*begin);
1003 for (
int i = 0; i != 7; i++)
1005 buffer[buffer_counter++] = (
unsigned char)(k & 255); k >>= 8;
1007 buffer[buffer_counter++] = (
unsigned char)k;
1011 if (begin == end || buffer_counter + 8 > max_buffer_bytes)
1013 HashBuffer(buffer, buffer_counter);
Hash function for data sequences.
int Hash(const Hashed2 &item) const
Hash function for items of type T that inherit from Hashed2.
HashFunction & AppendInts(const int_type(&ints)[num_ints])
Add a sequence of integers for hashing, given as a fixed-size c-array.
int Size() const
Return the number of items actually stored.
void UpdateUnused()
Reinitialize the internal list of unallocated items.
std::size_t MemoryUsage() const
Return total size of allocated memory (tables plus items), in bytes.
HashFunction & EncodeAndHashDoubles(double_const_iter begin, double_const_iter end)
Double encoding method: encode in little-endian byte-order.
int Hash(size_t p1, size_t p2, size_t p3) const
hash function for Hashed4 items.
void Unlink(int idx, int id)
Unlink an item id from the linked list of bin idx.
void Delete(int id)
Remove an item from the hash table.
const_iterator cbegin() const
const_iterator cend() const
HashTable(int block_size=16 *1024, int init_hash_size=32 *1024)
Main constructor of the HashTable class.
void HashBuffer(const void *buffer, size_t num_bytes)
Add a sequence of bytes for hashing.
void PrintStats() const
Print a histogram of bin sizes for debugging purposes.
HashFunction & EncodeAndHashInts(int_type_const_iter begin, int_type_const_iter end)
Integer encoding method; result is independent of endianness and type.
void PrintMemoryDetail() const
Write details of the memory usage to the mfem output stream.
std::string GetHash() const
Return the hash string for the current sequence and reset (clear) the sequence.
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 va...
HashFunction & AppendBytes(const void *seq, size_t num_bytes)
Add a sequence of bytes for hashing.
const_iterator(const base &it)
void DeleteAll()
Remove all items.
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...
HashFunction & AppendDoubles(const double *doubles, size_t num_doubles)
Add a sequence of doubles for hashing, given as a c-array.
int Hash(size_t p1, size_t p2) const
hash function for Hashed2 items.
void CheckRehash()
Check table fill factor and resize if necessary.
int BinSize(int idx) const
Return the size of the bin "idx".
HashFunction()
Default constructor: initialize the hash function.
const_iterator & operator++()
int NumFreeIds() const
Return the number of free/unused ids in the HashTable.
void Reparent(int id, int new_p1, int new_p2)
Change the key associated with an item.
T * Find(int p1, int p2)
Find item whose parents are p1, p2... Return NULL if it doesn't exist.
HashFunction & AppendDoubles(const double(&doubles)[num_doubles])
Add a sequence of doubles for hashing, given as a fixed-size c-array.
int Hash(const Hashed4 &item) const
Hash function for items of type T that inherit from Hashed4.
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
HashFunction & AppendInts(const int_type *ints, size_t num_ints)
Add a sequence of integers for hashing, given as a c-array.
const_iterator cbegin() const
int FindId(int p1, int p2) const
Find id of item whose parents are p1, p2... Return -1 if it doesn't exist.
bool IdExists(int id) const
Return true if item 'id' exists in (is used by) the container.
void Copy(Array ©) const
Create a copy of the internal array to the provided copy.
int NumIds() const
Return the total number of ids (used and unused) in the HashTable.
int Size() const
Return the logical size of the array.
HashFunction & AppendInts(const int_type_container &ints)
Add a sequence of integers for hashing, given as a container.
~HashFunction()
Destructor.
int GetId(int p1, int p2)
Get id of item whose parents are p1, p2... Create it if it doesn't exist.
HashTable & operator=(const HashTable &)=delete
Copy assignment not supported.
int Size() const
Return the number of elements currently stored in the HashTable.
HashFunction & AppendDoubles(const double_container &doubles)
Add a sequence of doubles for hashing, given as a container.
Base::const_iterator base
T & At(int index)
Access item of the array.
void DoRehash()
Double the size of the hash table (i.e., double the number of bins) and reinsert all items into the n...
void Insert(int idx, int id, T &item)
Insert the item 'id' into bin 'idx'.