Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef IPC_IPC_MESSAGE_TEMPLATES_H_ | |
| 6 #define IPC_IPC_MESSAGE_TEMPLATES_H_ | |
| 7 | |
| 8 #include <stdint.h> | |
| 9 | |
| 10 #include <type_traits> | |
| 11 | |
| 12 #include "base/logging.h" | |
| 13 #include "base/tuple.h" | |
| 14 #include "build/build_config.h" | |
| 15 #include "ipc/ipc_message.h" | |
| 16 #include "ipc/ipc_message_utils.h" | |
| 17 | |
| 18 namespace IPC { | |
| 19 | |
| 20 // This function is for all the async IPCs that don't pass an extra parameter | |
| 21 // using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM. | |
| 22 template <typename ObjT, typename Method, typename P, typename Tuple> | |
| 23 void DispatchToMethod(ObjT* obj, Method method, P*, const Tuple& tuple) { | |
| 24 base::DispatchToMethod(obj, method, tuple); | |
| 25 } | |
| 26 | |
| 27 template <typename ObjT, | |
| 28 typename Method, | |
| 29 typename P, | |
| 30 typename Tuple, | |
| 31 size_t... Ns> | |
| 32 void DispatchToMethodImpl(ObjT* obj, | |
| 33 Method method, | |
| 34 P* parameter, | |
| 35 const Tuple& tuple, | |
| 36 base::IndexSequence<Ns...>) { | |
| 37 // TODO(mdempsky): Apply UnwrapTraits like base::DispatchToMethod? | |
| 38 (obj->*method)(parameter, base::get<Ns>(tuple)...); | |
| 39 } | |
| 40 | |
| 41 // The following function is for async IPCs which have a dispatcher with an | |
| 42 // extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM. | |
| 43 template <typename ObjT, typename P, typename... Args, typename... Ts> | |
| 44 typename std::enable_if<sizeof...(Args) == sizeof...(Ts)>::type | |
| 45 DispatchToMethod(ObjT* obj, | |
| 46 void (ObjT::*method)(P*, Args...), | |
| 47 P* parameter, | |
| 48 const base::Tuple<Ts...>& tuple) { | |
| 49 DispatchToMethodImpl(obj, method, parameter, tuple, | |
| 50 base::MakeIndexSequence<sizeof...(Ts)>()); | |
| 51 } | |
| 52 | |
| 53 enum class MessageKind { | |
| 54 CONTROL, | |
| 55 ROUTED, | |
| 56 }; | |
| 57 | |
| 58 // Routing is a helper struct so MessageT's private common constructor has a | |
| 59 // different type signature than the public "int32_t routing_id" one. | |
| 60 struct Routing { | |
| 61 int32_t id; | |
| 62 }; | |
| 63 | |
| 64 // We want to restrict MessageT's constructors so that a routing_id is always | |
| 65 // provided for ROUTED messages and never provided for CONTROL messages, so | |
| 66 // use the SFINAE technique from N4387's "Implementation Hint" section. | |
| 67 #if defined(COMPILER_MSVC) | |
| 68 // MSVC 2013 doesn't support default arguments for template member functions | |
| 69 // of templated classes, so there we have to rely on the DCHECKs instead. | |
| 70 // 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
| |
| 71 #define IPC_MESSAGET_SFINAE(x) | |
| 72 #else | |
| 73 #define IPC_MESSAGET_SFINAE(x) \ | |
| 74 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
| |
| 75 #endif | |
| 76 | |
| 77 // MessageT is the common template used for all user-defined message types. | |
| 78 // It's intended to be used via the macros defined in ipc_message_macros.h. | |
| 79 template <typename Meta, | |
| 80 typename InTuple = typename Meta::InTuple, | |
| 81 typename OutTuple = typename Meta::OutTuple> | |
| 82 class MessageT; | |
| 83 | |
| 84 // Asynchronous message partial specialization. | |
| 85 template <typename Meta, typename... Ins> | |
| 86 class MessageT<Meta, base::Tuple<Ins...>, void> : public Message { | |
| 87 public: | |
| 88 using Param = base::Tuple<Ins...>; | |
| 89 enum { ID = Meta::ID }; | |
| 90 | |
| 91 // TODO(mdempsky): Remove. | |
|
vmpstr
2016/02/04 23:43:27
Can you elaborate on this todo?
mdempsky
2016/02/05 00:32:32
Done.
| |
| 92 using Schema = MessageT; | |
| 93 | |
| 94 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL) | |
| 95 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.
| |
| 96 DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName; | |
| 97 } | |
| 98 | |
| 99 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED) | |
| 100 MessageT(int32_t routing_id, const Ins&... ins) | |
| 101 : MessageT(Routing{routing_id}, ins...) { | |
| 102 DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName; | |
| 103 } | |
| 104 | |
| 105 static bool Read(const Message* msg, Param* p); | |
| 106 static void Log(std::string* name, const Message* msg, std::string* l); | |
| 107 | |
| 108 template <class T, class S, class P, class Method> | |
| 109 static bool Dispatch(const Message* msg, | |
| 110 T* obj, | |
| 111 S* sender, | |
| 112 P* parameter, | |
| 113 Method func) { | |
| 114 Param p; | |
| 115 if (Read(msg, &p)) { | |
| 116 DispatchToMethod(obj, func, parameter, p); | |
| 117 return true; | |
| 118 } | |
| 119 return false; | |
| 120 } | |
| 121 | |
| 122 private: | |
| 123 MessageT(Routing routing, const Ins&... ins); | |
| 124 }; | |
| 125 | |
| 126 // Synchronous message partial specialization. | |
| 127 template <typename Meta, typename... Ins, typename... Outs> | |
| 128 class MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>> | |
| 129 : public SyncMessage { | |
| 130 public: | |
| 131 using SendParam = base::Tuple<Ins...>; | |
| 132 using ReplyParam = base::Tuple<Outs...>; | |
| 133 enum { ID = Meta::ID }; | |
| 134 | |
| 135 // TODO(mdempsky): Remove. | |
| 136 using Schema = MessageT; | |
| 137 | |
| 138 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL) | |
| 139 MessageT(const Ins&... ins, Outs*... outs) | |
| 140 : MessageT(Routing{MSG_ROUTING_CONTROL}, ins..., outs...) { | |
| 141 DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName; | |
| 142 } | |
| 143 | |
| 144 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED) | |
| 145 MessageT(int32_t routing_id, const Ins&... ins, Outs*... outs) | |
| 146 : MessageT(Routing{routing_id}, ins..., outs...) { | |
| 147 DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName; | |
| 148 } | |
| 149 | |
| 150 static bool ReadSendParam(const Message* msg, SendParam* p); | |
| 151 static bool ReadReplyParam(const Message* msg, ReplyParam* p); | |
| 152 static void WriteReplyParams(Message* reply, const Outs&... outs); | |
| 153 static void Log(std::string* name, const Message* msg, std::string* l); | |
| 154 | |
| 155 template <class T, class S, class P, class Method> | |
| 156 static bool Dispatch(const Message* msg, | |
| 157 T* obj, | |
| 158 S* sender, | |
| 159 P* parameter, | |
| 160 Method func) { | |
| 161 SendParam send_params; | |
| 162 bool ok = ReadSendParam(msg, &send_params); | |
| 163 Message* reply = SyncMessage::GenerateReply(msg); | |
| 164 if (ok) { | |
| 165 ReplyParam reply_params; | |
| 166 base::DispatchToMethod(obj, func, send_params, &reply_params); | |
| 167 WriteParam(reply, reply_params); | |
| 168 LogReplyParamsToMessage(reply_params, msg); | |
| 169 } else { | |
| 170 NOTREACHED() << "Error deserializing message " << msg->type(); | |
| 171 reply->set_reply_error(); | |
| 172 } | |
| 173 sender->Send(reply); | |
| 174 return ok; | |
| 175 } | |
| 176 | |
| 177 template <class T, class P, class Method> | |
| 178 static bool DispatchDelayReply(const Message* msg, | |
| 179 T* obj, | |
| 180 P* parameter, | |
| 181 Method func) { | |
| 182 SendParam send_params; | |
| 183 bool ok = ReadSendParam(msg, &send_params); | |
| 184 Message* reply = SyncMessage::GenerateReply(msg); | |
| 185 if (ok) { | |
| 186 base::Tuple<Message&> t = base::MakeRefTuple(*reply); | |
| 187 ConnectMessageAndReply(msg, reply); | |
| 188 base::DispatchToMethod(obj, func, send_params, &t); | |
| 189 } else { | |
| 190 NOTREACHED() << "Error deserializing message " << msg->type(); | |
| 191 reply->set_reply_error(); | |
| 192 obj->Send(reply); | |
| 193 } | |
| 194 return ok; | |
| 195 } | |
| 196 | |
| 197 private: | |
| 198 MessageT(Routing routing, const Ins&... ins, Outs*... outs); | |
| 199 }; | |
| 200 | |
| 201 } // namespace IPC | |
| 202 | |
| 203 #if defined(IPC_MESSAGE_IMPL) | |
| 204 #include "ipc/ipc_message_templates_impl.h" | |
| 205 #endif | |
| 206 | |
| 207 #endif // IPC_IPC_MESSAGE_TEMPLATES_H_ | |
| OLD | NEW |