Home | History | Annotate | Download | only in Orc
      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