From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wm1-f45.google.com (mail-wm1-f45.google.com [209.85.128.45]) by sourceware.org (Postfix) with ESMTPS id A4B603857C5D for ; Fri, 22 Jul 2022 11:02:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org A4B603857C5D Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=palves.net Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-wm1-f45.google.com with SMTP id a11so2562479wmq.3 for ; Fri, 22 Jul 2022 04:02:09 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=1GsKB6Fe+IcpZuXWLyI+AeR8DOeU9RWRo73l7pmMT/Y=; b=bIYuO70dT1XvF7u6HtSenrmG0c0BsnGuNJJjhKT3Al1nFiwO2Rfe849mdVK35LkeL0 CCdQOwF6Nl6hONPouasYIuXe9KChfesMaajhvA+LTJAY3durbL42apyJwjUFChiDmWd8 zgMe9ga6ZOt1eV0Qi9TWnk8lR94SCvUACGICcf0zCVps24zzx654Q6vvxmi4GFRvLX1a NqbUaxxI2c74K1RFemZ+QPdgddJAi6Ww572UKcH+jyuaE3atY1BSCQJ9GPV4ti5eO1NI SgxlKtrj9YI18V+jFDCT4cFe4QxPm9z+H0f/EGq/XYF4cUIjvaEmgM4/CnI6jheUDyYD u+ng== X-Gm-Message-State: AJIora+T4ntggAinubpv6h/gdn1Ss9ARgE2XWU2C5sfemFn1OJbEZc7c RgyXwDTel6VouBmZXEBCYTN5dvCvUtg= X-Google-Smtp-Source: AGRyM1uh7XMVD8W9dTe7UU9j4UsYxadsZQ27XTvuPVVpV/mROr94mZ9cEX036Ez4dIIqBq2exXleeA== X-Received: by 2002:a05:600c:4fc9:b0:3a3:3537:1726 with SMTP id o9-20020a05600c4fc900b003a335371726mr15342wmq.26.1658487727907; Fri, 22 Jul 2022 04:02:07 -0700 (PDT) Received: from localhost ([2001:8a0:f924:2600:209d:85e2:409e:8726]) by smtp.gmail.com with ESMTPSA id c15-20020adfe70f000000b0021bbf6687b1sm5255594wrm.81.2022.07.22.04.02.06 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 22 Jul 2022 04:02:07 -0700 (PDT) From: Pedro Alves To: gdb-patches@sourceware.org Cc: Tom de Vries , Tom Tromey Subject: [PATCH 1/1] Introduce gdb::make_function_view Date: Fri, 22 Jul 2022 12:02:03 +0100 Message-Id: <20220722110203.4152339-2-pedro@palves.net> X-Mailer: git-send-email 2.36.0 In-Reply-To: <20220722110203.4152339-1-pedro@palves.net> References: <20220722110203.4152339-1-pedro@palves.net> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-9.9 required=5.0 tests=BAYES_00, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 22 Jul 2022 11:02:11 -0000 This adds gdb::make_function_view, which let's you create a function view from a callable without specifying the function_view's template parameter. For example, this: auto lambda = [&] (int) { ... }; auto fv = gdb::make_function_view (lambda); instead of: auto lambda = [&] (int) { ... }; gdb::function_view fv = lambda; It is particularly useful if you have a template function with an optional function_view parameter, whose type depends on the function's template parameters. Like: template void my_function (T v, gdb::function_view callback = nullptr); For such a function, the type of the callback argument you pass must already be a function_view. I.e., this wouldn't compile: auto lambda = [&] (int) { ... }; my_function (1, lambda); With gdb::make_function_view, you can write the call like so: auto lambda = [&] (int) { ... }; my_function (1, gdb::make_function_view (lambda)); Unit tests included. Tested by building with GCC 9.4, Clang 10, and GCC 4.8.5, on x86_64 GNU/Linux, and running the unit tests. Change-Id: I5c4b3b4455ed6f0d8878cf1be189bea3ee63f626 --- gdb/unittests/function-view-selftests.c | 82 ++++++++++++++- gdbsupport/function-view.h | 127 ++++++++++++++++++++++++ 2 files changed, 208 insertions(+), 1 deletion(-) diff --git a/gdb/unittests/function-view-selftests.c b/gdb/unittests/function-view-selftests.c index 7af0245c570..9ca920dc843 100644 --- a/gdb/unittests/function-view-selftests.c +++ b/gdb/unittests/function-view-selftests.c @@ -60,8 +60,81 @@ struct plus_one_int_func_obj int call_count = 0; }; +/* A template function where the function_view type is dependent on a + template parameter. */ + +template +static int +tmpl_func (T val, gdb::function_view callback) +{ + return callback (val) + 1; +} + +static int +make_func_view_test_func (int val) +{ + return val + 1; +} + +/* A function object with const operator(). */ + +struct func_obj_const_op +{ + int operator() (int val) const + { + return val + 1; + } +}; + +/* A function object with non-const operator(). */ + +struct func_obj_non_const_op +{ + int operator() (int val) + { + return val + 1; + } +}; + static void -run_tests () +test_make_function_view () +{ + /* Function reference. */ + SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (make_func_view_test_func))); + + /* Function pointer. */ + SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (&make_func_view_test_func))); + + /* Reference to const and non-const function pointers. */ + typedef int (*func_ptr) (int); + func_ptr ptr = make_func_view_test_func; + const func_ptr cptr = make_func_view_test_func; + SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (ptr))); + SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (cptr))); + + /* Lambdas. */ + + auto lambda = [] (int val) -> int { return val + 1; }; + + /* This wouldn't compile, since tmpl_func is a template and its + function_view argument's callable type is a dependent type. The + passed argument must be of the exact type of the function's + parameter. */ + // SELF_CHECK (3 == tmpl_func (1, lambda)); + + SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (lambda))); + + /* Regular function objects. */ + + func_obj_non_const_op fobj; + SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (fobj))); + + func_obj_const_op cfobj; + SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (cfobj))); +} + +static void +test_function_view () { /* A simple lambda. */ auto plus_one_lambda = [] (int val) { return ++val; }; @@ -168,6 +241,13 @@ run_tests () SELF_CHECK (!check_op_eq_null); } +static void +run_tests () +{ + test_function_view (); + test_make_function_view (); +} + } /* namespace function_view */ } /* namespace selftests */ diff --git a/gdbsupport/function-view.h b/gdbsupport/function-view.h index 1875cd104b7..856f74df46c 100644 --- a/gdbsupport/function-view.h +++ b/gdbsupport/function-view.h @@ -148,6 +148,47 @@ iterate_over_foos (process_one_foo); + There's also a gdb::make_function_view function that you can use to + automatically create a function_view from a callable without having + to specify the function_view's template parameter. E.g.: + + auto lambda = [&] (int) { ... }; + auto fv = gdb::make_function_view (lambda); + + This can be useful for example when calling a template function + whose function_view parameter type depends on the function's + template parameters. In such case, you can't rely on implicit + callable->function_view conversion for the function_view argument. + You must pass a function_view argument already of the right type to + the template function. E.g., with this: + + template + void my_function (T v, gdb::function_view callback = nullptr); + + this wouldn't compile: + + auto lambda = [&] (int) { ... }; + my_function (1, lambda); + + Note that this immediately dangles the temporary lambda object: + + gdb::function_view fv = [&] (int) { ... }; // dangles + my_function (fv); + + To avoid the dangling you'd have to use a named temporary for the + lambda: + + auto lambda = [&] (int) { ... }; + gdb::function_view fv = lambda; + my_function (fv); + + Using gdb::make_function_view instead automatically deduces the + function_view's full type, and, avoids worrying about dangling. For + the example above, we could write instead: + + auto lambda = [&] (int) { ... }; + my_function (1, gdb::make_function_view (lambda)); + You can find unit tests covering the whole API in unittests/function-view-selftests.c. */ @@ -318,6 +359,92 @@ constexpr inline bool operator!= (std::nullptr_t, const function_view &f) noexcept { return static_cast (f); } +namespace fv_detail { + +/* Helper traits type to automatically find the right function_view + type for a callable. */ + +/* Use partial specialization to get access to the callable's + signature, for all the different callable variants. */ + +template +struct function_view_traits; + +/* Main partial specialization with plain function signature type. + All others end up redirected here. */ +template +struct function_view_traits +{ + using type = gdb::function_view; +}; + +/* Function pointers. */ +template +struct function_view_traits + : function_view_traits +{ +}; + +/* Function references. */ +template +struct function_view_traits + : function_view_traits +{ +}; + +/* Reference to function pointers. */ +template +struct function_view_traits + : function_view_traits +{ +}; + +/* Reference to const function pointers. */ +template +struct function_view_traits + : function_view_traits +{ +}; + +/* Const member functions. function_view doesn't support these, but + we need this in order to extract the type of function objects. + Lambdas pass here, after starting at the operator() case, + below. */ +template +struct function_view_traits + : function_view_traits +{ +}; + +/* Member functions. Ditto, for function objects with non-const + operator(). */ +template +struct function_view_traits + : function_view_traits +{ +}; + +/* Function objects, lambdas, std::function, any type that defines + operator(). */ +template +struct function_view_traits + : function_view_traits ::type::operator())> +{ +}; + +} /* namespace fv_detail */ + +/* Make a function_view from a callable. Useful to automatically + deduce the function_view's template argument types. */ +template +auto make_function_view (Callable &&callable) + -> typename fv_detail::function_view_traits::type +{ + using fv = typename fv_detail::function_view_traits::type; + return fv (std::forward (callable)); +} + } /* namespace gdb */ #endif -- 2.36.0