--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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 */