From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id oX9iMmQImWnWcQMAWB0awg (envelope-from ) for ; Fri, 20 Feb 2026 20:20:36 -0500 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=polymtl.ca header.i=@polymtl.ca header.a=rsa-sha256 header.s=oct2025 header.b=BPuxkMrC; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id C83FF1E08D; Fri, 20 Feb 2026 20:20:36 -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.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,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 8B3081E08D for ; Fri, 20 Feb 2026 20:20:35 -0500 (EST) Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id DE02B4BAD159 for ; Sat, 21 Feb 2026 01:20:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DE02B4BAD159 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=polymtl.ca header.i=@polymtl.ca header.a=rsa-sha256 header.s=oct2025 header.b=BPuxkMrC Received: from smtp.polymtl.ca (smtp.polymtl.ca [132.207.4.11]) by sourceware.org (Postfix) with ESMTPS id C0A624B9DB47 for ; Sat, 21 Feb 2026 01:19:32 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C0A624B9DB47 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=polymtl.ca Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=polymtl.ca ARC-Filter: OpenARC Filter v1.0.0 sourceware.org C0A624B9DB47 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=132.207.4.11 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1771636772; cv=none; b=jFsTwohjnSDjtJ6wa4numiUJoCobK137106KeumCbyyFdJ32Axe3tH2zsAMoebngidYFF0SjEB4ix9Y/jhWwbX6UeYf38zf2piEzWtRNsAwL5JsNi3BU5VO2JUt3YG49nrkBjvgFK79d0l1goQheI6zHqtDB93TYOgsBv0iqBMo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1771636772; c=relaxed/simple; bh=gQQMTOTLIx74nBGjpKQyudMRs5wUl4ifaHlI0N1SqhM=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=TgwhJ4HItrjwRLBUBGSbtHYJb5/lLUt+JCkCkB3GwQSOJSHaut9XxUM3bUWb9fbi03A1XXeoLobk6NUczgGKv3eeHcg32XUnoKigWHveXPew9htkhJIO3+xtmskwHyKWfgW80w53sG9QWJcZ9H7onRrpP7vTWM+IQjo+rALIaBs= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C0A624B9DB47 Received: from simark.ca (simark.ca [158.69.221.121]) (authenticated bits=0) by smtp.polymtl.ca (8.14.7/8.14.7) with ESMTP id 61L1JQpF209417 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 20 Feb 2026 20:19:31 -0500 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp.polymtl.ca 61L1JQpF209417 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=polymtl.ca; s=oct2025; t=1771636771; bh=Nq92YZDJdBICpAR0sSIHAUnu44i74l0fPh95z6c+B0o=; h=From:To:Cc:Subject:Date:In-Reply-To:From; b=BPuxkMrCB/9d85ur6ff3Qx5JMXe3iN6VrgpDBNdN7zKpUYxiCtJTf1vhJ34WsUQmE lKuveYFkDM/1E8UmjQ+0HAA0jxD0PT5/w29uz+On7XNsUs2Voz1Rw1605nrBuGtPDh Wj/HXE9H0yVxCsTkozTC7MwlP2q3DyPFN/f2hM4spoGf52HMCRwEsBsZBT+27zrNqQ srCaWZkQIJN5srAn/3hZleMsxjLPeBorzahCpCxbWLpBp6xpx/EaNCVaPSS1EOpZy9 u19FmoDaBfe/8DUhGORfsBE4gnHkvhAME0wCG5Hl7A6X1nt+5KolbvmesthZiMGDrA WXXXsKwLh/rYw== Received: by simark.ca (Postfix) id 725EA1E08D; Fri, 20 Feb 2026 20:19:25 -0500 (EST) From: simon.marchi@polymtl.ca To: gdb-patches@sourceware.org Cc: Simon Marchi Subject: [PATCH v2 1/3] gdbsupport: add gdb::ranges::views::enumerate util Date: Fri, 20 Feb 2026 20:18:58 -0500 Message-ID: <20260221011924.2029855-1-simon.marchi@polymtl.ca> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260220202002.860008-1-simon.marchi@efficios.com> References: <20260220202002.860008-1-simon.marchi@efficios.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Poly-FromMTA: (simark.ca [158.69.221.121]) at Sat, 21 Feb 2026 01:19:26 +0000 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::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 . */ + +#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::ranges::views::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::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> result; + std::vector> 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 vec = { 1, 2, 3 }; + std::vector 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 vec; + std::vector> result; + std::vector> 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 vec = { 42 }; + std::vector> result; + std::vector> 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> result; + std::vector> expected { + {0, 17}, + {1, 38}, + {2, 99} + }; + + for (auto [i, val] : + gdb::ranges::views::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::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 . */ + +#ifndef GDBSUPPORT_ENUMERATE_H +#define GDBSUPPORT_ENUMERATE_H + +#include +#include +#include +#include + +namespace gdb::ranges::views +{ + +/* An iterator that wraps another iterator and yields tuples containing + both the index and the value. */ + +template +class enumerate_iterator +{ + using base_iterator = Iterator; +public: + using value_type + = std::tuple::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::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 +enumerate_range +enumerate (Range &&range) +{ + return enumerate_range (std::forward (range)); +} + +} /* namespace gdb::ranges::views */ + +#endif /* GDBSUPPORT_ENUMERATE_H */ base-commit: 3049829f1e6dd849e5d3ca71d633990f8d799ae6 -- 2.53.0