14#ifndef CXXUTILS_CONCURRENTHASHMAPIMPL_H
15#define CXXUTILS_CONCURRENTHASHMAPIMPL_H
29class ConcurrentHashmapImplTest;
50 std::is_trivial_v<T> &&
58 :
public std::unique_lock<std::mutex>
61 using std::unique_lock<std::mutex>::unique_lock;
83template <
unsigned ENTRIES_PER_CACHELINE>
194template <
template <
class>
class UPDATER_,
195 typename HASHER_ = std::hash<uintptr_t>,
196 typename MATCHER_ = std::equal_to<uintptr_t>,
197 uintptr_t NULLVAL_ = 0,
198 uintptr_t TOMBSTONE_ = NULLVAL_>
205 using Hasher_t = HASHER_;
207 using Matcher_t = MATCHER_;
209 static constexpr uintptr_t nullval = NULLVAL_;
211 static constexpr uintptr_t tombstone = TOMBSTONE_;
213 static constexpr size_t INVALID =
static_cast<size_t>(-1);
222 std::atomic<val_t> m_key;
223 std::atomic<val_t> m_val;
227 static constexpr size_t CACHELINE = 64;
232 static_assert (CACHELINE >=
sizeof (entry_t) &&
233 CACHELINE %
sizeof(entry_t) == 0);
236 static constexpr size_t ENTRIES_PER_CACHELINE = CACHELINE /
sizeof(entry_t);
238 static constexpr size_t ENTRIES_PER_CACHELINE_MASK = (ENTRIES_PER_CACHELINE-1);
241 friend class ::ConcurrentHashmapImplTest;
266 const Hasher_t&
hasher = Hasher_t(),
267 const Matcher_t&
matcher = Matcher_t());
277 static void*
operator new (size_t,
size_t capacity);
283 void operator delete (
void* p);
320 const entry_t&
entry (
size_t offset)
const;
371 const typename Updater_t::Context_t& ctx);
509 std::pair<const_iterator, bool>
510 put (val_t key,
size_t hash, val_t val,
512 const typename Updater_t::Context_t& ctx);
529 std::pair<const_iterator, bool>
531 val_t key,
size_t hash, val_t val,
533 const typename Updater_t::Context_t& ctx);
561 bool erase (val_t key,
size_t hash);
580 bool erase (
const Lock_t&
lock, val_t key,
size_t hash);
613 const typename Updater_t::Context_t& ctx);
644 const typename Updater_t::Context_t& ctx);
652 void quiescent (
const typename Updater_t::Context_t& ctx);
682 bool grow (
const Lock_t&
lock,
const typename Updater_t::Context_t& ctx);
692 bool grow (
const Lock_t&
lock,
size_t new_capacity,
const typename Updater_t::Context_t& ctx);
ElementLink & operator=(const ElementLink &)=default
bool operator!=(const DataVector< T > &a, const DataVector< T > &b)
Based on operator==.
void swap(DataVector< T > &a, DataVector< T > &b)
See DataVector<T, BASE>::swap().
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
size_t size() const
Number of registered mappings.
void clear()
Empty the pool.
Atomic min/max functions.
Helper to allow for external locking with put().
Hash table allowing concurrent, lockless reads.
*Longest probe needed so far std::atomic< size_t > m_longestProbe
Table(size_t capacity, const Hasher_t &hasher=Hasher_t(), const Matcher_t &matcher=Matcher_t())
Constructor.
*The key match object const Matcher_t & m_matcher
entry_t & entry(size_t offset)
Return the entry for an offset (non-const).
*The hash object const Hasher_t & m_hasher
*Maximum number of probes allowed before resizing the table const size_t m_maxProbe
*Number of entries in the table Must be a power of const size_t m_capacity
size_t probeRead(val_t key, size_t hash) const
Find a table entry for reading.
*The actual table entries entry_t m_entries[1]
const entry_t & entry(size_t offset) const
Return the entry for an offset.
size_t capacity() const
The number of entries in the table.
*Number of bits in the mask const size_t m_maskBits
size_t probeWrite(val_t key, size_t hash, bool &insert)
Find a table entry for writing.
CHMTableIterator< ENTRIES_PER_CACHELINE > TableIterator
Bidirectional iterator over occupied table entries.
val_t value() const
Return the value for this iterator.
val_t key() const
Return the key for this iterator.
*The current position in the table *Set to for an end iterator size_t m_offset
void next()
Advance the iterator to the next occupied entry.
*The table over which we re iterating const Table & m_table
bool valid() const
Check that the iterator is valid (not pointing at the end).
void prev()
Move the iterator back to the previous occupied entry.
const_iterator(const Table &table, size_t offset)
Constructor.
const_iterator(const Table &table, bool end)
Constructor.
Concept for a value that can be saved in a concurrent hash map.
A couple standard-library related concepts.
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
UPDATER_< Table > Updater_t
*Mutex to serialize changes to the map std::mutex m_mutex
*Number of entries in the map std::atomic< size_t > m_size
static uint64_t round_up(uint64_t)
void reserve(size_t capacity, const typename Updater_t::Context_t &ctx)
Increase the table capacity.
std::pair< const_iterator, const_iterator > const_iterator_range
const_iterator begin() const
A begin iterator for the container.
*The hash object const Hasher_t m_hasher
*Number of entries that have been erased std::atomic< size_t > m_erased
const Hasher_t & hasher() const
Return the hasher object.
void quiescent(const typename Updater_t::Context_t &ctx)
Called when this thread is no longer referencing anything from this container.
std::pair< const_iterator, bool > put(val_t key, size_t hash, val_t val, bool overwrite, const typename Updater_t::Context_t &ctx)
Add an entry to the table.
typename Updater_t::Context_t Context_t
size_t capacity() const
Return the current table size.
*The key match object const Matcher_t m_matcher
const_iterator_range range() const
Return a range that can be used to iterate over the container.
uintptr_t ConcurrentHashmapVal_t
Type used for keys and values — an unsigned big enough to hold a pointer.
bool grow(const Lock_t &lock, const typename Updater_t::Context_t &ctx)
Make the table larger.
const Matcher_t & matcher() const
Return the matcher object.
Updater_t & updater()
Access the Updater instance.
Lock_t lock()
Take a lock on the container.
const_iterator end() const
An end iterator for the container.
*The current table instance Must be holding the mutex to access this Table * m_table
*Updater object managing memory See above Updater_t m_updater
size_t erased() const
The number of erased elements in the current table.
void forceClear()
Erase the table by filling it with nulls.
ConcurrentHashmapImpl(Updater_t &&updater, size_t capacity_in, const Hasher_t &hasher, const Matcher_t &matcher, const typename Updater_t::Context_t &ctx)
Constructor.
bool erase(val_t key, size_t hash)
Erase an entry from the table.
ConcurrentBitset & insert(bit_t bit, bit_t new_nbits=0)
Set a bit to 1.
Helper to generate hash probes.
const size_t m_stride
Base increment between probes.
size_t offset() const
Offset of the element currently being probed.
const size_t m_boffs
Offset of the first entry we probe within its cacheline.
size_t nprobes() const
Return the number of probes performed so far.
const size_t m_mask
Mask for the table; i.e., capacity-1, but with the low bits corresponding to ENTRIES_PER_CACHELINE al...
static constexpr size_t ENTRIES_PER_CACHELINE_MASK
Mask for the within-cacheline part of indices.
CHMTableIterator(size_t hash, size_t mask, size_t maskBits, size_t probeLimit)
Constructor.
size_t m_bucket
Index of the start of the cacheline currently being probed.
size_t m_nprobes
Number of probes tried so far.
const size_t m_probeLimit
Maximum number of probes to try.
bool next()
Move to the next probe.