urcu: add lfht_filtered_iteration_adapter helper
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Mon, 29 Jul 2024 20:23:47 +0000 (20:23 +0000)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 30 Jul 2024 18:26:44 +0000 (14:26 -0400)
The urcu lfht macros often make use of caa_container_of (and other equivalent
variations) which use offsetof. Unfortunately, offsetof is conditionally
supported by compilers for non-POD types.

The tree already has lttng::utils::container_of to work around this
problem. This new utils makes it possible to iterate on the
elements of an lfht that match a given key without using those macros. Those iterations are the
main reason such warnings are emitted. The interface of
lfht_filtered_iteration_adapter also allows the use of ranged-for loops.

Change-Id: I9acd3fa9f6523de8006bc9107bcca6b6b654d6fa
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
src/common/urcu.hpp

index efd2dc75913ac218fcd558dd4440317eaea9d7c2..659e3c3d0477f9da5f4d3721e506e2ac0ba8b905 100644 (file)
@@ -111,7 +111,7 @@ class lfht_iteration_adapter {
 public:
        /* Nested iterator class defines the iterator for lfht_iteration_adapter. */
        class iterator : public std::iterator<std::input_iterator_tag, std::uint64_t> {
-               /* Allow lfht_iteration_adapter to access private members of iterator_base. */
+               /* Allow lfht_iteration_adapter to access private members of iterator. */
                friend lfht_iteration_adapter;
 
        public:
@@ -155,7 +155,7 @@ public:
                                *node);
                }
 
-       private:
+       protected:
                iterator(cds_lfht& ht, const cds_lfht_iter& it) : _ht(ht), _it(it)
                {
                }
@@ -187,13 +187,112 @@ public:
                return iterator(_ht, it);
        }
 
-private:
+protected:
        /* Reference to the hash table being iterated over. */
        cds_lfht& _ht;
        /* RCU read lock held during the iteration. */
        const lttng::urcu::read_lock_guard read_lock;
 };
 
+/*
+ * The lfht_filtered_iteration_adapter class template wraps the liburcu lfht API to provide
+ * iteration capabilities over a result set. It allows users to iterate over a lock-free hash
+ * table's elements matching a given key with ranged-for semantics while holding the RCU read lock.
+ * The reader lock is held for the lifetime of the iteration adapter (i.e. not the lifetime of the
+ * iterators it provides).
+ */
+template <typename ContainedType, typename NodeType, NodeType ContainedType::*Member, typename KeyType>
+class lfht_filtered_iteration_adapter
+       : public lfht_iteration_adapter<ContainedType, NodeType, Member> {
+public:
+       /* Nested iterator class defines the iterator for lfht_filtered_iteration_adapter. */
+       class iterator : public lfht_iteration_adapter<ContainedType, NodeType, Member>::iterator {
+               /* Allow lfht_filtered_iteration_adapter to access private members of iterator. */
+               friend lfht_filtered_iteration_adapter;
+
+       public:
+               iterator(const iterator& other) = default;
+               iterator(iterator&& other) noexcept = default;
+               ~iterator() = default;
+               iterator& operator=(const iterator&) = delete;
+               iterator& operator=(iterator&&) noexcept = delete;
+
+               /* Move to the next element in the result set. */
+               iterator& operator++()
+               {
+                       LTTNG_ASSERT(this->_it.node);
+                       /* NOLINTBEGIN(cppcoreguidelines-pro-type-const-cast) */
+                       cds_lfht_next_duplicate(
+                               &this->_ht,
+                               _match_function,
+                               reinterpret_cast<void *>(const_cast<KeyType *>(_key)),
+                               &this->_it);
+                       /* NOLINTEND(cppcoreguidelines-pro-type-const-cast) */
+                       return *this;
+               }
+
+       private:
+               iterator(cds_lfht& ht,
+                        const cds_lfht_iter& it,
+                        const KeyType *key,
+                        cds_lfht_match_fct match_function) :
+                       lfht_iteration_adapter<ContainedType, NodeType, Member>::iterator(ht, it),
+                       _key(key),
+                       _match_function(match_function)
+               {
+               }
+
+               /* Only used to create an end iterator. */
+               iterator(cds_lfht& ht, const cds_lfht_iter& it) :
+                       lfht_iteration_adapter<ContainedType, NodeType, Member>::iterator(ht, it),
+                       _key(nullptr),
+                       _match_function(nullptr)
+               {
+               }
+
+               const KeyType *_key;
+               const cds_lfht_match_fct _match_function;
+       };
+
+       explicit lfht_filtered_iteration_adapter(cds_lfht& ht,
+                                                const KeyType *key,
+                                                unsigned long key_hash,
+                                                cds_lfht_match_fct match_function) :
+               lfht_iteration_adapter<ContainedType, NodeType, Member>(ht),
+               _key(key),
+               _key_hash(key_hash),
+               _match_function(match_function)
+       {
+       }
+
+       /* Return an iterator to the first result. */
+       iterator begin() const noexcept
+       {
+               cds_lfht_iter it;
+
+               /* NOLINTBEGIN(cppcoreguidelines-pro-type-const-cast) */
+               cds_lfht_lookup(&this->_ht,
+                               _key_hash,
+                               _match_function,
+                               reinterpret_cast<void *>(const_cast<KeyType *>(_key)),
+                               &it);
+               /* NOLINTEND(cppcoreguidelines-pro-type-const-cast) */
+               return iterator(this->_ht, it, _key, _match_function);
+       }
+
+       iterator end() const noexcept
+       {
+               const cds_lfht_iter it = {};
+
+               return iterator(this->_ht, it);
+       }
+
+private:
+       const KeyType *_key;
+       const unsigned long _key_hash;
+       const cds_lfht_match_fct _match_function;
+};
+
 } /* namespace urcu */
 } /* namespace lttng */
 
This page took 0.026442 seconds and 4 git commands to generate.