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