refactor(furvm): integrate handle system into things

Sloppy af

Refs: #12
This commit is contained in:
2026-06-17 20:19:53 +02:00
parent 00bcc0e6a5
commit e9b38e95a2
7 changed files with 253 additions and 302 deletions
+27
View File
@@ -5,7 +5,9 @@
#include "furvm/executor.hpp" #include "furvm/executor.hpp"
#include "furvm/fwd.hpp" #include "furvm/fwd.hpp"
#include "furvm/module.hpp" #include "furvm/module.hpp"
#include "furvm/thing.hpp"
#include <cstring>
#include <memory> #include <memory>
#include <queue> #include <queue>
#include <string> #include <string>
@@ -102,6 +104,31 @@ public:
* @brief Removes unreferenced things from the thing list. * @brief Removes unreferenced things from the thing list.
*/ */
void collect(); void collect();
public:
thing_h emplace_thing(thing_t type) {
thing_id id = m_things.size();
if (!m_deadThings.empty()) {
id = m_deadThings.front();
m_deadThings.pop();
}
size_t size = thing_type_size(type);
void* data = nullptr;
for (auto it = m_deadThingData.begin(); it != m_deadThingData.end(); ++it) {
thing_t curType{};
std::memcpy(&curType, static_cast<char*>(*it) - sizeof(curType), sizeof(curType));
if (thing_type_size(curType) != size) continue;
data = *it;
m_deadThingData.erase(it);
break;
}
if (data == nullptr) data = m_thingArena.allocate<char>(sizeof(thing_t) + size);
memcpy(data, &type, sizeof(type));
data = static_cast<char*>(data) + sizeof(type);
thing_p thing = std::make_shared<class thing>(type, data);
return { id, m_things.emplace_back(std::move(thing)) };
}
private: private:
std::unordered_map<std::string, mod_p> m_modules; std::unordered_map<std::string, mod_p> m_modules;
+9 -9
View File
@@ -37,7 +37,7 @@ public:
std::size_t position; /**< Cursor to a current instruction in the bytecode. */ std::size_t position; /**< Cursor to a current instruction in the bytecode. */
std::size_t stackBase; /**< Snapshot of the stack size before this frame. */ std::size_t stackBase; /**< Snapshot of the stack size before this frame. */
std::vector<thing_p> variables; /**< Frame variables. */ std::vector<thing_h> variables; /**< Frame variables. */
}; };
public: public:
/** /**
@@ -104,28 +104,28 @@ public:
* *
* @param thing The thing to push. * @param thing The thing to push.
*/ */
void push_thing(const thing_p& thing); void push_thing(const thing_h& thing);
/** /**
* @brief Pushes a thing onto the stack. * @brief Pushes a thing onto the stack.
* *
* @param thing The thing to push. * @param thing The thing to push.
*/ */
void push_thing(thing_p&& thing); void push_thing(thing_h&& thing);
/** /**
* @brief Pops a thing from the stack. * @brief Pops a thing from the stack.
* *
* @return The popped thing. * @return The popped thing.
*/ */
thing_p pop_thing(); thing_h pop_thing();
/** /**
* @brief Returns the top thing on the stack. * @brief Returns the top thing on the stack.
* *
* @return The thing. * @return The thing.
*/ */
thing_p thing() const; thing_h thing() const;
public: public:
/** /**
* @brief Stores a thing in a variable. * @brief Stores a thing in a variable.
@@ -133,7 +133,7 @@ public:
* @param variable Variable to store the thing in. * @param variable Variable to store the thing in.
* @param thing Thing to store. * @param thing Thing to store.
*/ */
void store_thing(variable_t variable, const thing_p& thing); void store_thing(variable_t variable, const thing_h& thing);
/** /**
* @brief Stores a thing in a variable. * @brief Stores a thing in a variable.
@@ -141,7 +141,7 @@ public:
* @param variable Variable to store the thing in. * @param variable Variable to store the thing in.
* @param thing Thing to store. * @param thing Thing to store.
*/ */
void store_thing(variable_t variable, thing_p&& thing); void store_thing(variable_t variable, thing_h&& thing);
/** /**
* @brief Returns a thing stored in a variable. * @brief Returns a thing stored in a variable.
@@ -149,7 +149,7 @@ public:
* @param variable Variable where the thing is stored. * @param variable Variable where the thing is stored.
* @return The thing stored in the variable. * @return The thing stored in the variable.
*/ */
thing_p load_thing(variable_t variable) const; thing_h load_thing(variable_t variable) const;
public: public:
/** /**
* @brief Executes next instruction. * @brief Executes next instruction.
@@ -160,7 +160,7 @@ private:
context_p m_context; context_p m_context;
std::stack<struct frame> m_frames; std::stack<struct frame> m_frames;
std::stack<thing_p> m_stack; std::stack<thing_h> m_stack;
}; };
} // namespace furvm } // namespace furvm
+1 -1
View File
@@ -151,7 +151,7 @@ using thing_id = std::uint32_t;
/** /**
* @brief A handle to a furvm's thing. * @brief A handle to a furvm's thing.
*/ */
using thing_h = handle<thing_id, thing>; using thing_h = handle<thing_id, thing_p>;
// executor.hpp // executor.hpp
+19
View File
@@ -1,10 +1,26 @@
#ifndef FURVM_HANDLE_HPP #ifndef FURVM_HANDLE_HPP
#define FURVM_HANDLE_HPP #define FURVM_HANDLE_HPP
#include <limits>
#include <type_traits>
#include <utility> #include <utility>
namespace furvm { namespace furvm {
namespace detail {
template <typename Id, typename = void>
struct dead_id {
static constexpr Id value = {};
};
template <typename Id>
struct dead_id<Id, std::enable_if_t<std::is_integral_v<Id>>> {
static constexpr Id value = std::numeric_limits<Id>::max();
};
} // namespace detail
template <typename Id, typename T> template <typename Id, typename T>
class handle { class handle {
public: public:
@@ -25,6 +41,9 @@ public:
template <typename IdF, typename Value> template <typename IdF, typename Value>
handle(IdF&& id, Value&& value) handle(IdF&& id, Value&& value)
: m_id(std::forward<IdF>(id)), m_value(std::forward<Value>(value)) {} : m_id(std::forward<IdF>(id)), m_value(std::forward<Value>(value)) {}
handle()
: m_id(detail::dead_id<Id>::value), m_value() {}
public: public:
handle& operator=(value_type&& value) noexcept { handle& operator=(value_type&& value) noexcept {
m_value = std::move(value); m_value = std::move(value);
+17 -103
View File
@@ -1,7 +1,6 @@
#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 {
@@ -58,7 +57,9 @@ public:
static constexpr thing_id GENERATION_SIZE = 12; /**< Bit size of generation part in thing_handle. */ static constexpr thing_id GENERATION_SIZE = 12; /**< Bit size of generation part in thing_handle. */
public: public:
thing(const context_p& context, thing_t type); thing(thing_t type);
thing(thing_t type, void* data);
~thing(); ~thing();
@@ -74,104 +75,6 @@ public:
thing(const thing&) = delete; thing(const thing&) = delete;
thing& operator=(const thing&) = delete; thing& operator=(const thing&) = delete;
public:
/**
* @brief Adds two things together.
*
* @param lhs Left-hand-side thing.
* @param rhs Right-hand-side thing.
* @return Shared pointer to result thing.
*/
friend thing_p operator+(const thing_p& lhs, const thing_p& rhs);
/**
* @brief Subtracts two things together.
*
* @param lhs Left-hand-side thing.
* @param rhs Right-hand-side thing.
* @return Shared pointer to result thing.
*/
friend thing_p operator-(const thing_p& lhs, const thing_p& rhs);
/**
* @brief Multiplies two things together.
*
* @param lhs Left-hand-side thing.
* @param rhs Right-hand-side thing.
* @return Shared pointer to result thing.
*/
friend thing_p operator*(const thing_p& lhs, const thing_p& rhs);
/**
* @brief Divides two things together.
*
* @param lhs Left-hand-side thing.
* @param rhs Right-hand-side thing.
* @return Shared pointer to result thing.
*/
friend thing_p operator/(const thing_p& lhs, const thing_p& rhs);
/**
* @brief Modulos two things together.
*
* @param lhs Left-hand-side thing.
* @param rhs Right-hand-side thing.
* @return Shared pointer to result thing.
*/
friend thing_p operator%(const thing_p& lhs, const thing_p& rhs);
/**
* @brief Compares two things for equality.
*
* @param lhs Left-hand-side thing.
* @param rhs Right-hand-side thing.
* @return Shared pointer to result thing.
*/
friend thing_p operator==(const thing_p& lhs, const thing_p& rhs);
/**
* @brief Compares two things for equality.
*
* @param lhs Left-hand-side thing.
* @param rhs Right-hand-side thing.
* @return Shared pointer to result thing.
*/
friend thing_p operator!=(const thing_p& lhs, const thing_p& rhs);
/**
* @brief Compares if the left thing is less than the right thing.
*
* @param lhs Left-hand-side thing.
* @param rhs Right-hand-side thing.
* @return Shared pointer to result thing.
*/
friend thing_p operator<(const thing_p& lhs, const thing_p& rhs);
/**
* @brief Compares if the left thing is greater than the right thing.
*
* @param lhs Left-hand-side thing.
* @param rhs Right-hand-side thing.
* @return Shared pointer to result thing.
*/
friend thing_p operator>(const thing_p& lhs, const thing_p& rhs);
/**
* @brief Compares if the left thing is less than or equal to the right thing.
*
* @param lhs Left-hand-side thing.
* @param rhs Right-hand-side thing.
* @return Shared pointer to result thing.
*/
friend thing_p operator<=(const thing_p& lhs, const thing_p& rhs);
/**
* @brief Compares if the left thing is greater than or equal to the right thing.
*
* @param lhs Left-hand-side thing.
* @param rhs Right-hand-side thing.
* @return Shared pointer to result thing.
*/
friend thing_p operator>=(const thing_p& lhs, const thing_p& rhs);
public: public:
/** /**
* @brief Returns a clone of the thing. * @brief Returns a clone of the thing.
@@ -179,7 +82,7 @@ public:
* @param thing Thing to clone. * @param thing Thing to clone.
* @return Shared pointer to a clone of the thing. * @return Shared pointer to a clone of the thing.
*/ */
static thing_p clone(const thing_p& thing); static thing_h clone(const context_p& context, const thing_h& thing);
public: public:
/** /**
* @brief Returns an int32 value from this thing. * @brief Returns an int32 value from this thing.
@@ -194,6 +97,18 @@ public:
* @return The value. * @return The value.
*/ */
const std::int32_t& int32() const; const std::int32_t& int32() const;
public:
thing_h add(const context_p& context, const thing_h& rhs) const;
thing_h sub(const context_p& context, const thing_h& rhs) const;
thing_h mul(const context_p& context, const thing_h& rhs) const;
thing_h div(const context_p& context, const thing_h& rhs) const;
thing_h mod(const context_p& context, const thing_h& rhs) const;
thing_h equals(const context_p& context, const thing_h& rhs) const;
thing_h not_equals(const context_p& context, const thing_h& rhs) const;
thing_h less_than(const context_p& context, const thing_h& rhs) const;
thing_h greater_than(const context_p& context, const thing_h& rhs) const;
thing_h less_equals(const context_p& context, const thing_h& rhs) const;
thing_h greater_equals(const context_p& context, const thing_h& rhs) const;
public: public:
/** /**
* @brief Increments reference count of this thing by one. * @brief Increments reference count of this thing by one.
@@ -212,9 +127,8 @@ public:
*/ */
constexpr nref_t reference_count() const { return m_refCount; } constexpr nref_t reference_count() const { return m_refCount; }
private: private:
context_p m_context;
thing_t m_type; thing_t m_type;
bool m_ownData = true;
nref_t m_refCount = 0; nref_t m_refCount = 0;
void* m_data = nullptr; void* m_data = nullptr;
}; };
+32 -33
View File
@@ -8,7 +8,6 @@
#include "furvm/thing.hpp" #include "furvm/thing.hpp"
#include <cstdint> #include <cstdint>
#include <memory>
#include <stdexcept> #include <stdexcept>
namespace furvm { namespace furvm {
@@ -29,50 +28,50 @@ struct executor::frame executor::frame() const {
return m_frames.top(); return m_frames.top();
} }
void executor::push_thing(const thing_p& thing) { void executor::push_thing(const thing_h& thing) {
thing->add_reference(); (*thing)->add_reference();
m_stack.push(thing); m_stack.push(thing);
} }
void executor::push_thing(thing_p&& thing) { void executor::push_thing(thing_h&& thing) {
thing->add_reference(); (*thing)->add_reference();
m_stack.push(std::move(thing)); m_stack.push(std::move(thing));
} }
thing_p executor::pop_thing() { thing_h 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_h top = std::move(m_stack.top());
m_stack.pop(); m_stack.pop();
top->remove_reference(); (*top)->remove_reference();
return top; return top;
} }
thing_p executor::thing() const { thing_h executor::thing() const {
if (m_frames.top().stackBase >= m_stack.size()) throw stack_underflow(); if (m_frames.top().stackBase >= m_stack.size()) throw stack_underflow();
return m_stack.top(); return m_stack.top();
} }
void executor::store_thing(variable_t variable, const thing_p& thing) { void executor::store_thing(variable_t variable, const thing_h& thing) {
auto& frame = m_frames.top(); auto& frame = m_frames.top();
frame.variables.resize(variable + 1); frame.variables.resize(variable + 1);
if (frame.variables[variable] != nullptr) { if (*frame.variables[variable] != nullptr) {
frame.variables[variable]->remove_reference(); (*frame.variables[variable])->remove_reference();
} }
frame.variables[variable] = thing; frame.variables[variable] = thing;
thing->add_reference(); (*thing)->add_reference();
} }
void executor::store_thing(variable_t variable, thing_p&& thing) { void executor::store_thing(variable_t variable, thing_h&& thing) {
auto& frame = m_frames.top(); auto& frame = m_frames.top();
frame.variables.resize(variable + 1); frame.variables.resize(variable + 1);
if (frame.variables[variable] != nullptr) { if ((*frame.variables[variable]) != nullptr) {
frame.variables[variable]->remove_reference(); (*frame.variables[variable])->remove_reference();
} }
thing->add_reference(); (*thing)->add_reference();
frame.variables[variable] = std::move(thing); frame.variables[variable] = std::move(thing);
} }
thing_p executor::load_thing(variable_t variable) const { thing_h executor::load_thing(variable_t variable) const {
const auto& frame = m_frames.top(); const auto& frame = m_frames.top();
return frame.variables[variable]; return frame.variables[variable];
} }
@@ -86,8 +85,8 @@ void executor::step() {
switch (instr) { switch (instr) {
case instruction_t::NoOperation: break; case instruction_t::NoOperation: break;
case instruction_t::PushB2I: { case instruction_t::PushB2I: {
auto thing = std::make_shared<class thing>(m_context, thing_t::Int32); auto thing = m_context->emplace_thing(thing_t::Int32);
thing->int32() = (*frame.mod)->byte(frame.position++); (*thing)->int32() = (*frame.mod)->byte(frame.position++);
push_thing(std::move(thing)); push_thing(std::move(thing));
} break; } break;
case instruction_t::Drop: { case instruction_t::Drop: {
@@ -97,62 +96,62 @@ void executor::step() {
push_thing(thing()); push_thing(thing());
} break; } break;
case instruction_t::Clone: { case instruction_t::Clone: {
push_thing(std::move(thing::clone(thing()))); push_thing(std::move(thing::clone(m_context, thing())));
} break; } break;
case instruction_t::Add: { case instruction_t::Add: {
auto rhs = pop_thing(); auto rhs = pop_thing();
auto lhs = pop_thing(); auto lhs = pop_thing();
push_thing(lhs + rhs); push_thing((*lhs)->add(m_context, rhs));
} break; } break;
case instruction_t::Sub: { case instruction_t::Sub: {
auto rhs = pop_thing(); auto rhs = pop_thing();
auto lhs = pop_thing(); auto lhs = pop_thing();
push_thing(lhs - rhs); push_thing((*lhs)->sub(m_context, rhs));
} break; } break;
case instruction_t::Mul: { case instruction_t::Mul: {
auto rhs = pop_thing(); auto rhs = pop_thing();
auto lhs = pop_thing(); auto lhs = pop_thing();
push_thing(lhs * rhs); push_thing((*lhs)->mul(m_context, rhs));
} break; } break;
case instruction_t::Div: { case instruction_t::Div: {
auto rhs = pop_thing(); auto rhs = pop_thing();
auto lhs = pop_thing(); auto lhs = pop_thing();
push_thing(lhs / rhs); push_thing((*lhs)->div(m_context, rhs));
} break; } break;
case instruction_t::Mod: { case instruction_t::Mod: {
auto rhs = pop_thing(); auto rhs = pop_thing();
auto lhs = pop_thing(); auto lhs = pop_thing();
push_thing(lhs % rhs); push_thing((*lhs)->mod(m_context, rhs));
} break; } break;
case instruction_t::Equals: { case instruction_t::Equals: {
auto rhs = pop_thing(); auto rhs = pop_thing();
auto lhs = pop_thing(); auto lhs = pop_thing();
push_thing(lhs == rhs); push_thing((*lhs)->equals(m_context, rhs));
} break; } break;
case instruction_t::NotEquals: { case instruction_t::NotEquals: {
auto rhs = pop_thing(); auto rhs = pop_thing();
auto lhs = pop_thing(); auto lhs = pop_thing();
push_thing(lhs != rhs); push_thing((*lhs)->not_equals(m_context, rhs));
} break; } break;
case instruction_t::LessThan: { case instruction_t::LessThan: {
auto rhs = pop_thing(); auto rhs = pop_thing();
auto lhs = pop_thing(); auto lhs = pop_thing();
push_thing(lhs < rhs); push_thing((*lhs)->less_than(m_context, rhs));
} break; } break;
case instruction_t::GreaterThan: { case instruction_t::GreaterThan: {
auto rhs = pop_thing(); auto rhs = pop_thing();
auto lhs = pop_thing(); auto lhs = pop_thing();
push_thing(lhs > rhs); push_thing((*lhs)->greater_than(m_context, rhs));
} break; } break;
case instruction_t::LessEqual: { case instruction_t::LessEqual: {
auto rhs = pop_thing(); auto rhs = pop_thing();
auto lhs = pop_thing(); auto lhs = pop_thing();
push_thing(lhs <= rhs); push_thing((*lhs)->less_equals(m_context, rhs));
} break; } break;
case instruction_t::GreaterEqual: { case instruction_t::GreaterEqual: {
auto rhs = pop_thing(); auto rhs = pop_thing();
auto lhs = pop_thing(); auto lhs = pop_thing();
push_thing(lhs >= rhs); push_thing((*lhs)->greater_equals(m_context, rhs));
} break; } break;
case instruction_t::Load: { case instruction_t::Load: {
variable_t variable = static_cast<std::uint16_t>((*frame.mod)->byte(frame.position)) | variable_t variable = static_cast<std::uint16_t>((*frame.mod)->byte(frame.position)) |
@@ -188,7 +187,7 @@ void executor::step() {
case instruction_t::JumpNotZero: { case instruction_t::JumpNotZero: {
byte offset = (*frame.mod)->byte(frame.position++); byte offset = (*frame.mod)->byte(frame.position++);
auto cond = pop_thing(); auto cond = pop_thing();
if (cond->int32() != 0) frame.position += offset; if ((*cond)->int32() != 0) frame.position += offset;
} break; } break;
case instruction_t::Return: { case instruction_t::Return: {
pop_frame(); pop_frame();
+145 -153
View File
@@ -17,23 +17,10 @@ std::size_t thing_type_size(thing_t type) {
return 0; return 0;
} }
thing::thing(const context_p& context, thing_t type) thing::thing(thing_t type)
: m_context(context), m_type(type) { : m_type(type) {
std::size_t size = thing_type_size(type); std::size_t size = thing_type_size(type);
std::byte* data = nullptr; byte* data = new byte[size];
if (!m_context->m_deadThingData.empty()) {
thing_t itType{};
for (auto it = m_context->m_deadThingData.rbegin(); it != m_context->m_deadThingData.rend(); ++it) {
std::memcpy(&itType, static_cast<std::byte*>(*it) - sizeof(itType), sizeof(itType));
if (size == thing_type_size(itType)) {
data = static_cast<std::byte*>(*it);
m_context->m_deadThingData.erase(std::next(it).base());
break;
}
}
}
if (data == nullptr) data = m_context->m_thingArena.allocate<std::byte>(sizeof(type) + size);
if (data == nullptr) throw std::runtime_error("failed to allocate data for new thing"); if (data == nullptr) throw std::runtime_error("failed to allocate data for new thing");
std::memcpy(data, &type, sizeof(type)); std::memcpy(data, &type, sizeof(type));
m_data = data + sizeof(type); m_data = data + sizeof(type);
@@ -45,6 +32,20 @@ thing::thing(const context_p& context, thing_t type)
} }
} }
thing::thing(thing_t type, void* data)
: m_type(type), m_ownData(false) {
std::size_t size = thing_type_size(type);
if (data == nullptr) throw std::runtime_error("failed to allocate data for new thing");
std::memcpy(data, &type, sizeof(type));
m_data = static_cast<char*>(data) + sizeof(type);
switch (m_type) {
// Primitives are zero-initialized.
default:
case thing_t::Int32: std::memset(m_data, 0, size);
}
}
thing::~thing() { thing::~thing() {
switch (m_type) { switch (m_type) {
// Primitives are not destructed. // Primitives are not destructed.
@@ -52,19 +53,19 @@ thing::~thing() {
case thing_t::Int32: break; case thing_t::Int32: break;
} }
m_context->m_deadThingData.push_back(m_data); if (m_ownData) delete[] static_cast<char*>(m_data);
} }
thing::thing(thing&& other) noexcept thing::thing(thing&& other) noexcept
: m_context(std::move(other.m_context)), m_type(other.m_type), m_refCount(other.m_refCount), m_data(other.m_data) { : m_type(other.m_type), m_refCount(other.m_refCount), m_data(other.m_data) {
other.m_type = {}; other.m_type = {};
other.m_ownData = false;
other.m_refCount = {}; other.m_refCount = {};
other.m_data = nullptr; other.m_data = nullptr;
} }
thing& thing::operator=(thing&& other) noexcept { thing& thing::operator=(thing&& other) noexcept {
if (this == &other) return *this; if (this == &other) return *this;
m_context = std::move(other.m_context);
m_type = other.m_type; m_type = other.m_type;
m_refCount = other.m_refCount; m_refCount = other.m_refCount;
m_data = other.m_data; m_data = other.m_data;
@@ -79,145 +80,15 @@ static constexpr std::uint16_t thing_type_pair(thing_t lhs, thing_t rhs) {
return (static_cast<std::uint16_t>(lhs) << 8) | static_cast<std::uint16_t>(rhs); return (static_cast<std::uint16_t>(lhs) << 8) | static_cast<std::uint16_t>(rhs);
} }
thing_p operator+(const thing_p& lhs, const thing_p& rhs) { thing_h thing::clone(const context_p& context, const thing_h& thing) {
switch (thing_type_pair(lhs->m_type, rhs->m_type)) { auto th = context->emplace_thing((*thing)->m_type);
case thing_type_pair(thing_t::Int32, thing_t::Int32): { switch ((*thing)->m_type) {
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
res->int32() = lhs->int32() + rhs->int32();
return res;
}
default: throw std::runtime_error("unexpected operator");
}
}
thing_p operator-(const thing_p& lhs, const thing_p& rhs) {
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
res->int32() = lhs->int32() - rhs->int32();
return res;
}
default: throw std::runtime_error("unexpected operator");
}
}
thing_p operator*(const thing_p& lhs, const thing_p& rhs) {
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
res->int32() = lhs->int32() * rhs->int32();
return res;
}
default: throw std::runtime_error("unexpected operator");
}
}
thing_p operator/(const thing_p& lhs, const thing_p& rhs) {
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
res->int32() = lhs->int32() / rhs->int32();
return res;
}
default: throw std::runtime_error("unexpected operator");
}
}
thing_p operator%(const thing_p& lhs, const thing_p& rhs) {
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
res->int32() = lhs->int32() % rhs->int32();
return res;
}
default: throw std::runtime_error("unexpected operator");
}
}
thing_p operator==(const thing_p& lhs, const thing_p& rhs) {
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
res->int32() = static_cast<std::int32_t>(lhs->int32() == rhs->int32());
return res;
}
default: throw std::runtime_error("unexpected operator");
}
}
thing_p operator!=(const thing_p& lhs, const thing_p& rhs) {
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
res->int32() = static_cast<std::int32_t>(lhs->int32() != rhs->int32());
return res;
}
default: throw std::runtime_error("unexpected operator");
}
}
thing_p operator<(const thing_p& lhs, const thing_p& rhs) {
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
res->int32() = static_cast<std::int32_t>(lhs->int32() < rhs->int32());
return res;
}
default: throw std::runtime_error("unexpected operator");
}
}
thing_p operator>(const thing_p& lhs, const thing_p& rhs) {
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
res->int32() = static_cast<std::int32_t>(lhs->int32() > rhs->int32());
return res;
}
default: throw std::runtime_error("unexpected operator");
}
}
thing_p operator<=(const thing_p& lhs, const thing_p& rhs) {
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
res->int32() = static_cast<std::int32_t>(lhs->int32() <= rhs->int32());
return res;
}
default: throw std::runtime_error("unexpected operator");
}
}
thing_p operator>=(const thing_p& lhs, const thing_p& rhs) {
switch (thing_type_pair(lhs->m_type, rhs->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
auto res = std::make_shared<thing>(lhs->m_context, thing_t::Int32);
res->int32() = static_cast<std::int32_t>(lhs->int32() >= rhs->int32());
return res;
}
default: throw std::runtime_error("unexpected operator");
}
}
thing_p thing::clone(const thing_p& thing) {
thing_id 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_id idx = id & ((1ULL << ((sizeof(id) * 8) - GENERATION_SIZE)) - 1);
auto th = std::make_shared<class thing>(thing->m_context, thing->m_type);
switch (thing->m_type) {
// Primitives // Primitives
default: { default: {
memcpy(th->m_data, thing->m_data, thing_type_size(thing->m_type)); 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);
} }
@@ -231,6 +102,127 @@ const std::int32_t& thing::int32() const {
return *static_cast<std::int32_t*>(m_data); return *static_cast<std::int32_t*>(m_data);
} }
thing_h thing::add(const context_p& context, const thing_h& rhs) const {
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
thing_h res = context->emplace_thing(thing_t::Int32);
(*res)->int32() = int32() + (*rhs)->int32();
return res;
}
default: throw std::runtime_error("unreachable");
}
}
thing_h thing::sub(const context_p& context, const thing_h& rhs) const {
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
thing_h res = context->emplace_thing(thing_t::Int32);
(*res)->int32() = int32() - (*rhs)->int32();
return res;
}
default: throw std::runtime_error("unreachable");
}
}
thing_h thing::mul(const context_p& context, const thing_h& rhs) const {
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
thing_h res = context->emplace_thing(thing_t::Int32);
(*res)->int32() = int32() * (*rhs)->int32();
return res;
}
default: throw std::runtime_error("unreachable");
}
}
thing_h thing::div(const context_p& context, const thing_h& rhs) const {
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
thing_h res = context->emplace_thing(thing_t::Int32);
(*res)->int32() = int32() / (*rhs)->int32();
return res;
}
default: throw std::runtime_error("unreachable");
}
}
thing_h thing::mod(const context_p& context, const thing_h& rhs) const {
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
thing_h res = context->emplace_thing(thing_t::Int32);
(*res)->int32() = int32() % (*rhs)->int32();
return res;
}
default: throw std::runtime_error("unreachable");
}
}
thing_h thing::equals(const context_p& context, const thing_h& rhs) const {
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
thing_h res = context->emplace_thing(thing_t::Int32);
(*res)->int32() = static_cast<std::int32_t>(int32() == (*rhs)->int32());
return res;
}
default: throw std::runtime_error("unreachable");
}
}
thing_h thing::not_equals(const context_p& context, const thing_h& rhs) const {
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
thing_h res = context->emplace_thing(thing_t::Int32);
(*res)->int32() = static_cast<std::int32_t>(int32() != (*rhs)->int32());
return res;
}
default: throw std::runtime_error("unreachable");
}
}
thing_h thing::less_than(const context_p& context, const thing_h& rhs) const {
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
thing_h res = context->emplace_thing(thing_t::Int32);
(*res)->int32() = static_cast<std::int32_t>(int32() < (*rhs)->int32());
return res;
}
default: throw std::runtime_error("unreachable");
}
}
thing_h thing::greater_than(const context_p& context, const thing_h& rhs) const {
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
thing_h res = context->emplace_thing(thing_t::Int32);
(*res)->int32() = static_cast<std::int32_t>(int32() > (*rhs)->int32());
return res;
}
default: throw std::runtime_error("unreachable");
}
}
thing_h thing::less_equals(const context_p& context, const thing_h& rhs) const {
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
thing_h res = context->emplace_thing(thing_t::Int32);
(*res)->int32() = static_cast<std::int32_t>(int32() <= (*rhs)->int32());
return res;
}
default: throw std::runtime_error("unreachable");
}
}
thing_h thing::greater_equals(const context_p& context, const thing_h& rhs) const {
switch (thing_type_pair(m_type, (*rhs)->m_type)) {
case thing_type_pair(thing_t::Int32, thing_t::Int32): {
thing_h res = context->emplace_thing(thing_t::Int32);
(*res)->int32() = static_cast<std::int32_t>(int32() >= (*rhs)->int32());
return res;
}
default: throw std::runtime_error("unreachable");
}
}
} // namespace furvm } // namespace furvm
// NOLINTEND(cppcoreguidelines-no-malloc) // NOLINTEND(cppcoreguidelines-no-malloc)