22 using key_type =
typename T::key_type;
23 using iterator_type =
typename T::iterator;
25 static constexpr std::false_type test(...) {
return {}; }
27 static constexpr
auto test(U* u) ->
28 typename std::is_same<iterator_type, decltype(u->find(key_type(),
size_t(0)))>::
type {
return {}; }
30 static constexpr
bool value = test<T>(
nullptr);
45 template<
class Map,
class Key,
47 typename Map::iterator
50 return map.find(key, hash);
53 template<
class Map,
class Key,
55 typename Map::iterator
95 template<
class KEY,
class VALUE,
class HASH = std::hash<KEY>,
96 class PRED = std::equal_to<KEY>,
size_t BINS = 16,
97 class BINMAP = std::unordered_map<KEY, VALUE, HASH, PRED>>
137 m_biniterator = src.m_biniterator;
138 m_locked = src.m_locked;
140 *(
const_cast<bool*
>(&src.m_locked)) =
false;
161 return *m_biniterator;
168 return &(*m_biniterator);
176 return m_umc && m_bin >= 0
177 && m_biniterator != m_umc->m_bins[m_bin].map.end();
187 m_biniterator = src.m_biniterator;
188 m_locked = src.m_locked;
190 *(
const_cast<bool*
>(&src.m_locked)) =
false;
196 if (m_umc != other.m_umc)
198 if (m_bin == -1 && other.m_bin == -1)
200 return m_bin == other.m_bin && m_biniterator == other.m_biniterator;
213 while (m_biniterator == m_umc->m_bins[m_bin].map.end()) {
214 if (m_bin == BINS - 1) {
227 if (m_bin >= 0 && !m_locked) {
228 m_umc->m_bins[m_bin].lock();
235 if (m_bin >= 0 && m_locked) {
236 m_umc->m_bins[m_bin].unlock();
249 return (m_biniterator != m_umc->m_bins[m_bin].map.end());
266 void rebin(
int newbin)
272 m_biniterator = m_umc->m_bins[m_bin].map.begin();
287 while (i.m_biniterator == m_bins[i.m_bin].map.end()) {
288 if (i.m_bin == BINS - 1) {
293 i.rebin(i.m_bin + 1);
316 size_t hash = m_hash(key);
317 size_t b = whichbin(hash);
322 if (it == bin.map.end()) {
330 i.m_bin = (unsigned)b;
331 i.m_biniterator = it;
332 i.m_locked = do_lock;
346 size_t hash = m_hash(key);
347 size_t b = whichbin(hash);
348 bool inserted =
false;
353 iret.m_bin = (unsigned)b;
354 iret.m_locked = do_lock;
358 if (iret.m_biniterator == bin.map.end()) {
360 auto result = bin.map.emplace(key, value);
365 iret.m_biniterator =
result.first;
368 return { iret, inserted };
378 size_t hash = m_hash(key);
379 size_t b = whichbin(hash);
384 bool found = (it != bin.map.end());
402 size_t hash = m_hash(key);
403 size_t b = whichbin(hash);
407 auto result = bin.map.emplace(key, value);
413 value =
result.first->second;
430 bool insert(
const KEY& key,
const VALUE&
value,
bool do_lock =
true)
432 size_t hash = m_hash(key);
433 size_t b = whichbin(hash);
437 auto result = bin.map.emplace(key, value);
451 void erase(
const KEY& key,
bool do_lock =
true)
453 size_t hash = m_hash(key);
454 size_t b = whichbin(hash);
458 bin.map.erase(key, hash);
465 bool empty() {
return m_size == 0; }
468 size_t size() {
return size_t(m_size); }
475 size_t hash = m_hash(key);
476 size_t b = whichbin(hash);
487 static constexpr
size_t nobin_mask() {
return ~size_t(0) >> log2(BINS); }
513 void read_lock()
const
519 "oops, m_nrlocks = %d, m_nwlocks = %d",
520 (
int)m_nrlocks, (
int)m_nwlocks);
523 void read_unlock()
const
527 "oops, m_nrlocks = %d, m_nwlocks = %d",
528 (
int)m_nrlocks, (
int)m_nwlocks);
540 "oops, m_nrlocks = %d, m_nwlocks = %d",
541 (
int)m_nrlocks, (
int)m_nwlocks);
548 "oops, m_nrlocks = %d, m_nwlocks = %d",
549 (
int)m_nrlocks, (
int)m_nwlocks);
560 static constexpr
int log2(
unsigned n)
562 return n < 2 ? 0 : 1 + log2(n / 2);
566 size_t whichbin(
size_t hash)
568 constexpr
int LOG2_BINS = log2(BINS);
569 constexpr
int BIN_SHIFT = 8 *
sizeof(size_t) - LOG2_BINS;
571 static_assert(1 << LOG2_BINS == BINS,
572 "Number of bins must be a power of two");
573 static_assert(~
size_t(0) >> BIN_SHIFT == (BINS - 1),
"Hash overflow");
578 size_t bin = hash >> BIN_SHIFT;
void erase(const KEY &key, bool do_lock=true)
iterator & operator=(const iterator &src)
iterator(unordered_map_concurrent *umc=NULL)
static constexpr size_t nobin_mask()
unordered_map_concurrent()
~unordered_map_concurrent()
bool retrieve(const KEY &key, VALUE &value, bool do_lock=true)
bool empty()
Return true if the entire map is empty.
iterator(const iterator &src)
void unlock_bin(size_t bin)
size_t size()
Return the total number of entries in the map.
**But if you need a result
bool insert_retrieve(const KEY &key, VALUE &value, VALUE &mapvalue, bool do_lock=true)
bool operator!=(const iterator &other)
void unlock()
Unlock the bin we point to, if locked.
Wrappers and utilities for multithreading.
std::pair< iterator, bool > find_or_insert(const KEY &key, const VALUE &value, bool do_lock=true)
bool insert(const KEY &key, const VALUE &value, bool do_lock=true)
iterator begin()
Return an interator pointing to the first entry in the map.
size_t lock_bin(const KEY &key)
const BinMap_t::value_type * operator->() const
BINMAP::iterator BinMap_iterator_t
GLboolean GLboolean GLboolean b
void lock()
Lock the bin we point to, if not already locked.
Map::iterator find_with_hash(Map &map, const Key &key, size_t hash)
const BinMap_t::value_type & operator*() const
iterator find(const KEY &key, bool do_lock=true)
bool operator==(const iterator &other) const
#define OIIO_NAMESPACE_END
#define OIIO_NAMESPACE_BEGIN