diff --git a/furvm/include/furvm/context.hpp b/furvm/include/furvm/context.hpp index 436ff35..f2e9298 100644 --- a/furvm/include/furvm/context.hpp +++ b/furvm/include/furvm/context.hpp @@ -5,7 +5,9 @@ #include "furvm/executor.hpp" #include "furvm/fwd.hpp" #include "furvm/module.hpp" +#include "furvm/thing.hpp" +#include #include #include #include @@ -102,6 +104,31 @@ public: * @brief Removes unreferenced things from the thing list. */ 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(*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(sizeof(thing_t) + size); + memcpy(data, &type, sizeof(type)); + data = static_cast(data) + sizeof(type); + + thing_p thing = std::make_shared(type, data); + return { id, m_things.emplace_back(std::move(thing)) }; + } private: std::unordered_map m_modules; diff --git a/furvm/include/furvm/executor.hpp b/furvm/include/furvm/executor.hpp index 24436fe..b550789 100644 --- a/furvm/include/furvm/executor.hpp +++ b/furvm/include/furvm/executor.hpp @@ -37,7 +37,7 @@ public: 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::vector variables; /**< Frame variables. */ + std::vector variables; /**< Frame variables. */ }; public: /** @@ -104,28 +104,28 @@ public: * * @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. * * @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. * * @return The popped thing. */ - thing_p pop_thing(); + thing_h pop_thing(); /** * @brief Returns the top thing on the stack. * * @return The thing. */ - thing_p thing() const; + thing_h thing() const; public: /** * @brief Stores a thing in a variable. @@ -133,7 +133,7 @@ public: * @param variable Variable to store the thing in. * @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. @@ -141,7 +141,7 @@ public: * @param variable Variable to store the thing in. * @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. @@ -149,7 +149,7 @@ public: * @param variable Variable where the thing is stored. * @return The thing stored in the variable. */ - thing_p load_thing(variable_t variable) const; + thing_h load_thing(variable_t variable) const; public: /** * @brief Executes next instruction. @@ -160,7 +160,7 @@ private: context_p m_context; std::stack m_frames; - std::stack m_stack; + std::stack m_stack; }; } // namespace furvm diff --git a/furvm/include/furvm/fwd.hpp b/furvm/include/furvm/fwd.hpp index e5afc2c..d947449 100644 --- a/furvm/include/furvm/fwd.hpp +++ b/furvm/include/furvm/fwd.hpp @@ -151,7 +151,7 @@ using thing_id = std::uint32_t; /** * @brief A handle to a furvm's thing. */ -using thing_h = handle; +using thing_h = handle; // executor.hpp diff --git a/furvm/include/furvm/handle.hpp b/furvm/include/furvm/handle.hpp index c1f3503..7f10bfc 100644 --- a/furvm/include/furvm/handle.hpp +++ b/furvm/include/furvm/handle.hpp @@ -1,10 +1,26 @@ #ifndef FURVM_HANDLE_HPP #define FURVM_HANDLE_HPP +#include +#include #include namespace furvm { +namespace detail { + +template +struct dead_id { + static constexpr Id value = {}; +}; + +template +struct dead_id>> { + static constexpr Id value = std::numeric_limits::max(); +}; + +} // namespace detail + template class handle { public: @@ -25,6 +41,9 @@ public: template handle(IdF&& id, Value&& value) : m_id(std::forward(id)), m_value(std::forward(value)) {} + + handle() + : m_id(detail::dead_id::value), m_value() {} public: handle& operator=(value_type&& value) noexcept { m_value = std::move(value); diff --git a/furvm/include/furvm/thing.hpp b/furvm/include/furvm/thing.hpp index d85c5fc..1320a0c 100644 --- a/furvm/include/furvm/thing.hpp +++ b/furvm/include/furvm/thing.hpp @@ -1,7 +1,6 @@ #ifndef FURVM_THING_HPP #define FURVM_THING_HPP -#include "furvm/context.hpp" // IWYU pragma: keep #include "furvm/fwd.hpp" namespace furvm { @@ -58,7 +57,9 @@ public: static constexpr thing_id GENERATION_SIZE = 12; /**< Bit size of generation part in thing_handle. */ public: - thing(const context_p& context, thing_t type); + thing(thing_t type); + + thing(thing_t type, void* data); ~thing(); @@ -74,104 +75,6 @@ public: thing(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: /** * @brief Returns a clone of the thing. @@ -179,7 +82,7 @@ public: * @param thing Thing to clone. * @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: /** * @brief Returns an int32 value from this thing. @@ -194,6 +97,18 @@ public: * @return The value. */ 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: /** * @brief Increments reference count of this thing by one. @@ -212,11 +127,10 @@ public: */ constexpr nref_t reference_count() const { return m_refCount; } private: - context_p m_context; - thing_t m_type; - - nref_t m_refCount = 0; - void* m_data = nullptr; + thing_t m_type; + bool m_ownData = true; + nref_t m_refCount = 0; + void* m_data = nullptr; }; } // namespace furvm diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index 4feb333..2f7cf63 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -8,7 +8,6 @@ #include "furvm/thing.hpp" #include -#include #include namespace furvm { @@ -29,50 +28,50 @@ struct executor::frame executor::frame() const { return m_frames.top(); } -void executor::push_thing(const thing_p& thing) { - thing->add_reference(); +void executor::push_thing(const thing_h& thing) { + (*thing)->add_reference(); m_stack.push(thing); } -void executor::push_thing(thing_p&& thing) { - thing->add_reference(); +void executor::push_thing(thing_h&& thing) { + (*thing)->add_reference(); 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(); - thing_p top = std::move(m_stack.top()); + thing_h top = std::move(m_stack.top()); m_stack.pop(); - top->remove_reference(); + (*top)->remove_reference(); return top; } -thing_p executor::thing() const { +thing_h executor::thing() const { if (m_frames.top().stackBase >= m_stack.size()) throw stack_underflow(); 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(); frame.variables.resize(variable + 1); - if (frame.variables[variable] != nullptr) { - frame.variables[variable]->remove_reference(); + if (*frame.variables[variable] != nullptr) { + (*frame.variables[variable])->remove_reference(); } 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(); frame.variables.resize(variable + 1); - if (frame.variables[variable] != nullptr) { - frame.variables[variable]->remove_reference(); + if ((*frame.variables[variable]) != nullptr) { + (*frame.variables[variable])->remove_reference(); } - thing->add_reference(); + (*thing)->add_reference(); 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(); return frame.variables[variable]; } @@ -86,8 +85,8 @@ void executor::step() { switch (instr) { case instruction_t::NoOperation: break; case instruction_t::PushB2I: { - auto thing = std::make_shared(m_context, thing_t::Int32); - thing->int32() = (*frame.mod)->byte(frame.position++); + auto thing = m_context->emplace_thing(thing_t::Int32); + (*thing)->int32() = (*frame.mod)->byte(frame.position++); push_thing(std::move(thing)); } break; case instruction_t::Drop: { @@ -97,62 +96,62 @@ void executor::step() { push_thing(thing()); } break; case instruction_t::Clone: { - push_thing(std::move(thing::clone(thing()))); + push_thing(std::move(thing::clone(m_context, thing()))); } break; case instruction_t::Add: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs + rhs); + push_thing((*lhs)->add(m_context, rhs)); } break; case instruction_t::Sub: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs - rhs); + push_thing((*lhs)->sub(m_context, rhs)); } break; case instruction_t::Mul: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs * rhs); + push_thing((*lhs)->mul(m_context, rhs)); } break; case instruction_t::Div: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs / rhs); + push_thing((*lhs)->div(m_context, rhs)); } break; case instruction_t::Mod: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs % rhs); + push_thing((*lhs)->mod(m_context, rhs)); } break; case instruction_t::Equals: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs == rhs); + push_thing((*lhs)->equals(m_context, rhs)); } break; case instruction_t::NotEquals: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs != rhs); + push_thing((*lhs)->not_equals(m_context, rhs)); } break; case instruction_t::LessThan: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs < rhs); + push_thing((*lhs)->less_than(m_context, rhs)); } break; case instruction_t::GreaterThan: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs > rhs); + push_thing((*lhs)->greater_than(m_context, rhs)); } break; case instruction_t::LessEqual: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs <= rhs); + push_thing((*lhs)->less_equals(m_context, rhs)); } break; case instruction_t::GreaterEqual: { auto rhs = pop_thing(); auto lhs = pop_thing(); - push_thing(lhs >= rhs); + push_thing((*lhs)->greater_equals(m_context, rhs)); } break; case instruction_t::Load: { variable_t variable = static_cast((*frame.mod)->byte(frame.position)) | @@ -188,7 +187,7 @@ void executor::step() { case instruction_t::JumpNotZero: { byte offset = (*frame.mod)->byte(frame.position++); auto cond = pop_thing(); - if (cond->int32() != 0) frame.position += offset; + if ((*cond)->int32() != 0) frame.position += offset; } break; case instruction_t::Return: { pop_frame(); diff --git a/furvm/src/thing.cpp b/furvm/src/thing.cpp index 75cae45..8cd4f80 100644 --- a/furvm/src/thing.cpp +++ b/furvm/src/thing.cpp @@ -17,23 +17,10 @@ std::size_t thing_type_size(thing_t type) { return 0; } -thing::thing(const context_p& context, thing_t type) - : m_context(context), m_type(type) { +thing::thing(thing_t type) + : m_type(type) { std::size_t size = thing_type_size(type); - std::byte* data = nullptr; - 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(*it) - sizeof(itType), sizeof(itType)); - if (size == thing_type_size(itType)) { - data = static_cast(*it); - m_context->m_deadThingData.erase(std::next(it).base()); - break; - } - } - } - if (data == nullptr) data = m_context->m_thingArena.allocate(sizeof(type) + size); - + byte* data = new byte[size]; if (data == nullptr) throw std::runtime_error("failed to allocate data for new thing"); std::memcpy(data, &type, 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(data) + sizeof(type); + + switch (m_type) { + // Primitives are zero-initialized. + default: + case thing_t::Int32: std::memset(m_data, 0, size); + } +} + thing::~thing() { switch (m_type) { // Primitives are not destructed. @@ -52,19 +53,19 @@ thing::~thing() { case thing_t::Int32: break; } - m_context->m_deadThingData.push_back(m_data); + if (m_ownData) delete[] static_cast(m_data); } 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_ownData = false; other.m_refCount = {}; other.m_data = nullptr; } thing& thing::operator=(thing&& other) noexcept { if (this == &other) return *this; - m_context = std::move(other.m_context); m_type = other.m_type; m_refCount = other.m_refCount; 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(lhs) << 8) | static_cast(rhs); } -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(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(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(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(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(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(lhs->m_context, thing_t::Int32); - res->int32() = static_cast(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(lhs->m_context, thing_t::Int32); - res->int32() = static_cast(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(lhs->m_context, thing_t::Int32); - res->int32() = static_cast(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(lhs->m_context, thing_t::Int32); - res->int32() = static_cast(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(lhs->m_context, thing_t::Int32); - res->int32() = static_cast(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(lhs->m_context, thing_t::Int32); - res->int32() = static_cast(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(thing->m_context, thing->m_type); - switch (thing->m_type) { +thing_h thing::clone(const context_p& context, const thing_h& thing) { + auto th = context->emplace_thing((*thing)->m_type); + switch ((*thing)->m_type) { // Primitives 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); } @@ -231,6 +102,127 @@ const std::int32_t& thing::int32() const { return *static_cast(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(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(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(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(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(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(int32() >= (*rhs)->int32()); + return res; + } + default: throw std::runtime_error("unreachable"); + } +} + } // namespace furvm // NOLINTEND(cppcoreguidelines-no-malloc)