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