1 //===- llvm/ExecutionEngine/Orc/RPCSerialization.h --------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef LLVM_EXECUTIONENGINE_ORC_RPCSERIALIZATION_H 11 #define LLVM_EXECUTIONENGINE_ORC_RPCSERIALIZATION_H 12 13 #include "OrcError.h" 14 #include "llvm/Support/thread.h" 15 #include <mutex> 16 #include <sstream> 17 18 namespace llvm { 19 namespace orc { 20 namespace rpc { 21 22 template <typename T> 23 class RPCTypeName; 24 25 /// TypeNameSequence is a utility for rendering sequences of types to a string 26 /// by rendering each type, separated by ", ". 27 template <typename... ArgTs> class RPCTypeNameSequence {}; 28 29 /// Render an empty TypeNameSequence to an ostream. 30 template <typename OStream> 31 OStream &operator<<(OStream &OS, const RPCTypeNameSequence<> &V) { 32 return OS; 33 } 34 35 /// Render a TypeNameSequence of a single type to an ostream. 36 template <typename OStream, typename ArgT> 37 OStream &operator<<(OStream &OS, const RPCTypeNameSequence<ArgT> &V) { 38 OS << RPCTypeName<ArgT>::getName(); 39 return OS; 40 } 41 42 /// Render a TypeNameSequence of more than one type to an ostream. 43 template <typename OStream, typename ArgT1, typename ArgT2, typename... ArgTs> 44 OStream& 45 operator<<(OStream &OS, const RPCTypeNameSequence<ArgT1, ArgT2, ArgTs...> &V) { 46 OS << RPCTypeName<ArgT1>::getName() << ", " 47 << RPCTypeNameSequence<ArgT2, ArgTs...>(); 48 return OS; 49 } 50 51 template <> 52 class RPCTypeName<void> { 53 public: 54 static const char* getName() { return "void"; } 55 }; 56 57 template <> 58 class RPCTypeName<int8_t> { 59 public: 60 static const char* getName() { return "int8_t"; } 61 }; 62 63 template <> 64 class RPCTypeName<uint8_t> { 65 public: 66 static const char* getName() { return "uint8_t"; } 67 }; 68 69 template <> 70 class RPCTypeName<int16_t> { 71 public: 72 static const char* getName() { return "int16_t"; } 73 }; 74 75 template <> 76 class RPCTypeName<uint16_t> { 77 public: 78 static const char* getName() { return "uint16_t"; } 79 }; 80 81 template <> 82 class RPCTypeName<int32_t> { 83 public: 84 static const char* getName() { return "int32_t"; } 85 }; 86 87 template <> 88 class RPCTypeName<uint32_t> { 89 public: 90 static const char* getName() { return "uint32_t"; } 91 }; 92 93 template <> 94 class RPCTypeName<int64_t> { 95 public: 96 static const char* getName() { return "int64_t"; } 97 }; 98 99 template <> 100 class RPCTypeName<uint64_t> { 101 public: 102 static const char* getName() { return "uint64_t"; } 103 }; 104 105 template <> 106 class RPCTypeName<bool> { 107 public: 108 static const char* getName() { return "bool"; } 109 }; 110 111 template <> 112 class RPCTypeName<std::string> { 113 public: 114 static const char* getName() { return "std::string"; } 115 }; 116 117 template <typename T1, typename T2> 118 class RPCTypeName<std::pair<T1, T2>> { 119 public: 120 static const char* getName() { 121 std::lock_guard<std::mutex> Lock(NameMutex); 122 if (Name.empty()) 123 raw_string_ostream(Name) << "std::pair<" << RPCTypeNameSequence<T1, T2>() 124 << ">"; 125 return Name.data(); 126 } 127 private: 128 static std::mutex NameMutex; 129 static std::string Name; 130 }; 131 132 template <typename T1, typename T2> 133 std::mutex RPCTypeName<std::pair<T1, T2>>::NameMutex; 134 template <typename T1, typename T2> 135 std::string RPCTypeName<std::pair<T1, T2>>::Name; 136 137 template <typename... ArgTs> 138 class RPCTypeName<std::tuple<ArgTs...>> { 139 public: 140 static const char* getName() { 141 std::lock_guard<std::mutex> Lock(NameMutex); 142 if (Name.empty()) 143 raw_string_ostream(Name) << "std::tuple<" 144 << RPCTypeNameSequence<ArgTs...>() << ">"; 145 return Name.data(); 146 } 147 private: 148 static std::mutex NameMutex; 149 static std::string Name; 150 }; 151 152 template <typename... ArgTs> 153 std::mutex RPCTypeName<std::tuple<ArgTs...>>::NameMutex; 154 template <typename... ArgTs> 155 std::string RPCTypeName<std::tuple<ArgTs...>>::Name; 156 157 template <typename T> 158 class RPCTypeName<std::vector<T>> { 159 public: 160 static const char*getName() { 161 std::lock_guard<std::mutex> Lock(NameMutex); 162 if (Name.empty()) 163 raw_string_ostream(Name) << "std::vector<" << RPCTypeName<T>::getName() 164 << ">"; 165 return Name.data(); 166 } 167 168 private: 169 static std::mutex NameMutex; 170 static std::string Name; 171 }; 172 173 template <typename T> 174 std::mutex RPCTypeName<std::vector<T>>::NameMutex; 175 template <typename T> 176 std::string RPCTypeName<std::vector<T>>::Name; 177 178 179 /// The SerializationTraits<ChannelT, T> class describes how to serialize and 180 /// deserialize an instance of type T to/from an abstract channel of type 181 /// ChannelT. It also provides a representation of the type's name via the 182 /// getName method. 183 /// 184 /// Specializations of this class should provide the following functions: 185 /// 186 /// @code{.cpp} 187 /// 188 /// static const char* getName(); 189 /// static Error serialize(ChannelT&, const T&); 190 /// static Error deserialize(ChannelT&, T&); 191 /// 192 /// @endcode 193 /// 194 /// The third argument of SerializationTraits is intended to support SFINAE. 195 /// E.g.: 196 /// 197 /// @code{.cpp} 198 /// 199 /// class MyVirtualChannel { ... }; 200 /// 201 /// template <DerivedChannelT> 202 /// class SerializationTraits<DerivedChannelT, bool, 203 /// typename std::enable_if< 204 /// std::is_base_of<VirtChannel, DerivedChannel>::value 205 /// >::type> { 206 /// public: 207 /// static const char* getName() { ... }; 208 /// } 209 /// 210 /// @endcode 211 template <typename ChannelT, typename WireType, 212 typename ConcreteType = WireType, typename = void> 213 class SerializationTraits; 214 215 template <typename ChannelT> 216 class SequenceTraits { 217 public: 218 static Error emitSeparator(ChannelT &C) { return Error::success(); } 219 static Error consumeSeparator(ChannelT &C) { return Error::success(); } 220 }; 221 222 /// Utility class for serializing sequences of values of varying types. 223 /// Specializations of this class contain 'serialize' and 'deserialize' methods 224 /// for the given channel. The ArgTs... list will determine the "over-the-wire" 225 /// types to be serialized. The serialize and deserialize methods take a list 226 /// CArgTs... ("caller arg types") which must be the same length as ArgTs..., 227 /// but may be different types from ArgTs, provided that for each CArgT there 228 /// is a SerializationTraits specialization 229 /// SerializeTraits<ChannelT, ArgT, CArgT> with methods that can serialize the 230 /// caller argument to over-the-wire value. 231 template <typename ChannelT, typename... ArgTs> 232 class SequenceSerialization; 233 234 template <typename ChannelT> 235 class SequenceSerialization<ChannelT> { 236 public: 237 static Error serialize(ChannelT &C) { return Error::success(); } 238 static Error deserialize(ChannelT &C) { return Error::success(); } 239 }; 240 241 template <typename ChannelT, typename ArgT> 242 class SequenceSerialization<ChannelT, ArgT> { 243 public: 244 245 template <typename CArgT> 246 static Error serialize(ChannelT &C, const CArgT &CArg) { 247 return SerializationTraits<ChannelT, ArgT, CArgT>::serialize(C, CArg); 248 } 249 250 template <typename CArgT> 251 static Error deserialize(ChannelT &C, CArgT &CArg) { 252 return SerializationTraits<ChannelT, ArgT, CArgT>::deserialize(C, CArg); 253 } 254 }; 255 256 template <typename ChannelT, typename ArgT, typename... ArgTs> 257 class SequenceSerialization<ChannelT, ArgT, ArgTs...> { 258 public: 259 260 template <typename CArgT, typename... CArgTs> 261 static Error serialize(ChannelT &C, const CArgT &CArg, 262 const CArgTs&... CArgs) { 263 if (auto Err = 264 SerializationTraits<ChannelT, ArgT, CArgT>::serialize(C, CArg)) 265 return Err; 266 if (auto Err = SequenceTraits<ChannelT>::emitSeparator(C)) 267 return Err; 268 return SequenceSerialization<ChannelT, ArgTs...>::serialize(C, CArgs...); 269 } 270 271 template <typename CArgT, typename... CArgTs> 272 static Error deserialize(ChannelT &C, CArgT &CArg, 273 CArgTs&... CArgs) { 274 if (auto Err = 275 SerializationTraits<ChannelT, ArgT, CArgT>::deserialize(C, CArg)) 276 return Err; 277 if (auto Err = SequenceTraits<ChannelT>::consumeSeparator(C)) 278 return Err; 279 return SequenceSerialization<ChannelT, ArgTs...>::deserialize(C, CArgs...); 280 } 281 }; 282 283 template <typename ChannelT, typename... ArgTs> 284 Error serializeSeq(ChannelT &C, const ArgTs &... Args) { 285 return SequenceSerialization<ChannelT, ArgTs...>::serialize(C, Args...); 286 } 287 288 template <typename ChannelT, typename... ArgTs> 289 Error deserializeSeq(ChannelT &C, ArgTs &... Args) { 290 return SequenceSerialization<ChannelT, ArgTs...>::deserialize(C, Args...); 291 } 292 293 /// SerializationTraits default specialization for std::pair. 294 template <typename ChannelT, typename T1, typename T2> 295 class SerializationTraits<ChannelT, std::pair<T1, T2>> { 296 public: 297 static Error serialize(ChannelT &C, const std::pair<T1, T2> &V) { 298 return serializeSeq(C, V.first, V.second); 299 } 300 301 static Error deserialize(ChannelT &C, std::pair<T1, T2> &V) { 302 return deserializeSeq(C, V.first, V.second); 303 } 304 }; 305 306 /// SerializationTraits default specialization for std::tuple. 307 template <typename ChannelT, typename... ArgTs> 308 class SerializationTraits<ChannelT, std::tuple<ArgTs...>> { 309 public: 310 311 /// RPC channel serialization for std::tuple. 312 static Error serialize(ChannelT &C, const std::tuple<ArgTs...> &V) { 313 return serializeTupleHelper(C, V, llvm::index_sequence_for<ArgTs...>()); 314 } 315 316 /// RPC channel deserialization for std::tuple. 317 static Error deserialize(ChannelT &C, std::tuple<ArgTs...> &V) { 318 return deserializeTupleHelper(C, V, llvm::index_sequence_for<ArgTs...>()); 319 } 320 321 private: 322 // Serialization helper for std::tuple. 323 template <size_t... Is> 324 static Error serializeTupleHelper(ChannelT &C, const std::tuple<ArgTs...> &V, 325 llvm::index_sequence<Is...> _) { 326 return serializeSeq(C, std::get<Is>(V)...); 327 } 328 329 // Serialization helper for std::tuple. 330 template <size_t... Is> 331 static Error deserializeTupleHelper(ChannelT &C, std::tuple<ArgTs...> &V, 332 llvm::index_sequence<Is...> _) { 333 return deserializeSeq(C, std::get<Is>(V)...); 334 } 335 }; 336 337 /// SerializationTraits default specialization for std::vector. 338 template <typename ChannelT, typename T> 339 class SerializationTraits<ChannelT, std::vector<T>> { 340 public: 341 342 /// Serialize a std::vector<T> from std::vector<T>. 343 static Error serialize(ChannelT &C, const std::vector<T> &V) { 344 if (auto Err = serializeSeq(C, static_cast<uint64_t>(V.size()))) 345 return Err; 346 347 for (const auto &E : V) 348 if (auto Err = serializeSeq(C, E)) 349 return Err; 350 351 return Error::success(); 352 } 353 354 /// Deserialize a std::vector<T> to a std::vector<T>. 355 static Error deserialize(ChannelT &C, std::vector<T> &V) { 356 uint64_t Count = 0; 357 if (auto Err = deserializeSeq(C, Count)) 358 return Err; 359 360 V.resize(Count); 361 for (auto &E : V) 362 if (auto Err = deserializeSeq(C, E)) 363 return Err; 364 365 return Error::success(); 366 } 367 }; 368 369 } // end namespace rpc 370 } // end namespace orc 371 } // end namespace llvm 372 373 #endif // LLVM_EXECUTIONENGINE_ORC_RPCSERIALIZATION_H 374