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