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