[06/10,gdbsupport] Factor out base_next_iterator

Message ID 20260501124504.2233495-7-tdevries@suse.de
State New
Headers
Series Add superblocks range loops |

Commit Message

Tom de Vries May 1, 2026, 12:45 p.m. UTC
  Template struct next_iterator<T> allows iterating over the "next" field of T.

I decided to generalize this to be able to use any field.

A first thought was to use macros, but nowadays we try to do things more in
native c++, so I didn't explore that further.

Instead, this patch factors out base_next_iterator, which contains all parts
not specific to "next", in other words, everything except the operator++.

I also explored using a pointer-to-member template argument T::next:
...
     template<typename T, auto F = &T::next>
     struct next_iterator
     {
       ...
       self_type &operator++ ()
       {
	 m_item = m_item->*F;
	 return *this;
       }
       ...
     }
...
but that meant that using an incomplete T was no longer allowed (see
test_next_iterator_incomplete_type), so it's not a drop-in replacement.
---
 gdbsupport/next-iterator.h | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)
  

Comments

Tom Tromey May 8, 2026, 7:17 p.m. UTC | #1
>>>>> "Tom" == Tom de Vries <tdevries@suse.de> writes:

Tom> +    m_item = static_cast<D *>(this)->next ();

Space before paren.

Tom
  

Patch

diff --git a/gdbsupport/next-iterator.h b/gdbsupport/next-iterator.h
index 9f0aba7f8c4..feee2c2a7c7 100644
--- a/gdbsupport/next-iterator.h
+++ b/gdbsupport/next-iterator.h
@@ -21,27 +21,27 @@ 
 
 #include "gdbsupport/iterator-range.h"
 
-/* An iterator that uses the 'next' field of a type to iterate.  This
-   can be used with various GDB types that are stored as linked
-   lists.  */
+/* An iterator base class for iterating over a field of a type.  In order to
+   form a functioning iterator, classes inheriting this should define a next
+   function, which determines the actual field that is iterated over.  */
 
-template<typename T>
-struct next_iterator
+template<typename T, class D>
+struct base_next_iterator
 {
-  using self_type = next_iterator;
+  using self_type = base_next_iterator;
   using value_type = T *;
   using reference = T *&;
   using pointer = T **;
   using iterator_category = std::forward_iterator_tag;
   using difference_type = int;
 
-  explicit next_iterator (T *item)
+  explicit base_next_iterator (T *item)
     : m_item (item)
   {
   }
 
   /* Create a one-past-the-end iterator.  */
-  next_iterator ()
+  base_next_iterator ()
     : m_item (nullptr)
   {
   }
@@ -63,15 +63,31 @@  struct next_iterator
 
   self_type &operator++ ()
   {
-    m_item = m_item->next;
+    m_item = static_cast<D *>(this)->next ();
     return *this;
   }
 
-private:
+protected:
 
   T *m_item;
 };
 
+/* An iterator that uses the 'next' field of a type to iterate.  This
+   can be used with various GDB types that are stored as linked
+   lists.  Note that we're using CRTP here.  */
+
+template<typename T>
+struct next_iterator : base_next_iterator<T, next_iterator<T>>
+{
+  using base_next_iterator<T, next_iterator<T>>::base_next_iterator;
+  using base_next_iterator<T, next_iterator<T>>::m_item;
+
+  T *next ()
+  {
+    return m_item->next;
+  }
+};
+
 /* A convenience wrapper to make a range type around a next_iterator.  */
 
 template <typename T>