15 #include "../config/config.hpp" 18 #include <type_traits> 93 HashTable(
int block_size = 16*1024,
int init_hash_size = 32*1024);
108 T*
Get(
int p1,
int p2);
121 T*
Get(
int p1,
int p2,
int p3,
int p4 = -1 );
133 int GetId(
int p1,
int p2);
146 int GetId(
int p1,
int p2,
int p3,
int p4 = -1);
157 T*
Find(
int p1,
int p2);
170 T*
Find(
int p1,
int p2,
int p3,
int p4 = -1);
180 const T*
Find(
int p1,
int p2)
const;
193 const T*
Find(
int p1,
int p2,
int p3,
int p4 = -1)
const;
205 int FindId(
int p1,
int p2)
const;
218 int FindId(
int p1,
int p2,
int p3,
int p4 = -1)
const;
255 void Alloc(
int id,
int p1,
int p2);
271 void Reparent(
int id,
int new_p1,
int new_p2);
284 void Reparent(
int id,
int new_p1,
int new_p2,
int new_p3,
int new_p4 = -1);
336 iterator
end() {
return iterator(); }
339 const_iterator
cend()
const {
return const_iterator(); }
364 inline int Hash(
size_t p1,
size_t p2)
const 365 {
return (984120265ul*p1 + 125965121ul*p2) &
mask; }
377 inline int Hash(
size_t p1,
size_t p2,
size_t p3)
const 378 {
return (984120265ul*p1 + 125965121ul*p2 + 495698413ul*p3) &
mask; }
410 int SearchList(
int id,
int p1,
int p2,
int p3)
const;
421 inline void Insert(
int idx,
int id, T &item);
429 void Unlink(
int idx,
int id);
461 void HashBuffer(
const void *buffer,
size_t num_bytes);
464 template <
typename int_type_const_iter>
466 int_type_const_iter end);
469 template <
typename double_const_iter>
471 double_const_iter end);
487 template <
typename int_type>
494 template <
typename int_type,
size_t num_
ints>
501 template <
typename int_type_container>
514 template <
size_t num_
doubles>
521 template <
typename double_container>
537 mask = init_hash_size-1;
538 MFEM_VERIFY(!(init_hash_size & mask),
"init_size must be a power of two.");
540 table =
new int[init_hash_size];
541 for (
int i = 0; i < init_hash_size; i++)
549 :
Base(other), mask(other.mask)
552 table =
new int[size];
553 memcpy(table, other.
table, size*
sizeof(
int));
566 inline void sort3(
int &
a,
int &
b,
int &c)
568 if (
a >
b) { std::swap(
a,
b); }
569 if (
a > c) { std::swap(
a, c); }
570 if (
b > c) { std::swap(
b, c); }
573 inline void sort4(
int &
a,
int &
b,
int &c,
int &d)
575 if (
a >
b) { std::swap(
a,
b); }
576 if (
a > c) { std::swap(
a, c); }
577 if (
a > d) { std::swap(
a, d); }
581 inline void sort4_ext(
int &
a,
int &
b,
int &c,
int &d)
598 return &(Base::At(GetId(p1, p2)));
604 return &(Base::At(GetId(p1, p2, p3, p4)));
611 if (p1 > p2) { std::swap(p1, p2); }
612 int idx = Hash(p1, p2);
613 int id = SearchList(table[idx], p1, p2);
614 if (
id >= 0) {
return id; }
620 new_id = unused.Last();
625 new_id = Base::Append();
627 T& item = Base::At(new_id);
632 Insert(idx, new_id, item);
642 internal::sort4_ext(p1, p2, p3, p4);
643 int idx = Hash(p1, p2, p3);
644 int id = SearchList(table[idx], p1, p2, p3);
645 if (
id >= 0) {
return id; }
651 new_id = unused.Last();
656 new_id = Base::Append();
658 T& item = Base::At(new_id);
664 Insert(idx, new_id, item);
673 int id = FindId(p1, p2);
674 return (
id >= 0) ? &(Base::At(
id)) : NULL;
680 int id = FindId(p1, p2, p3, p4);
681 return (
id >= 0) ? &(Base::At(
id)) : NULL;
687 int id = FindId(p1, p2);
688 return (
id >= 0) ? &(Base::At(
id)) : NULL;
694 int id = FindId(p1, p2, p3, p4);
695 return (
id >= 0) ? &(Base::At(
id)) : NULL;
701 if (p1 > p2) { std::swap(p1, p2); }
702 return SearchList(table[Hash(p1, p2)], p1, p2);
708 internal::sort4_ext(p1, p2, p3, p4);
709 return SearchList(table[Hash(p1, p2, p3)], p1, p2, p3);
717 const T& item = Base::At(
id);
718 if (item.p1 == p1 && item.p2 == p2) {
return id; }
729 const T& item = Base::At(
id);
730 if (item.p1 == p1 && item.p2 == p2 && item.p3 == p3) {
return id; }
739 const int fill_factor = 2;
742 if (Base::Size() > (mask+1) * fill_factor)
754 int new_table_size = 2*(mask+1);
755 table =
new int[new_table_size];
756 for (
int i = 0; i < new_table_size; i++) { table[i] = -1; }
757 mask = new_table_size-1;
759 #if defined(MFEM_DEBUG) && !defined(MFEM_USE_MPI) 760 mfem::out << _MFEM_FUNC_NAME <<
": rehashing to size " << new_table_size
765 for (iterator it = begin(); it != end(); ++it)
767 Insert(Hash(*it), it.index(), *it);
775 item.next = table[idx];
783 int* p_id = table + idx;
786 T& item = Base::At(*p_id);
794 MFEM_ABORT(
"HashTable<>::Unlink: item not found!");
800 T& item = Base::At(
id);
801 Unlink(Hash(item),
id);
810 for (
int i = 0; i <= mask; i++) { table[i] = -1; }
818 while (
id >= Base::Size())
820 Base::At(Base::Append()).next = -2;
823 T& item = Base::At(
id);
830 Insert(Hash(p1, p2),
id, item);
839 for (
int i = 0; i < Base::Size(); i++)
841 if (Base::At(i).next == -2) { unused.Append(i); }
848 T& item = Base::At(
id);
849 Unlink(Hash(item),
id);
851 if (new_p1 > new_p2) { std::swap(new_p1, new_p2); }
856 int new_idx = Hash(new_p1, new_p2);
857 Insert(new_idx,
id, item);
862 int new_p1,
int new_p2,
int new_p3,
int new_p4)
864 T& item = Base::At(
id);
865 Unlink(Hash(item),
id);
867 internal::sort4_ext(new_p1, new_p2, new_p3, new_p4);
873 int new_idx = Hash(new_p1, new_p2, new_p3);
874 Insert(new_idx,
id, item);
880 return (mask+1) *
sizeof(int) + Base::MemoryUsage() + unused.
MemoryUsage();
886 mfem::out << Base::MemoryUsage() <<
" + " << (mask+1) *
sizeof(
int)
887 <<
" + " << unused.MemoryUsage();
897 const T& item = Base::At(
id);
907 int table_size = mask+1;
908 mfem::out <<
"Hash table size: " << table_size <<
"\n";
909 mfem::out <<
"Item count: " << Size() <<
"\n";
910 mfem::out <<
"BlockArray size: " << Base::Size() <<
"\n";
915 for (
int i = 0; i < H; i++) { hist[i] = 0; }
917 for (
int i = 0; i < table_size; i++)
920 if (bs >= H) { bs = H-1; }
925 for (
int i = 0; i < H; i++)
928 << hist[i] <<
" bins" << std::endl;
933 template <
typename int_type_const_iter>
934 HashFunction &HashFunction::EncodeAndHashInts(int_type_const_iter begin,
935 int_type_const_iter end)
947 typename std::remove_reference<decltype(*begin)>::type
949 "invalid iterator type");
952 if (hash_data ==
nullptr) {
return *
this; }
954 constexpr
int max_buffer_bytes = 64*1024;
955 unsigned char buffer[max_buffer_bytes];
956 int buffer_counter = 0;
959 int byte_counter = 0;
961 buffer[buffer_counter] = (k >= 0) ? 0 : (k = -k, 128);
965 buffer[buffer_counter + byte_counter] = (
unsigned char)(k % 256);
968 buffer[buffer_counter] |= byte_counter;
969 buffer_counter += (byte_counter + 1);
974 buffer_counter + (1 +
sizeof(*begin)) > max_buffer_bytes)
976 HashBuffer(buffer, buffer_counter);
983 template <
typename double_const_iter>
984 HashFunction &HashFunction::EncodeAndHashDoubles(double_const_iter begin,
985 double_const_iter end)
990 std::is_same<decltype(*begin),
const double &>::value,
991 "invalid iterator type");
994 if (hash_data ==
nullptr) {
return *
this; }
996 constexpr
int max_buffer_bytes = 64*1024;
997 unsigned char buffer[max_buffer_bytes];
998 int buffer_counter = 0;
1001 auto k =
reinterpret_cast<const uint64_t &
>(*begin);
1002 for (
int i = 0; i != 7; i++)
1004 buffer[buffer_counter++] = (
unsigned char)(k & 255); k >>= 8;
1006 buffer[buffer_counter++] = (
unsigned char)k;
1010 if (begin == end || buffer_counter + 8 > max_buffer_bytes)
1012 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'.