Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 1/3] gdbsupport: add gdb::enumerate util
@ 2026-02-20 20:19 Simon Marchi
  2026-02-20 20:19 ` [PATCH 2/3] gdb/dwarf: use enumerate in index-write.c Simon Marchi
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Simon Marchi @ 2026-02-20 20:19 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@polymtl.ca>

Add a "enumerate" utility, that acts pretty much like Python's
enumerate().  It makes the code slightly nicer, for when you would
otherwise need to handle the counter by hand.

It can be used like this:

  std::vector<int> my_vector;
  for (auto [i, val] : gdb::enumerate (my_vector))
    ...

`i` will hold the 0-based index of the current iteration, and `val` will
be a reference to the value of the current iteration.

Change-Id: I1870ab50537bcf54bba44a30a0b01ab397be16e3
---
 gdb/Makefile.in                     |   1 +
 gdb/unittests/enumerate-selftests.c | 153 ++++++++++++++++++++++++++++
 gdbsupport/enumerate.h              | 130 +++++++++++++++++++++++
 3 files changed, 284 insertions(+)
 create mode 100644 gdb/unittests/enumerate-selftests.c
 create mode 100644 gdbsupport/enumerate.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2aa95be968ac..93701c962fed 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -462,6 +462,7 @@ SELFTESTS_SRCS = \
 	unittests/common-utils-selftests.c \
 	unittests/copy_bitwise-selftests.c \
 	unittests/enum-flags-selftests.c \
+	unittests/enumerate-selftests.c \
 	unittests/environ-selftests.c \
 	unittests/filtered_iterator-selftests.c \
 	unittests/format_pieces-selftests.c \
diff --git a/gdb/unittests/enumerate-selftests.c b/gdb/unittests/enumerate-selftests.c
new file mode 100644
index 000000000000..5d2a4cb4e69e
--- /dev/null
+++ b/gdb/unittests/enumerate-selftests.c
@@ -0,0 +1,153 @@
+/* Self tests for the enumerate range adapter.
+
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "gdbsupport/selftest.h"
+#include "gdbsupport/enumerate.h"
+
+#include <vector>
+#include <array>
+
+namespace selftests {
+
+static void
+test_enumerate ()
+{
+  /* Test basic enumeration over a vector.  */
+  {
+    std::vector<int> vec = { 10, 20, 30, 40 };
+    std::vector<std::pair<std::size_t, int>> result;
+    std::vector<std::pair<std::size_t, int>> expected {
+      {0, 10},
+      {1, 20},
+      {2, 30},
+      {3, 40}
+    };
+
+    for (auto [i, val] : gdb::enumerate (vec))
+      result.push_back ({ i, val });
+
+    SELF_CHECK (result == expected);
+  }
+
+  /* Test enumeration over an std::array.  */
+  {
+    std::array<int, 3> arr = { 5, 6, 7 };
+    std::vector<std::pair<std::size_t, int>> result;
+    std::vector<std::pair<std::size_t, int>> expected {
+      {0, 5},
+      {1, 6},
+      {2, 7}
+    };
+
+    for (auto [i, val] : gdb::enumerate (arr))
+      result.push_back ({ i, val });
+
+    SELF_CHECK (result == expected);
+  }
+
+  /* Test enumeration over a C array.  */
+  {
+    int arr[] = { 8, 9, 10 };
+    std::vector<std::pair<std::size_t, int>> result;
+    std::vector<std::pair<std::size_t, int>> expected {
+      {0, 8},
+      {1, 9},
+      {2, 10}
+    };
+
+    for (auto [i, val] : gdb::enumerate (arr))
+      result.push_back ({ i, val });
+
+    SELF_CHECK (result == expected);
+  }
+
+  /* Test that enumeration allows modification of elements.  */
+  {
+    std::vector<int> vec = { 1, 2, 3 };
+    std::vector<int> expected = { 10, 20, 30 };
+
+    for (auto [i, val] : gdb::enumerate (vec))
+      val *= 10;
+
+    SELF_CHECK (vec == expected);
+  }
+
+  /* Test enumeration over an empty container.  */
+  {
+    std::vector<int> vec;
+    std::vector<std::pair<std::size_t, int>> result;
+    std::vector<std::pair<std::size_t, int>> expected;
+
+    for (auto [i, val] : gdb::enumerate (vec))
+      result.push_back ({ i, val });
+
+    SELF_CHECK (result == expected);
+  }
+
+  /* Test enumeration over a single-element container.  */
+  {
+    std::vector<int> vec = { 42 };
+    std::vector<std::pair<std::size_t, int>> result;
+    std::vector<std::pair<std::size_t, int>> expected {
+      {0, 42}
+    };
+
+    for (auto [i, val] : gdb::enumerate (vec))
+      result.push_back ({ i, val });
+
+    SELF_CHECK (result == expected);
+  }
+
+  /* Test enumeration over an rvalue container.  */
+  {
+    std::vector<std::pair<std::size_t, int>> result;
+    std::vector<std::pair<std::size_t, int>> expected {
+      {0, 17},
+      {1, 38},
+      {2, 99}
+    };
+
+    for (auto [i, val] : gdb::enumerate (std::vector<int> { 17, 38, 99 }))
+      result.push_back ({ i, val });
+
+    SELF_CHECK (result == expected);
+  }
+
+  /* Test enumeration with const container.  */
+  {
+    const std::vector<int> vec = { 100, 200 };
+    std::vector<std::pair<std::size_t, int>> result;
+    std::vector<std::pair<std::size_t, int>> expected {
+      {0, 100},
+      {1, 200}
+    };
+
+    for (auto [i, val] : gdb::enumerate (vec))
+      result.push_back ({ i, val });
+
+    SELF_CHECK (result == expected);
+  }
+}
+
+} /* namespace selftests */
+
+INIT_GDB_FILE (enumerate_selftests)
+{
+  selftests::register_test ("enumerate", selftests::test_enumerate);
+}
diff --git a/gdbsupport/enumerate.h b/gdbsupport/enumerate.h
new file mode 100644
index 000000000000..6182c5f8b7c0
--- /dev/null
+++ b/gdbsupport/enumerate.h
@@ -0,0 +1,130 @@
+/* An enumerate range adapter for GDB, the GNU debugger.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDBSUPPORT_ENUMERATE_H
+#define GDBSUPPORT_ENUMERATE_H
+
+#include <cstddef>
+#include <iterator>
+#include <utility>
+
+namespace gdb
+{
+
+/* Value type of enumerate_iterator.  */
+
+template<typename T>
+struct enumerated_element
+{
+  std::size_t index;
+  T value;
+};
+
+/* An iterator that wraps another iterator and yields
+   enumerated_element objects containing both the index and the
+   value.  */
+
+template<typename Iterator>
+class enumerate_iterator
+{
+  using base_iterator = Iterator;
+public:
+  using value_type
+    = enumerated_element<typename std::iterator_traits<base_iterator>
+				    ::reference>;
+
+  explicit enumerate_iterator (Iterator it)
+    : m_it (std::move (it))
+  {}
+
+  value_type operator* () const
+  { return { m_index, *m_it }; }
+
+  enumerate_iterator &operator++ ()
+  {
+    ++m_it;
+    ++m_index;
+    return *this;
+  }
+
+  bool operator== (const enumerate_iterator &other) const
+  { return m_it == other.m_it; }
+
+  bool operator!= (const enumerate_iterator &other) const
+  { return m_it != other.m_it; }
+
+private:
+  Iterator m_it {};
+  std::size_t m_index = 0;
+};
+
+/* A range adapter that allows iteration on both index and value.  */
+
+template<typename Range>
+class enumerate_range
+{
+  using base_iterator = decltype (std::begin (std::declval<Range &> ()));
+
+public:
+  using iterator = enumerate_iterator<base_iterator>;
+
+  explicit enumerate_range (Range &&range)
+    : m_range (std::forward<Range> (range))
+  {}
+
+  iterator begin ()
+  { return iterator (std::begin (m_range)); }
+
+  iterator end ()
+  { return iterator (std::end (m_range)); }
+
+private:
+  Range m_range;
+};
+
+/* Return an enumerate_range for RANGE, allowing iteration with both
+   index and value.
+
+   Example usage:
+
+     std::vector<int> vec = {10, 20, 30};
+     for (auto [i, val] : gdb::enumerate (vec))
+       printf ("%zu: %d\n", i, val);
+
+   This prints:
+
+     0: 10
+     1: 20
+     2: 30
+
+   The value is a reference to the element in the container, so
+   modifications are possible:
+
+     for (auto [i, val] : gdb::enumerate (vec))
+       val *= 2;  */
+
+template<typename Range>
+enumerate_range<Range>
+enumerate (Range &&range)
+{
+  return enumerate_range<Range> (std::forward<Range> (range));
+}
+
+} /* namespace gdb */
+
+#endif /* GDBSUPPORT_ENUMERATE_H */

base-commit: 0dc2bdec3a05b4202be5ace9beb7f4d2c40fcb3a
-- 
2.53.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 2/3] gdb/dwarf: use enumerate in index-write.c
  2026-02-20 20:19 [PATCH 1/3] gdbsupport: add gdb::enumerate util Simon Marchi
@ 2026-02-20 20:19 ` Simon Marchi
  2026-02-20 20:19 ` [PATCH 3/3] gdb: use enumerate in gdbtypes.c Simon Marchi
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 10+ messages in thread
From: Simon Marchi @ 2026-02-20 20:19 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@polymtl.ca>

Use the new enumerate util to get rid of some manual counters.

Change-Id: I0573f0890e9b775a5181d8c0d435bb7ba661cae4
---
 gdb/dwarf2/index-write.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c
index c4e75898f4c0..66beff663072 100644
--- a/gdb/dwarf2/index-write.c
+++ b/gdb/dwarf2/index-write.c
@@ -24,6 +24,7 @@
 #include "cli/cli-decode.h"
 #include "exceptions.h"
 #include "gdbsupport/byte-vector.h"
+#include "gdbsupport/enumerate.h"
 #include "gdbsupport/filestuff.h"
 #include "gdbsupport/gdb_unlinker.h"
 #include "gdbsupport/pathstuff.h"
@@ -1461,32 +1462,28 @@ write_debug_names (dwarf2_per_bfd *per_bfd, cooked_index *table,
   unit_lists units = get_unit_lists (*per_bfd);
   debug_names nametable (per_bfd, dwarf5_is_dwarf64, dwarf5_byte_order);
   data_buf comp_unit_list;
-  int comp_unit_counter = 0;
 
-  for (const auto per_cu : units.comp)
+  for (auto [i, per_cu] : gdb::enumerate (units.comp))
     {
-      nametable.add_cu (per_cu, comp_unit_counter);
+      nametable.add_cu (per_cu, i);
       comp_unit_list.append_uint (nametable.dwarf5_offset_size (),
 				  dwarf5_byte_order,
 				  to_underlying (per_cu->sect_off ()));
-      comp_unit_counter++;
     }
 
   data_buf type_unit_list;
-  int type_unit_counter = 0;
 
-  for (const auto per_cu : units.type)
+  for (auto [i, per_cu] : gdb::enumerate (units.type))
     {
-      nametable.add_cu (per_cu, type_unit_counter);
+      nametable.add_cu (per_cu, i);
       type_unit_list.append_uint (nametable.dwarf5_offset_size (),
 				  dwarf5_byte_order,
 				  to_underlying (per_cu->sect_off ()));
-      type_unit_counter++;
     }
 
-   /* Verify that all units are represented.  */
-  gdb_assert (comp_unit_counter == per_bfd->num_comp_units);
-  gdb_assert (type_unit_counter == per_bfd->num_type_units);
+  /* Verify that all units are represented.  */
+  gdb_assert (units.comp.size () == per_bfd->num_comp_units);
+  gdb_assert (units.type.size () == per_bfd->num_type_units);
 
   for (const cooked_index_entry *entry : table->all_entries ())
     nametable.insert (entry);
@@ -1525,11 +1522,11 @@ write_debug_names (dwarf2_per_bfd *per_bfd, cooked_index *table,
   header.append_uint (2, dwarf5_byte_order, 0);
 
   /* comp_unit_count - The number of CUs in the CU list.  */
-  header.append_uint (4, dwarf5_byte_order, comp_unit_counter);
+  header.append_uint (4, dwarf5_byte_order, units.comp.size ());
 
   /* local_type_unit_count - The number of TUs in the local TU
      list.  */
-  header.append_uint (4, dwarf5_byte_order, type_unit_counter);
+  header.append_uint (4, dwarf5_byte_order, units.type.size ());
 
   /* foreign_type_unit_count - The number of TUs in the foreign TU
      list.  */
-- 
2.53.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 3/3] gdb: use enumerate in gdbtypes.c
  2026-02-20 20:19 [PATCH 1/3] gdbsupport: add gdb::enumerate util Simon Marchi
  2026-02-20 20:19 ` [PATCH 2/3] gdb/dwarf: use enumerate in index-write.c Simon Marchi
@ 2026-02-20 20:19 ` Simon Marchi
  2026-02-20 20:47 ` [PATCH 1/3] gdbsupport: add gdb::enumerate util Tom Tromey
  2026-02-21  1:18 ` [PATCH v2 1/3] gdbsupport: add gdb::ranges::views::enumerate util simon.marchi
  3 siblings, 0 replies; 10+ messages in thread
From: Simon Marchi @ 2026-02-20 20:19 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@polymtl.ca>

Use the new enumerate util to move to a range-based loop, while keeping
the counter.

Change-Id: If82eaec7afa4e78fa51e973fae4d0ecef728ea95
---
 gdb/gdbtypes.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 2b6244d6f38b..396588e70e0c 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -44,6 +44,7 @@
 #include "rust-lang.h"
 #include "ada-lang.h"
 #include "extract-store-integer.h"
+#include "gdbsupport/enumerate.h"
 
 /* The value of an invalid conversion badness.  */
 #define INVALID_CONVERSION 100
@@ -4765,12 +4766,12 @@ rank_one_type (struct type *parm, struct type *arg, struct value *value)
 static void
 print_args (gdb::array_view<struct field> args, int spaces)
 {
-  for (int i = 0; i < args.size (); i++)
+  for (auto [i, arg] : gdb::enumerate (args))
     {
       gdb_printf
-	("%*s[%d] name '%s'\n", spaces, "", i,
-	 args[i].name () != NULL ? args[i].name () : "<NULL>");
-      recursive_dump_type (args[i].type (), spaces + 2);
+	("%*s[%zu] name '%s'\n", spaces, "", i,
+	 arg.name () != nullptr ? arg.name () : "<NULL>");
+      recursive_dump_type (arg.type (), spaces + 2);
     }
 }
 
-- 
2.53.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/3] gdbsupport: add gdb::enumerate util
  2026-02-20 20:19 [PATCH 1/3] gdbsupport: add gdb::enumerate util Simon Marchi
  2026-02-20 20:19 ` [PATCH 2/3] gdb/dwarf: use enumerate in index-write.c Simon Marchi
  2026-02-20 20:19 ` [PATCH 3/3] gdb: use enumerate in gdbtypes.c Simon Marchi
@ 2026-02-20 20:47 ` Tom Tromey
  2026-02-21  0:58   ` Simon Marchi
  2026-02-21  1:18 ` [PATCH v2 1/3] gdbsupport: add gdb::ranges::views::enumerate util simon.marchi
  3 siblings, 1 reply; 10+ messages in thread
From: Tom Tromey @ 2026-02-20 20:47 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches, Simon Marchi

>>>>> "Simon" == Simon Marchi <simon.marchi@efficios.com> writes:

Simon> From: Simon Marchi <simon.marchi@polymtl.ca>
Simon> Add a "enumerate" utility, that acts pretty much like Python's
Simon> enumerate().  It makes the code slightly nicer, for when you would
Simon> otherwise need to handle the counter by hand.

Very handy.

Simon> +namespace gdb
Simon> +{
Simon> +

I suggest adding more namespaces and calling this
gdb::ranges::views::enumerate.  Then when gdb uses C++23, we can perhaps
just s/gdb/std/ and not reformat everything.

https://en.cppreference.com/w/cpp/ranges/enumerate_view.html

... in particular note (2)

I guess we could go the other way but I tend to think it's better in the
end to just use the standard names and not supply renamings of things.

Simon> +template<typename T>
Simon> +struct enumerated_element
Simon> +{
Simon> +  std::size_t index;
Simon> +  T value;
Simon> +};

C++23 uses a tuple here.

It also uses a reference but I am not sure if that matters for us.

Tom

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/3] gdbsupport: add gdb::enumerate util
  2026-02-20 20:47 ` [PATCH 1/3] gdbsupport: add gdb::enumerate util Tom Tromey
@ 2026-02-21  0:58   ` Simon Marchi
  0 siblings, 0 replies; 10+ messages in thread
From: Simon Marchi @ 2026-02-21  0:58 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches, Simon Marchi



On 2026-02-20 15:47, Tom Tromey wrote:
>>>>>> "Simon" == Simon Marchi <simon.marchi@efficios.com> writes:
> 
> Simon> From: Simon Marchi <simon.marchi@polymtl.ca>
> Simon> Add a "enumerate" utility, that acts pretty much like Python's
> Simon> enumerate().  It makes the code slightly nicer, for when you would
> Simon> otherwise need to handle the counter by hand.
> 
> Very handy.
> 
> Simon> +namespace gdb
> Simon> +{
> Simon> +
> 
> I suggest adding more namespaces and calling this
> gdb::ranges::views::enumerate.  Then when gdb uses C++23, we can perhaps
> just s/gdb/std/ and not reformat everything.
> 
> https://en.cppreference.com/w/cpp/ranges/enumerate_view.html
> 
> ... in particular note (2)
> 
> I guess we could go the other way but I tend to think it's better in the
> end to just use the standard names and not supply renamings of things.

I don't have a strong opinion about this, but I don't mind doing as you
propose.  It's just unfortunate that `gdb::ranges::views::enumerate` is
a bit verbose for nothing, but if this is what we'll have to use when we
get to C++23, then so be it.  Perhaps we will have increased the 80
character limit by then, who knows.

> Simon> +template<typename T>
> Simon> +struct enumerated_element
> Simon> +{
> Simon> +  std::size_t index;
> Simon> +  T value;
> Simon> +};
> 
> C++23 uses a tuple here.
> 
> It also uses a reference but I am not sure if that matters for us.

In my version it's also a reference because of:

  using value_type
    = enumerated_element<typename std::iterator_traits<base_iterator>
				    ::reference>;

We want it to be a reference in most cases, to avoid copying the value.

I can try to use a tuple.  It will probably not make a big difference,
because I expect all uses to use structured bindings:

  for ([i, v] : ...)

Thanks,

Simon

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 1/3] gdbsupport: add gdb::ranges::views::enumerate util
  2026-02-20 20:19 [PATCH 1/3] gdbsupport: add gdb::enumerate util Simon Marchi
                   ` (2 preceding siblings ...)
  2026-02-20 20:47 ` [PATCH 1/3] gdbsupport: add gdb::enumerate util Tom Tromey
@ 2026-02-21  1:18 ` simon.marchi
  2026-02-21  1:18   ` [PATCH v2 2/3] gdb/dwarf: use enumerate in index-write.c simon.marchi
                     ` (3 more replies)
  3 siblings, 4 replies; 10+ messages in thread
From: simon.marchi @ 2026-02-21  1:18 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@polymtl.ca>

Add a "enumerate" utility, that acts pretty much like Python's
enumerate().  It makes the code slightly nicer, for when you would
otherwise need to handle the counter by hand.

It can be used like this:

  std::vector<int> my_vector;
  for (auto [i, val] : gdb::ranges::views::enumerate (my_vector))
    ...

`i` will hold the 0-based index of the current iteration, and `val` will
be a reference to the value of the current iteration.

The name is chosen to match std::ranges::views::enumerate from C++23,
making it easy to switch to that eventually.

Change-Id: I1870ab50537bcf54bba44a30a0b01ab397be16e3
---
 gdb/Makefile.in                     |   1 +
 gdb/unittests/enumerate-selftests.c | 154 ++++++++++++++++++++++++++++
 gdbsupport/enumerate.h              | 121 ++++++++++++++++++++++
 3 files changed, 276 insertions(+)
 create mode 100644 gdb/unittests/enumerate-selftests.c
 create mode 100644 gdbsupport/enumerate.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2aa95be968ac..93701c962fed 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -462,6 +462,7 @@ SELFTESTS_SRCS = \
 	unittests/common-utils-selftests.c \
 	unittests/copy_bitwise-selftests.c \
 	unittests/enum-flags-selftests.c \
+	unittests/enumerate-selftests.c \
 	unittests/environ-selftests.c \
 	unittests/filtered_iterator-selftests.c \
 	unittests/format_pieces-selftests.c \
diff --git a/gdb/unittests/enumerate-selftests.c b/gdb/unittests/enumerate-selftests.c
new file mode 100644
index 000000000000..ddda29f66251
--- /dev/null
+++ b/gdb/unittests/enumerate-selftests.c
@@ -0,0 +1,154 @@
+/* Self tests for the enumerate range adapter.
+
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "gdbsupport/selftest.h"
+#include "gdbsupport/enumerate.h"
+
+#include <vector>
+#include <array>
+
+namespace selftests {
+
+static void
+test_enumerate ()
+{
+  /* Test basic enumeration over a vector.  */
+  {
+    std::vector<int> vec = { 10, 20, 30, 40 };
+    std::vector<std::pair<std::size_t, int>> result;
+    std::vector<std::pair<std::size_t, int>> expected {
+      {0, 10},
+      {1, 20},
+      {2, 30},
+      {3, 40}
+    };
+
+    for (auto [i, val] : gdb::ranges::views::enumerate (vec))
+      result.push_back ({ i, val });
+
+    SELF_CHECK (result == expected);
+  }
+
+  /* Test enumeration over an std::array.  */
+  {
+    std::array<int, 3> arr = { 5, 6, 7 };
+    std::vector<std::pair<std::size_t, int>> result;
+    std::vector<std::pair<std::size_t, int>> expected {
+      {0, 5},
+      {1, 6},
+      {2, 7}
+    };
+
+    for (auto [i, val] : gdb::ranges::views::enumerate (arr))
+      result.push_back ({ i, val });
+
+    SELF_CHECK (result == expected);
+  }
+
+  /* Test enumeration over a C array.  */
+  {
+    int arr[] = { 8, 9, 10 };
+    std::vector<std::pair<std::size_t, int>> result;
+    std::vector<std::pair<std::size_t, int>> expected {
+      {0, 8},
+      {1, 9},
+      {2, 10}
+    };
+
+    for (auto [i, val] : gdb::ranges::views::enumerate (arr))
+      result.push_back ({ i, val });
+
+    SELF_CHECK (result == expected);
+  }
+
+  /* Test that enumeration allows modification of elements.  */
+  {
+    std::vector<int> vec = { 1, 2, 3 };
+    std::vector<int> expected = { 10, 20, 30 };
+
+    for (auto [i, val] : gdb::ranges::views::enumerate (vec))
+      val *= 10;
+
+    SELF_CHECK (vec == expected);
+  }
+
+  /* Test enumeration over an empty container.  */
+  {
+    std::vector<int> vec;
+    std::vector<std::pair<std::size_t, int>> result;
+    std::vector<std::pair<std::size_t, int>> expected;
+
+    for (auto [i, val] : gdb::ranges::views::enumerate (vec))
+      result.push_back ({ i, val });
+
+    SELF_CHECK (result == expected);
+  }
+
+  /* Test enumeration over a single-element container.  */
+  {
+    std::vector<int> vec = { 42 };
+    std::vector<std::pair<std::size_t, int>> result;
+    std::vector<std::pair<std::size_t, int>> expected {
+      {0, 42}
+    };
+
+    for (auto [i, val] : gdb::ranges::views::enumerate (vec))
+      result.push_back ({ i, val });
+
+    SELF_CHECK (result == expected);
+  }
+
+  /* Test enumeration over an rvalue container.  */
+  {
+    std::vector<std::pair<std::size_t, int>> result;
+    std::vector<std::pair<std::size_t, int>> expected {
+      {0, 17},
+      {1, 38},
+      {2, 99}
+    };
+
+    for (auto [i, val] :
+	 gdb::ranges::views::enumerate (std::vector<int> { 17, 38, 99 }))
+      result.push_back ({ i, val });
+
+    SELF_CHECK (result == expected);
+  }
+
+  /* Test enumeration with const container.  */
+  {
+    const std::vector<int> vec = { 100, 200 };
+    std::vector<std::pair<std::size_t, int>> result;
+    std::vector<std::pair<std::size_t, int>> expected {
+      {0, 100},
+      {1, 200}
+    };
+
+    for (auto [i, val] : gdb::ranges::views::enumerate (vec))
+      result.push_back ({ i, val });
+
+    SELF_CHECK (result == expected);
+  }
+}
+
+} /* namespace selftests */
+
+INIT_GDB_FILE (enumerate_selftests)
+{
+  selftests::register_test ("enumerate", selftests::test_enumerate);
+}
diff --git a/gdbsupport/enumerate.h b/gdbsupport/enumerate.h
new file mode 100644
index 000000000000..504d789f0ac3
--- /dev/null
+++ b/gdbsupport/enumerate.h
@@ -0,0 +1,121 @@
+/* An enumerate range adapter for GDB, the GNU debugger.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDBSUPPORT_ENUMERATE_H
+#define GDBSUPPORT_ENUMERATE_H
+
+#include <cstddef>
+#include <iterator>
+#include <tuple>
+#include <utility>
+
+namespace gdb::ranges::views
+{
+
+/* An iterator that wraps another iterator and yields tuples containing
+   both the index and the value.  */
+
+template<typename Iterator>
+class enumerate_iterator
+{
+  using base_iterator = Iterator;
+public:
+  using value_type
+    = std::tuple<std::size_t,
+		 typename std::iterator_traits<base_iterator>::reference>;
+
+  explicit enumerate_iterator (Iterator it)
+    : m_it (std::move (it))
+  {}
+
+  value_type operator* () const
+  { return { m_index, *m_it }; }
+
+  enumerate_iterator &operator++ ()
+  {
+    ++m_it;
+    ++m_index;
+    return *this;
+  }
+
+  bool operator== (const enumerate_iterator &other) const
+  { return m_it == other.m_it; }
+
+  bool operator!= (const enumerate_iterator &other) const
+  { return m_it != other.m_it; }
+
+private:
+  Iterator m_it;
+  std::size_t m_index = 0;
+};
+
+/* A range adapter that allows iteration on both index and value.  */
+
+template<typename Range>
+class enumerate_range
+{
+  using base_iterator = decltype (std::begin (std::declval<Range &> ()));
+
+public:
+  using iterator = enumerate_iterator<base_iterator>;
+
+  explicit enumerate_range (Range &&range)
+    : m_range (std::forward<Range> (range))
+  {}
+
+  iterator begin ()
+  { return iterator (std::begin (m_range)); }
+
+  iterator end ()
+  { return iterator (std::end (m_range)); }
+
+private:
+  Range m_range;
+};
+
+/* Return an enumerate_range for RANGE, allowing iteration with both
+   index and value.
+
+   Example usage:
+
+     std::vector<int> vec = {10, 20, 30};
+     for (auto [i, val] : gdb::ranges::views::enumerate (vec))
+       printf ("%zu: %d\n", i, val);
+
+   This prints:
+
+     0: 10
+     1: 20
+     2: 30
+
+   The value is a reference to the element in the container, so
+   modifications are possible:
+
+     for (auto [i, val] : gdb::ranges::views::enumerate (vec))
+       val *= 2;  */
+
+template<typename Range>
+enumerate_range<Range>
+enumerate (Range &&range)
+{
+  return enumerate_range<Range> (std::forward<Range> (range));
+}
+
+} /* namespace gdb::ranges::views */
+
+#endif /* GDBSUPPORT_ENUMERATE_H */

base-commit: 3049829f1e6dd849e5d3ca71d633990f8d799ae6
-- 
2.53.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 2/3] gdb/dwarf: use enumerate in index-write.c
  2026-02-21  1:18 ` [PATCH v2 1/3] gdbsupport: add gdb::ranges::views::enumerate util simon.marchi
@ 2026-02-21  1:18   ` simon.marchi
  2026-02-21  1:19   ` [PATCH v2 3/3] gdb: use enumerate in gdbtypes.c simon.marchi
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 10+ messages in thread
From: simon.marchi @ 2026-02-21  1:18 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@polymtl.ca>

Use the new enumerate util to get rid of some manual counters.

Change-Id: I0573f0890e9b775a5181d8c0d435bb7ba661cae4
---
 gdb/dwarf2/index-write.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c
index c4e75898f4c0..2877f30dc816 100644
--- a/gdb/dwarf2/index-write.c
+++ b/gdb/dwarf2/index-write.c
@@ -24,6 +24,7 @@
 #include "cli/cli-decode.h"
 #include "exceptions.h"
 #include "gdbsupport/byte-vector.h"
+#include "gdbsupport/enumerate.h"
 #include "gdbsupport/filestuff.h"
 #include "gdbsupport/gdb_unlinker.h"
 #include "gdbsupport/pathstuff.h"
@@ -1461,32 +1462,28 @@ write_debug_names (dwarf2_per_bfd *per_bfd, cooked_index *table,
   unit_lists units = get_unit_lists (*per_bfd);
   debug_names nametable (per_bfd, dwarf5_is_dwarf64, dwarf5_byte_order);
   data_buf comp_unit_list;
-  int comp_unit_counter = 0;
 
-  for (const auto per_cu : units.comp)
+  for (auto [i, per_cu] : gdb::ranges::views::enumerate (units.comp))
     {
-      nametable.add_cu (per_cu, comp_unit_counter);
+      nametable.add_cu (per_cu, i);
       comp_unit_list.append_uint (nametable.dwarf5_offset_size (),
 				  dwarf5_byte_order,
 				  to_underlying (per_cu->sect_off ()));
-      comp_unit_counter++;
     }
 
   data_buf type_unit_list;
-  int type_unit_counter = 0;
 
-  for (const auto per_cu : units.type)
+  for (auto [i, per_cu] : gdb::ranges::views::enumerate (units.type))
     {
-      nametable.add_cu (per_cu, type_unit_counter);
+      nametable.add_cu (per_cu, i);
       type_unit_list.append_uint (nametable.dwarf5_offset_size (),
 				  dwarf5_byte_order,
 				  to_underlying (per_cu->sect_off ()));
-      type_unit_counter++;
     }
 
-   /* Verify that all units are represented.  */
-  gdb_assert (comp_unit_counter == per_bfd->num_comp_units);
-  gdb_assert (type_unit_counter == per_bfd->num_type_units);
+  /* Verify that all units are represented.  */
+  gdb_assert (units.comp.size () == per_bfd->num_comp_units);
+  gdb_assert (units.type.size () == per_bfd->num_type_units);
 
   for (const cooked_index_entry *entry : table->all_entries ())
     nametable.insert (entry);
@@ -1525,11 +1522,11 @@ write_debug_names (dwarf2_per_bfd *per_bfd, cooked_index *table,
   header.append_uint (2, dwarf5_byte_order, 0);
 
   /* comp_unit_count - The number of CUs in the CU list.  */
-  header.append_uint (4, dwarf5_byte_order, comp_unit_counter);
+  header.append_uint (4, dwarf5_byte_order, units.comp.size ());
 
   /* local_type_unit_count - The number of TUs in the local TU
      list.  */
-  header.append_uint (4, dwarf5_byte_order, type_unit_counter);
+  header.append_uint (4, dwarf5_byte_order, units.type.size ());
 
   /* foreign_type_unit_count - The number of TUs in the foreign TU
      list.  */
-- 
2.53.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 3/3] gdb: use enumerate in gdbtypes.c
  2026-02-21  1:18 ` [PATCH v2 1/3] gdbsupport: add gdb::ranges::views::enumerate util simon.marchi
  2026-02-21  1:18   ` [PATCH v2 2/3] gdb/dwarf: use enumerate in index-write.c simon.marchi
@ 2026-02-21  1:19   ` simon.marchi
  2026-03-14 17:32   ` [PATCH v2 1/3] gdbsupport: add gdb::ranges::views::enumerate util Simon Marchi
  2026-04-16 19:52   ` Simon Marchi
  3 siblings, 0 replies; 10+ messages in thread
From: simon.marchi @ 2026-02-21  1:19 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@polymtl.ca>

Use the new enumerate util to move to a range-based loop, while keeping
the counter.

Change-Id: If82eaec7afa4e78fa51e973fae4d0ecef728ea95
---
 gdb/gdbtypes.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 2b6244d6f38b..73f65e72b167 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -44,6 +44,7 @@
 #include "rust-lang.h"
 #include "ada-lang.h"
 #include "extract-store-integer.h"
+#include "gdbsupport/enumerate.h"
 
 /* The value of an invalid conversion badness.  */
 #define INVALID_CONVERSION 100
@@ -4765,12 +4766,12 @@ rank_one_type (struct type *parm, struct type *arg, struct value *value)
 static void
 print_args (gdb::array_view<struct field> args, int spaces)
 {
-  for (int i = 0; i < args.size (); i++)
+  for (auto [i, arg] : gdb::ranges::views::enumerate (args))
     {
       gdb_printf
-	("%*s[%d] name '%s'\n", spaces, "", i,
-	 args[i].name () != NULL ? args[i].name () : "<NULL>");
-      recursive_dump_type (args[i].type (), spaces + 2);
+	("%*s[%zu] name '%s'\n", spaces, "", i,
+	 arg.name () != nullptr ? arg.name () : "<NULL>");
+      recursive_dump_type (arg.type (), spaces + 2);
     }
 }
 
-- 
2.53.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/3] gdbsupport: add gdb::ranges::views::enumerate util
  2026-02-21  1:18 ` [PATCH v2 1/3] gdbsupport: add gdb::ranges::views::enumerate util simon.marchi
  2026-02-21  1:18   ` [PATCH v2 2/3] gdb/dwarf: use enumerate in index-write.c simon.marchi
  2026-02-21  1:19   ` [PATCH v2 3/3] gdb: use enumerate in gdbtypes.c simon.marchi
@ 2026-03-14 17:32   ` Simon Marchi
  2026-04-16 19:52   ` Simon Marchi
  3 siblings, 0 replies; 10+ messages in thread
From: Simon Marchi @ 2026-03-14 17:32 UTC (permalink / raw)
  To: gdb-patches

Ping.

On 2026-02-20 20:18, simon.marchi@polymtl.ca wrote:
> From: Simon Marchi <simon.marchi@polymtl.ca>
> 
> Add a "enumerate" utility, that acts pretty much like Python's
> enumerate().  It makes the code slightly nicer, for when you would
> otherwise need to handle the counter by hand.
> 
> It can be used like this:
> 
>   std::vector<int> my_vector;
>   for (auto [i, val] : gdb::ranges::views::enumerate (my_vector))
>     ...
> 
> `i` will hold the 0-based index of the current iteration, and `val` will
> be a reference to the value of the current iteration.
> 
> The name is chosen to match std::ranges::views::enumerate from C++23,
> making it easy to switch to that eventually.
> 
> Change-Id: I1870ab50537bcf54bba44a30a0b01ab397be16e3
> ---
>  gdb/Makefile.in                     |   1 +
>  gdb/unittests/enumerate-selftests.c | 154 ++++++++++++++++++++++++++++
>  gdbsupport/enumerate.h              | 121 ++++++++++++++++++++++
>  3 files changed, 276 insertions(+)
>  create mode 100644 gdb/unittests/enumerate-selftests.c
>  create mode 100644 gdbsupport/enumerate.h
> 
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 2aa95be968ac..93701c962fed 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -462,6 +462,7 @@ SELFTESTS_SRCS = \
>  	unittests/common-utils-selftests.c \
>  	unittests/copy_bitwise-selftests.c \
>  	unittests/enum-flags-selftests.c \
> +	unittests/enumerate-selftests.c \
>  	unittests/environ-selftests.c \
>  	unittests/filtered_iterator-selftests.c \
>  	unittests/format_pieces-selftests.c \
> diff --git a/gdb/unittests/enumerate-selftests.c b/gdb/unittests/enumerate-selftests.c
> new file mode 100644
> index 000000000000..ddda29f66251
> --- /dev/null
> +++ b/gdb/unittests/enumerate-selftests.c
> @@ -0,0 +1,154 @@
> +/* Self tests for the enumerate range adapter.
> +
> +   Copyright (C) 2026 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include "gdbsupport/selftest.h"
> +#include "gdbsupport/enumerate.h"
> +
> +#include <vector>
> +#include <array>
> +
> +namespace selftests {
> +
> +static void
> +test_enumerate ()
> +{
> +  /* Test basic enumeration over a vector.  */
> +  {
> +    std::vector<int> vec = { 10, 20, 30, 40 };
> +    std::vector<std::pair<std::size_t, int>> result;
> +    std::vector<std::pair<std::size_t, int>> expected {
> +      {0, 10},
> +      {1, 20},
> +      {2, 30},
> +      {3, 40}
> +    };
> +
> +    for (auto [i, val] : gdb::ranges::views::enumerate (vec))
> +      result.push_back ({ i, val });
> +
> +    SELF_CHECK (result == expected);
> +  }
> +
> +  /* Test enumeration over an std::array.  */
> +  {
> +    std::array<int, 3> arr = { 5, 6, 7 };
> +    std::vector<std::pair<std::size_t, int>> result;
> +    std::vector<std::pair<std::size_t, int>> expected {
> +      {0, 5},
> +      {1, 6},
> +      {2, 7}
> +    };
> +
> +    for (auto [i, val] : gdb::ranges::views::enumerate (arr))
> +      result.push_back ({ i, val });
> +
> +    SELF_CHECK (result == expected);
> +  }
> +
> +  /* Test enumeration over a C array.  */
> +  {
> +    int arr[] = { 8, 9, 10 };
> +    std::vector<std::pair<std::size_t, int>> result;
> +    std::vector<std::pair<std::size_t, int>> expected {
> +      {0, 8},
> +      {1, 9},
> +      {2, 10}
> +    };
> +
> +    for (auto [i, val] : gdb::ranges::views::enumerate (arr))
> +      result.push_back ({ i, val });
> +
> +    SELF_CHECK (result == expected);
> +  }
> +
> +  /* Test that enumeration allows modification of elements.  */
> +  {
> +    std::vector<int> vec = { 1, 2, 3 };
> +    std::vector<int> expected = { 10, 20, 30 };
> +
> +    for (auto [i, val] : gdb::ranges::views::enumerate (vec))
> +      val *= 10;
> +
> +    SELF_CHECK (vec == expected);
> +  }
> +
> +  /* Test enumeration over an empty container.  */
> +  {
> +    std::vector<int> vec;
> +    std::vector<std::pair<std::size_t, int>> result;
> +    std::vector<std::pair<std::size_t, int>> expected;
> +
> +    for (auto [i, val] : gdb::ranges::views::enumerate (vec))
> +      result.push_back ({ i, val });
> +
> +    SELF_CHECK (result == expected);
> +  }
> +
> +  /* Test enumeration over a single-element container.  */
> +  {
> +    std::vector<int> vec = { 42 };
> +    std::vector<std::pair<std::size_t, int>> result;
> +    std::vector<std::pair<std::size_t, int>> expected {
> +      {0, 42}
> +    };
> +
> +    for (auto [i, val] : gdb::ranges::views::enumerate (vec))
> +      result.push_back ({ i, val });
> +
> +    SELF_CHECK (result == expected);
> +  }
> +
> +  /* Test enumeration over an rvalue container.  */
> +  {
> +    std::vector<std::pair<std::size_t, int>> result;
> +    std::vector<std::pair<std::size_t, int>> expected {
> +      {0, 17},
> +      {1, 38},
> +      {2, 99}
> +    };
> +
> +    for (auto [i, val] :
> +	 gdb::ranges::views::enumerate (std::vector<int> { 17, 38, 99 }))
> +      result.push_back ({ i, val });
> +
> +    SELF_CHECK (result == expected);
> +  }
> +
> +  /* Test enumeration with const container.  */
> +  {
> +    const std::vector<int> vec = { 100, 200 };
> +    std::vector<std::pair<std::size_t, int>> result;
> +    std::vector<std::pair<std::size_t, int>> expected {
> +      {0, 100},
> +      {1, 200}
> +    };
> +
> +    for (auto [i, val] : gdb::ranges::views::enumerate (vec))
> +      result.push_back ({ i, val });
> +
> +    SELF_CHECK (result == expected);
> +  }
> +}
> +
> +} /* namespace selftests */
> +
> +INIT_GDB_FILE (enumerate_selftests)
> +{
> +  selftests::register_test ("enumerate", selftests::test_enumerate);
> +}
> diff --git a/gdbsupport/enumerate.h b/gdbsupport/enumerate.h
> new file mode 100644
> index 000000000000..504d789f0ac3
> --- /dev/null
> +++ b/gdbsupport/enumerate.h
> @@ -0,0 +1,121 @@
> +/* An enumerate range adapter for GDB, the GNU debugger.
> +   Copyright (C) 2026 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GDBSUPPORT_ENUMERATE_H
> +#define GDBSUPPORT_ENUMERATE_H
> +
> +#include <cstddef>
> +#include <iterator>
> +#include <tuple>
> +#include <utility>
> +
> +namespace gdb::ranges::views
> +{
> +
> +/* An iterator that wraps another iterator and yields tuples containing
> +   both the index and the value.  */
> +
> +template<typename Iterator>
> +class enumerate_iterator
> +{
> +  using base_iterator = Iterator;
> +public:
> +  using value_type
> +    = std::tuple<std::size_t,
> +		 typename std::iterator_traits<base_iterator>::reference>;
> +
> +  explicit enumerate_iterator (Iterator it)
> +    : m_it (std::move (it))
> +  {}
> +
> +  value_type operator* () const
> +  { return { m_index, *m_it }; }
> +
> +  enumerate_iterator &operator++ ()
> +  {
> +    ++m_it;
> +    ++m_index;
> +    return *this;
> +  }
> +
> +  bool operator== (const enumerate_iterator &other) const
> +  { return m_it == other.m_it; }
> +
> +  bool operator!= (const enumerate_iterator &other) const
> +  { return m_it != other.m_it; }
> +
> +private:
> +  Iterator m_it;
> +  std::size_t m_index = 0;
> +};
> +
> +/* A range adapter that allows iteration on both index and value.  */
> +
> +template<typename Range>
> +class enumerate_range
> +{
> +  using base_iterator = decltype (std::begin (std::declval<Range &> ()));
> +
> +public:
> +  using iterator = enumerate_iterator<base_iterator>;
> +
> +  explicit enumerate_range (Range &&range)
> +    : m_range (std::forward<Range> (range))
> +  {}
> +
> +  iterator begin ()
> +  { return iterator (std::begin (m_range)); }
> +
> +  iterator end ()
> +  { return iterator (std::end (m_range)); }
> +
> +private:
> +  Range m_range;
> +};
> +
> +/* Return an enumerate_range for RANGE, allowing iteration with both
> +   index and value.
> +
> +   Example usage:
> +
> +     std::vector<int> vec = {10, 20, 30};
> +     for (auto [i, val] : gdb::ranges::views::enumerate (vec))
> +       printf ("%zu: %d\n", i, val);
> +
> +   This prints:
> +
> +     0: 10
> +     1: 20
> +     2: 30
> +
> +   The value is a reference to the element in the container, so
> +   modifications are possible:
> +
> +     for (auto [i, val] : gdb::ranges::views::enumerate (vec))
> +       val *= 2;  */
> +
> +template<typename Range>
> +enumerate_range<Range>
> +enumerate (Range &&range)
> +{
> +  return enumerate_range<Range> (std::forward<Range> (range));
> +}
> +
> +} /* namespace gdb::ranges::views */
> +
> +#endif /* GDBSUPPORT_ENUMERATE_H */
> 
> base-commit: 3049829f1e6dd849e5d3ca71d633990f8d799ae6


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/3] gdbsupport: add gdb::ranges::views::enumerate util
  2026-02-21  1:18 ` [PATCH v2 1/3] gdbsupport: add gdb::ranges::views::enumerate util simon.marchi
                     ` (2 preceding siblings ...)
  2026-03-14 17:32   ` [PATCH v2 1/3] gdbsupport: add gdb::ranges::views::enumerate util Simon Marchi
@ 2026-04-16 19:52   ` Simon Marchi
  3 siblings, 0 replies; 10+ messages in thread
From: Simon Marchi @ 2026-04-16 19:52 UTC (permalink / raw)
  To: gdb-patches

On 2/20/26 8:18 PM, simon.marchi@polymtl.ca wrote:
> From: Simon Marchi <simon.marchi@polymtl.ca>
> 
> Add a "enumerate" utility, that acts pretty much like Python's
> enumerate().  It makes the code slightly nicer, for when you would
> otherwise need to handle the counter by hand.
> 
> It can be used like this:
> 
>   std::vector<int> my_vector;
>   for (auto [i, val] : gdb::ranges::views::enumerate (my_vector))
>     ...
> 
> `i` will hold the 0-based index of the current iteration, and `val` will
> be a reference to the value of the current iteration.
> 
> The name is chosen to match std::ranges::views::enumerate from C++23,
> making it easy to switch to that eventually.
> 
> Change-Id: I1870ab50537bcf54bba44a30a0b01ab397be16e3

I pushed all 3 patches of this series.

Simon

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-04-16 19:53 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-02-20 20:19 [PATCH 1/3] gdbsupport: add gdb::enumerate util Simon Marchi
2026-02-20 20:19 ` [PATCH 2/3] gdb/dwarf: use enumerate in index-write.c Simon Marchi
2026-02-20 20:19 ` [PATCH 3/3] gdb: use enumerate in gdbtypes.c Simon Marchi
2026-02-20 20:47 ` [PATCH 1/3] gdbsupport: add gdb::enumerate util Tom Tromey
2026-02-21  0:58   ` Simon Marchi
2026-02-21  1:18 ` [PATCH v2 1/3] gdbsupport: add gdb::ranges::views::enumerate util simon.marchi
2026-02-21  1:18   ` [PATCH v2 2/3] gdb/dwarf: use enumerate in index-write.c simon.marchi
2026-02-21  1:19   ` [PATCH v2 3/3] gdb: use enumerate in gdbtypes.c simon.marchi
2026-03-14 17:32   ` [PATCH v2 1/3] gdbsupport: add gdb::ranges::views::enumerate util Simon Marchi
2026-04-16 19:52   ` Simon Marchi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox