#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Endian.h" #include "revng/ADT/CompilationTime.h" #include "revng/ADT/Concepts.h" namespace detail { inline constexpr auto IntegerEndianness = llvm::support::little; inline constexpr auto Unaligned = llvm::support::unaligned; template inline constexpr size_t packedTupleSize() { size_t Result = 0; compile_time::repeat>([&Result]() { using ElementType = std::tuple_element_t; static_assert(IsIntegralOrEnum); Result += sizeof(ElementType); }); return Result; } template struct SerializedIntsSize {}; template struct SerializedIntsSize { static constexpr size_t Size = packedTupleSize>(); }; template struct SerializedIntsSize { static constexpr size_t Size = packedTupleSize(); }; template void writeNext(uint8_t *&Ptr, const T &Value) { // LLVM 19.1+ has writeNext which automatically bumps the pointer, for now we // need to bump it manually after using `write` llvm::support::endian::write(Ptr, Value, IntegerEndianness); Ptr += sizeof(T); } template T readNext(const uint8_t *&Ptr) { return llvm::support::endian::readNext(Ptr, IntegerEndianness); } } // namespace detail // This is a minimal (de)serialization library for integers and enums. This can // convert parameters packs and tuples from and to bytes. The members are stored // in a packed (without alignment padding) little-endian format, this is // equivalent of `memcpy`-ing the equivalent `packed` struct on x86. template inline constexpr size_t packedSize = detail::SerializedIntsSize::Size; template inline auto toBytes(const Args &...Values) { std::array> Result; uint8_t *Ptr = Result.data(); (detail::writeNext(Ptr, Values), ...); return Result; } template inline auto toBytes(const T &Value) { return compile_time::callWithIndexSequence([&Value]() { return toBytes(std::get(Value)...); }); } template inline void fromBytes(llvm::ArrayRef Data, ArgsT &...Args) { revng_assert(Data.size() == packedSize); const uint8_t *Ptr = Data.data(); ((Args = detail::readNext(Ptr)), ...); } template inline void fromBytes(llvm::ArrayRef Data, T &Value) { compile_time::callWithIndexSequence([&Data, &Value]() { fromBytes(Data, std::get(Value)...); }); }