94 HashTable(
int block_size = 16*1024,
int init_hash_size = 32*1024);
122 T*
Get(
int p1,
int p2,
int p3,
int p4 = -1 );
147 int GetId(
int p1,
int p2,
int p3,
int p4 = -1);
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;
219 int FindId(
int p1,
int p2,
int p3,
int p4 = -1)
const;
285 void Reparent(
int id,
int new_p1,
int new_p2,
int new_p3,
int new_p4 = -1);
367 inline int Hash(
size_t p1,
size_t p2)
const
368 {
return (984120265ul*p1 + 125965121ul*p2) &
mask; }
380 inline int Hash(
size_t p1,
size_t p2,
size_t p3)
const
381 {
return (984120265ul*p1 + 125965121ul*p2 + 495698413ul*p3) &
mask; }
424 inline void Insert(
int idx,
int id, T &item);
464 void HashBuffer(
const void *buffer,
size_t num_bytes);
467 template <
typename int_type_const_iter>
469 int_type_const_iter end);
472 template <
typename double_const_iter>
474 double_const_iter end);
490 template <
typename int_type>
497 template <
typename int_type,
size_t num_
ints>
504 template <
typename int_type_container>
517 template <
size_t num_
doubles>
524 template <
typename double_container>
540 mask = init_hash_size-1;
541 MFEM_VERIFY(!(init_hash_size &
mask),
"init_size must be a power of two.");
543 table =
new int[init_hash_size];
544 for (
int i = 0; i < init_hash_size; i++)
552 :
Base(other), mask(other.mask)
569inline void sort3(
int &
a,
int &
b,
int &c)
571 if (
a >
b) { std::swap(
a,
b); }
572 if (
a > c) { std::swap(
a, c); }
573 if (
b > c) { std::swap(
b, c); }
576inline void sort4(
int &
a,
int &
b,
int &c,
int &d)
578 if (
a >
b) { std::swap(
a,
b); }
579 if (
a > c) { std::swap(
a, c); }
580 if (
a > d) { std::swap(
a, d); }
584inline void sort4_ext(
int &
a,
int &
b,
int &c,
int &d)
601 return &(Base::At(GetId(p1, p2)));
607 return &(Base::At(GetId(p1, p2, p3, p4)));
614 if (p1 > p2) { std::swap(p1, p2); }
615 int idx = Hash(p1, p2);
616 int id = SearchList(table[idx], p1, p2);
617 if (
id >= 0) {
return id; }
623 new_id = unused.Last();
628 new_id = Base::Append();
630 T& item = Base::At(new_id);
635 Insert(idx, new_id, item);
645 internal::sort4_ext(p1, p2, p3, p4);
646 int idx = Hash(p1, p2, p3);
647 int id = SearchList(table[idx], p1, p2, p3);
648 if (
id >= 0) {
return id; }
654 new_id = unused.Last();
659 new_id = Base::Append();
661 T& item = Base::At(new_id);
667 Insert(idx, new_id, item);
676 int id = FindId(p1, p2);
677 return (
id >= 0) ? &(Base::At(
id)) : NULL;
683 int id = FindId(p1, p2, p3, p4);
684 return (
id >= 0) ? &(Base::At(
id)) : NULL;
690 int id = FindId(p1, p2);
691 return (
id >= 0) ? &(Base::At(
id)) : NULL;
697 int id = FindId(p1, p2, p3, p4);
698 return (
id >= 0) ? &(Base::At(
id)) : NULL;
704 if (p1 > p2) { std::swap(p1, p2); }
705 return SearchList(table[Hash(p1, p2)], p1, p2);
711 internal::sort4_ext(p1, p2, p3, p4);
712 return SearchList(table[Hash(p1, p2, p3)], p1, p2, p3);
720 const T& item = Base::At(
id);
721 if (item.p1 == p1 && item.p2 == p2) {
return id; }
732 const T& item = Base::At(
id);
733 if (item.p1 == p1 && item.p2 == p2 && item.p3 == p3) {
return id; }
742 const int fill_factor = 2;
745 if (Base::Size() > (mask+1) * fill_factor)
757 int new_table_size = 2*(mask+1);
758 table =
new int[new_table_size];
759 for (
int i = 0; i < new_table_size; i++) { table[i] = -1; }
760 mask = new_table_size-1;
762#if defined(MFEM_DEBUG) && !defined(MFEM_USE_MPI)
763 mfem::out << _MFEM_FUNC_NAME <<
": rehashing to size " << new_table_size
768 for (
iterator it = begin(); it != end(); ++it)
770 Insert(Hash(*it), it.index(), *it);
778 item.next = table[idx];
786 int* p_id = table + idx;
789 T& item = Base::At(*p_id);
797 MFEM_ABORT(
"HashTable<>::Unlink: item not found!");
803 T& item = Base::At(
id);
804 Unlink(Hash(item),
id);
813 for (
int i = 0; i <= mask; i++) { table[i] = -1; }
821 while (
id >= Base::Size())
823 Base::At(Base::Append()).next = -2;
826 T& item = Base::At(
id);
833 Insert(Hash(p1, p2),
id, item);
842 for (
int i = 0; i < Base::Size(); i++)
844 if (Base::At(i).next == -2) { unused.Append(i); }
851 T& item = Base::At(
id);
852 Unlink(Hash(item),
id);
854 if (new_p1 > new_p2) { std::swap(new_p1, new_p2); }
859 int new_idx = Hash(new_p1, new_p2);
860 Insert(new_idx,
id, item);
865 int new_p1,
int new_p2,
int new_p3,
int new_p4)
867 T& item = Base::At(
id);
868 Unlink(Hash(item),
id);
870 internal::sort4_ext(new_p1, new_p2, new_p3, new_p4);
876 int new_idx = Hash(new_p1, new_p2, new_p3);
877 Insert(new_idx,
id, item);
883 return (mask+1) *
sizeof(int) + Base::MemoryUsage() + unused.MemoryUsage();
889 mfem::out << Base::MemoryUsage() <<
" + " << (mask+1) *
sizeof(
int)
890 <<
" + " << unused.MemoryUsage();
900 const T& item = Base::At(
id);
910 int table_size = mask+1;
911 mfem::out <<
"Hash table size: " << table_size <<
"\n";
912 mfem::out <<
"Item count: " << Size() <<
"\n";
913 mfem::out <<
"BlockArray size: " << Base::Size() <<
"\n";
918 for (
int i = 0; i < H; i++) { hist[i] = 0; }
920 for (
int i = 0; i < table_size; i++)
923 if (bs >= H) { bs = H-1; }
928 for (
int i = 0; i < H; i++)
931 << hist[i] <<
" bins" << std::endl;
936template <
typename int_type_const_iter>
938 int_type_const_iter end)
950 typename std::remove_reference<
decltype(*begin)>::type
952 "invalid iterator type");
955 if (
hash_data ==
nullptr) {
return *
this; }
957 constexpr int max_buffer_bytes = 64*1024;
958 unsigned char buffer[max_buffer_bytes];
959 int buffer_counter = 0;
962 int byte_counter = 0;
964 buffer[buffer_counter] = (k >= 0) ? 0 : (k = -k, 128);
968 buffer[buffer_counter + byte_counter] = (
unsigned char)(k % 256);
971 buffer[buffer_counter] |= byte_counter;
972 buffer_counter += (byte_counter + 1);
977 buffer_counter + (1 +
sizeof(*begin)) > max_buffer_bytes)
986template <
typename double_const_iter>
988 double_const_iter end)
993 std::is_same<
decltype(*begin),
const real_t &>::value,
994 "invalid iterator type");
997 if (
hash_data ==
nullptr) {
return *
this; }
999 constexpr int max_buffer_bytes = 64*1024;
1000 unsigned char buffer[max_buffer_bytes];
1001 int buffer_counter = 0;
1002 while (begin != end)
1004 auto k =
reinterpret_cast<const uint64_t &
>(*begin);
1005 for (
int i = 0; i != 7; i++)
1007 buffer[buffer_counter++] = (
unsigned char)(k & 255); k >>= 8;
1009 buffer[buffer_counter++] = (
unsigned char)k;
1013 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 va...
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)
Find item whose parents are p1, p2... Return NULL if it doesn't exist.
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 id of item whose parents are p1, p2... Create it if it doesn't exist.
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 opti...
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 id of item whose parents are p1, p2... Return -1 if it doesn't 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 nullptr if no value correspond ...
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...