From 99666495e79f353ce937ce2416bba2ea8631388e Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Fri, 19 Jun 2026 15:14:25 +0200 Subject: [PATCH] refactor(furvm): improve serialization Refs: #12 --- furvm/include/furvm/detail/serialization.hpp | 25 +++++ furvm/include/furvm/module.hpp | 5 + furvm/include/furvm/serializer.hpp | 20 ---- furvm/src/detail/serialization.cpp | 49 +++++++++ furvm/src/main.cpp | 3 +- furvm/src/module.cpp | 33 +++++- furvm/src/serializer.cpp | 100 ------------------- 7 files changed, 113 insertions(+), 122 deletions(-) create mode 100644 furvm/include/furvm/detail/serialization.hpp delete mode 100644 furvm/include/furvm/serializer.hpp create mode 100644 furvm/src/detail/serialization.cpp delete mode 100644 furvm/src/serializer.cpp diff --git a/furvm/include/furvm/detail/serialization.hpp b/furvm/include/furvm/detail/serialization.hpp new file mode 100644 index 0000000..34fc51e --- /dev/null +++ b/furvm/include/furvm/detail/serialization.hpp @@ -0,0 +1,25 @@ +#ifndef FURVM_DETAIL_SERIALIZATION_HPP +#define FURVM_DETAIL_SERIALIZATION_HPP + +#include +#include +#include + +namespace furvm { +namespace detail { + +std::ostream& serialize(std::ostream& os, std::int8_t value); +std::ostream& serialize(std::ostream& os, std::int16_t value); +std::ostream& serialize(std::ostream& os, std::int32_t value); +std::ostream& serialize(std::ostream& os, std::int64_t value); +std::ostream& serialize(std::ostream& os, std::uint8_t value); +std::ostream& serialize(std::ostream& os, std::uint16_t value); +std::ostream& serialize(std::ostream& os, std::uint32_t value); +std::ostream& serialize(std::ostream& os, std::uint64_t value); + +std::ostream& serialize(std::ostream& os, const std::string& value); + +} // namespace detail +} // namespace furvm + +#endif // FURVM_DETAIL_SERIALIZATION_HPP diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index 02ba7b0..cdc5919 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -5,6 +5,7 @@ #include "furvm/fwd.hpp" #include "furvm/handle.hpp" +#include #include #include #include @@ -17,6 +18,8 @@ class mod { friend class serializer; public: using bytecode_t = std::vector; /**< An alias to a vector of bytes. */ + + static constexpr char MAGIC[4] = { 'F', 'u', 'r', 'M' }; /** Furvm module file magic. */ public: /** * @brief Construct a new module. @@ -91,6 +94,8 @@ public: } void erase_function(function_id id) { m_functions.erase(id); } +public: + std::ostream& serialize(std::ostream& os) const; private: bytecode_t m_bytecode; diff --git a/furvm/include/furvm/serializer.hpp b/furvm/include/furvm/serializer.hpp deleted file mode 100644 index 276dd43..0000000 --- a/furvm/include/furvm/serializer.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef FURVM_SERIALIZER_HPP -#define FURVM_SERIALIZER_HPP - -#include "furvm/fwd.hpp" - -#include - -namespace furvm { - -class serializer { -public: - static constexpr byte MODULE_MAGIC[4] = { 'F', 'u', 'r', 'M' }; - static constexpr std::uint32_t VERSION = 0; -public: - static bool serialize_module(std::ostream& os, const mod_p& mod); -}; - -} // namespace furvm - -#endif // FURVM_SERIALIZER_HPP diff --git a/furvm/src/detail/serialization.cpp b/furvm/src/detail/serialization.cpp new file mode 100644 index 0000000..49a5d5d --- /dev/null +++ b/furvm/src/detail/serialization.cpp @@ -0,0 +1,49 @@ +#include "furvm/detail/serialization.hpp" + +#include + +namespace furvm::detail { + +std::ostream& serialize(std::ostream& os, std::int8_t value) { + return os << (char)((value >> 0ULL) & 0xFF); +} + +std::ostream& serialize(std::ostream& os, std::int16_t value) { + return os << (char)((value >> 0ULL) & 0xFF) << (char)((value >> 8ULL) & 0xFF); +} + +std::ostream& serialize(std::ostream& os, std::int32_t value) { + return os << (char)((value >> 0ULL) & 0xFF) << (char)((value >> 8ULL) & 0xFF) << (char)((value >> 16ULL) & 0xFF) + << (char)((value >> 24ULL) & 0xFF); +} + +std::ostream& serialize(std::ostream& os, std::int64_t value) { + return os << (char)((value >> 0ULL) & 0xFF) << (char)((value >> 8ULL) & 0xFF) << (char)((value >> 16ULL) & 0xFF) + << (char)((value >> 24ULL) & 0xFF) << (char)((value >> 32ULL) & 0xFF) << (char)((value >> 40ULL) & 0xFF) + << (char)((value >> 48ULL) & 0xFF) << (char)((value >> 56ULL) & 0xFF); +} + +std::ostream& serialize(std::ostream& os, std::uint8_t value) { + return os << (char)((value >> 0ULL) & 0xFF); +} + +std::ostream& serialize(std::ostream& os, std::uint16_t value) { + return os << (char)((value >> 0ULL) & 0xFF) << (char)((value >> 8ULL) & 0xFF); +} + +std::ostream& serialize(std::ostream& os, std::uint32_t value) { + return os << (char)((value >> 0ULL) & 0xFF) << (char)((value >> 8ULL) & 0xFF) << (char)((value >> 16ULL) & 0xFF) + << (char)((value >> 24ULL) & 0xFF); +} + +std::ostream& serialize(std::ostream& os, std::uint64_t value) { + return os << (char)((value >> 0ULL) & 0xFF) << (char)((value >> 8ULL) & 0xFF) << (char)((value >> 16ULL) & 0xFF) + << (char)((value >> 24ULL) & 0xFF) << (char)((value >> 32ULL) & 0xFF) << (char)((value >> 40ULL) & 0xFF) + << (char)((value >> 48ULL) & 0xFF) << (char)((value >> 56ULL) & 0xFF); +} + +std::ostream& serialize(std::ostream& os, const std::string& value) { + return serialize(os, std::uint16_t(value.size())).write(value.data(), static_cast(value.size())); +} + +} // namespace furvm::detail diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index dd6edbc..34d4cf2 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -6,7 +6,6 @@ #include "furvm/fwd.hpp" #include "furvm/instruction.hpp" #include "furvm/module.hpp" -#include "furvm/serializer.hpp" #include "furvm/thing.hpp" #include @@ -29,6 +28,8 @@ int main(void) { furvm::mod_h mainModule = context->emplace_module("main", s_bytecode.begin(), s_bytecode.end()); furvm::function_h mainFunc = mainModule->emplace_function("main", 0); + mainModule->serialize(std::cout); + furvm::executor_h executor = context->emplace_executor(context); executor->push_frame(mainModule, *mainFunc); diff --git a/furvm/src/module.cpp b/furvm/src/module.cpp index ce10db3..97d45f1 100644 --- a/furvm/src/module.cpp +++ b/furvm/src/module.cpp @@ -1,3 +1,34 @@ #include "furvm/module.hpp" -namespace furvm {} \ No newline at end of file +#include "furvm/detail/serialization.hpp" +#include "furvm/fwd.hpp" + +#include + +namespace furvm { + +std::ostream& mod::serialize(std::ostream& os) const { + os << MAGIC; + detail::serialize(os, std::uint32_t(0)); // version + + detail::serialize(os, function_id(m_functionMap.size())); + for (const auto& [name, id] : m_functionMap) { + detail::serialize(os, name); + function_h func = m_functions.at(id); + detail::serialize(os, std::uint8_t(func->type())); + switch (func->type()) { + case function_t::Normal: { + detail::serialize(os, func->position()); + } break; + case function_t::Native: break; + case function_t::Import: { + detail::serialize(os, func->imp().mod); + detail::serialize(os, func->imp().function); + } break; + } + } + + detail::serialize(os, std::uint64_t(m_bytecode.size())); + return os.write(reinterpret_cast(m_bytecode.data()), static_cast(m_bytecode.size())); +} +} // namespace furvm diff --git a/furvm/src/serializer.cpp b/furvm/src/serializer.cpp deleted file mode 100644 index c07cf80..0000000 --- a/furvm/src/serializer.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "furvm/serializer.hpp" - -#include "furvm/function.hpp" // IWYU pragma: keep -#include "furvm/fwd.hpp" -#include "furvm/module.hpp" // IWYU pragma: keep - -#include -#include - -namespace furvm { - -template -static inline void write_raw(std::ostream& os, const T& value) { - os.write(reinterpret_cast(&value), sizeof(T)); -} - -template -static inline void read_raw(std::istream& is, T& value) { - is.read(reinterpret_cast(&value), sizeof(T)); -} - -static inline void write_u64(std::ostream& os, std::uint64_t value) { - os.put(static_cast((value >> 0ULL) & 0xFF)); - os.put(static_cast((value >> 8ULL) & 0xFF)); - os.put(static_cast((value >> 16ULL) & 0xFF)); - os.put(static_cast((value >> 24ULL) & 0xFF)); - os.put(static_cast((value >> 32ULL) & 0xFF)); - os.put(static_cast((value >> 40ULL) & 0xFF)); - os.put(static_cast((value >> 48ULL) & 0xFF)); - os.put(static_cast((value >> 56ULL) & 0xFF)); -} - -static inline void read_u64(std::istream& is, std::uint64_t& value) { - value = (static_cast(is.get()) << 0) | (static_cast(is.get()) << 8) | - (static_cast(is.get()) << 16) | (static_cast(is.get()) << 24) | - (static_cast(is.get()) << 32) | (static_cast(is.get()) << 40) | - (static_cast(is.get()) << 48) | (static_cast(is.get()) << 56); -} - -static inline void write_u32(std::ostream& os, std::uint32_t value) { - os.put(static_cast((value >> 0ULL) & 0xFF)); - os.put(static_cast((value >> 8ULL) & 0xFF)); - os.put(static_cast((value >> 16ULL) & 0xFF)); - os.put(static_cast((value >> 24ULL) & 0xFF)); -} - -static inline void read_u32(std::istream& is, std::uint32_t& value) { - value = static_cast(is.get() << 0) | static_cast(is.get() << 8) | - static_cast(is.get() << 16) | static_cast(is.get() << 24); -} - -static inline void write_u16(std::ostream& os, std::uint16_t value) { - os.put(static_cast((value >> 0ULL) & 0xFF)); - os.put(static_cast((value >> 8ULL) & 0xFF)); -} - -static inline void read_u16(std::istream& is, std::uint16_t& value) { - value = static_cast(is.get() << 0) | static_cast(is.get() << 8); -} - -static inline void write_u8(std::ostream& os, std::uint8_t value) { - os.put(static_cast((value >> 0ULL) & 0xFF)); -} - -static inline void read_u8(std::istream& is, std::uint8_t& value) { - value = static_cast(is.get() << 0); -} - -bool serializer::serialize_module(std::ostream& os, const mod_p& mod) { - // os.write(reinterpret_cast(MODULE_MAGIC), sizeof(MODULE_MAGIC)); - // write_u32(os, VERSION); - - // write_u32(os, mod->m_functions.size()); - // for (function_id id = 0; id < static_cast(mod->m_functions.size()); ++id) { - // const auto& func = mod->function_at(id); - // write_u16(os, id); - // write_u8(os, static_cast(func->type())); - // switch (func->type()) { - // case function_t::Normal: { - // write_u64(os, func->position()); - // } break; - // case function_t::Native: { - // // TODO: Replace with a reference to the function's name from constant pool - // throw std::runtime_error("cannot serialize native functions yet"); - // } break; - // case function_t::Import: { - // // TODO: Replace with a reference to the module's and function's name from constant pool - // throw std::runtime_error("cannot serialize import functions yet"); - // } break; - // } - // } - - // write_u64(os, mod->m_bytecode.size()); - // os.write(reinterpret_cast(mod->m_bytecode.data()), - // static_cast(mod->m_bytecode.size())); - - return false; -} - -} // namespace furvm