Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //===---- SimplePackedSerialization.h - simple serialization ----*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // The behavior of the utilities in this header must be synchronized with the
  10. // behavior of the utilities in
  11. // compiler-rt/lib/orc/simple_packed_serialization.h.
  12. //
  13. // The Simple Packed Serialization (SPS) utilities are used to generate
  14. // argument and return buffers for wrapper functions using the following
  15. // serialization scheme:
  16. //
  17. // Primitives (signed types should be two's complement):
  18. //   bool, char, int8_t, uint8_t -- 8-bit (0=false, 1=true)
  19. //   int16_t, uint16_t           -- 16-bit little endian
  20. //   int32_t, uint32_t           -- 32-bit little endian
  21. //   int64_t, int64_t            -- 64-bit little endian
  22. //
  23. // Sequence<T>:
  24. //   Serialized as the sequence length (as a uint64_t) followed by the
  25. //   serialization of each of the elements without padding.
  26. //
  27. // Tuple<T1, ..., TN>:
  28. //   Serialized as each of the element types from T1 to TN without padding.
  29. //
  30. //===----------------------------------------------------------------------===//
  31.  
  32. #ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEPACKEDSERIALIZATION_H
  33. #define LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEPACKEDSERIALIZATION_H
  34.  
  35. #include "llvm/ADT/STLExtras.h"
  36. #include "llvm/ADT/SmallVector.h"
  37. #include "llvm/ADT/StringMap.h"
  38. #include "llvm/ADT/StringRef.h"
  39. #include "llvm/Support/Error.h"
  40. #include "llvm/Support/SwapByteOrder.h"
  41.  
  42. #include <limits>
  43. #include <optional>
  44. #include <string>
  45. #include <tuple>
  46. #include <type_traits>
  47. #include <utility>
  48. #include <vector>
  49.  
  50. namespace llvm {
  51. namespace orc {
  52. namespace shared {
  53.  
  54. /// Output char buffer with overflow check.
  55. class SPSOutputBuffer {
  56. public:
  57.   SPSOutputBuffer(char *Buffer, size_t Remaining)
  58.       : Buffer(Buffer), Remaining(Remaining) {}
  59.   bool write(const char *Data, size_t Size) {
  60.     assert(Data && "Data must not be null");
  61.     if (Size > Remaining)
  62.       return false;
  63.     memcpy(Buffer, Data, Size);
  64.     Buffer += Size;
  65.     Remaining -= Size;
  66.     return true;
  67.   }
  68.  
  69. private:
  70.   char *Buffer = nullptr;
  71.   size_t Remaining = 0;
  72. };
  73.  
  74. /// Input char buffer with underflow check.
  75. class SPSInputBuffer {
  76. public:
  77.   SPSInputBuffer() = default;
  78.   SPSInputBuffer(const char *Buffer, size_t Remaining)
  79.       : Buffer(Buffer), Remaining(Remaining) {}
  80.   bool read(char *Data, size_t Size) {
  81.     if (Size > Remaining)
  82.       return false;
  83.     memcpy(Data, Buffer, Size);
  84.     Buffer += Size;
  85.     Remaining -= Size;
  86.     return true;
  87.   }
  88.  
  89.   const char *data() const { return Buffer; }
  90.   bool skip(size_t Size) {
  91.     if (Size > Remaining)
  92.       return false;
  93.     Buffer += Size;
  94.     Remaining -= Size;
  95.     return true;
  96.   }
  97.  
  98. private:
  99.   const char *Buffer = nullptr;
  100.   size_t Remaining = 0;
  101. };
  102.  
  103. /// Specialize to describe how to serialize/deserialize to/from the given
  104. /// concrete type.
  105. template <typename SPSTagT, typename ConcreteT, typename _ = void>
  106. class SPSSerializationTraits;
  107.  
  108. /// A utility class for serializing to a blob from a variadic list.
  109. template <typename... ArgTs> class SPSArgList;
  110.  
  111. // Empty list specialization for SPSArgList.
  112. template <> class SPSArgList<> {
  113. public:
  114.   static size_t size() { return 0; }
  115.  
  116.   static bool serialize(SPSOutputBuffer &OB) { return true; }
  117.   static bool deserialize(SPSInputBuffer &IB) { return true; }
  118.  
  119.   static bool serializeToSmallVector(SmallVectorImpl<char> &V) { return true; }
  120.  
  121.   static bool deserializeFromSmallVector(const SmallVectorImpl<char> &V) {
  122.     return true;
  123.   }
  124. };
  125.  
  126. // Non-empty list specialization for SPSArgList.
  127. template <typename SPSTagT, typename... SPSTagTs>
  128. class SPSArgList<SPSTagT, SPSTagTs...> {
  129. public:
  130.   // FIXME: This typedef is here to enable SPS arg serialization from
  131.   // JITLink. It can be removed once JITLink can access SPS directly.
  132.   using OutputBuffer = SPSOutputBuffer;
  133.  
  134.   template <typename ArgT, typename... ArgTs>
  135.   static size_t size(const ArgT &Arg, const ArgTs &...Args) {
  136.     return SPSSerializationTraits<SPSTagT, ArgT>::size(Arg) +
  137.            SPSArgList<SPSTagTs...>::size(Args...);
  138.   }
  139.  
  140.   template <typename ArgT, typename... ArgTs>
  141.   static bool serialize(SPSOutputBuffer &OB, const ArgT &Arg,
  142.                         const ArgTs &...Args) {
  143.     return SPSSerializationTraits<SPSTagT, ArgT>::serialize(OB, Arg) &&
  144.            SPSArgList<SPSTagTs...>::serialize(OB, Args...);
  145.   }
  146.  
  147.   template <typename ArgT, typename... ArgTs>
  148.   static bool deserialize(SPSInputBuffer &IB, ArgT &Arg, ArgTs &...Args) {
  149.     return SPSSerializationTraits<SPSTagT, ArgT>::deserialize(IB, Arg) &&
  150.            SPSArgList<SPSTagTs...>::deserialize(IB, Args...);
  151.   }
  152. };
  153.  
  154. /// SPS serialization for integral types, bool, and char.
  155. template <typename SPSTagT>
  156. class SPSSerializationTraits<
  157.     SPSTagT, SPSTagT,
  158.     std::enable_if_t<std::is_same<SPSTagT, bool>::value ||
  159.                      std::is_same<SPSTagT, char>::value ||
  160.                      std::is_same<SPSTagT, int8_t>::value ||
  161.                      std::is_same<SPSTagT, int16_t>::value ||
  162.                      std::is_same<SPSTagT, int32_t>::value ||
  163.                      std::is_same<SPSTagT, int64_t>::value ||
  164.                      std::is_same<SPSTagT, uint8_t>::value ||
  165.                      std::is_same<SPSTagT, uint16_t>::value ||
  166.                      std::is_same<SPSTagT, uint32_t>::value ||
  167.                      std::is_same<SPSTagT, uint64_t>::value>> {
  168. public:
  169.   static size_t size(const SPSTagT &Value) { return sizeof(SPSTagT); }
  170.  
  171.   static bool serialize(SPSOutputBuffer &OB, const SPSTagT &Value) {
  172.     SPSTagT Tmp = Value;
  173.     if (sys::IsBigEndianHost)
  174.       sys::swapByteOrder(Tmp);
  175.     return OB.write(reinterpret_cast<const char *>(&Tmp), sizeof(Tmp));
  176.   }
  177.  
  178.   static bool deserialize(SPSInputBuffer &IB, SPSTagT &Value) {
  179.     SPSTagT Tmp;
  180.     if (!IB.read(reinterpret_cast<char *>(&Tmp), sizeof(Tmp)))
  181.       return false;
  182.     if (sys::IsBigEndianHost)
  183.       sys::swapByteOrder(Tmp);
  184.     Value = Tmp;
  185.     return true;
  186.   }
  187. };
  188.  
  189. // Any empty placeholder suitable as a substitute for void when deserializing
  190. class SPSEmpty {};
  191.  
  192. /// SPS tag type for tuples.
  193. ///
  194. /// A blob tuple should be serialized by serializing each of the elements in
  195. /// sequence.
  196. template <typename... SPSTagTs> class SPSTuple {
  197. public:
  198.   /// Convenience typedef of the corresponding arg list.
  199.   typedef SPSArgList<SPSTagTs...> AsArgList;
  200. };
  201.  
  202. /// SPS tag type for optionals.
  203. ///
  204. /// SPSOptionals should be serialized as a bool with true indicating that an
  205. /// SPSTagT value is present, and false indicating that there is no value.
  206. /// If the boolean is true then the serialized SPSTagT will follow immediately
  207. /// after it.
  208. template <typename SPSTagT> class SPSOptional {};
  209.  
  210. /// SPS tag type for sequences.
  211. ///
  212. /// SPSSequences should be serialized as a uint64_t sequence length,
  213. /// followed by the serialization of each of the elements.
  214. template <typename SPSElementTagT> class SPSSequence;
  215.  
  216. /// SPS tag type for strings, which are equivalent to sequences of chars.
  217. using SPSString = SPSSequence<char>;
  218.  
  219. /// SPS tag type for maps.
  220. ///
  221. /// SPS maps are just sequences of (Key, Value) tuples.
  222. template <typename SPSTagT1, typename SPSTagT2>
  223. using SPSMap = SPSSequence<SPSTuple<SPSTagT1, SPSTagT2>>;
  224.  
  225. /// Serialization for SPSEmpty type.
  226. template <> class SPSSerializationTraits<SPSEmpty, SPSEmpty> {
  227. public:
  228.   static size_t size(const SPSEmpty &EP) { return 0; }
  229.   static bool serialize(SPSOutputBuffer &OB, const SPSEmpty &BE) {
  230.     return true;
  231.   }
  232.   static bool deserialize(SPSInputBuffer &IB, SPSEmpty &BE) { return true; }
  233. };
  234.  
  235. /// Specialize this to implement 'trivial' sequence serialization for
  236. /// a concrete sequence type.
  237. ///
  238. /// Trivial sequence serialization uses the sequence's 'size' member to get the
  239. /// length of the sequence, and uses a range-based for loop to iterate over the
  240. /// elements.
  241. ///
  242. /// Specializing this template class means that you do not need to provide a
  243. /// specialization of SPSSerializationTraits for your type.
  244. template <typename SPSElementTagT, typename ConcreteSequenceT>
  245. class TrivialSPSSequenceSerialization {
  246. public:
  247.   static constexpr bool available = false;
  248. };
  249.  
  250. /// Specialize this to implement 'trivial' sequence deserialization for
  251. /// a concrete sequence type.
  252. ///
  253. /// Trivial deserialization calls a static 'reserve(SequenceT&)' method on your
  254. /// specialization (you must implement this) to reserve space, and then calls
  255. /// a static 'append(SequenceT&, ElementT&) method to append each of the
  256. /// deserialized elements.
  257. ///
  258. /// Specializing this template class means that you do not need to provide a
  259. /// specialization of SPSSerializationTraits for your type.
  260. template <typename SPSElementTagT, typename ConcreteSequenceT>
  261. class TrivialSPSSequenceDeserialization {
  262. public:
  263.   static constexpr bool available = false;
  264. };
  265.  
  266. /// Trivial std::string -> SPSSequence<char> serialization.
  267. template <> class TrivialSPSSequenceSerialization<char, std::string> {
  268. public:
  269.   static constexpr bool available = true;
  270. };
  271.  
  272. /// Trivial SPSSequence<char> -> std::string deserialization.
  273. template <> class TrivialSPSSequenceDeserialization<char, std::string> {
  274. public:
  275.   static constexpr bool available = true;
  276.  
  277.   using element_type = char;
  278.  
  279.   static void reserve(std::string &S, uint64_t Size) { S.reserve(Size); }
  280.   static bool append(std::string &S, char C) {
  281.     S.push_back(C);
  282.     return true;
  283.   }
  284. };
  285.  
  286. /// Trivial std::vector<T> -> SPSSequence<SPSElementTagT> serialization.
  287. template <typename SPSElementTagT, typename T>
  288. class TrivialSPSSequenceSerialization<SPSElementTagT, std::vector<T>> {
  289. public:
  290.   static constexpr bool available = true;
  291. };
  292.  
  293. /// Trivial SPSSequence<SPSElementTagT> -> std::vector<T> deserialization.
  294. template <typename SPSElementTagT, typename T>
  295. class TrivialSPSSequenceDeserialization<SPSElementTagT, std::vector<T>> {
  296. public:
  297.   static constexpr bool available = true;
  298.  
  299.   using element_type = typename std::vector<T>::value_type;
  300.  
  301.   static void reserve(std::vector<T> &V, uint64_t Size) { V.reserve(Size); }
  302.   static bool append(std::vector<T> &V, T E) {
  303.     V.push_back(std::move(E));
  304.     return true;
  305.   }
  306. };
  307.  
  308. /// Trivial SmallVectorImpl<T> -> SPSSequence<char> serialization.
  309. template <typename SPSElementTagT, typename T>
  310. class TrivialSPSSequenceSerialization<SPSElementTagT, SmallVectorImpl<T>> {
  311. public:
  312.   static constexpr bool available = true;
  313. };
  314.  
  315. /// Trivial SPSSequence<SPSElementTagT> -> SmallVectorImpl<T> deserialization.
  316. template <typename SPSElementTagT, typename T>
  317. class TrivialSPSSequenceDeserialization<SPSElementTagT, SmallVectorImpl<T>> {
  318. public:
  319.   static constexpr bool available = true;
  320.  
  321.   using element_type = typename SmallVectorImpl<T>::value_type;
  322.  
  323.   static void reserve(SmallVectorImpl<T> &V, uint64_t Size) { V.reserve(Size); }
  324.   static bool append(SmallVectorImpl<T> &V, T E) {
  325.     V.push_back(std::move(E));
  326.     return true;
  327.   }
  328. };
  329.  
  330. /// Trivial SmallVectorImpl<T> -> SPSSequence<char> serialization.
  331. template <typename SPSElementTagT, typename T, unsigned N>
  332. class TrivialSPSSequenceSerialization<SPSElementTagT, SmallVector<T, N>>
  333.     : public TrivialSPSSequenceSerialization<SPSElementTagT,
  334.                                              SmallVectorImpl<T>> {};
  335.  
  336. /// Trivial SPSSequence<SPSElementTagT> -> SmallVectorImpl<T> deserialization.
  337. template <typename SPSElementTagT, typename T, unsigned N>
  338. class TrivialSPSSequenceDeserialization<SPSElementTagT, SmallVector<T, N>>
  339.     : public TrivialSPSSequenceDeserialization<SPSElementTagT,
  340.                                                SmallVectorImpl<T>> {};
  341.  
  342. /// Trivial ArrayRef<T> -> SPSSequence<SPSElementTagT> serialization.
  343. template <typename SPSElementTagT, typename T>
  344. class TrivialSPSSequenceSerialization<SPSElementTagT, ArrayRef<T>> {
  345. public:
  346.   static constexpr bool available = true;
  347. };
  348.  
  349. /// Specialized SPSSequence<char> -> ArrayRef<char> serialization.
  350. ///
  351. /// On deserialize, points directly into the input buffer.
  352. template <> class SPSSerializationTraits<SPSSequence<char>, ArrayRef<char>> {
  353. public:
  354.   static size_t size(const ArrayRef<char> &A) {
  355.     return SPSArgList<uint64_t>::size(static_cast<uint64_t>(A.size())) +
  356.            A.size();
  357.   }
  358.  
  359.   static bool serialize(SPSOutputBuffer &OB, const ArrayRef<char> &A) {
  360.     if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(A.size())))
  361.       return false;
  362.     if (A.empty()) // Empty ArrayRef may have null data, so bail out early.
  363.       return true;
  364.     return OB.write(A.data(), A.size());
  365.   }
  366.  
  367.   static bool deserialize(SPSInputBuffer &IB, ArrayRef<char> &A) {
  368.     uint64_t Size;
  369.     if (!SPSArgList<uint64_t>::deserialize(IB, Size))
  370.       return false;
  371.     if (Size > std::numeric_limits<size_t>::max())
  372.       return false;
  373.     A = {Size ? IB.data() : nullptr, static_cast<size_t>(Size)};
  374.     return IB.skip(Size);
  375.   }
  376. };
  377.  
  378. /// 'Trivial' sequence serialization: Sequence is serialized as a uint64_t size
  379. /// followed by a for-earch loop over the elements of the sequence to serialize
  380. /// each of them.
  381. template <typename SPSElementTagT, typename SequenceT>
  382. class SPSSerializationTraits<SPSSequence<SPSElementTagT>, SequenceT,
  383.                              std::enable_if_t<TrivialSPSSequenceSerialization<
  384.                                  SPSElementTagT, SequenceT>::available>> {
  385. public:
  386.   static size_t size(const SequenceT &S) {
  387.     size_t Size = SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size()));
  388.     for (const auto &E : S)
  389.       Size += SPSArgList<SPSElementTagT>::size(E);
  390.     return Size;
  391.   }
  392.  
  393.   static bool serialize(SPSOutputBuffer &OB, const SequenceT &S) {
  394.     if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))
  395.       return false;
  396.     for (const auto &E : S)
  397.       if (!SPSArgList<SPSElementTagT>::serialize(OB, E))
  398.         return false;
  399.     return true;
  400.   }
  401.  
  402.   static bool deserialize(SPSInputBuffer &IB, SequenceT &S) {
  403.     using TBSD = TrivialSPSSequenceDeserialization<SPSElementTagT, SequenceT>;
  404.     uint64_t Size;
  405.     if (!SPSArgList<uint64_t>::deserialize(IB, Size))
  406.       return false;
  407.     TBSD::reserve(S, Size);
  408.     for (size_t I = 0; I != Size; ++I) {
  409.       typename TBSD::element_type E;
  410.       if (!SPSArgList<SPSElementTagT>::deserialize(IB, E))
  411.         return false;
  412.       if (!TBSD::append(S, std::move(E)))
  413.         return false;
  414.     }
  415.     return true;
  416.   }
  417. };
  418.  
  419. /// SPSTuple serialization for std::tuple.
  420. template <typename... SPSTagTs, typename... Ts>
  421. class SPSSerializationTraits<SPSTuple<SPSTagTs...>, std::tuple<Ts...>> {
  422. private:
  423.   using TupleArgList = typename SPSTuple<SPSTagTs...>::AsArgList;
  424.   using ArgIndices = std::make_index_sequence<sizeof...(Ts)>;
  425.  
  426.   template <std::size_t... I>
  427.   static size_t size(const std::tuple<Ts...> &T, std::index_sequence<I...>) {
  428.     return TupleArgList::size(std::get<I>(T)...);
  429.   }
  430.  
  431.   template <std::size_t... I>
  432.   static bool serialize(SPSOutputBuffer &OB, const std::tuple<Ts...> &T,
  433.                         std::index_sequence<I...>) {
  434.     return TupleArgList::serialize(OB, std::get<I>(T)...);
  435.   }
  436.  
  437.   template <std::size_t... I>
  438.   static bool deserialize(SPSInputBuffer &IB, std::tuple<Ts...> &T,
  439.                           std::index_sequence<I...>) {
  440.     return TupleArgList::deserialize(IB, std::get<I>(T)...);
  441.   }
  442.  
  443. public:
  444.   static size_t size(const std::tuple<Ts...> &T) {
  445.     return size(T, ArgIndices{});
  446.   }
  447.  
  448.   static bool serialize(SPSOutputBuffer &OB, const std::tuple<Ts...> &T) {
  449.     return serialize(OB, T, ArgIndices{});
  450.   }
  451.  
  452.   static bool deserialize(SPSInputBuffer &IB, std::tuple<Ts...> &T) {
  453.     return deserialize(IB, T, ArgIndices{});
  454.   }
  455. };
  456.  
  457. /// SPSTuple serialization for std::pair.
  458. template <typename SPSTagT1, typename SPSTagT2, typename T1, typename T2>
  459. class SPSSerializationTraits<SPSTuple<SPSTagT1, SPSTagT2>, std::pair<T1, T2>> {
  460. public:
  461.   static size_t size(const std::pair<T1, T2> &P) {
  462.     return SPSArgList<SPSTagT1>::size(P.first) +
  463.            SPSArgList<SPSTagT2>::size(P.second);
  464.   }
  465.  
  466.   static bool serialize(SPSOutputBuffer &OB, const std::pair<T1, T2> &P) {
  467.     return SPSArgList<SPSTagT1>::serialize(OB, P.first) &&
  468.            SPSArgList<SPSTagT2>::serialize(OB, P.second);
  469.   }
  470.  
  471.   static bool deserialize(SPSInputBuffer &IB, std::pair<T1, T2> &P) {
  472.     return SPSArgList<SPSTagT1>::deserialize(IB, P.first) &&
  473.            SPSArgList<SPSTagT2>::deserialize(IB, P.second);
  474.   }
  475. };
  476.  
  477. /// SPSOptional serialization for std::optional.
  478. template <typename SPSTagT, typename T>
  479. class SPSSerializationTraits<SPSOptional<SPSTagT>, std::optional<T>> {
  480. public:
  481.   static size_t size(const std::optional<T> &Value) {
  482.     size_t Size = SPSArgList<bool>::size(!!Value);
  483.     if (Value)
  484.       Size += SPSArgList<SPSTagT>::size(*Value);
  485.     return Size;
  486.   }
  487.  
  488.   static bool serialize(SPSOutputBuffer &OB, const std::optional<T> &Value) {
  489.     if (!SPSArgList<bool>::serialize(OB, !!Value))
  490.       return false;
  491.     if (Value)
  492.       return SPSArgList<SPSTagT>::serialize(OB, *Value);
  493.     return true;
  494.   }
  495.  
  496.   static bool deserialize(SPSInputBuffer &IB, std::optional<T> &Value) {
  497.     bool HasValue;
  498.     if (!SPSArgList<bool>::deserialize(IB, HasValue))
  499.       return false;
  500.     if (HasValue) {
  501.       Value = T();
  502.       return SPSArgList<SPSTagT>::deserialize(IB, *Value);
  503.     } else
  504.       Value = std::optional<T>();
  505.     return true;
  506.   }
  507. };
  508.  
  509. /// Serialization for StringRefs.
  510. ///
  511. /// Serialization is as for regular strings. Deserialization points directly
  512. /// into the blob.
  513. template <> class SPSSerializationTraits<SPSString, StringRef> {
  514. public:
  515.   static size_t size(const StringRef &S) {
  516.     return SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size())) +
  517.            S.size();
  518.   }
  519.  
  520.   static bool serialize(SPSOutputBuffer &OB, StringRef S) {
  521.     if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))
  522.       return false;
  523.     if (S.empty()) // Empty StringRef may have null data, so bail out early.
  524.       return true;
  525.     return OB.write(S.data(), S.size());
  526.   }
  527.  
  528.   static bool deserialize(SPSInputBuffer &IB, StringRef &S) {
  529.     const char *Data = nullptr;
  530.     uint64_t Size;
  531.     if (!SPSArgList<uint64_t>::deserialize(IB, Size))
  532.       return false;
  533.     Data = IB.data();
  534.     if (!IB.skip(Size))
  535.       return false;
  536.     S = StringRef(Size ? Data : nullptr, Size);
  537.     return true;
  538.   }
  539. };
  540.  
  541. /// Serialization for StringMap<ValueT>s.
  542. template <typename SPSValueT, typename ValueT>
  543. class SPSSerializationTraits<SPSSequence<SPSTuple<SPSString, SPSValueT>>,
  544.                              StringMap<ValueT>> {
  545. public:
  546.   static size_t size(const StringMap<ValueT> &M) {
  547.     size_t Sz = SPSArgList<uint64_t>::size(static_cast<uint64_t>(M.size()));
  548.     for (auto &E : M)
  549.       Sz += SPSArgList<SPSString, SPSValueT>::size(E.first(), E.second);
  550.     return Sz;
  551.   }
  552.  
  553.   static bool serialize(SPSOutputBuffer &OB, const StringMap<ValueT> &M) {
  554.     if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(M.size())))
  555.       return false;
  556.  
  557.     for (auto &E : M)
  558.       if (!SPSArgList<SPSString, SPSValueT>::serialize(OB, E.first(), E.second))
  559.         return false;
  560.  
  561.     return true;
  562.   }
  563.  
  564.   static bool deserialize(SPSInputBuffer &IB, StringMap<ValueT> &M) {
  565.     uint64_t Size;
  566.     assert(M.empty() && "M already contains elements");
  567.  
  568.     if (!SPSArgList<uint64_t>::deserialize(IB, Size))
  569.       return false;
  570.  
  571.     while (Size--) {
  572.       StringRef S;
  573.       ValueT V;
  574.       if (!SPSArgList<SPSString, SPSValueT>::deserialize(IB, S, V))
  575.         return false;
  576.       if (!M.insert(std::make_pair(S, V)).second)
  577.         return false;
  578.     }
  579.  
  580.     return true;
  581.   }
  582. };
  583.  
  584. /// SPS tag type for errors.
  585. class SPSError;
  586.  
  587. /// SPS tag type for expecteds, which are either a T or a string representing
  588. /// an error.
  589. template <typename SPSTagT> class SPSExpected;
  590.  
  591. namespace detail {
  592.  
  593. /// Helper type for serializing Errors.
  594. ///
  595. /// llvm::Errors are move-only, and not inspectable except by consuming them.
  596. /// This makes them unsuitable for direct serialization via
  597. /// SPSSerializationTraits, which needs to inspect values twice (once to
  598. /// determine the amount of space to reserve, and then again to serialize).
  599. ///
  600. /// The SPSSerializableError type is a helper that can be
  601. /// constructed from an llvm::Error, but inspected more than once.
  602. struct SPSSerializableError {
  603.   bool HasError = false;
  604.   std::string ErrMsg;
  605. };
  606.  
  607. /// Helper type for serializing Expected<T>s.
  608. ///
  609. /// See SPSSerializableError for more details.
  610. ///
  611. // FIXME: Use std::variant for storage once we have c++17.
  612. template <typename T> struct SPSSerializableExpected {
  613.   bool HasValue = false;
  614.   T Value{};
  615.   std::string ErrMsg;
  616. };
  617.  
  618. inline SPSSerializableError toSPSSerializable(Error Err) {
  619.   if (Err)
  620.     return {true, toString(std::move(Err))};
  621.   return {false, {}};
  622. }
  623.  
  624. inline Error fromSPSSerializable(SPSSerializableError BSE) {
  625.   if (BSE.HasError)
  626.     return make_error<StringError>(BSE.ErrMsg, inconvertibleErrorCode());
  627.   return Error::success();
  628. }
  629.  
  630. template <typename T>
  631. SPSSerializableExpected<T> toSPSSerializable(Expected<T> E) {
  632.   if (E)
  633.     return {true, std::move(*E), {}};
  634.   else
  635.     return {false, T(), toString(E.takeError())};
  636. }
  637.  
  638. template <typename T>
  639. Expected<T> fromSPSSerializable(SPSSerializableExpected<T> BSE) {
  640.   if (BSE.HasValue)
  641.     return std::move(BSE.Value);
  642.   else
  643.     return make_error<StringError>(BSE.ErrMsg, inconvertibleErrorCode());
  644. }
  645.  
  646. } // end namespace detail
  647.  
  648. /// Serialize to a SPSError from a detail::SPSSerializableError.
  649. template <>
  650. class SPSSerializationTraits<SPSError, detail::SPSSerializableError> {
  651. public:
  652.   static size_t size(const detail::SPSSerializableError &BSE) {
  653.     size_t Size = SPSArgList<bool>::size(BSE.HasError);
  654.     if (BSE.HasError)
  655.       Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
  656.     return Size;
  657.   }
  658.  
  659.   static bool serialize(SPSOutputBuffer &OB,
  660.                         const detail::SPSSerializableError &BSE) {
  661.     if (!SPSArgList<bool>::serialize(OB, BSE.HasError))
  662.       return false;
  663.     if (BSE.HasError)
  664.       if (!SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg))
  665.         return false;
  666.     return true;
  667.   }
  668.  
  669.   static bool deserialize(SPSInputBuffer &IB,
  670.                           detail::SPSSerializableError &BSE) {
  671.     if (!SPSArgList<bool>::deserialize(IB, BSE.HasError))
  672.       return false;
  673.  
  674.     if (!BSE.HasError)
  675.       return true;
  676.  
  677.     return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
  678.   }
  679. };
  680.  
  681. /// Serialize to a SPSExpected<SPSTagT> from a
  682. /// detail::SPSSerializableExpected<T>.
  683. template <typename SPSTagT, typename T>
  684. class SPSSerializationTraits<SPSExpected<SPSTagT>,
  685.                              detail::SPSSerializableExpected<T>> {
  686. public:
  687.   static size_t size(const detail::SPSSerializableExpected<T> &BSE) {
  688.     size_t Size = SPSArgList<bool>::size(BSE.HasValue);
  689.     if (BSE.HasValue)
  690.       Size += SPSArgList<SPSTagT>::size(BSE.Value);
  691.     else
  692.       Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
  693.     return Size;
  694.   }
  695.  
  696.   static bool serialize(SPSOutputBuffer &OB,
  697.                         const detail::SPSSerializableExpected<T> &BSE) {
  698.     if (!SPSArgList<bool>::serialize(OB, BSE.HasValue))
  699.       return false;
  700.  
  701.     if (BSE.HasValue)
  702.       return SPSArgList<SPSTagT>::serialize(OB, BSE.Value);
  703.  
  704.     return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
  705.   }
  706.  
  707.   static bool deserialize(SPSInputBuffer &IB,
  708.                           detail::SPSSerializableExpected<T> &BSE) {
  709.     if (!SPSArgList<bool>::deserialize(IB, BSE.HasValue))
  710.       return false;
  711.  
  712.     if (BSE.HasValue)
  713.       return SPSArgList<SPSTagT>::deserialize(IB, BSE.Value);
  714.  
  715.     return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
  716.   }
  717. };
  718.  
  719. /// Serialize to a SPSExpected<SPSTagT> from a detail::SPSSerializableError.
  720. template <typename SPSTagT>
  721. class SPSSerializationTraits<SPSExpected<SPSTagT>,
  722.                              detail::SPSSerializableError> {
  723. public:
  724.   static size_t size(const detail::SPSSerializableError &BSE) {
  725.     assert(BSE.HasError && "Cannot serialize expected from a success value");
  726.     return SPSArgList<bool>::size(false) +
  727.            SPSArgList<SPSString>::size(BSE.ErrMsg);
  728.   }
  729.  
  730.   static bool serialize(SPSOutputBuffer &OB,
  731.                         const detail::SPSSerializableError &BSE) {
  732.     assert(BSE.HasError && "Cannot serialize expected from a success value");
  733.     if (!SPSArgList<bool>::serialize(OB, false))
  734.       return false;
  735.     return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
  736.   }
  737. };
  738.  
  739. /// Serialize to a SPSExpected<SPSTagT> from a T.
  740. template <typename SPSTagT, typename T>
  741. class SPSSerializationTraits<SPSExpected<SPSTagT>, T> {
  742. public:
  743.   static size_t size(const T &Value) {
  744.     return SPSArgList<bool>::size(true) + SPSArgList<SPSTagT>::size(Value);
  745.   }
  746.  
  747.   static bool serialize(SPSOutputBuffer &OB, const T &Value) {
  748.     if (!SPSArgList<bool>::serialize(OB, true))
  749.       return false;
  750.     return SPSArgList<SPSTagT>::serialize(Value);
  751.   }
  752. };
  753.  
  754. } // end namespace shared
  755. } // end namespace orc
  756. } // end namespace llvm
  757.  
  758. #endif // LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEPACKEDSERIALIZATION_H
  759.