Chromium Code Reviews| 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..207d77928d28214782bc266ecd081ed696c0096f |
| --- /dev/null |
| +++ b/ipc/ipc_message_templates.h |
| @@ -0,0 +1,207 @@ |
| +// 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? |
| + (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 { |
| + 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. |
|
vmpstr
2016/02/04 23:43:27
I'm not really up to date, but is MSVC2015 here? O
mdempsky
2016/02/05 00:32:32
No idea.
danakj
2016/02/05 00:41:04
https://groups.google.com/a/chromium.org/forum/#!t
vmpstr
2016/02/05 01:24:31
My point was simply that this seems to already wor
mdempsky
2016/02/05 02:06:10
Understood. I'm going to lean towards something m
|
| +#define IPC_MESSAGET_SFINAE(x) |
| +#else |
| +#define IPC_MESSAGET_SFINAE(x) \ |
| + template <bool X = (x), typename std::enable_if<X, bool>::type = false> |
|
vmpstr
2016/02/04 23:43:27
Is the extra bool X = (x) just convenience? Or doe
mdempsky
2016/02/05 00:32:32
I'm pretty sure it's necessary. I think it's beca
vmpstr
2016/02/05 01:24:31
I guess my initial concern was that if one explici
mdempsky
2016/02/05 02:06:10
I did too, but alas, that's not what the C++ commi
|
| +#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. |
|
vmpstr
2016/02/04 23:43:27
Can you elaborate on this todo?
mdempsky
2016/02/05 00:32:32
Done.
|
| + using Schema = MessageT; |
| + |
| + IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL) |
| + MessageT(const Ins&... ins) : MessageT(Routing{MSG_ROUTING_CONTROL}, ins...) { |
|
vmpstr
2016/02/04 23:43:27
Is this syntax allowed? I keep being confused betw
mdempsky
2016/02/05 00:32:32
Blah, looks like still no. Done.
|
| + 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. |
| + 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_ |