From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id CUYdOh7CmGmiKQMAWB0awg (envelope-from ) for ; Fri, 20 Feb 2026 15:20:46 -0500 Received: by simark.ca (Postfix, from userid 112) id E9B301E0BA; Fri, 20 Feb 2026 15:20:46 -0500 (EST) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-2.3 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 86AA01E08D for ; Fri, 20 Feb 2026 15:20:45 -0500 (EST) Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 0DEC24BA23EE for ; Fri, 20 Feb 2026 20:20:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0DEC24BA23EE Received: from simark.ca (simark.ca [158.69.221.121]) by sourceware.org (Postfix) with ESMTPS id 1FC494BAD148 for ; Fri, 20 Feb 2026 20:20:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1FC494BAD148 Authentication-Results: sourceware.org; dmarc=fail (p=none dis=none) header.from=efficios.com Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=efficios.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 1FC494BAD148 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=158.69.221.121 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1771618805; cv=none; b=sJ1AnXlYQ26BdQ+p00WsKX8YPEIyBMkcYfzhAkf54qkABXcq8WbnRKWhnW/zlpa4ns5sTVSeptydSdHTJzmbdn/Gn9GdXNyr0S0+WQSAByM/ncJuoN2fYZe4ihdNiF0jyZW2BW89e/RS+W4DduwE3RmDCaMvO1jIc3QBhKxVtUc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1771618805; c=relaxed/simple; bh=ualCRPnr/Q0I4eKSQe1zAtTWLFQMPq69YlxqjY6g2KQ=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=nRHykMr2eBJu4ekA+x+Bbgz1G6y4eC+/ORJ1ZM9PMEsMF+FFbjcURSNEWWJ3pV+kzwyVjaH1HMgWxj2ADflRd+1TAYBwzThmS9TIylUK7XC/G1iz31Oi9YEx6P8Zb4ylsUvzStQwYf95L+q/WI+mEyTFh2y8h92pk2DVB7/EYME= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1FC494BAD148 Received: by simark.ca (Postfix) id 966121E08D; Fri, 20 Feb 2026 15:20:03 -0500 (EST) From: Simon Marchi To: gdb-patches@sourceware.org Cc: Simon Marchi Subject: [PATCH 1/3] gdbsupport: add gdb::enumerate util Date: Fri, 20 Feb 2026 15:19:41 -0500 Message-ID: <20260220202002.860008-1-simon.marchi@efficios.com> X-Mailer: git-send-email 2.53.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org From: Simon Marchi 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 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 . */ + +#include "gdbsupport/selftest.h" +#include "gdbsupport/enumerate.h" + +#include +#include + +namespace selftests { + +static void +test_enumerate () +{ + /* Test basic enumeration over a vector. */ + { + std::vector vec = { 10, 20, 30, 40 }; + std::vector> result; + std::vector> 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 arr = { 5, 6, 7 }; + std::vector> result; + std::vector> 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> result; + std::vector> 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 vec = { 1, 2, 3 }; + std::vector 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 vec; + std::vector> result; + std::vector> 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 vec = { 42 }; + std::vector> result; + std::vector> 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> result; + std::vector> expected { + {0, 17}, + {1, 38}, + {2, 99} + }; + + for (auto [i, val] : gdb::enumerate (std::vector { 17, 38, 99 })) + result.push_back ({ i, val }); + + SELF_CHECK (result == expected); + } + + /* Test enumeration with const container. */ + { + const std::vector vec = { 100, 200 }; + std::vector> result; + std::vector> 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 . */ + +#ifndef GDBSUPPORT_ENUMERATE_H +#define GDBSUPPORT_ENUMERATE_H + +#include +#include +#include + +namespace gdb +{ + +/* Value type of enumerate_iterator. */ + +template +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 +class enumerate_iterator +{ + using base_iterator = Iterator; +public: + using value_type + = enumerated_element + ::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 +class enumerate_range +{ + using base_iterator = decltype (std::begin (std::declval ())); + +public: + using iterator = enumerate_iterator; + + explicit enumerate_range (Range &&range) + : m_range (std::forward (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 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 +enumerate_range +enumerate (Range &&range) +{ + return enumerate_range (std::forward (range)); +} + +} /* namespace gdb */ + +#endif /* GDBSUPPORT_ENUMERATE_H */ base-commit: 0dc2bdec3a05b4202be5ace9beb7f4d2c40fcb3a -- 2.53.0