refactor: replace type_p with type_ref in thing

Damn, this was such a great call.

Closes: #46
This commit is contained in:
2026-07-07 19:29:30 +02:00
parent 2519560451
commit 7de645d323
5 changed files with 76 additions and 94 deletions
+41 -57
View File
@@ -28,19 +28,10 @@ public:
/**
* @brief Constructs a thing.
*
* @param type Thing type.
* @param type Thing type reference.
* @param allocator Allocator for the thing's data.
*/
thing(const type& type, const mod_container& modules = nullptr, const allocator_type& allocator = {})
: thing(std::make_shared<class type>(type), modules, allocator) {}
/**
* @brief Constructs a thing.
*
* @param type Thing type.
* @param allocator Allocator for the thing's data.
*/
thing(const type_p& type, const mod_container& modules = nullptr, const allocator_type& allocator = {})
thing(const type_ref& type, const mod_container& modules = nullptr, const allocator_type& allocator = {})
: m_type(type), m_size(compute_size(resolve_type(type, modules))), m_modules(modules), m_allocator(allocator) {
// TODO: Account for alignment
m_data = m_allocator.allocate(m_size);
@@ -95,14 +86,15 @@ public:
*/
thing clone() const {
auto type = resolve_type(m_type, m_modules);
if (m_size == 0) {
return reference();
}
thing res(type, m_modules, m_allocator);
switch (type->t) {
case type_t::Primitive:
case type_t::Reference: {
std::memcpy(res.m_data, m_data, m_size);
} break;
case type_t::Array: {
copy_list(type, res.get<array_t>(), get<array_t>());
copy_list(*type.type, res.get<array_t>(), get<array_t>());
} break;
case type_t::Import:
default: throw std::runtime_error("unreachable");
@@ -111,18 +103,18 @@ public:
}
public:
/**
* @brief Returns the thing's type.
* @brief Returns the thing's type reference.
*
* @return The type.
*/
constexpr auto type() const { return *m_type; }
/**
* @brief Returns the thing's type.
*
* @return The shared pointer to the type.
* @return The type reference.
*/
auto type() { return m_type; }
/**
* @brief Returns the thing's type reference.
*
* @return The type reference.
*/
constexpr auto type() const { return m_type; }
public:
/**
* @brief Returns a raw data pointer.
@@ -266,18 +258,9 @@ public:
}
}
thing reference() const {
thing res = { std::make_shared<class type>(m_type), m_modules, m_allocator };
res.get<reference_t>() = m_data;
return std::move(res);
}
thing reference() const { return { m_type, m_data, m_modules, m_allocator }; }
thing resolve() const {
thing rsv = { resolve_type(m_type, m_modules), m_data, m_allocator };
while (rsv.type()->t == type_t::Reference)
rsv = { rsv.m_type->reference, rsv.get<reference_t>(), std::move(rsv.m_allocator) };
return rsv;
}
constexpr bool is_reference() const { return m_size == 0; }
void resize(long_t newSize) {
if (m_type->t != type_t::Array) throw bad_thing_access();
@@ -297,18 +280,18 @@ public:
if (m_type->t != type_t::Array) throw bad_thing_access();
std::size_t elementSize = compute_size_na(*m_type->array.type);
thing res = { std::make_shared<class type>(*m_type->array.type), m_modules, m_allocator };
if (m_type->array.size == 0) {
auto& array = get<array_t>();
if (index < 0 || index >= array.dynamic.size) throw std::out_of_range("index out of range");
res.get<reference_t>() = array.dynamic.data + (index * elementSize);
return std::move(res);
return { { m_type.mod, m_type->array.type },
array.dynamic.data + (index * elementSize),
m_modules,
m_allocator };
}
std::byte* data = reinterpret_cast<array_t*>(m_data)->data;
if (index < 0 || index >= m_type->array.size) throw std::out_of_range("index out of range");
res.get<reference_t>() = data + (index * elementSize);
return std::move(res);
return { { m_type.mod, m_type->array.type }, data + (index * elementSize), m_modules, m_allocator };
}
std::size_t size() const {
@@ -317,10 +300,12 @@ public:
return m_type->array.size;
}
public:
static type_p resolve_type(const type_p& initType, const mod_container& modules) {
type_p rsv = initType;
while (rsv->t == type_t::Import)
rsv = *modules->at(initType->imp.mod)->type_at(initType->imp.type);
static type_ref resolve_type(const type_ref& initType, const mod_container& modules) {
type_ref rsv = initType;
while (rsv->t == type_t::Import) {
auto mod = modules->at(initType->imp.mod);
rsv = type_ref{ mod, mod->type_at(initType->imp.type) };
}
return rsv;
}
private:
@@ -350,8 +335,7 @@ private:
}
switch (innerType->t) {
case type_t::Primitive:
case type_t::Reference: std::memcpy(dst.data, src.data, size); break;
case type_t::Primitive: std::memcpy(dst.data, src.data, size); break;
case type_t::Array:
for (std::size_t i = 0; i < size; ++i) {
copy_list(*innerType->array.type,
@@ -366,7 +350,6 @@ private:
static std::size_t compute_size_na(const type_p& type) {
switch (type->t) {
case type_t::Primitive: return type->primitive;
case type_t::Reference: return sizeof(reference_t);
case type_t::Array: {
if (type->array.size == 0) return sizeof(array_t);
return compute_size_na(*type->array.type) * type->array.size;
@@ -377,23 +360,24 @@ private:
throw std::runtime_error("unreachable");
}
static std::size_t compute_size_na(const type_ref& type) { return compute_size_na(*type.type); }
// NOTE: Align to 4 bytes
static std::size_t compute_size(const type_p& type) { return (compute_size_na(type) + 3) & ~3; }
static std::size_t compute_size(const type_ref& type) { return compute_size(*type.type); }
private:
thing(const type_p& type, std::byte* data, const allocator_type& allocator = {})
: m_type(type), m_size(0), m_data(data), m_allocator(allocator) {}
thing(const type_ref& type, std::byte* data, const mod_container& modules, const allocator_type& allocator = {})
: m_type(type), m_size(0), m_data(data), m_modules(modules), m_allocator(allocator) {}
private:
template <typename Op>
thing binary_op(const thing& rhs, const Op& op) const {
const thing lhsRsv = resolve();
const thing rhsRsv = rhs.resolve();
if (m_type->t == type_t::Primitive && rhs.type()->t == type_t::Primitive) {
type_ref type = m_type->primitive >= rhs.type()->primitive ? m_type : rhs.type();
std::size_t size = std::max(m_type->primitive, rhs.type()->primitive);
if (lhsRsv.type().t == type_t::Primitive && rhsRsv.type().t == type_t::Primitive) {
std::size_t size = std::max(lhsRsv.type().primitive, rhsRsv.type().primitive);
long_t result = op(integer(), rhs.integer());
long_t result = op(lhsRsv.integer(), rhsRsv.integer());
thing res({ size }, m_modules, m_allocator);
thing res(type, m_modules, m_allocator);
switch (size) {
case sizeof(byte_t): res.get<byte_t>() = result; break;
case sizeof(short_t): res.get<short_t>() = result; break;
@@ -407,7 +391,7 @@ private:
throw std::runtime_error("unexpected operation");
}
private:
type_p m_type;
type_ref m_type;
std::size_t m_size;
std::byte* m_data;
+13 -15
View File
@@ -10,14 +10,12 @@ namespace furvm {
enum class type_t : std::uint32_t {
Primitive = 0,
Reference,
Array,
Import,
};
using primitive_type = std::uint64_t;
using reference_type = type_p;
/**
* @brief Array type.
@@ -41,21 +39,17 @@ struct import_type {
struct type {
type_t t;
union {
primitive_type primitive;
reference_type reference;
primitive_type primitive{};
array_type array;
import_type imp;
};
type(type_t type)
: t(type), primitive(0) {}
: t(type) {}
type(primitive_type primitive)
: t(type_t::Primitive), primitive(primitive) {}
type(const reference_type& reference)
: t(type_t::Reference), reference(reference) {}
type(const type_h& type, std::size_t size = 0)
: t(type_t::Array), array(array_type{ type, size }) {}
@@ -67,7 +61,6 @@ struct type {
~type() {
switch (t) {
case type_t::Reference: reference.~reference_type(); break;
case type_t::Array: array.~array_type(); break;
case type_t::Import: imp.~import_type(); break;
default: break;
@@ -78,7 +71,6 @@ struct type {
: t(other.t) {
switch (t) {
case type_t::Primitive: primitive = other.primitive; break;
case type_t::Reference: reference = std::move(other.reference); break;
case type_t::Array: array = std::move(other.array); break;
case type_t::Import: imp = std::move(other.imp); break;
}
@@ -89,7 +81,6 @@ struct type {
t = other.t;
switch (t) {
case type_t::Primitive: primitive = other.primitive; break;
case type_t::Reference: reference = std::move(other.reference); break;
case type_t::Array: array = std::move(other.array); break;
case type_t::Import: imp = std::move(other.imp); break;
}
@@ -101,7 +92,6 @@ struct type {
: t(other.t) {
switch (t) {
case type_t::Primitive: primitive = other.primitive; break;
case type_t::Reference: reference = other.reference; break;
case type_t::Array: array = other.array; break;
case type_t::Import: imp = other.imp; break;
}
@@ -112,7 +102,6 @@ struct type {
t = other.t;
switch (t) {
case type_t::Primitive: primitive = other.primitive; break;
case type_t::Reference: reference = other.reference; break;
case type_t::Array: array = other.array; break;
case type_t::Import: imp = other.imp; break;
}
@@ -126,8 +115,6 @@ using short_t = std::int16_t; /**< A 2-byte integer. */
using int_t = std::int32_t; /**< A 4-byte integer. */
using long_t = std::int64_t; /**< An 8-byte integer. */
using reference_t = std::byte*;
/**
* @brief Array type's data layout.
*/
@@ -159,6 +146,17 @@ inline static type intType = { sizeof(int_t) }; // NOLINT
*/
inline static type longType = { sizeof(long_t) }; // NOLINT
/**
* @brief Reference to a type.
*/
struct type_ref {
mod_h mod;
type_h type;
class type* operator->() { return &**type; }
const class type* operator->() const { return &**type; }
};
} // namespace furvm
#endif // FURVM_TYPE_HPP
+16 -14
View File
@@ -83,6 +83,10 @@ thing_h executor::load_thing(variable_t variable) const {
return frame.variables[variable];
}
static type_ref get_type_ref(const mod_h& mod, type_id id) {
return { mod, mod->type_at(id) };
}
void executor::step() {
if ((m_flags & executor_flags::Suspended) == executor_flags::Suspended) return;
@@ -92,7 +96,7 @@ void executor::step() {
switch (instr) {
case instruction_t::NoOperation: break;
case instruction_t::PushB2I: {
push_thing({ *m_context->at("core")->type_at(2), m_context, m_context->thing_alloc() })->get<int_t>() =
push_thing({ get_type_ref(m_context->at("core"), 2), m_context, m_context->thing_alloc() })->get<int_t>() =
frame.mod->byte(frame.position++);
} break;
case instruction_t::Array: {
@@ -102,8 +106,8 @@ void executor::step() {
(static_cast<type_id>(frame.mod->byte(frame.position + 3)) << 24);
frame.position += 4;
auto type = furvm::thing<>::resolve_type(*frame.mod->type_at(typeId), m_context);
if (type == nullptr || type->t != type_t::Array || *type->array.type == nullptr)
auto type = furvm::thing<>::resolve_type(get_type_ref(frame.mod, typeId), m_context);
if (*type.type == nullptr || type->t != type_t::Array || *type->array.type == nullptr)
throw std::runtime_error("invalid array type");
auto array = push_thing({ type, m_context, m_context->thing_alloc() });
@@ -190,29 +194,27 @@ void executor::step() {
push_thing(lhs->greater_equals(*rhs));
} break;
case instruction_t::Pointerof: {
auto thing = pop_thing()->resolve();
auto ptr = push_thing({ *m_context->at("core")->type_at(4), m_context, m_context->thing_alloc() });
switch (furvm::thing<>::resolve_type(thing.type(), m_context)->t) {
case type_t::Primitive: ptr->get<std::uintptr_t>() = reinterpret_cast<std::uintptr_t>(thing.raw()); break;
auto thing = pop_thing();
auto ptr = push_thing({ get_type_ref(m_context->at("core"), 4), m_context, m_context->thing_alloc() });
switch (furvm::thing<>::resolve_type(thing->type(), m_context)->t) {
case type_t::Primitive: ptr->get<std::uintptr_t>() = reinterpret_cast<std::uintptr_t>(thing->raw()); break;
case type_t::Array:
ptr->get<std::uintptr_t>() = reinterpret_cast<std::uintptr_t>(thing.get<array_t>().data);
ptr->get<std::uintptr_t>() = reinterpret_cast<std::uintptr_t>(thing->get<array_t>().data);
break;
case type_t::Reference:
case type_t::Import:
default: throw std::runtime_error("unreachable");
}
} break;
case instruction_t::Sizeof: {
auto thing = pop_thing()->resolve();
auto size = push_thing({ *m_context->at("core")->type_at(3), m_context, m_context->thing_alloc() });
auto type = furvm::thing<>::resolve_type(thing.type(), m_context);
auto thing = pop_thing();
auto size = push_thing({ get_type_ref(m_context->at("core"), 3), m_context, m_context->thing_alloc() });
auto type = furvm::thing<>::resolve_type(thing->type(), m_context);
switch (type->t) {
case type_t::Primitive: size->get<long_t>() = static_cast<long_t>(type->primitive); break;
case type_t::Array:
size->get<long_t>() =
(type->array.size == 0) ? thing.get<array_t>().dynamic.size : static_cast<long_t>(type->array.size);
(type->array.size == 0) ? thing->get<array_t>().dynamic.size : static_cast<long_t>(type->array.size);
break;
case type_t::Reference:
case type_t::Import:
default: throw std::runtime_error("unreachable");
}
+5 -5
View File
@@ -11,16 +11,15 @@
#include <sstream>
static void print_thing(const furvm::thing<furvm::thing_allocator>& thing) {
auto rsv = thing.resolve();
switch (rsv.type()->t) {
switch (thing.type()->t) {
case furvm::type_t::Primitive: {
std::cout << rsv.integer();
std::cout << thing.integer();
} break;
case furvm::type_t::Array: {
std::cout << "{ ";
for (furvm::long_t i = 0; i < rsv.size(); ++i) {
for (furvm::long_t i = 0; i < thing.size(); ++i) {
if (i > 0) std::cout << ", ";
print_thing(rsv.at(i));
print_thing(thing.at(i));
}
std::cout << " }\n";
} break;
@@ -52,6 +51,7 @@ int main(int argc, char** argv) {
0,
0,
0,
static_cast<furvm::byte>(furvm::instruction_t::Reference),
static_cast<furvm::byte>(furvm::instruction_t::Call),
1,
0,
-2
View File
@@ -56,7 +56,6 @@ std::ostream& mod::serialize(std::ostream& os) const {
auto type = *m_types.at(id);
switch (type->t) {
case type_t::Primitive: detail::serialize(os, type->primitive); break;
case type_t::Reference: throw std::runtime_error("reference type serialization is unimplemented");
case type_t::Array: {
detail::serialize(os, type->array.size);
detail::serialize(os, type->array.type.id());
@@ -134,7 +133,6 @@ mod mod::load(std::istream& is) {
detail::load(is, primitive);
mod.emplace_type(id, std::make_shared<class type>(primitive)).dispatch();
} break;
case type_t::Reference: throw std::runtime_error("reference type serialization is unimplemented");
case type_t::Array: {
std::size_t size = 0;
detail::load(is, size);