feat(furvm): add clone function to thing

Closes #9
This commit is contained in:
2026-06-10 19:32:07 +02:00
parent efe028a54f
commit 0534359503
6 changed files with 91 additions and 15 deletions
+7
View File
@@ -120,6 +120,13 @@ public:
*/ */
void push_thing(const thing_p& thing); 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. * @brief Pops a thing from the stack.
* *
+5
View File
@@ -35,6 +35,11 @@ enum class instruction_t : byte {
*/ */
Duplicate, Duplicate,
/**
* @brief Clones top element on the stack.
*/
Clone,
/** /**
* @brief Pops the current call frame. * @brief Pops the current call frame.
*/ */
+27 -4
View File
@@ -1,6 +1,7 @@
#ifndef FURVM_THING_HPP #ifndef FURVM_THING_HPP
#define FURVM_THING_HPP #define FURVM_THING_HPP
#include "furvm/context.hpp" // IWYU pragma: keep
#include "furvm/fwd.hpp" #include "furvm/fwd.hpp"
namespace furvm { namespace furvm {
@@ -80,12 +81,12 @@ public:
/** /**
* @brief Move constructor. * @brief Move constructor.
*/ */
thing(thing&&) noexcept = default; thing(thing&&) noexcept;
/** /**
* @brief Move constructor. * @brief Move constructor.
*/ */
thing& operator=(thing&&) noexcept = default; thing& operator=(thing&&) noexcept;
thing(const thing&) = delete; thing(const thing&) = delete;
thing& operator=(const thing&) = delete; thing& operator=(const thing&) = delete;
@@ -94,10 +95,32 @@ public:
* @brief Returns a new thing. * @brief Returns a new thing.
* *
* @param context Furvm context. * @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. * @return Shared pointer to the new thing.
*/ */
static thing_p create(const context_p& context, thing_t type); template <typename... Args,
typename = std::enable_if_t<std::is_constructible_v<thing, rzecz, thing_handle, Args..., const context_p&>>>
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<thing>(rzecz{}, id, std::forward<Args>(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: public:
/** /**
* @brief Returns an int32 value from this thing. * @brief Returns an int32 value from this thing.
+8 -3
View File
@@ -42,6 +42,11 @@ void executor::push_thing(const thing_p& thing) {
m_stack.push(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() { thing_p executor::pop_thing() {
if (m_frames.top().stackBase >= m_stack.size()) throw stack_underflow(); if (m_frames.top().stackBase >= m_stack.size()) throw stack_underflow();
thing_p top = std::move(m_stack.top()); thing_p top = std::move(m_stack.top());
@@ -66,7 +71,7 @@ void executor::step() {
case instruction_t::PushB2I: { case instruction_t::PushB2I: {
auto thing = thing::create(m_context, thing_t::Int32); auto thing = thing::create(m_context, thing_t::Int32);
thing->int32() = frame.mod->byte(frame.position++); thing->int32() = frame.mod->byte(frame.position++);
m_stack.push(std::move(thing)); push_thing(std::move(thing));
} break; } break;
case instruction_t::Drop: { case instruction_t::Drop: {
pop_thing(); pop_thing();
@@ -75,7 +80,7 @@ void executor::step() {
push_thing(thing()); push_thing(thing());
} break; } break;
case instruction_t::Clone: { case instruction_t::Clone: {
push_thing(thing::clone(thing())); push_thing(std::move(thing::clone(thing())));
} break; } break;
case instruction_t::Return: { case instruction_t::Return: {
pop_frame(); pop_frame();
@@ -84,7 +89,7 @@ void executor::step() {
case instruction_t::ReturnValue: { case instruction_t::ReturnValue: {
auto value = pop_thing(); auto value = pop_thing();
pop_frame(); pop_frame();
m_stack.push(std::move(value)); push_thing(std::move(value));
} break; } break;
case instruction_t::PushConstant: throw std::runtime_error("unimplemented"); case instruction_t::PushConstant: throw std::runtime_error("unimplemented");
default: throw std::runtime_error("unknown instruction"); default: throw std::runtime_error("unknown instruction");
+3 -1
View File
@@ -8,9 +8,11 @@
#include <cstddef> #include <cstddef>
#include <memory> #include <memory>
static constexpr std::array<furvm::byte, 4> s_bytecode = { static constexpr std::array<furvm::byte, 6> s_bytecode = {
furvm::byte(furvm::instruction_t::PushB2I), furvm::byte(furvm::instruction_t::PushB2I),
67, 67,
furvm::byte(furvm::instruction_t::Clone),
furvm::byte(furvm::instruction_t::Drop),
furvm::byte(furvm::instruction_t::Drop), furvm::byte(furvm::instruction_t::Drop),
furvm::byte(furvm::instruction_t::Return), furvm::byte(furvm::instruction_t::Return),
}; };
+41 -7
View File
@@ -55,17 +55,51 @@ thing::~thing() {
m_context->m_deadThingData.push_back(m_data); m_context->m_deadThingData.push_back(m_data);
} }
thing_p thing::create(const context_p& context, thing_t type) { thing::thing(thing&& other) noexcept
thing_handle id = context->m_things.size(); : m_id(other.m_id),
if (!context->m_deadThings.empty()) { m_type(other.m_type),
id = context->m_deadThings.front(); m_context(std::move(other.m_context)),
context->m_deadThings.pop(); 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; id += 1 << GENERATION_SIZE;
} }
thing_handle idx = id & ((1ULL << ((sizeof(id) * 8) - GENERATION_SIZE)) - 1); thing_handle idx = id & ((1ULL << ((sizeof(id) * 8) - GENERATION_SIZE)) - 1);
auto th = std::make_shared<thing>(rzecz{}, id, type, context); auto th = std::make_shared<class thing>(rzecz{}, id, thing->m_type, thing->m_context);
context->m_things.emplace(context->m_things.begin() + idx, th); 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); return std::move(th);
} }