ATLAS Offline Software
ConcurrentStrMap.icc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration.
3  */
4 /**
5  * @file CxxUtils/ConcurrentStrMap.icc
6  * @author scott snyder <snyder@bnl.gov>
7  * @date Dec, 2020
8  * @brief Hash map from strings to integers allowing concurrent, lockless reads.
9  */
10 
11 
12 namespace CxxUtils {
13 
14 
15 #define T_CONCURRENTSTRMAP template <class VALUE, template <class> class UPDATER> \
16  ATH_REQUIRES (detail::IsConcurrentHashmapPayload<VALUE> && \
17  detail::IsUpdater<UPDATER>)
18 
19 #define CONCURRENTSTRMAP ConcurrentStrMap<VALUE, UPDATER>
20 
21 
22 /**
23  * @brief Constructor.
24  * @param updater Object used to manage memory
25  * (see comments at the start of the class).
26  * @param capacity The initial table capacity.
27  * (Will be rounded up to a power of two.)
28  * @param ctx Execution context.
29  */
30 T_CONCURRENTSTRMAP
31 CONCURRENTSTRMAP::ConcurrentStrMap (Updater_t&& updater,
32  size_type capacity /*= 64*/,
33  const Context_t& ctx
34  /* = Updater_t::defaultContext()*/)
35  : m_impl (std::move (updater),
36  capacity,
37  Hasher(),
38  Matcher(),
39  ctx)
40 {
41 }
42 
43 
44 /**
45  * @brief Constructor from another map.
46  * @param updater Object used to manage memory
47  * (see comments at the start of the class).
48  * @param capacity The initial table capacity of the new table.
49  * (Will be rounded up to a power of two.)
50  * @param ctx Execution context.
51  *
52  * (Not really a copy constructor since we need to pass @c updater.)
53  */
54 T_CONCURRENTSTRMAP
55 CONCURRENTSTRMAP::ConcurrentStrMap (const ConcurrentStrMap& other,
56  Updater_t&& updater,
57  size_type capacity /*= 64*/,
58  const Context_t& ctx
59  /*= Updater_t::defaultContext()*/)
60  : m_impl (std::move (updater),
61  capacity,
62  Hasher(),
63  Matcher(),
64  ctx)
65 {
66  // not using reference, because our iterator doesn't return a reference
67  for (const auto p : other) {
68  this->emplace (p.first, p.second, ctx);
69  }
70 }
71 
72 
73 /**
74  * @brief Constructor from a range.
75  * @param f Start iterator for the range.
76  * @param l End iterator for the range.
77  * @param updater Object used to manage memory
78  * (see comments at the start of the class).
79  * @param capacity The initial table capacity of the new table.
80  * (Will be rounded up to a power of two.)
81  * @param ctx Execution context.
82  *
83  * Constructor from a range of pairs.
84  */
85 T_CONCURRENTSTRMAP
86 template <class InputIterator>
87 CONCURRENTSTRMAP::ConcurrentStrMap (InputIterator f,
88  InputIterator l,
89  Updater_t&& updater,
90  size_t capacity /*= 64*/,
91  const Context_t& ctx
92  /*= Updater_t::defaultContext()*/)
93  : m_impl (std::move (updater),
94  capacity,
95  Hasher(),
96  Matcher(),
97  ctx)
98 {
99  Lock_t lck = lock();
100  if constexpr (std::is_rvalue_reference_v<typename InputIterator::reference>)
101  {
102  for (; f != l; ++f) {
103  this->emplace (lck, std::move (f->first), f->second, ctx);
104  }
105  }
106  else {
107  for (; f != l; ++f) {
108  this->emplace (lck, f->first, f->second, ctx);
109  }
110  }
111 }
112 
113 
114 /**
115  * @brief Destructor.
116  */
117 T_CONCURRENTSTRMAP
118 CONCURRENTSTRMAP::~ConcurrentStrMap()
119 {
120  // Need to delete the strings that we've stored.
121  auto [begin, end] = m_impl.range();
122  while (begin != end) {
123  if (begin.key() != Impl_t::nullval) {
124  delete keyAsString (begin.key());
125  }
126  begin.next();
127  }
128 }
129 
130 
131 /**
132  * @brief Return the number of items currently in the map.
133  */
134 T_CONCURRENTSTRMAP
135 inline
136 auto CONCURRENTSTRMAP::size() const -> size_type
137 {
138  return m_impl.size();
139 }
140 
141 
142 /**
143  * @brief Test if the map is currently empty.
144  */
145 T_CONCURRENTSTRMAP
146 inline
147 bool CONCURRENTSTRMAP::empty() const
148 {
149  return !m_impl.size();
150 }
151 
152 
153 /**
154  * @brief Return the current size (capacity) of the hash table.
155  */
156 T_CONCURRENTSTRMAP
157 inline
158 auto CONCURRENTSTRMAP::capacity() const -> size_t
159 {
160  return m_impl.capacity();
161 }
162 
163 
164 /**
165  * @brief Constructor.
166  * @param it Iterator of the underlying table.
167  */
168 T_CONCURRENTSTRMAP
169 inline
170 CONCURRENTSTRMAP::const_iterator::const_iterator (typename Impl_t::const_iterator it)
171  : m_impl (it)
172 {
173 }
174 
175 
176 /**
177  * @brief Test if this iterator is valid.
178  *
179  * This should be the same as testing for != end().
180  */
181 T_CONCURRENTSTRMAP
182 inline
183 auto CONCURRENTSTRMAP::const_iterator::valid() const -> bool
184 {
185  return m_impl.valid();
186 }
187 
188 
189 /**
190  * @brief iterator_facade requirement: Increment the iterator.
191  */
192 T_CONCURRENTSTRMAP
193 inline
194 auto CONCURRENTSTRMAP::const_iterator::increment() -> void
195 {
196  m_impl.next();
197 }
198 
199 
200 /**
201  * @brief iterator_facade requirement: Decrement the iterator.
202  */
203 T_CONCURRENTSTRMAP
204 inline
205 auto CONCURRENTSTRMAP::const_iterator::decrement() -> void
206 {
207  m_impl.prev();
208 }
209 
210 
211 /**
212  * @brief iterator_facade requirement: Dereference the iterator.
213  */
214 T_CONCURRENTSTRMAP
215 inline
216 auto CONCURRENTSTRMAP::const_iterator::dereference() const
217  -> const const_iterator_value
218 {
219  return const_iterator_value (*keyAsString (m_impl.key()),
220  mappedAsMapped (m_impl.value()));
221 }
222 
223 
224 /**
225  * @brief iterator_facade requirement: Equality test.
226  */
227 T_CONCURRENTSTRMAP
228 inline
229 auto CONCURRENTSTRMAP::const_iterator::equal (const const_iterator& other) const
230  -> bool
231 {
232  return !(m_impl != other.m_impl);
233 }
234 
235 
236 /**
237  * @brief Return an iterator range covering the entire map.
238  */
239 T_CONCURRENTSTRMAP
240 auto CONCURRENTSTRMAP::range() const -> const_iterator_range
241 {
242  auto [begin, end] = m_impl.range();
243  return const_iterator_range (begin, end);
244 }
245 
246 
247 /**
248  * @brief Iterator at the start of the map.
249  */
250 T_CONCURRENTSTRMAP
251 inline
252 auto CONCURRENTSTRMAP::begin() const -> const_iterator
253 {
254  return const_iterator (m_impl.begin());
255 }
256 
257 
258 /**
259  * @brief Iterator at the end of the map.
260  */
261 T_CONCURRENTSTRMAP
262 inline
263 auto CONCURRENTSTRMAP::end() const -> const_iterator
264 {
265  return const_iterator (m_impl.end());
266 }
267 
268 
269 /**
270  * @brief Iterator at the start of the map.
271  */
272 T_CONCURRENTSTRMAP
273 inline
274 auto CONCURRENTSTRMAP::cbegin() const -> const_iterator
275 {
276  return begin();
277 }
278 
279 
280 /**
281  * @brief Iterator at the end of the map.
282  */
283 T_CONCURRENTSTRMAP
284 inline
285 auto CONCURRENTSTRMAP::cend() const -> const_iterator
286 {
287  return end();
288 }
289 
290 
291 /**
292  * @brief Test if a key is in the container.
293  * @param key The key to test.
294  */
295 T_CONCURRENTSTRMAP
296 inline
297 bool CONCURRENTSTRMAP::contains (const key_type& key) const
298 {
299  return get(key).valid();
300 }
301 
302 
303 /**
304  * @brief Return the number of times a given key is in the container.
305  * @param key The key to test.
306  *
307  * Returns either 0 or 1, depending on whether or not the key is in the map.
308  */
309 T_CONCURRENTSTRMAP
310 inline
311 auto CONCURRENTSTRMAP::count (const key_type& key) const -> size_type
312 {
313  return contains (key) ? 1 : 0;
314 }
315 
316 
317 /**
318  * @brief Look up an element in the map.
319  * @param key The element to find.
320  *
321  * Returns either an iterator referencing the found element or end().
322  */
323 T_CONCURRENTSTRMAP
324 inline
325 auto CONCURRENTSTRMAP::find (const key_type& key) const -> const_iterator
326 {
327  return const_iterator (this->get (key));
328 }
329 
330 
331 /**
332  * @brief Look up an element in the map.
333  * @param key The element to find.
334  *
335  * Returns the value associated with the key.
336  * Throws @c std::out_of_range if the key does not exist in the map.
337  */
338 T_CONCURRENTSTRMAP
339 auto CONCURRENTSTRMAP::at (const key_type& key) const -> mapped_type
340 {
341  typename Impl_t::const_iterator it = this->get (key);
342  if (!it.valid()) {
343  throw std::out_of_range ("ConcurrentStrMap::at");
344  }
345  return mappedAsMapped (it.value());
346 }
347 
348 
349 /**
350  * @brief Return a range of iterators with entries matching @c key.
351  * @param key The element to find.
352  *
353  * As keys are unique in this container, this is either a single-element
354  * range, or both iterators are equal to end().
355  */
356 T_CONCURRENTSTRMAP
357 auto CONCURRENTSTRMAP::equal_range (const key_type& key) const
358  -> std::pair<const_iterator, const_iterator>
359 {
360  const_iterator i1 = find (key);
361  const_iterator i2 = i1;
362  if (i2.valid()) {
363  ++i2;
364  }
365  return std::make_pair (i1, i2);
366 }
367 
368 
369 /**
370  * @brief Take a lock on the container.
371  *
372  * Take a lock on the container.
373  * The lock can then be passed to insertion methods, allowing to factor out
374  * the locking inside loops. The lock will be released when the
375  * lock object is destroyed.
376  */
377 T_CONCURRENTSTRMAP
378 inline
379 auto CONCURRENTSTRMAP::lock() -> Lock_t
380 {
381  return m_impl.lock();
382 }
383 
384 
385 /**
386  * @brief Add an element to the map.
387  * @param key The key of the new item to add.
388  * @param val The value of the new item to add.
389  * @param ctx Execution context.
390  *
391  * This will not overwrite an existing entry.
392  * The first element in the returned pair is an iterator referencing
393  * the added item. The second is a flag that is true if a new element
394  * was added.
395  */
396 T_CONCURRENTSTRMAP
397 inline
398 auto CONCURRENTSTRMAP::emplace (const key_type& key,
399  mapped_type val,
400  const Context_t& ctx
401  /*= Updater_t::defaultContext()*/)
402  -> std::pair<const_iterator, bool>
403 {
404  return put (std::make_unique<key_type> (key), val, false, ctx);
405 }
406 
407 
408 /**
409  * @brief Add an element to the map, with external locking.
410  * @param lock The lock object returned from lock().
411  * @param key The key of the new item to add.
412  * @param val The value of the new item to add.
413  * @param ctx Execution context.
414  *
415  * This will not overwrite an existing entry.
416  * The first element in the returned pair is an iterator referencing
417  * the added item. The second is a flag that is true if a new element
418  * was added.
419  */
420 T_CONCURRENTSTRMAP
421 inline
422 auto CONCURRENTSTRMAP::emplace (const Lock_t& lock,
423  const key_type& key,
424  mapped_type val,
425  const Context_t& ctx
426  /*= Updater_t::defaultContext()*/)
427  -> std::pair<const_iterator, bool>
428 {
429  return put (lock, std::make_unique<key_type> (key), val, false, ctx);
430 }
431 
432 
433 /**
434  * @brief Add an element to the map.
435  * @param key The key of the new item to add.
436  * @param val The value of the new item to add.
437  * @param ctx Execution context.
438  *
439  * This will not overwrite an existing entry.
440  * The first element in the returned pair is an iterator referencing
441  * the added item. The second is a flag that is true if a new element
442  * was added.
443  */
444 T_CONCURRENTSTRMAP
445 inline
446 auto CONCURRENTSTRMAP::emplace (key_type&& key,
447  mapped_type val,
448  const Context_t& ctx
449  /*= Updater_t::defaultContext()*/)
450  -> std::pair<const_iterator, bool>
451 {
452  return put (std::make_unique<key_type> (std::move (key)), val, false, ctx);
453 }
454 
455 
456 /**
457  * @brief Add an element to the map, with external locking.
458  * @param lock The lock object returned from lock().
459  * @param key The key of the new item to add.
460  * @param val The value of the new item to add.
461  * @param ctx Execution context.
462  *
463  * This will not overwrite an existing entry.
464  * The first element in the returned pair is an iterator referencing
465  * the added item. The second is a flag that is true if a new element
466  * was added.
467  */
468 T_CONCURRENTSTRMAP
469 inline
470 auto CONCURRENTSTRMAP::emplace (const Lock_t& lock,
471  key_type&& key,
472  mapped_type val,
473  const Context_t& ctx
474  /*= Updater_t::defaultContext()*/)
475  -> std::pair<const_iterator, bool>
476 {
477  return put (lock, std::make_unique<key_type> (std::move (key)), val, false, ctx);
478 }
479 
480 
481 /**
482  * @brief Add an element to the map, or overwrite an existing one.
483  * @param key The key of the new item to add.
484  * @param val The value of the new item to add.
485  * @param ctx Execution context.
486  *
487  * This will overwrite an existing entry.
488  * The first element in the returned pair is an iterator referencing
489  * the added item. The second is a flag that is true if a new element
490  * was added.
491  */
492 T_CONCURRENTSTRMAP
493 inline
494 auto CONCURRENTSTRMAP::insert_or_assign (const key_type& key,
495  mapped_type val,
496  const Context_t& ctx
497  /*= Updater_t::defaultContext()*/)
498  -> std::pair<const_iterator, bool>
499 {
500  return put (std::make_unique<key_type> (key), val, true, ctx);
501 }
502 
503 
504 /**
505  * @brief Add an element to the map, or overwrite an existing one,
506  * with external locking.
507  * @param lock The lock object returned from lock().
508  * @param key The key of the new item to add.
509  * @param val The value of the new item to add.
510  * @param ctx Execution context.
511  *
512  * This will overwrite an existing entry.
513  * The first element in the returned pair is an iterator referencing
514  * the added item. The second is a flag that is true if a new element
515  * was added.
516  */
517 T_CONCURRENTSTRMAP
518 inline
519 auto CONCURRENTSTRMAP::insert_or_assign (const Lock_t& lock,
520  const key_type& key,
521  mapped_type val,
522  const Context_t& ctx
523  /*= Updater_t::defaultContext()*/)
524  -> std::pair<const_iterator, bool>
525 {
526  return put (lock, std::make_unique<key_type> (key), val, true, ctx);
527 }
528 
529 
530 /**
531  * @brief Add an element to the map, or overwrite an existing one.
532  * @param key The key of the new item to add.
533  * @param val The value of the new item to add.
534  * @param ctx Execution context.
535  *
536  * This will overwrite an existing entry.
537  * The first element in the returned pair is an iterator referencing
538  * the added item. The second is a flag that is true if a new element
539  * was added.
540  */
541 T_CONCURRENTSTRMAP
542 inline
543 auto CONCURRENTSTRMAP::insert_or_assign (key_type&& key,
544  mapped_type val,
545  const Context_t& ctx
546  /*= Updater_t::defaultContext()*/)
547  -> std::pair<const_iterator, bool>
548 {
549  return put (std::make_unique<key_type> (std::move (key)), val, true, ctx);
550 }
551 
552 
553 /**
554  * @brief Add an element to the map, or overwrite an existing one,
555  * with external locking.
556  * @param lock The lock object returned from lock().
557  * @param key The key of the new item to add.
558  * @param val The value of the new item to add.
559  * @param ctx Execution context.
560  *
561  * This will overwrite an existing entry.
562  * The first element in the returned pair is an iterator referencing
563  * the added item. The second is a flag that is true if a new element
564  * was added.
565  */
566 T_CONCURRENTSTRMAP
567 inline
568 auto CONCURRENTSTRMAP::insert_or_assign (const Lock_t& lock,
569  key_type&& key,
570  mapped_type val,
571  const Context_t& ctx
572  /*= Updater_t::defaultContext()*/)
573  -> std::pair<const_iterator, bool>
574 {
575  return put (lock, std::make_unique<key_type> (std::move (key)), val, true, ctx);
576 }
577 
578 
579 /**
580  * @brief Add an element to the map.
581  * @param p The item to add.
582  * Should be a pair where first is the string key
583  * and second is the integer value.
584  * @param ctx Execution context.
585  *
586  * This will not overwrite an existing entry.
587  * The first element in the returned pair is an iterator referencing
588  * the added item. The second is a flag that is true if a new element
589  * was added.
590  *
591  * For external locking, use emplace().
592  */
593 T_CONCURRENTSTRMAP
594 template <class PAIR>
595 inline
596 auto CONCURRENTSTRMAP::insert (const PAIR& p,
597  const Context_t& ctx /*= Updater_t::defaultContext()*/)
598  -> std::pair<const_iterator, bool>
599 {
600  return emplace (p.first, p.second, ctx);
601 }
602 
603 
604 /**
605  * @brief Add an element to the map.
606  * @param p The item to add.
607  * Should be a pair where first is the string key
608  * and second is the integer value.
609  * @param ctx Execution context.
610  *
611  * This will not overwrite an existing entry.
612  * The first element in the returned pair is an iterator referencing
613  * the added item. The second is a flag that is true if a new element
614  * was added.
615  */
616 T_CONCURRENTSTRMAP
617 template <class PAIR>
618 inline
619 auto CONCURRENTSTRMAP::insert (PAIR&& p,
620  const Context_t& ctx /*= Updater_t::defaultContext()*/)
621  -> std::pair<const_iterator, bool>
622 {
623  return emplace (std::move (p.first), p.second, ctx);
624 }
625 
626 
627 /**
628  * @brief Insert a range of elements to the map.
629  * @param first Start of the range.
630  * @param last End of the range.
631  * @param ctx Execution context.
632  *
633  * The range should be a sequence of pairs where first is the string key
634  * and second is the integer value.
635  */
636 T_CONCURRENTSTRMAP
637 template <class InputIterator>
638 void CONCURRENTSTRMAP::insert (InputIterator first, InputIterator last,
639  const Context_t& ctx /*= Updater_t::defaultContext()*/)
640 {
641  Lock_t lck = lock();
642  if constexpr (std::is_rvalue_reference_v<typename InputIterator::reference>)
643  {
644  for (; first != last; ++first) {
645  emplace (lck, std::move (first->first), first->second, ctx);
646  }
647  }
648  else {
649  for (; first != last; ++first) {
650  emplace (lck, first->first, first->second, ctx);
651  }
652  }
653 }
654 
655 
656 /**
657  * @brief Increase the table capacity.
658  * @param capacity The new table capacity.
659  * @param ctx Execution context.
660  *
661  * No action will be taken if @c capacity is smaller
662  * than the current capacity.
663  */
664 T_CONCURRENTSTRMAP
665 inline
666 void CONCURRENTSTRMAP::reserve (size_type capacity,
667  const Context_t& ctx
668  /*= Updater_t::defaultContext()*/)
669 {
670  return m_impl.reserve (capacity, ctx);
671 }
672 
673 
674 /**
675  * @brief Increase the table capacity.
676  * @param capacity The new table capacity.
677  *
678  * No action will be taken if @c capacity is smaller
679  * than the current capacity.
680  */
681 T_CONCURRENTSTRMAP
682 inline
683 void CONCURRENTSTRMAP::rehash (size_type capacity)
684 {
685  return reserve (capacity);
686 }
687 
688 
689 /**
690  * @brief Called when this thread is no longer referencing anything
691  * from this container.
692  * @param ctx Execution context.
693  */
694 T_CONCURRENTSTRMAP
695 inline
696 void CONCURRENTSTRMAP::quiescent (const Context_t& ctx)
697 {
698  return m_impl.quiescent (ctx);
699 }
700 
701 
702 /**
703  * @brief Swap this container with another.
704  * @param other The container with which to swap.
705  *
706  * This will also call swap on the Updater object; hence, the Updater
707  * object must also support swap.
708  *
709  * This operation is NOT thread-safe. No other threads may be accessing
710  * either container during this operation.
711  */
712 T_CONCURRENTSTRMAP
713 void CONCURRENTSTRMAP::swap (ConcurrentStrMap& other)
714 {
715  m_impl.swap (other.m_impl);
716 }
717 
718 
719 /**
720  * @brief Access the Updater instance.
721  */
722 T_CONCURRENTSTRMAP
723 auto CONCURRENTSTRMAP::updater() -> Updater_t&
724 {
725  return m_impl.updater();
726 }
727 
728 
729 /**
730  * @brief Convert an underlying key value to a string pointer.
731  * @param val The underlying key value.
732  */
733 T_CONCURRENTSTRMAP
734 inline
735 auto CONCURRENTSTRMAP::keyAsString (val_t val) -> const std::string*
736 {
737  return reinterpret_cast<std::string*> (val);
738 }
739 
740 
741 /**
742  * @brief Convert a string pointer to an underlying key value.
743  * @param s The string pointer.
744  */
745 T_CONCURRENTSTRMAP
746 inline
747 auto CONCURRENTSTRMAP::keyAsVal (const std::string* s) -> val_t
748 {
749  return reinterpret_cast<val_t> (s);
750 }
751 
752 
753 /**
754  * @brief Convert an underlying mapped value to this type's mapped value.
755  * @param val The underlying mapped value.
756  */
757 T_CONCURRENTSTRMAP
758 inline
759 auto CONCURRENTSTRMAP::mappedAsMapped (val_t val) -> mapped_type
760 {
761  return CxxUtils::detail::UIntConv<mapped_type>::uintToVal (val);
762 }
763 
764 
765 /**
766  * @brief Convert this type's mapped value to an underlying mapped value.
767  * @param val The mapped value.
768  */
769 T_CONCURRENTSTRMAP
770 inline
771 auto CONCURRENTSTRMAP::mappedAsVal (mapped_type val) -> val_t
772 {
773  return CxxUtils::detail::UIntConv<mapped_type>::valToUInt (val);
774 }
775 
776 
777 /**
778  * @brief Do a lookup in the table.
779  * @param key The key to look up.
780  *
781  * Returns an iterator of the underlying map pointing at the found
782  * entry or end();
783  */
784 T_CONCURRENTSTRMAP
785 auto CONCURRENTSTRMAP::get (const key_type& key) const
786  -> typename Impl_t::const_iterator
787 {
788  size_t hash = m_impl.hasher() (key);
789  return m_impl.get (keyAsVal(&key), hash);
790 }
791 
792 
793 /**
794  * @brief Insert / overwrite an entry in the table.
795  * @param key The key of the new item to add.
796  * @param val The value of the new item to add.
797  * @param overwrite If true, allow overwriting an existing entry.
798  * @param ctx Execution context.
799  *
800  * The first element in the returned pair is an iterator referencing
801  * the added item. The second is a flag that is true if a new element
802  * was added.
803  */
804 T_CONCURRENTSTRMAP
805 auto CONCURRENTSTRMAP::put (std::unique_ptr<key_type> key,
806  mapped_type val,
807  bool overwrite /*= true*/,
808  const Context_t& ctx /*= Updater_t::defaultContext()*/)
809  -> std::pair<const_iterator, bool>
810 {
811  size_t hash = m_impl.hasher() (*key);
812  auto [it, flag] = m_impl.put (keyAsVal(key.get()), hash,
813  mappedAsVal (val),
814  overwrite, ctx);
815  if (flag) (void)key.release();
816  return std::make_pair (const_iterator (it), flag);
817 }
818 
819 
820 /**
821  * @brief Insert / overwrite an entry in the table, with external locking.
822  * @param lock The lock object returned from lock().
823  * @param key The key of the new item to add.
824  * @param val The value of the new item to add.
825  * @param overwrite If true, allow overwriting an existing entry.
826  * @param ctx Execution context.
827  *
828  * The first element in the returned pair is an iterator referencing
829  * the added item. The second is a flag that is true if a new element
830  * was added.
831  */
832 T_CONCURRENTSTRMAP
833 auto CONCURRENTSTRMAP::put (const Lock_t& lock,
834  std::unique_ptr<key_type> key,
835  mapped_type val,
836  bool overwrite /*= true*/,
837  const Context_t& ctx /*= Updater_t::defaultContext()*/)
838  -> std::pair<const_iterator, bool>
839 {
840  size_t hash = m_impl.hasher() (*key);
841  auto [it, flag] = m_impl.put (lock,
842  keyAsVal(key.get()), hash,
843  mappedAsVal (val),
844  overwrite, ctx);
845  if (flag) (void)key.release();
846  return std::make_pair (const_iterator (it), flag);
847 }
848 
849 
850 /**
851  * @brief Hash function from the underlying representation type.
852  */
853 T_CONCURRENTSTRMAP
854 inline
855 auto CONCURRENTSTRMAP::Hasher::operator() (const val_t p) const -> size_t
856 {
857  return m_hash (*keyAsString(p));
858 }
859 
860 
861 /**
862  * @brief Hash function from a std::string.
863  */
864 T_CONCURRENTSTRMAP
865 inline
866 auto CONCURRENTSTRMAP::Hasher::operator() (const std::string& s) const -> size_t
867 {
868  return m_hash (s);
869 }
870 
871 
872 /**
873  * @brief Compare two keys (as the underlying representation type) for equality.
874  */
875 T_CONCURRENTSTRMAP
876 inline
877 auto CONCURRENTSTRMAP::Matcher::operator() (const val_t a, const val_t b) const -> bool
878 {
879  // First test if the keys (pointers) themselves are equal.
880  if (a == b) return true;
881  // Otherwise, need to test the strings to which they point.
882  return *keyAsString(a) == *keyAsString(b);
883 }
884 
885 
886 #undef T_CONCURRENTSTRMAP
887 #undef CONCURRENTSTRMAP
888 
889 
890 } // namespace CxxUtils