34 #ifndef OPENIMAGEIO_UNORDERED_MAP_CONCURRENT_H
35 #define OPENIMAGEIO_UNORDERED_MAP_CONCURRENT_H
37 #include <boost/unordered_map.hpp>
79 template<
class KEY,
class VALUE,
class HASH=boost::hash<KEY>,
80 class PRED=std::equal_to<KEY>,
size_t BINS=16>
81 class unordered_map_concurrent {
83 typedef boost::unordered_map<KEY,VALUE,HASH,PRED> BinMap_t;
84 typedef typename boost::unordered_map<KEY,VALUE,HASH,PRED>::iterator BinMap_iterator_t;
87 unordered_map_concurrent () { m_size = 0; }
89 ~unordered_map_concurrent () {
98 friend class unordered_map_concurrent<KEY,VALUE,HASH,PRED,BINS>;
102 iterator (unordered_map_concurrent *umc = NULL)
103 : m_umc(umc), m_bin(-1), m_locked(false) { }
108 iterator (
const iterator &src) {
111 m_biniterator = src.m_biniterator;
112 m_locked = src.m_locked;
114 *(
const_cast<bool *
>(&src.m_locked)) =
false;
119 ~iterator () { clear(); }
132 typename BinMap_t::value_type & operator* () {
133 return *m_biniterator;
138 typename BinMap_t::value_type * operator-> () {
139 return &(*m_biniterator);
146 return m_umc && m_bin >= 0 &&
147 m_biniterator != m_umc->m_bins[m_bin].map.end();
152 iterator& operator= (
const iterator &src) {
156 m_biniterator = src.m_biniterator;
157 m_locked = src.m_locked;
159 *(
const_cast<bool *
>(&src.m_locked)) =
false;
163 bool operator== (
const iterator &other)
const {
164 if (m_umc != other.m_umc)
166 if (m_bin == -1 && other.m_bin == -1)
168 return m_bin == other.m_bin &&
169 m_biniterator == other.m_biniterator;
171 bool operator!= (
const iterator &other) {
172 return ! (*
this == other);
183 while (m_biniterator == m_umc->m_bins[m_bin].map.end()) {
184 if (m_bin == BINS-1) {
192 void operator++ (
int) { ++(*this); }
196 if (m_bin >= 0 && !m_locked) {
197 m_umc->m_bins[m_bin].lock();
203 if (m_bin >= 0 && m_locked) {
204 m_umc->m_bins[m_bin].unlock();
214 bool incr_no_lock () {
216 return (m_biniterator != m_umc->m_bins[m_bin].map.end());
232 void rebin (
int newbin) {
237 m_biniterator = m_umc->m_bins[m_bin].map.begin();
240 unordered_map_concurrent *m_umc;
242 BinMap_iterator_t m_biniterator;
251 while (i.m_biniterator == m_bins[i.m_bin].map.end()) {
252 if (i.m_bin == BINS-1) {
277 iterator find (
const KEY &key,
bool do_lock =
true) {
278 size_t b = whichbin(key);
279 Bin &bin (m_bins[b]);
282 typename BinMap_t::iterator it = bin.map.find (key);
283 if (it == bin.map.end()) {
291 i.m_bin = (unsigned) b;
292 i.m_biniterator = it;
293 i.m_locked = do_lock;
302 bool insert (
const KEY &key,
const VALUE &value,
303 bool do_lock =
true) {
304 size_t b = whichbin(key);
305 Bin &bin (m_bins[b]);
308 bool add = (bin.map.find (key) == bin.map.end());
311 bin.map[key] = value;
323 void erase (
const KEY &key,
bool do_lock =
true) {
324 size_t b = whichbin(key);
325 Bin &bin (m_bins[b]);
328 typename BinMap_t::iterator it = bin.map.find (key);
329 if (it != bin.map.end()) {
337 bool empty() {
return m_size == 0; }
342 size_t lock_bin (
const KEY &key) {
343 size_t b = whichbin(key);
350 void unlock_bin (
size_t bin) {
351 m_bins[bin].unlock ();
357 mutable spin_mutex mutex;
360 mutable atomic_int m_nlocks;
377 DASSERT_MSG (m_nlocks == 1,
"oops, m_nlocks = %d", (
int)m_nlocks);
380 void unlock ()
const {
382 DASSERT_MSG (m_nlocks == 1,
"oops, m_nlocks = %d", (
int)m_nlocks);
394 size_t whichbin (
const KEY &key) {
395 size_t h = m_hash(key);
396 h = (size_t) murmur::fmix (uint64_t(h));
406 #endif // OPENIMAGEIO_UNORDERED_MAP_CONCURRENT_H