refactor: replace type_p with type_ref in thing
Damn, this was such a great call. Closes: #46
This commit is contained in:
@@ -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);
|
||||
@@ -94,15 +85,16 @@ public:
|
||||
* @return A clone of this thing.
|
||||
*/
|
||||
thing clone() const {
|
||||
auto type = resolve_type(m_type, m_modules);
|
||||
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;
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user