refactor(furvm): improve serialization

Refs: #12
This commit is contained in:
2026-06-19 15:14:25 +02:00
parent 6f023765b5
commit 99666495e7
7 changed files with 113 additions and 122 deletions
@@ -0,0 +1,25 @@
#ifndef FURVM_DETAIL_SERIALIZATION_HPP
#define FURVM_DETAIL_SERIALIZATION_HPP
#include <cstdint>
#include <ostream>
#include <string>
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
+5
View File
@@ -5,6 +5,7 @@
#include "furvm/fwd.hpp"
#include "furvm/handle.hpp"
#include <ostream>
#include <string>
#include <unordered_map>
#include <utility>
@@ -17,6 +18,8 @@ class mod {
friend class serializer;
public:
using bytecode_t = std::vector<byte>; /**< 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;
-20
View File
@@ -1,20 +0,0 @@
#ifndef FURVM_SERIALIZER_HPP
#define FURVM_SERIALIZER_HPP
#include "furvm/fwd.hpp"
#include <ostream>
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
+49
View File
@@ -0,0 +1,49 @@
#include "furvm/detail/serialization.hpp"
#include <ostream>
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<std::streamsize>(value.size()));
}
} // namespace furvm::detail
+2 -1
View File
@@ -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 <array>
@@ -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);
+32 -1
View File
@@ -1,3 +1,34 @@
#include "furvm/module.hpp"
namespace furvm {}
#include "furvm/detail/serialization.hpp"
#include "furvm/fwd.hpp"
#include <ios>
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<const char*>(m_bytecode.data()), static_cast<std::streamsize>(m_bytecode.size()));
}
} // namespace furvm
-100
View File
@@ -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 <istream>
#include <ostream>
namespace furvm {
template <typename T>
static inline void write_raw(std::ostream& os, const T& value) {
os.write(reinterpret_cast<const char*>(&value), sizeof(T));
}
template <typename T>
static inline void read_raw(std::istream& is, T& value) {
is.read(reinterpret_cast<char*>(&value), sizeof(T));
}
static inline void write_u64(std::ostream& os, std::uint64_t value) {
os.put(static_cast<char>((value >> 0ULL) & 0xFF));
os.put(static_cast<char>((value >> 8ULL) & 0xFF));
os.put(static_cast<char>((value >> 16ULL) & 0xFF));
os.put(static_cast<char>((value >> 24ULL) & 0xFF));
os.put(static_cast<char>((value >> 32ULL) & 0xFF));
os.put(static_cast<char>((value >> 40ULL) & 0xFF));
os.put(static_cast<char>((value >> 48ULL) & 0xFF));
os.put(static_cast<char>((value >> 56ULL) & 0xFF));
}
static inline void read_u64(std::istream& is, std::uint64_t& value) {
value = (static_cast<std::uint64_t>(is.get()) << 0) | (static_cast<std::uint64_t>(is.get()) << 8) |
(static_cast<std::uint64_t>(is.get()) << 16) | (static_cast<std::uint64_t>(is.get()) << 24) |
(static_cast<std::uint64_t>(is.get()) << 32) | (static_cast<std::uint64_t>(is.get()) << 40) |
(static_cast<std::uint64_t>(is.get()) << 48) | (static_cast<std::uint64_t>(is.get()) << 56);
}
static inline void write_u32(std::ostream& os, std::uint32_t value) {
os.put(static_cast<char>((value >> 0ULL) & 0xFF));
os.put(static_cast<char>((value >> 8ULL) & 0xFF));
os.put(static_cast<char>((value >> 16ULL) & 0xFF));
os.put(static_cast<char>((value >> 24ULL) & 0xFF));
}
static inline void read_u32(std::istream& is, std::uint32_t& value) {
value = static_cast<std::uint32_t>(is.get() << 0) | static_cast<std::uint32_t>(is.get() << 8) |
static_cast<std::uint32_t>(is.get() << 16) | static_cast<std::uint32_t>(is.get() << 24);
}
static inline void write_u16(std::ostream& os, std::uint16_t value) {
os.put(static_cast<char>((value >> 0ULL) & 0xFF));
os.put(static_cast<char>((value >> 8ULL) & 0xFF));
}
static inline void read_u16(std::istream& is, std::uint16_t& value) {
value = static_cast<std::uint16_t>(is.get() << 0) | static_cast<std::uint16_t>(is.get() << 8);
}
static inline void write_u8(std::ostream& os, std::uint8_t value) {
os.put(static_cast<char>((value >> 0ULL) & 0xFF));
}
static inline void read_u8(std::istream& is, std::uint8_t& value) {
value = static_cast<std::uint8_t>(is.get() << 0);
}
bool serializer::serialize_module(std::ostream& os, const mod_p& mod) {
// os.write(reinterpret_cast<const char*>(MODULE_MAGIC), sizeof(MODULE_MAGIC));
// write_u32(os, VERSION);
// write_u32(os, mod->m_functions.size());
// for (function_id id = 0; id < static_cast<function_id>(mod->m_functions.size()); ++id) {
// const auto& func = mod->function_at(id);
// write_u16(os, id);
// write_u8(os, static_cast<std::uint8_t>(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<const char*>(mod->m_bytecode.data()),
// static_cast<std::streamsize>(mod->m_bytecode.size()));
return false;
}
} // namespace furvm