From 053435950369fe25277daaead80e23e37b13acfc Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Wed, 10 Jun 2026 19:32:07 +0200 Subject: [PATCH] feat(furvm): add clone function to thing Closes #9 --- furvm/include/furvm/executor.hpp | 7 +++++ furvm/include/furvm/instruction.hpp | 5 +++ furvm/include/furvm/thing.hpp | 31 ++++++++++++++++--- furvm/src/executor.cpp | 11 +++++-- furvm/src/main.cpp | 4 ++- furvm/src/thing.cpp | 48 ++++++++++++++++++++++++----- 6 files changed, 91 insertions(+), 15 deletions(-) diff --git a/furvm/include/furvm/executor.hpp b/furvm/include/furvm/executor.hpp index 27e6b1a..118c44c 100644 --- a/furvm/include/furvm/executor.hpp +++ b/furvm/include/furvm/executor.hpp @@ -120,6 +120,13 @@ public: */ void push_thing(const thing_p& thing); + /** + * @brief Pushes a thing onto the stack. + * + * @param thing The thing to push. + */ + void push_thing(thing_p&& thing); + /** * @brief Pops a thing from the stack. * diff --git a/furvm/include/furvm/instruction.hpp b/furvm/include/furvm/instruction.hpp index c0a524f..7758037 100644 --- a/furvm/include/furvm/instruction.hpp +++ b/furvm/include/furvm/instruction.hpp @@ -35,6 +35,11 @@ enum class instruction_t : byte { */ Duplicate, + /** + * @brief Clones top element on the stack. + */ + Clone, + /** * @brief Pops the current call frame. */ diff --git a/furvm/include/furvm/thing.hpp b/furvm/include/furvm/thing.hpp index 3a8d368..c1a1a16 100644 --- a/furvm/include/furvm/thing.hpp +++ b/furvm/include/furvm/thing.hpp @@ -1,6 +1,7 @@ #ifndef FURVM_THING_HPP #define FURVM_THING_HPP +#include "furvm/context.hpp" // IWYU pragma: keep #include "furvm/fwd.hpp" namespace furvm { @@ -80,12 +81,12 @@ public: /** * @brief Move constructor. */ - thing(thing&&) noexcept = default; + thing(thing&&) noexcept; /** * @brief Move constructor. */ - thing& operator=(thing&&) noexcept = default; + thing& operator=(thing&&) noexcept; thing(const thing&) = delete; thing& operator=(const thing&) = delete; @@ -94,10 +95,32 @@ public: * @brief Returns a new thing. * * @param context Furvm context. - * @param type Type of the new thing. + * @param args Arguments to forward to the thing constructor. * @return Shared pointer to the new thing. */ - static thing_p create(const context_p& context, thing_t type); + template >> + static thing_p create(const context_p& context, Args&&... args) { + thing_handle id = context->m_things.size(); + if (!context->m_deadThings.empty()) { + id = context->m_deadThings.front(); + context->m_deadThings.pop(); + id += 1 << GENERATION_SIZE; + } + thing_handle idx = id & ((1ULL << ((sizeof(id) * 8) - GENERATION_SIZE)) - 1); + + auto th = std::make_shared(rzecz{}, id, std::forward(args)..., context); + context->m_things.emplace(context->m_things.begin() + idx, th); + return std::move(th); + } + + /** + * @brief Returns a clone of the thing. + * + * @param thing Thing to clone. + * @return Shared pointer to a clone of the thing. + */ + static thing_p clone(const thing_p& thing); public: /** * @brief Returns an int32 value from this thing. diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index 762a4f9..48b4072 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -42,6 +42,11 @@ void executor::push_thing(const thing_p& thing) { m_stack.push(thing); } +void executor::push_thing(thing_p&& thing) { + thing->add_reference(); + m_stack.push(std::move(thing)); +} + thing_p executor::pop_thing() { if (m_frames.top().stackBase >= m_stack.size()) throw stack_underflow(); thing_p top = std::move(m_stack.top()); @@ -66,7 +71,7 @@ void executor::step() { case instruction_t::PushB2I: { auto thing = thing::create(m_context, thing_t::Int32); thing->int32() = frame.mod->byte(frame.position++); - m_stack.push(std::move(thing)); + push_thing(std::move(thing)); } break; case instruction_t::Drop: { pop_thing(); @@ -75,7 +80,7 @@ void executor::step() { push_thing(thing()); } break; case instruction_t::Clone: { - push_thing(thing::clone(thing())); + push_thing(std::move(thing::clone(thing()))); } break; case instruction_t::Return: { pop_frame(); @@ -84,7 +89,7 @@ void executor::step() { case instruction_t::ReturnValue: { auto value = pop_thing(); pop_frame(); - m_stack.push(std::move(value)); + push_thing(std::move(value)); } break; case instruction_t::PushConstant: throw std::runtime_error("unimplemented"); default: throw std::runtime_error("unknown instruction"); diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index 53474eb..6bf1767 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -8,9 +8,11 @@ #include #include -static constexpr std::array s_bytecode = { +static constexpr std::array s_bytecode = { furvm::byte(furvm::instruction_t::PushB2I), 67, + furvm::byte(furvm::instruction_t::Clone), + furvm::byte(furvm::instruction_t::Drop), furvm::byte(furvm::instruction_t::Drop), furvm::byte(furvm::instruction_t::Return), }; diff --git a/furvm/src/thing.cpp b/furvm/src/thing.cpp index 2e6a059..64e2a45 100644 --- a/furvm/src/thing.cpp +++ b/furvm/src/thing.cpp @@ -55,17 +55,51 @@ thing::~thing() { m_context->m_deadThingData.push_back(m_data); } -thing_p thing::create(const context_p& context, thing_t type) { - thing_handle id = context->m_things.size(); - if (!context->m_deadThings.empty()) { - id = context->m_deadThings.front(); - context->m_deadThings.pop(); +thing::thing(thing&& other) noexcept + : m_id(other.m_id), + m_type(other.m_type), + m_context(std::move(other.m_context)), + m_refCount(other.m_refCount), + m_data(other.m_data) { + other.m_id = {}; + other.m_type = {}; + other.m_refCount = {}; + other.m_data = nullptr; +} + +thing& thing::operator=(thing&& other) noexcept { + if (this == &other) return *this; + m_id = other.m_id; + m_type = other.m_type; + m_context = std::move(other.m_context); + m_refCount = other.m_refCount; + m_data = other.m_data; + + other.m_id = {}; + other.m_type = {}; + other.m_refCount = {}; + other.m_data = nullptr; + return *this; +} + +thing_p thing::clone(const thing_p& thing) { + thing_handle id = thing->m_context->m_things.size(); + if (!thing->m_context->m_deadThings.empty()) { + id = thing->m_context->m_deadThings.front(); + thing->m_context->m_deadThings.pop(); id += 1 << GENERATION_SIZE; } thing_handle idx = id & ((1ULL << ((sizeof(id) * 8) - GENERATION_SIZE)) - 1); - auto th = std::make_shared(rzecz{}, id, type, context); - context->m_things.emplace(context->m_things.begin() + idx, th); + auto th = std::make_shared(rzecz{}, id, thing->m_type, thing->m_context); + switch (thing->m_type) { + // Primitives + default: { + memcpy(th->m_data, thing->m_data, thing_type_size(thing->m_type)); + } + } + + thing->m_context->m_things.emplace(thing->m_context->m_things.begin() + idx, th); return std::move(th); }