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