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);
468 void HashBuffer(
const void *buffer,
size_t num_bytes);
471 template <
typename int_type_const_iter>
473 int_type_const_iter end);
476 template <
typename double_const_iter>
478 double_const_iter end);
494 template <
typename int_type>
501 template <
typename int_type,
size_t num_
ints>
508 template <
typename int_type_container>
521 template <
size_t num_
doubles>
528 template <
typename double_container>
544 mask = init_hash_size-1;
545 MFEM_VERIFY(!(init_hash_size &
mask),
"init_size must be a power of two.");
547 table =
new int[init_hash_size];
548 for (
int i = 0; i < init_hash_size; i++)
556 :
Base(other), mask(other.mask)
573inline void sort3(
int &
a,
int &
b,
int &c)
575 if (
a >
b) { std::swap(
a,
b); }
576 if (
a > c) { std::swap(
a, c); }
577 if (
b > c) { std::swap(
b, c); }
580inline void sort4(
int &
a,
int &
b,
int &c,
int &d)
582 if (
a >
b) { std::swap(
a,
b); }
583 if (
a > c) { std::swap(
a, c); }
584 if (
a > d) { std::swap(
a, d); }
588inline void sort4_ext(
int &
a,
int &
b,
int &c,
int &d)
605 return &(Base::At(GetId(p1, p2)));
611 return &(Base::At(GetId(p1, p2, p3, p4)));
618 if (p1 > p2) { std::swap(p1, p2); }
619 int idx = Hash(p1, p2);
620 int id = SearchList(table[idx], p1, p2);
621 if (
id >= 0) {
return id; }
627 new_id = unused.Last();
632 new_id = Base::Append();
634 T& item = Base::At(new_id);
639 Insert(idx, new_id, item);
649 internal::sort4_ext(p1, p2, p3, p4);
650 int idx = Hash(p1, p2, p3);
651 int id = SearchList(table[idx], p1, p2, p3);
652 if (
id >= 0) {
return id; }
658 new_id = unused.Last();
663 new_id = Base::Append();
665 T& item = Base::At(new_id);
671 Insert(idx, new_id, item);
680 int id = FindId(p1, p2);
681 return (
id >= 0) ? &(Base::At(
id)) : NULL;
687 int id = FindId(p1, p2, p3, p4);
688 return (
id >= 0) ? &(Base::At(
id)) : NULL;
694 int id = FindId(p1, p2);
695 return (
id >= 0) ? &(Base::At(
id)) : NULL;
701 int id = FindId(p1, p2, p3, p4);
702 return (
id >= 0) ? &(Base::At(
id)) : NULL;
708 if (p1 > p2) { std::swap(p1, p2); }
709 return SearchList(table[Hash(p1, p2)], p1, p2);
715 internal::sort4_ext(p1, p2, p3, p4);
716 return SearchList(table[Hash(p1, p2, p3)], p1, p2, p3);
724 const T& item = Base::At(
id);
725 if (item.p1 == p1 && item.p2 == p2) {
return id; }
736 const T& item = Base::At(
id);
737 if (item.p1 == p1 && item.p2 == p2 && item.p3 == p3) {
return id; }
746 const int fill_factor = 2;
749 if (Base::Size() > (mask+1) * fill_factor)
761 int new_table_size = 2*(mask+1);
762 table =
new int[new_table_size];
763 for (
int i = 0; i < new_table_size; i++) { table[i] = -1; }
764 mask = new_table_size-1;
766#if defined(MFEM_DEBUG) && !defined(MFEM_USE_MPI)
767 mfem::out << _MFEM_FUNC_NAME <<
": rehashing to size " << new_table_size
772 for (
iterator it = begin(); it != end(); ++it)
774 Insert(Hash(*it), it.index(), *it);
782 item.next = table[idx];
790 int* p_id = table + idx;
793 T& item = Base::At(*p_id);
801 MFEM_ABORT(
"HashTable<>::Unlink: item not found!");
807 T& item = Base::At(
id);
808 Unlink(Hash(item),
id);
817 for (
int i = 0; i <= mask; i++) { table[i] = -1; }
825 while (
id >= Base::Size())
827 Base::At(Base::Append()).next = -2;
830 T& item = Base::At(
id);
837 Insert(Hash(p1, p2),
id, item);
846 for (
int i = 0; i < Base::Size(); i++)
848 if (Base::At(i).next == -2) { unused.Append(i); }
855 T& item = Base::At(
id);
856 Unlink(Hash(item),
id);
858 if (new_p1 > new_p2) { std::swap(new_p1, new_p2); }
863 int new_idx = Hash(new_p1, new_p2);
864 Insert(new_idx,
id, item);
869 int new_p1,
int new_p2,
int new_p3,
int new_p4)
871 T& item = Base::At(
id);
872 Unlink(Hash(item),
id);
874 internal::sort4_ext(new_p1, new_p2, new_p3, new_p4);
880 int new_idx = Hash(new_p1, new_p2, new_p3);
881 Insert(new_idx,
id, item);
887 return (mask+1) *
sizeof(int) + Base::MemoryUsage() + unused.MemoryUsage();
893 mfem::out << Base::MemoryUsage() <<
" + " << (mask+1) *
sizeof(
int)
894 <<
" + " << unused.MemoryUsage();
904 const T& item = Base::At(
id);
914 int table_size = mask+1;
915 mfem::out <<
"Hash table size: " << table_size <<
"\n";
916 mfem::out <<
"Item count: " << Size() <<
"\n";
917 mfem::out <<
"BlockArray size: " << Base::Size() <<
"\n";
922 for (
int i = 0; i < H; i++) { hist[i] = 0; }
924 for (
int i = 0; i < table_size; i++)
927 if (bs >= H) { bs = H-1; }
932 for (
int i = 0; i < H; i++)
935 << hist[i] <<
" bins" << std::endl;
940template <
typename int_type_const_iter>
942 int_type_const_iter end)
954 typename std::remove_reference<
decltype(*begin)>::type
956 "invalid iterator type");
959 if (
hash_data ==
nullptr) {
return *
this; }
961 constexpr int max_buffer_bytes = 64*1024;
962 unsigned char buffer[max_buffer_bytes];
963 int buffer_counter = 0;
966 int byte_counter = 0;
968 buffer[buffer_counter] = (k >= 0) ? 0 : (k = -k, 128);
972 buffer[buffer_counter + byte_counter] = (
unsigned char)(k % 256);
975 buffer[buffer_counter] |= byte_counter;
976 buffer_counter += (byte_counter + 1);
981 buffer_counter + (1 +
sizeof(*begin)) > max_buffer_bytes)
990template <
typename double_const_iter>
992 double_const_iter end)
997 std::is_same<
decltype(*begin),
const real_t &>::value,
998 "invalid iterator type");
1001 if (
hash_data ==
nullptr) {
return *
this; }
1003 constexpr int max_buffer_bytes = 64*1024;
1004 unsigned char buffer[max_buffer_bytes];
1005 int buffer_counter = 0;
1006 while (begin != end)
1008 auto k =
reinterpret_cast<const uint64_t &
>(*begin);
1009 for (
int i = 0; i != 7; i++)
1011 buffer[buffer_counter++] = (
unsigned char)(k & 255); k >>= 8;
1013 buffer[buffer_counter++] = (
unsigned char)k;
1017 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...