2 * Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration.
5 * @file CxxUtils/ConcurrentPtrSet.icc
6 * @author scott snyder <snyder@bnl.gov>
8 * @brief A set of pointers, alowing concurrent, lockless reads.
15 #define T_CONCURRENTPTRSET template <class VALUE, template <class> class UPDATER> \
16 ATH_REQUIRES (detail::IsUpdater<UPDATER>)
19 #define CONCURRENTPTRSET ConcurrentPtrSet<VALUE, UPDATER>
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.
31 CONCURRENTPTRSET::ConcurrentPtrSet (Updater_t&& updater,
32 size_type capacity /*= 64*/,
34 /* = Updater_t::defaultContext()*/)
35 : m_impl (std::move (updater),
45 * @brief Constructor from another set.
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.
52 * (Not really a copy constructor since we need to pass @c updater.)
55 CONCURRENTPTRSET::ConcurrentPtrSet (const ConcurrentPtrSet& other,
57 size_type capacity /*= 64*/,
59 /*= Updater_t::defaultContext()*/)
60 : m_impl (std::move (updater),
66 for (const auto p : other) {
73 * @brief Constructor from a range.
74 * @param f Start iterator for the range.
75 * @param l End iterator for the range.
76 * @param updater Object used to manage memory
77 * (see comments at the start of the class).
78 * @param capacity The initial table capacity of the new table.
79 * (Will be rounded up to a power of two.)
80 * @param ctx Execution context.
83 template <class InputIterator>
84 CONCURRENTPTRSET::ConcurrentPtrSet (InputIterator f,
87 size_t capacity /*= 64*/,
89 /*= Updater_t::defaultContext()*/)
90 : m_impl (std::move (updater),
98 this->put (lck, *f, ctx);
107 CONCURRENTPTRSET::~ConcurrentPtrSet()
113 * @brief Return the number of items currently in the set.
117 auto CONCURRENTPTRSET::size() const -> size_type
119 return m_impl.size();
124 * @brief Test if the set is currently empty.
128 bool CONCURRENTPTRSET::empty() const
130 return !m_impl.size();
135 * @brief Return the current size (capacity) of the hash table.
139 auto CONCURRENTPTRSET::capacity() const -> size_t
141 return m_impl.capacity();
146 * @brief Constructor.
147 * @param it Iterator of the underlying table.
151 CONCURRENTPTRSET::const_iterator::const_iterator (typename Impl_t::const_iterator it)
158 * @brief Test if this iterator is valid.
160 * This should be the same as testing for != end().
164 auto CONCURRENTPTRSET::const_iterator::valid() const -> bool
166 return m_impl.valid();
171 * @brief iterator_facade requirement: Increment the iterator.
175 auto CONCURRENTPTRSET::const_iterator::increment() -> void
182 * @brief iterator_facade requirement: Decrement the iterator.
186 auto CONCURRENTPTRSET::const_iterator::decrement() -> void
193 * @brief iterator_facade requirement: Dereference the iterator.
197 auto CONCURRENTPTRSET::const_iterator::dereference() const
200 return keyAsPtr (m_impl.key());
205 * @brief iterator_facade requirement: Equality test.
209 auto CONCURRENTPTRSET::const_iterator::equal (const const_iterator& other) const
212 return !(m_impl != other.m_impl);
217 * @brief Return an iterator range covering the entire set.
220 auto CONCURRENTPTRSET::range() const -> const_iterator_range
222 auto [begin, end] = m_impl.range();
223 return const_iterator_range (begin, end);
228 * @brief Iterator at the start of the set.
232 auto CONCURRENTPTRSET::begin() const -> const_iterator
234 return const_iterator (m_impl.begin());
239 * @brief Iterator at the end of the set.
243 auto CONCURRENTPTRSET::end() const -> const_iterator
245 return const_iterator (m_impl.end());
250 * @brief Iterator at the start of the set.
254 auto CONCURRENTPTRSET::cbegin() const -> const_iterator
261 * @brief Iterator at the end of the set.
265 auto CONCURRENTPTRSET::cend() const -> const_iterator
272 * @brief Test if a key is in the container.
273 * @param key The key to test.
277 bool CONCURRENTPTRSET::contains (const const_key_type key) const
279 return get(key).valid();
284 * @brief Return the number of times a given key is in the container.
285 * @param key The key to test.
287 * Returns either 0 or 1, depending on whether or not the key is in the set.
291 auto CONCURRENTPTRSET::count (const const_key_type key) const -> size_type
293 return contains (key) ? 1 : 0;
298 * @brief Look up an element in the set.
299 * @param key The element to find.
301 * Returns either an iterator referencing the found element or end().
305 auto CONCURRENTPTRSET::find (const const_key_type key) const -> const_iterator
307 return const_iterator (this->get (key));
312 * @brief Return a range of iterators with entries matching @c key.
313 * @param key The element to find.
315 * As keys are unique in this container, this is either a single-element
316 * range, or both iterators are equal to end().
319 auto CONCURRENTPTRSET::equal_range (const const_key_type key) const
320 -> std::pair<const_iterator, const_iterator>
322 const_iterator i1 = find (key);
323 const_iterator i2 = i1;
327 return std::make_pair (i1, i2);
332 * @brief Take a lock on the container.
334 * Take a lock on the container.
335 * The lock can then be passed to insertion methods, allowing to factor out
336 * the locking inside loops. The lock will be released when the
337 * lock object is destroyed.
341 auto CONCURRENTPTRSET::lock() -> Lock_t
343 return m_impl.lock();
348 * @brief Add an element to the set.
349 * @param key The key of the new item to add.
350 * @param ctx Execution context.
352 * This will not overwrite an existing entry.
353 * The first element in the returned pair is an iterator referencing
354 * the added item. The second is a flag that is true if a new element
359 auto CONCURRENTPTRSET::emplace (const key_type key,
361 /*= Updater_t::defaultContext()*/)
362 -> std::pair<const_iterator, bool>
364 return put (key, ctx);
369 * @brief Add an element to the set, with external locking.
370 * @param lock The lock object returned from lock().
371 * @param key The key of the new item to add.
372 * @param ctx Execution context.
374 * This will not overwrite an existing entry.
375 * The first element in the returned pair is an iterator referencing
376 * the added item. The second is a flag that is true if a new element
381 auto CONCURRENTPTRSET::emplace (const Lock_t& lock,
384 /*= Updater_t::defaultContext()*/)
385 -> std::pair<const_iterator, bool>
387 return put (lock, key, ctx);
392 * @brief Add an element to the set.
393 * @param p The item to add.
395 * This will not overwrite an existing entry.
396 * The first element in the returned pair is an iterator referencing
397 * the added item. The second is a flag that is true if a new element
400 * This is the same as emplace(). Use that for the case of external locking.
404 auto CONCURRENTPTRSET::insert (const key_type p)
405 -> std::pair<const_iterator, bool>
412 * @brief Insert a range of elements to the set.
413 * @param first Start of the range.
414 * @param last End of the range.
417 template <class InputIterator>
418 void CONCURRENTPTRSET::insert (InputIterator first, InputIterator last)
421 const Context_t& ctx = Updater_t::defaultContext();
422 for (; first != last; ++first) {
423 emplace (lck, *first, ctx);
429 * @brief Increase the table capacity.
430 * @param capacity The new table capacity.
431 * @param ctx Execution context.
433 * No action will be taken if @c capacity is smaller
434 * than the current capacity.
438 void CONCURRENTPTRSET::reserve (size_type capacity,
440 /*= Updater_t::defaultContext()*/)
442 return m_impl.reserve (capacity, ctx);
447 * @brief Increase the table capacity.
448 * @param capacity The new table capacity.
450 * No action will be taken if @c capacity is smaller
451 * than the current capacity.
455 void CONCURRENTPTRSET::rehash (size_type capacity)
457 return reserve (capacity);
462 * @brief Erase the table and change the capacity.
463 * @param capacity The new table capacity.
464 * @param ctx Execution context.
468 void CONCURRENTPTRSET::clear (size_t capacity,
469 const Context_t& ctx /*= Updater_t::defaultContext()*/)
471 m_impl.clear (capacity, ctx);
476 * @brief Erase the table (don't change the capacity).
477 * @param ctx Execution context.
481 void CONCURRENTPTRSET::clear (const Context_t& ctx /*= Updater_t::defaultContext()*/)
488 * @brief Called when this thread is no longer referencing anything
489 * from this container.
490 * @param ctx Execution context.
494 void CONCURRENTPTRSET::quiescent (const Context_t& ctx)
496 return m_impl.quiescent (ctx);
501 * @brief Swap this container with another.
502 * @param other The container with which to swap.
504 * This will also call swap on the Updater object; hence, the Updater
505 * object must also support swap.
507 * This operation is NOT thread-safe. No other threads may be accessing
508 * either container during this operation.
511 void CONCURRENTPTRSET::swap (ConcurrentPtrSet& other)
513 m_impl.swap (other.m_impl);
518 * @brief Access the Updater instance.
521 auto CONCURRENTPTRSET::updater() -> Updater_t&
523 return m_impl.updater();
528 * @brief Convert an underlying key value to a pointer.
529 * @param val The underlying key value.
533 auto CONCURRENTPTRSET::keyAsPtr (val_t val) -> key_type
535 return reinterpret_cast<key_type> (val);
540 * @brief Convert a pointer to an underlying key value.
541 * @param val The pointer.
545 auto CONCURRENTPTRSET::keyAsVal (const const_key_type p) -> val_t
547 return reinterpret_cast<val_t> (p);
552 * @brief Do a lookup in the table.
553 * @param key The key to look up.
555 * Returns an iterator of the underlying map pointing at the found
559 auto CONCURRENTPTRSET::get (const const_key_type key) const
560 -> typename Impl_t::const_iterator
562 size_t hash = m_impl.hasher() (key);
563 return m_impl.get (keyAsVal(key), hash);
568 * @brief Insert an entry in the table.
569 * @param key The new item to add.
570 * @param ctx Execution context.
572 * The first element in the returned pair is an iterator referencing
573 * the added item. The second is a flag that is true if a new element
577 auto CONCURRENTPTRSET::put (const key_type key,
578 const Context_t& ctx /*= Updater_t::defaultContext()*/)
579 -> std::pair<const_iterator, bool>
581 size_t hash = m_impl.hasher() (key);
582 auto [it, flag] = m_impl.put (keyAsVal(key), hash,
585 return std::make_pair (const_iterator (it), flag);
590 * @brief Insert an entry in the table, with external locking.
591 * @param lock The lock object returned from lock().
592 * @param key The new item to add.
593 * @param ctx Execution context.
595 * The first element in the returned pair is an iterator referencing
596 * the added item. The second is a flag that is true if a new element
600 auto CONCURRENTPTRSET::put (const Lock_t& lock,
602 const Context_t& ctx /*= Updater_t::defaultContext()*/)
603 -> std::pair<const_iterator, bool>
605 size_t hash = m_impl.hasher() (key);
606 auto [it, flag] = m_impl.put (lock,
610 return std::make_pair (const_iterator (it), flag);
615 * @brief Hash function from the underlying representation type.
619 auto CONCURRENTPTRSET::Hasher::operator() (const val_t p) const -> size_t
621 return m_hash (keyAsPtr(p));
626 * @brief Hash function from a pointer.
630 auto CONCURRENTPTRSET::Hasher::operator() (const const_key_type p) const -> size_t
637 * @brief Compare two keys (as the underlying representation type) for equality.
641 auto CONCURRENTPTRSET::Matcher::operator() (const val_t a, const val_t b) const -> bool
647 #undef T_CONCURRENTPTRSET
648 #undef CONCURRENTPTRSET
651 } // namespace CxxUtils