From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gateway20.websitewelcome.com (gateway20.websitewelcome.com [192.185.65.13]) by sourceware.org (Postfix) with ESMTPS id 913F739B680C for ; Wed, 28 Apr 2021 01:01:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 913F739B680C Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=tromey.com Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=tom@tromey.com Received: from cm10.websitewelcome.com (cm10.websitewelcome.com [100.42.49.4]) by gateway20.websitewelcome.com (Postfix) with ESMTP id 2BEFD400F99E8 for ; Tue, 27 Apr 2021 19:50:22 -0500 (CDT) Received: from box5379.bluehost.com ([162.241.216.53]) by cmsmtp with SMTP id bYaGlqT2IL7DmbYaGlsbEf; Tue, 27 Apr 2021 20:01:44 -0500 X-Authority-Reason: nr=8 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=tromey.com; s=default; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=4393CsWW0nFYqfx5nY7yj/mIhiHQMpGB4odmBKjgwWY=; b=lnXzN3BnlXijE81jqXqyIjb2rK N/r8vX4D4CmKpF8upGMX7YkRETwNf4nzcnCfMYobX47oO7bB6XhDqCdkjnHoQ0RJ6ckuw/4MChvXZ /hLvZWeRNLKLvkemxgLkqwGYG; Received: from 97-122-70-176.hlrn.qwest.net ([97.122.70.176]:32966 helo=localhost.localdomain) by box5379.bluehost.com with esmtpsa (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94) (envelope-from ) id 1lbYaG-003tiR-Gh; Tue, 27 Apr 2021 19:01:44 -0600 From: Tom Tromey To: gcc-patches@gcc.gnu.org Cc: Tom Tromey Subject: [PATCH v2 19/21] libcc1: use variadic templates for callbacks Date: Tue, 27 Apr 2021 19:01:17 -0600 Message-Id: <20210428010119.806184-20-tom@tromey.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210428010119.806184-1-tom@tromey.com> References: <20210428010119.806184-1-tom@tromey.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - box5379.bluehost.com X-AntiAbuse: Original Domain - gcc.gnu.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - tromey.com X-BWhitelist: no X-Source-IP: 97.122.70.176 X-Source-L: No X-Exim-ID: 1lbYaG-003tiR-Gh X-Source: X-Source-Args: X-Source-Dir: X-Source-Sender: 97-122-70-176.hlrn.qwest.net (localhost.localdomain) [97.122.70.176]:32966 X-Source-Auth: tom+tromey.com X-Email-Count: 20 X-Source-Cap: ZWx5bnJvYmk7ZWx5bnJvYmk7Ym94NTM3OS5ibHVlaG9zdC5jb20= X-Local-Domain: yes X-Spam-Status: No, score=-3031.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, JMQ_SPF_NEUTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_SBL_CSS, SPF_HELO_PASS, SPF_NEUTRAL, TXREP, URIBL_CSS, URIBL_CSS_A autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 28 Apr 2021 01:01:51 -0000 This patch completes the transition of libcc1 from the use of separate template functions for different arities to the use of variadic functions. This is how I had wanted it to work from the very beginning, and is possible now with C++11. I had thought that variadic callbacks required C++17, but it turns out that the approach taken here is basically equivalent to std::apply -- just a bit wordier. libcc1/ChangeLog 2021-04-27 Tom Tromey * rpc.hh (argument_wrapper) : Replace cast operator. (argument_wrapper) : Likewise. (unmarshall): Add std::tuple overloads. (callback): Remove. (class invoker): New. * libcp1plugin.cc (plugin_init): Update. * libcp1.cc (libcp1::add_callbacks): Update. * libcc1plugin.cc (plugin_init): Update. * libcc1.cc (libcc1::add_callbacks): Update. * connection.cc (cc1_plugin::connection::do_wait): Update. --- libcc1/ChangeLog | 13 +++ libcc1/connection.cc | 2 +- libcc1/libcc1.cc | 12 +-- libcc1/libcc1plugin.cc | 20 ++-- libcc1/libcp1.cc | 17 ++-- libcc1/libcp1plugin.cc | 20 ++-- libcc1/rpc.hh | 219 +++++++++++------------------------------ 7 files changed, 101 insertions(+), 202 deletions(-) diff --git a/libcc1/connection.cc b/libcc1/connection.cc index 66d573911080..45560b9b790e 100644 --- a/libcc1/connection.cc +++ b/libcc1/connection.cc @@ -129,7 +129,7 @@ cc1_plugin::connection::do_wait (bool want_result) return FAIL; callback_ftype *callback - = m_callbacks.find_callback (method_name); + = m_callbacks.find_callback (method_name.get ()); // The call to CALLBACK is where we may end up in a // reentrant call. if (callback == NULL || !callback (this)) diff --git a/libcc1/libcc1.cc b/libcc1/libcc1.cc index cbc54ee0a044..febadc8420b0 100644 --- a/libcc1/libcc1.cc +++ b/libcc1/libcc1.cc @@ -143,15 +143,13 @@ void libcc1::add_callbacks () { cc1_plugin::callback_ftype *fun - = cc1_plugin::callback; + = cc1_plugin::invoker::invoke; connection->add_callback ("binding_oracle", fun); - fun = cc1_plugin::callback; + fun = cc1_plugin::invoker::invoke; connection->add_callback ("address_oracle", fun); } diff --git a/libcc1/libcc1plugin.cc b/libcc1/libcc1plugin.cc index d6951ab1a4d2..4d6a3a11ee22 100644 --- a/libcc1/libcc1plugin.cc +++ b/libcc1/libcc1plugin.cc @@ -762,46 +762,46 @@ plugin_init (struct plugin_name_args *plugin_info, #define GCC_METHOD0(R, N) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD1(R, N, A) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD2(R, N, A, B) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD3(R, N, A, B, C) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD4(R, N, A, B, C, D) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD5(R, N, A, B, C, D, E) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } diff --git a/libcc1/libcp1.cc b/libcc1/libcp1.cc index d22d9dc6af8c..a93349833901 100644 --- a/libcc1/libcp1.cc +++ b/libcc1/libcp1.cc @@ -166,23 +166,18 @@ void libcp1::add_callbacks () { cc1_plugin::callback_ftype *fun - = cc1_plugin::callback; + = cc1_plugin::invoker::invoke; connection->add_callback ("binding_oracle", fun); - fun = cc1_plugin::callback; + fun = cc1_plugin::invoker::invoke; connection->add_callback ("address_oracle", fun); - fun = cc1_plugin::callback; + fun = cc1_plugin::invoker::invoke; connection->add_callback ("enter_scope", fun); - fun = cc1_plugin::callback; + fun = cc1_plugin::invoker::invoke; connection->add_callback ("leave_scope", fun); } diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc index 64cde651139c..79694b919641 100644 --- a/libcc1/libcp1plugin.cc +++ b/libcc1/libcp1plugin.cc @@ -3509,46 +3509,46 @@ plugin_init (struct plugin_name_args *plugin_info, #define GCC_METHOD0(R, N) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD1(R, N, A) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD2(R, N, A, B) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD3(R, N, A, B, C) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD4(R, N, A, B, C, D) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD5(R, N, A, B, C, D, E) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } #define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \ { \ cc1_plugin::callback_ftype *fun \ - = cc1_plugin::callback; \ + = cc1_plugin::invoker::invoke; \ current_context->add_callback (# N, fun); \ } diff --git a/libcc1/rpc.hh b/libcc1/rpc.hh index 09cd7bdda616..8e43fa146dcc 100644 --- a/libcc1/rpc.hh +++ b/libcc1/rpc.hh @@ -43,7 +43,7 @@ namespace cc1_plugin argument_wrapper (const argument_wrapper &) = delete; argument_wrapper &operator= (const argument_wrapper &) = delete; - operator T () const { return m_object; } + T get () const { return m_object; } status unmarshall (connection *conn) { @@ -68,7 +68,7 @@ namespace cc1_plugin typedef typename std::remove_const::type type; - operator const type * () const + const type *get () const { return m_object.get (); } @@ -88,17 +88,14 @@ namespace cc1_plugin }; // There are two kinds of template functions here: "call" and - // "callback". "call" is implemented with variadic templates, but - // "callback" is repeated multiple times to handle different numbers - // of arguments. (This could be improved with C++17 and - // std::apply.) + // "invoker". // The "call" template is used for making a remote procedure call. // It starts a query ('Q') packet, marshalls its arguments, waits // for a result, and finally reads and returns the result via an // "out" parameter. - // The "callback" template is used when receiving a remote procedure + // The "invoker" template is used when receiving a remote procedure // call. This template function is suitable for use with the // "callbacks" and "connection" classes. It decodes incoming // arguments, passes them to the wrapped function, and finally @@ -123,175 +120,71 @@ namespace cc1_plugin return OK; } - template - status - callback (connection *conn) + // The base case -- just return OK. + template + typename std::enable_if::type + unmarshall (connection *, std::tuple &) { - R result; - - if (!unmarshall_check (conn, 0)) - return FAIL; - result = func (conn); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); - } - - template - status - callback (connection *conn) - { - argument_wrapper arg; - R result; - - if (!unmarshall_check (conn, 1)) - return FAIL; - if (!arg.unmarshall (conn)) - return FAIL; - result = func (conn, arg); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); + return OK; } - template - status - callback (connection *conn) + // Unmarshall this argument, then unmarshall all subsequent args. + template + typename std::enable_if::type + unmarshall (connection *conn, std::tuple &value) { - argument_wrapper arg1; - argument_wrapper arg2; - R result; - - if (!unmarshall_check (conn, 2)) - return FAIL; - if (!arg1.unmarshall (conn)) - return FAIL; - if (!arg2.unmarshall (conn)) + if (!std::get (value).unmarshall (conn)) return FAIL; - result = func (conn, arg1, arg2); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); + return unmarshall (conn, value); } - template - status - callback (connection *conn) + // Wrap a static function that is suitable for use as a callback. + // This is a template function inside a template class to work + // around limitations with multiple variadic packs. + template + class invoker { - argument_wrapper arg1; - argument_wrapper arg2; - argument_wrapper arg3; - R result; + // Base case -- we can call the function. + template + static typename std::enable_if::type + call (connection *conn, const std::tuple...> &, + T... args) + { + return func (conn, args...); + } - if (!unmarshall_check (conn, 3)) - return FAIL; - if (!arg1.unmarshall (conn)) - return FAIL; - if (!arg2.unmarshall (conn)) - return FAIL; - if (!arg3.unmarshall (conn)) - return FAIL; - result = func (conn, arg1, arg2, arg3); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); - } + // Unpack one argument and continue the recursion. + template + static typename std::enable_if::type + call (connection *conn, const std::tuple...> &value, + T... args) + { + return call (conn, value, args..., + std::get (value).get ()); + } - template - status - callback (connection *conn) - { - argument_wrapper arg1; - argument_wrapper arg2; - argument_wrapper arg3; - argument_wrapper arg4; - R result; + public: - if (!unmarshall_check (conn, 4)) - return FAIL; - if (!arg1.unmarshall (conn)) - return FAIL; - if (!arg2.unmarshall (conn)) - return FAIL; - if (!arg3.unmarshall (conn)) - return FAIL; - if (!arg4.unmarshall (conn)) - return FAIL; - result = func (conn, arg1, arg2, arg3, arg4); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); - } + // A callback function that reads arguments from the connection, + // calls the wrapped function, and then sends the result back on + // the connection. + template + static status + invoke (connection *conn) + { + if (!unmarshall_check (conn, sizeof... (Arg))) + return FAIL; + std::tuple...> wrapped; + if (!unmarshall<0> (conn, wrapped)) + return FAIL; - template - status - callback (connection *conn) - { - argument_wrapper arg1; - argument_wrapper arg2; - argument_wrapper arg3; - argument_wrapper arg4; - argument_wrapper arg5; - R result; - - if (!unmarshall_check (conn, 5)) - return FAIL; - if (!arg1.unmarshall (conn)) - return FAIL; - if (!arg2.unmarshall (conn)) - return FAIL; - if (!arg3.unmarshall (conn)) - return FAIL; - if (!arg4.unmarshall (conn)) - return FAIL; - if (!arg5.unmarshall (conn)) - return FAIL; - result = func (conn, arg1, arg2, arg3, arg4, arg5); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); - } + R result = call<0, func> (conn, wrapped); - template - status - callback (connection *conn) - { - argument_wrapper arg1; - argument_wrapper arg2; - argument_wrapper arg3; - argument_wrapper arg4; - argument_wrapper arg5; - argument_wrapper arg6; - argument_wrapper arg7; - R result; - - if (!unmarshall_check (conn, 7)) - return FAIL; - if (!arg1.unmarshall (conn)) - return FAIL; - if (!arg2.unmarshall (conn)) - return FAIL; - if (!arg3.unmarshall (conn)) - return FAIL; - if (!arg4.unmarshall (conn)) - return FAIL; - if (!arg5.unmarshall (conn)) - return FAIL; - if (!arg6.unmarshall (conn)) - return FAIL; - if (!arg7.unmarshall (conn)) - return FAIL; - result = func (conn, arg1, arg2, arg3, arg4, arg5, arg6, arg7); - if (!conn->send ('R')) - return FAIL; - return marshall (conn, result); - } + if (!conn->send ('R')) + return FAIL; + return marshall (conn, result); + } + }; }; #endif // CC1_PLUGIN_RPC_HH -- 2.26.2