Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: simon.marchi@polymtl.ca
To: gdb-patches@sourceware.org
Cc: Simon Marchi <simon.marchi@polymtl.ca>
Subject: [PATCH v2 1/3] gdbsupport: add gdb::ranges::views::enumerate util
Date: Fri, 20 Feb 2026 20:18:58 -0500	[thread overview]
Message-ID: <20260221011924.2029855-1-simon.marchi@polymtl.ca> (raw)
In-Reply-To: <20260220202002.860008-1-simon.marchi@efficios.com>

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


  parent reply	other threads:[~2026-02-21  1:20 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 ` simon.marchi [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260221011924.2029855-1-simon.marchi@polymtl.ca \
    --to=simon.marchi@polymtl.ca \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox