Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Unified Diff: ipc/ipc_message_templates.h

Issue 1532053002: use variadic macros/templates in IPC message implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: stricter legacy compat macros Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ipc/ipc_message_templates.h
diff --git a/ipc/ipc_message_templates.h b/ipc/ipc_message_templates.h
new file mode 100644
index 0000000000000000000000000000000000000000..17dfc1b9ff221169167c2f3103089a219e14fa5e
--- /dev/null
+++ b/ipc/ipc_message_templates.h
@@ -0,0 +1,210 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_MESSAGE_TEMPLATES_H_
+#define IPC_IPC_MESSAGE_TEMPLATES_H_
+
+#include <stdint.h>
+
+#include <type_traits>
+
+#include "base/logging.h"
+#include "base/tuple.h"
+#include "build/build_config.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_utils.h"
+
+namespace IPC {
+
+// This function is for all the async IPCs that don't pass an extra parameter
+// using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
+template <typename ObjT, typename Method, typename P, typename Tuple>
+void DispatchToMethod(ObjT* obj, Method method, P*, const Tuple& tuple) {
+ base::DispatchToMethod(obj, method, tuple);
+}
+
+template <typename ObjT,
+ typename Method,
+ typename P,
+ typename Tuple,
+ size_t... Ns>
+void DispatchToMethodImpl(ObjT* obj,
+ Method method,
+ P* parameter,
+ const Tuple& tuple,
+ base::IndexSequence<Ns...>) {
+ // TODO(mdempsky): Apply UnwrapTraits like base::DispatchToMethod?
dcheng 2016/02/05 21:31:41 Do we need that here though? I don't think we'd ne
mdempsky 2016/02/05 22:36:06 I don't know, hence the question mark. :) IPC is
+ (obj->*method)(parameter, base::get<Ns>(tuple)...);
+}
+
+// The following function is for async IPCs which have a dispatcher with an
+// extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
+template <typename ObjT, typename P, typename... Args, typename... Ts>
+typename std::enable_if<sizeof...(Args) == sizeof...(Ts)>::type
+DispatchToMethod(ObjT* obj,
+ void (ObjT::*method)(P*, Args...),
+ P* parameter,
+ const base::Tuple<Ts...>& tuple) {
+ DispatchToMethodImpl(obj, method, parameter, tuple,
+ base::MakeIndexSequence<sizeof...(Ts)>());
+}
+
+enum class MessageKind {
+ CONTROL,
+ ROUTED,
+};
+
+// Routing is a helper struct so MessageT's private common constructor has a
+// different type signature than the public "int32_t routing_id" one.
+struct Routing {
+ explicit Routing(int32_t id) : id(id) {}
+ int32_t id;
+};
+
+// We want to restrict MessageT's constructors so that a routing_id is always
+// provided for ROUTED messages and never provided for CONTROL messages, so
+// use the SFINAE technique from N4387's "Implementation Hint" section.
+#if defined(COMPILER_MSVC)
+// MSVC 2013 doesn't support default arguments for template member functions
+// of templated classes, so there we have to rely on the DCHECKs instead.
+// TODO(mdempsky): Reevaluate once MSVC 2015.
+#define IPC_MESSAGET_SFINAE(x)
+#else
+#define IPC_MESSAGET_SFINAE(x) \
+ template <bool X = (x), typename std::enable_if<X, bool>::type = false>
+#endif
+
+// MessageT is the common template used for all user-defined message types.
+// It's intended to be used via the macros defined in ipc_message_macros.h.
+template <typename Meta,
+ typename InTuple = typename Meta::InTuple,
+ typename OutTuple = typename Meta::OutTuple>
+class MessageT;
+
+// Asynchronous message partial specialization.
+template <typename Meta, typename... Ins>
+class MessageT<Meta, base::Tuple<Ins...>, void> : public Message {
+ public:
+ using Param = base::Tuple<Ins...>;
+ enum { ID = Meta::ID };
+
+ // TODO(mdempsky): Remove. Uses of MyMessage::Schema::Param can be replaced
+ // with just MyMessage::Param.
+ using Schema = MessageT;
+
+ IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
+ MessageT(const Ins&... ins) : MessageT(Routing(MSG_ROUTING_CONTROL), ins...) {
+ DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
+ }
+
+ IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
+ MessageT(int32_t routing_id, const Ins&... ins)
+ : MessageT(Routing(routing_id), ins...) {
+ DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
+ }
+
+ static bool Read(const Message* msg, Param* p);
+ static void Log(std::string* name, const Message* msg, std::string* l);
+
+ template <class T, class S, class P, class Method>
+ static bool Dispatch(const Message* msg,
+ T* obj,
+ S* sender,
+ P* parameter,
+ Method func) {
+ Param p;
+ if (Read(msg, &p)) {
+ DispatchToMethod(obj, func, parameter, p);
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ MessageT(Routing routing, const Ins&... ins);
+};
+
+// Synchronous message partial specialization.
+template <typename Meta, typename... Ins, typename... Outs>
+class MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>>
+ : public SyncMessage {
+ public:
+ using SendParam = base::Tuple<Ins...>;
+ using ReplyParam = base::Tuple<Outs...>;
+ enum { ID = Meta::ID };
+
+ // TODO(mdempsky): Remove. Uses of MyMessage::Schema::{Send,Reply}Param can
+ // be replaced with just MyMessage::{Send,Reply}Param.
+ using Schema = MessageT;
+
+ IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
+ MessageT(const Ins&... ins, Outs*... outs)
+ : MessageT(Routing(MSG_ROUTING_CONTROL), ins..., outs...) {
+ DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
+ }
+
+ IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
+ MessageT(int32_t routing_id, const Ins&... ins, Outs*... outs)
+ : MessageT(Routing(routing_id), ins..., outs...) {
+ DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
+ }
+
+ static bool ReadSendParam(const Message* msg, SendParam* p);
+ static bool ReadReplyParam(const Message* msg, ReplyParam* p);
+ static void WriteReplyParams(Message* reply, const Outs&... outs);
+ static void Log(std::string* name, const Message* msg, std::string* l);
+
+ template <class T, class S, class P, class Method>
+ static bool Dispatch(const Message* msg,
+ T* obj,
+ S* sender,
+ P* parameter,
+ Method func) {
+ SendParam send_params;
+ bool ok = ReadSendParam(msg, &send_params);
+ Message* reply = SyncMessage::GenerateReply(msg);
+ if (ok) {
+ ReplyParam reply_params;
+ base::DispatchToMethod(obj, func, send_params, &reply_params);
+ WriteParam(reply, reply_params);
+ LogReplyParamsToMessage(reply_params, msg);
+ } else {
+ NOTREACHED() << "Error deserializing message " << msg->type();
+ reply->set_reply_error();
+ }
+ sender->Send(reply);
+ return ok;
+ }
+
+ template <class T, class P, class Method>
+ static bool DispatchDelayReply(const Message* msg,
+ T* obj,
+ P* parameter,
+ Method func) {
+ SendParam send_params;
+ bool ok = ReadSendParam(msg, &send_params);
+ Message* reply = SyncMessage::GenerateReply(msg);
+ if (ok) {
+ base::Tuple<Message&> t = base::MakeRefTuple(*reply);
+ ConnectMessageAndReply(msg, reply);
+ base::DispatchToMethod(obj, func, send_params, &t);
+ } else {
+ NOTREACHED() << "Error deserializing message " << msg->type();
+ reply->set_reply_error();
+ obj->Send(reply);
+ }
+ return ok;
+ }
+
+ private:
+ MessageT(Routing routing, const Ins&... ins, Outs*... outs);
+};
+
+} // namespace IPC
+
+#if defined(IPC_MESSAGE_IMPL)
+#include "ipc/ipc_message_templates_impl.h"
+#endif
+
+#endif // IPC_IPC_MESSAGE_TEMPLATES_H_

Powered by Google App Engine
This is Rietveld 408576698