15 #include "../config/config.hpp"
18 #include <type_traits>
77 HashTable(
int block_size = 16*1024,
int init_hash_size = 32*1024);
82 T*
Get(
int p1,
int p2);
83 T*
Get(
int p1,
int p2,
int p3,
int p4 = -1 );
86 int GetId(
int p1,
int p2);
87 int GetId(
int p1,
int p2,
int p3,
int p4 = -1);
90 T*
Find(
int p1,
int p2);
91 T*
Find(
int p1,
int p2,
int p3,
int p4 = -1);
93 const T*
Find(
int p1,
int p2)
const;
94 const T*
Find(
int p1,
int p2,
int p3,
int p4 = -1)
const;
97 int FindId(
int p1,
int p2)
const;
98 int FindId(
int p1,
int p2,
int p3,
int p4 = -1)
const;
123 void Alloc(
int id,
int p1,
int p2);
130 void Reparent(
int id,
int new_p1,
int new_p2);
131 void Reparent(
int id,
int new_p1,
int new_p2,
int new_p3,
int new_p4 = -1);
180 iterator
end() {
return iterator(); }
183 const_iterator
cend()
const {
return const_iterator(); }
191 inline int Hash(
int p1,
int p2)
const
192 {
return (984120265*p1 + 125965121*p2) &
mask; }
194 inline int Hash(
int p1,
int p2,
int p3)
const
195 {
return (984120265*p1 + 125965121*p2 + 495698413*p3) &
mask; }
205 int SearchList(
int id,
int p1,
int p2,
int p3)
const;
207 inline void Insert(
int idx,
int id, T &item);
208 void Unlink(
int idx,
int id);
224 void HashBuffer(
const void *buffer,
size_t num_bytes);
227 template <
typename int_type_const_iter>
229 int_type_const_iter end);
232 template <
typename double_const_iter>
234 double_const_iter end);
250 template <
typename int_type>
257 template <
typename int_type,
size_t num_
ints>
264 template <
typename int_type_container>
277 template <
size_t num_
doubles>
284 template <
typename double_container>
300 mask = init_hash_size-1;
301 MFEM_VERIFY(!(init_hash_size &
mask),
"init_size must be a power of two.");
303 table =
new int[init_hash_size];
304 for (
int i = 0; i < init_hash_size; i++)
312 :
Base(other), mask(other.mask)
329 inline void sort3(
int &
a,
int &
b,
int &c)
331 if (a > b) { std::swap(a, b); }
332 if (a > c) { std::swap(a, c); }
333 if (b > c) { std::swap(b, c); }
336 inline void sort4(
int &a,
int &b,
int &c,
int &d)
338 if (a > b) { std::swap(a, b); }
339 if (a > c) { std::swap(a, c); }
340 if (a > d) { std::swap(a, d); }
344 inline void sort4_ext(
int &a,
int &b,
int &c,
int &d)
361 return &(Base::At(GetId(p1, p2)));
367 return &(Base::At(GetId(p1, p2, p3, p4)));
374 if (p1 > p2) { std::swap(p1, p2); }
375 int idx = Hash(p1, p2);
376 int id = SearchList(table[idx], p1, p2);
377 if (
id >= 0) {
return id; }
383 new_id = unused.Last();
388 new_id = Base::Append();
390 T& item = Base::At(new_id);
395 Insert(idx, new_id, item);
405 internal::sort4_ext(p1, p2, p3, p4);
406 int idx = Hash(p1, p2, p3);
407 int id = SearchList(table[idx], p1, p2, p3);
408 if (
id >= 0) {
return id; }
414 new_id = unused.Last();
419 new_id = Base::Append();
421 T& item = Base::At(new_id);
427 Insert(idx, new_id, item);
436 int id = FindId(p1, p2);
437 return (
id >= 0) ? &(Base::At(
id)) : NULL;
443 int id = FindId(p1, p2, p3, p4);
444 return (
id >= 0) ? &(Base::At(
id)) : NULL;
450 int id = FindId(p1, p2);
451 return (
id >= 0) ? &(Base::At(
id)) : NULL;
457 int id = FindId(p1, p2, p3, p4);
458 return (
id >= 0) ? &(Base::At(
id)) : NULL;
464 if (p1 > p2) { std::swap(p1, p2); }
465 return SearchList(table[Hash(p1, p2)], p1, p2);
471 internal::sort4_ext(p1, p2, p3, p4);
472 return SearchList(table[Hash(p1, p2, p3)], p1, p2, p3);
480 const T& item = Base::At(
id);
481 if (item.p1 == p1 && item.p2 == p2) {
return id; }
492 const T& item = Base::At(
id);
493 if (item.p1 == p1 && item.p2 == p2 && item.p3 == p3) {
return id; }
502 const int fill_factor = 2;
505 if (Base::Size() > (mask+1) * fill_factor)
517 int new_table_size = 2*(mask+1);
518 table =
new int[new_table_size];
519 for (
int i = 0; i < new_table_size; i++) { table[i] = -1; }
520 mask = new_table_size-1;
522 #if defined(MFEM_DEBUG) && !defined(MFEM_USE_MPI)
523 mfem::out << _MFEM_FUNC_NAME <<
": rehashing to size " << new_table_size
528 for (
iterator it = begin(); it != end(); ++it)
530 Insert(Hash(*it), it.index(), *it);
538 item.next = table[idx];
546 int* p_id = table + idx;
549 T& item = Base::At(*p_id);
557 MFEM_ABORT(
"HashTable<>::Unlink: item not found!");
563 T& item = Base::At(
id);
564 Unlink(Hash(item),
id);
573 for (
int i = 0; i <= mask; i++) { table[i] = -1; }
581 while (
id >= Base::Size())
583 Base::At(Base::Append()).next = -2;
586 T& item = Base::At(
id);
593 Insert(Hash(p1, p2),
id, item);
601 for (
int i = 0; i < Base::Size(); i++)
603 if (Base::At(i).next == -2) { unused.Append(i); }
610 T& item = Base::At(
id);
611 Unlink(Hash(item),
id);
613 if (new_p1 > new_p2) { std::swap(new_p1, new_p2); }
618 int new_idx = Hash(new_p1, new_p2);
619 Insert(new_idx,
id, item);
624 int new_p1,
int new_p2,
int new_p3,
int new_p4)
626 T& item = Base::At(
id);
627 Unlink(Hash(item),
id);
629 internal::sort4_ext(new_p1, new_p2, new_p3, new_p4);
635 int new_idx = Hash(new_p1, new_p2, new_p3);
636 Insert(new_idx,
id, item);
642 return (mask+1) *
sizeof(int) + Base::MemoryUsage() + unused.MemoryUsage();
648 mfem::out << Base::MemoryUsage() <<
" + " << (mask+1) *
sizeof(
int)
649 <<
" + " << unused.MemoryUsage();
653 template <
typename int_type_const_iter>
655 int_type_const_iter end)
667 typename std::remove_reference<decltype(*begin)>::type
669 "invalid iterator type");
672 if (
hash_data ==
nullptr) {
return *
this; }
674 constexpr
int max_buffer_bytes = 64*1024;
675 unsigned char buffer[max_buffer_bytes];
676 int buffer_counter = 0;
679 int byte_counter = 0;
681 buffer[buffer_counter] = (k >= 0) ? 0 : (k = -k, 128);
685 buffer[buffer_counter + byte_counter] = (
unsigned char)(k % 256);
688 buffer[buffer_counter] |= byte_counter;
689 buffer_counter += (byte_counter + 1);
694 buffer_counter + (1 +
sizeof(*begin)) > max_buffer_bytes)
703 template <
typename double_const_iter>
705 double_const_iter end)
710 std::is_same<decltype(*begin),
const double &>::value,
711 "invalid iterator type");
714 if (
hash_data ==
nullptr) {
return *
this; }
716 constexpr
int max_buffer_bytes = 64*1024;
717 unsigned char buffer[max_buffer_bytes];
718 int buffer_counter = 0;
721 auto k =
reinterpret_cast<const uint64_t &
>(*begin);
722 for (
int i = 0; i != 7; i++)
724 buffer[buffer_counter++] = (
unsigned char)(k & 255); k >>= 8;
726 buffer[buffer_counter++] = (
unsigned char)k;
730 if (begin == end || buffer_counter + 8 > max_buffer_bytes)
Hash function for data sequences.
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 logical size of the array.
void UpdateUnused()
Reinitialize the internal list of unallocated items.
int Hash(int p1, int p2, int p3) const
HashFunction & EncodeAndHashDoubles(double_const_iter begin, double_const_iter end)
Double encoding method: encode in little-endian byte-order.
int Hash(const Hashed4 &item) const
const_iterator cbegin() const
void Unlink(int idx, int id)
void Delete(int id)
Remove an item from the hash table.
bool IdExists(int id) const
Return true if item 'id' exists in (is used by) the container.
HashTable(int block_size=16 *1024, int init_hash_size=32 *1024)
void HashBuffer(const void *buffer, size_t num_bytes)
Add a sequence of bytes for hashing.
int Size() const
Return the number of items actually stored.
int SearchList(int id, int p1, int p2) const
void Copy(Array ©) const
Create a copy of the internal array to the provided copy.
HashFunction & EncodeAndHashInts(int_type_const_iter begin, int_type_const_iter end)
Integer encoding method; result is independent of endianness and type.
T * Get(int p1, int p2)
Get item whose parents are 'p1', 'p2'... Create it if it doesn't exist.
std::string GetHash() const
Return the hash string for the current sequence and reset (clear) the sequence.
HashFunction & AppendBytes(const void *seq, size_t num_bytes)
Add a sequence of bytes for hashing.
const_iterator(const base &it)
void PrintMemoryDetail() const
Write details of the memory usage to the mfem output stream.
int Hash(int p1, int p2) const
int Size() const
Return the number of elements currently stored in the HashTable.
void DeleteAll()
Remove all items.
HashFunction & AppendDoubles(const double *doubles, size_t num_doubles)
Add a sequence of doubles for hashing, given as a c-array.
void CheckRehash()
Check table load factor and resize if necessary.
HashFunction()
Default constructor: initialize the hash function.
const_iterator & operator++()
void Reparent(int id, int new_p1, int new_p2)
Make an item hashed under different parent IDs.
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 NumIds() const
Return the total number of ids (used and unused) in the HashTable.
int Hash(const Hashed2 &item) const
int NumFreeIds() const
Return the number of free/unused ids in the HashTable.
HashFunction & AppendInts(const int_type *ints, size_t num_ints)
Add a sequence of integers for hashing, given as a c-array.
long MemoryUsage() const
Return total size of allocated memory (tables plus items), in bytes.
const_iterator cbegin() const
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.
HashFunction & AppendDoubles(const double_container &doubles)
Add a sequence of doubles for hashing, given as a container.
Base::const_iterator base
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
int FindId(int p1, int p2) const
Find id of item whose parents are p1, p2... Return -1 if it doesn't exist.
T & At(int index)
Access item of the array.
void Insert(int idx, int id, T &item)
const_iterator cend() const