//===--- simple_packed_serialization.h - simple serialization ---*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file is a part of the ORC runtime support library. // // The behavior of the utilities in this header must be synchronized with the // behavior of the utilities in // llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h. // // The Simple Packed Serialization (SPS) utilities are used to generate // argument and return buffers for wrapper functions using the following // serialization scheme: // // Primitives: // bool, char, int8_t, uint8_t -- Two's complement 8-bit (0=false, 1=true) // int16_t, uint16_t -- Two's complement 16-bit little endian // int32_t, uint32_t -- Two's complement 32-bit little endian // int64_t, int64_t -- Two's complement 64-bit little endian // // Sequence<T>: // Serialized as the sequence length (as a uint64_t) followed by the // serialization of each of the elements without padding. // // Tuple<T1, ..., TN>: // Serialized as each of the element types from T1 to TN without padding. // //===----------------------------------------------------------------------===// #ifndef ORC_RT_SIMPLE_PACKED_SERIALIZATION_H #define ORC_RT_SIMPLE_PACKED_SERIALIZATION_H #include "adt.h" #include "endianness.h" #include "error.h" #include "stl_extras.h" #include <optional> #include <string> #include <string_view> #include <tuple> #include <type_traits> #include <unordered_map> #include <utility> #include <vector> namespace __orc_rt { /// Output char buffer with overflow check. class SPSOutputBuffer { … }; /// Input char buffer with underflow check. class SPSInputBuffer { … }; /// Specialize to describe how to serialize/deserialize to/from the given /// concrete type. template <typename SPSTagT, typename ConcreteT, typename _ = void> class SPSSerializationTraits; /// A utility class for serializing to a blob from a variadic list. template <typename... ArgTs> class SPSArgList; // Empty list specialization for SPSArgList. template <> class SPSArgList<> { … }; // Non-empty list specialization for SPSArgList. SPSArgList<SPSTagT, SPSTagTs...>; /// SPS serialization for integral types, bool, and char. SPSSerializationTraits<SPSTagT, SPSTagT, std::enable_if_t<std::is_same<SPSTagT, bool>::value || std::is_same<SPSTagT, char>::value || std::is_same<SPSTagT, int8_t>::value || std::is_same<SPSTagT, int16_t>::value || std::is_same<SPSTagT, int32_t>::value || std::is_same<SPSTagT, int64_t>::value || std::is_same<SPSTagT, uint8_t>::value || std::is_same<SPSTagT, uint16_t>::value || std::is_same<SPSTagT, uint32_t>::value || std::is_same<SPSTagT, uint64_t>::value>>; /// Any empty placeholder suitable as a substitute for void when deserializing class SPSEmpty { … }; /// Represents an address in the executor. class SPSExecutorAddr { … }; /// SPS tag type for tuples. /// /// A blob tuple should be serialized by serializing each of the elements in /// sequence. template <typename... SPSTagTs> class SPSTuple { … }; /// SPS tag type for optionals. /// /// SPSOptionals should be serialized as a bool with true indicating that an /// SPSTagT value is present, and false indicating that there is no value. /// If the boolean is true then the serialized SPSTagT will follow immediately /// after it. template <typename SPSTagT> class SPSOptional { … }; /// SPS tag type for sequences. /// /// SPSSequences should be serialized as a uint64_t sequence length, /// followed by the serialization of each of the elements. template <typename SPSElementTagT> class SPSSequence; /// SPS tag type for strings, which are equivalent to sequences of chars. SPSString; /// SPS tag type for maps. /// /// SPS maps are just sequences of (Key, Value) tuples. SPSMap; /// Serialization for SPSEmpty type. template <> class SPSSerializationTraits<SPSEmpty, SPSEmpty> { … }; /// Specialize this to implement 'trivial' sequence serialization for /// a concrete sequence type. /// /// Trivial sequence serialization uses the sequence's 'size' member to get the /// length of the sequence, and uses a range-based for loop to iterate over the /// elements. /// /// Specializing this template class means that you do not need to provide a /// specialization of SPSSerializationTraits for your type. template <typename SPSElementTagT, typename ConcreteSequenceT> class TrivialSPSSequenceSerialization { … }; /// Specialize this to implement 'trivial' sequence deserialization for /// a concrete sequence type. /// /// Trivial deserialization calls a static 'reserve(SequenceT&)' method on your /// specialization (you must implement this) to reserve space, and then calls /// a static 'append(SequenceT&, ElementT&) method to append each of the /// deserialized elements. /// /// Specializing this template class means that you do not need to provide a /// specialization of SPSSerializationTraits for your type. template <typename SPSElementTagT, typename ConcreteSequenceT> class TrivialSPSSequenceDeserialization { … }; /// Trivial std::string -> SPSSequence<char> serialization. template <> class TrivialSPSSequenceSerialization<char, std::string> { … }; /// Trivial SPSSequence<char> -> std::string deserialization. template <> class TrivialSPSSequenceDeserialization<char, std::string> { … }; /// Trivial std::vector<T> -> SPSSequence<SPSElementTagT> serialization. TrivialSPSSequenceSerialization<SPSElementTagT, std::vector<T>>; /// Trivial span<T> -> SPSSequence<SPSElementTagT> serialization. TrivialSPSSequenceSerialization<SPSElementTagT, span<T>>; /// Trivial SPSSequence<SPSElementTagT> -> std::vector<T> deserialization. TrivialSPSSequenceDeserialization<SPSElementTagT, std::vector<T>>; /// Trivial std::unordered_map<K, V> -> SPSSequence<SPSTuple<SPSKey, SPSValue>> /// serialization. TrivialSPSSequenceSerialization<SPSTuple<SPSKeyTagT, SPSValueTagT>, std::unordered_map<K, V>>; /// Trivial SPSSequence<SPSTuple<SPSKey, SPSValue>> -> std::unordered_map<K, V> /// deserialization. TrivialSPSSequenceDeserialization<SPSTuple<SPSKeyTagT, SPSValueTagT>, std::unordered_map<K, V>>; /// 'Trivial' sequence serialization: Sequence is serialized as a uint64_t size /// followed by a for-earch loop over the elements of the sequence to serialize /// each of them. SPSSerializationTraits<SPSSequence<SPSElementTagT>, SequenceT, std::enable_if_t<TrivialSPSSequenceSerialization<SPSElementTagT, SequenceT>::available>>; /// Trivial serialization / deserialization for span<char> template <> class SPSSerializationTraits<SPSSequence<char>, span<const char>> { … }; /// SPSTuple serialization for std::tuple. SPSSerializationTraits<SPSTuple<SPSTagTs...>, std::tuple<Ts...>>; /// SPSTuple serialization for std::pair. SPSSerializationTraits<SPSTuple<SPSTagT1, SPSTagT2>, std::pair<T1, T2>>; /// SPSOptional serialization for std::optional. SPSSerializationTraits<SPSOptional<SPSTagT>, std::optional<T>>; /// Serialization for string_views. /// /// Serialization is as for regular strings. Deserialization points directly /// into the blob. template <> class SPSSerializationTraits<SPSString, std::string_view> { … }; /// SPS tag type for errors. class SPSError; /// SPS tag type for expecteds, which are either a T or a string representing /// an error. template <typename SPSTagT> class SPSExpected; namespace detail { /// Helper type for serializing Errors. /// /// llvm::Errors are move-only, and not inspectable except by consuming them. /// This makes them unsuitable for direct serialization via /// SPSSerializationTraits, which needs to inspect values twice (once to /// determine the amount of space to reserve, and then again to serialize). /// /// The SPSSerializableError type is a helper that can be /// constructed from an llvm::Error, but inspected more than once. struct SPSSerializableError { … }; /// Helper type for serializing Expected<T>s. /// /// See SPSSerializableError for more details. /// // FIXME: Use std::variant for storage once we have c++17. template <typename T> struct SPSSerializableExpected { … }; inline SPSSerializableError toSPSSerializable(Error Err) { … } inline Error fromSPSSerializable(SPSSerializableError BSE) { … } template <typename T> SPSSerializableExpected<T> toSPSSerializable(Expected<T> E) { … } template <typename T> Expected<T> fromSPSSerializable(SPSSerializableExpected<T> BSE) { … } } // end namespace detail /// Serialize to a SPSError from a detail::SPSSerializableError. template <> class SPSSerializationTraits<SPSError, detail::SPSSerializableError> { … }; /// Serialize to a SPSExpected<SPSTagT> from a /// detail::SPSSerializableExpected<T>. SPSSerializationTraits<SPSExpected<SPSTagT>, detail::SPSSerializableExpected<T>>; /// Serialize to a SPSExpected<SPSTagT> from a detail::SPSSerializableError. SPSSerializationTraits<SPSExpected<SPSTagT>, detail::SPSSerializableError>; /// Serialize to a SPSExpected<SPSTagT> from a T. SPSSerializationTraits<SPSExpected<SPSTagT>, T>; } // end namespace __orc_rt #endif // ORC_RT_SIMPLE_PACKED_SERIALIZATION_H