Compare commits

..

5 Commits

Author SHA1 Message Date
CHatingPython 9549a7b61a docs(furvm): document the thing
Refs: #12
2026-06-21 20:40:31 +02:00
CHatingPython 51483db283 docs(furvm): document the function
Refs: #12
2026-06-21 20:17:07 +02:00
CHatingPython 3759c0361f docs(furvm): document the handle 2026-06-21 20:08:41 +02:00
CHatingPython 1ead2f6592 docs(furvm): document the function
Refs: #12
2026-06-21 19:45:59 +02:00
CHatingPython b6d3387388 docs(furvm): document the executor
Refs: #12
2026-06-21 19:40:33 +02:00
6 changed files with 431 additions and 73 deletions
+22 -14
View File
@@ -36,7 +36,7 @@ public:
* Call frame. * Call frame.
*/ */
struct frame { struct frame {
mod_h mod; /**< Shared pointer to a module with the bytecode. */ mod_h mod; /**< Handle to the frame's module. */
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. */
@@ -83,8 +83,8 @@ public:
/** /**
* @brief Pushes a new frame. * @brief Pushes a new frame.
* *
* @param mod Module. * @param mod Handle to the frame's module.
* @param function Function handle. * @param function Frame's function.
*/ */
void push_frame(const mod_h& mod, function function); void push_frame(const mod_h& mod, function function);
@@ -102,6 +102,11 @@ public:
*/ */
frame frame() const; frame frame() const;
public: public:
/**
* @brief Pushes a thing handle onto the stack.
*
* @param handle Thing handle.
*/
template <typename HandleFwd> template <typename HandleFwd>
void push_thing(HandleFwd&& handle) { void push_thing(HandleFwd&& handle) {
m_stack.emplace(std::forward<HandleFwd>(handle)); m_stack.emplace(std::forward<HandleFwd>(handle));
@@ -110,45 +115,48 @@ public:
/** /**
* @brief Pushes a thing onto the stack. * @brief Pushes a thing onto the stack.
* *
* @param thing The thing to push. * Registers a new thing and pushes its handle onto the stack.
*
* @param thing Thing.
* @return The pushed handle.
*/ */
thing_h push_thing(class thing<>&& thing); thing_h push_thing(class thing<>&& thing);
/** /**
* @brief Pops a thing from the stack. * @brief Pops a thing from the stack.
* *
* @return The popped thing. * @return A handle to the popped thing.
*/ */
thing_h 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 A handle to the top thing.
*/ */
thing_h thing() const; thing_h thing() const;
public: public:
/** /**
* @brief Stores a thing in a variable. * @brief Stores a thing in a frame variable.
* *
* @param variable Variable to store the thing in. * @param variable Id of the variable in which the handle will be put.
* @param thing Thing to store. * @param thing Thing handle.
*/ */
void store_thing(variable_t variable, const thing_h& thing); void store_thing(variable_t variable, const thing_h& thing);
/** /**
* @brief Stores a thing in a variable. * @brief Stores a thing in a frame variable.
* *
* @param variable Variable to store the thing in. * @param variable Id of the variable in which the handle will be put.
* @param thing Thing to store. * @param thing Thing handle.
*/ */
void store_thing(variable_t variable, thing_h&& 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.
* *
* @param variable Variable where the thing is stored. * @param variable Id of the variable from which the handle will be fetched.
* @return The thing stored in the variable. * @return A handle stored in the variable.
*/ */
thing_h load_thing(variable_t variable) const; thing_h load_thing(variable_t variable) const;
public: public:
+30 -3
View File
@@ -16,8 +16,14 @@ enum class function_t : std::uint8_t {
Import, /**< A function imported from another module. */ Import, /**< A function imported from another module. */
}; };
/**
* @brief A native function.
*/
using native_function = std::function<void(executor&)>; using native_function = std::function<void(executor&)>;
/**
* @brief A function import.
*/
struct import_function { struct import_function {
mod_id mod; mod_id mod;
function_id function; function_id function;
@@ -25,18 +31,39 @@ struct import_function {
class function { class function {
public: public:
/**
* @brief Constructs a normal function.
*
* @param name Name of the function.
* @param position Offset in bytecode of the function.
*/
template <typename Name> template <typename Name>
function(Name&& name, bytecode_pos position) function(Name&& name, bytecode_pos position)
: m_name(std::forward<Name>(name)), m_type(function_t::Normal), m_value(position) {} : m_name(std::forward<Name>(name)), m_type(function_t::Normal), m_value(position) {}
/**
* @brief Constructs a native function.
*
* @param name Name of the function.
* @param native Native function.
*/
template <typename Name> template <typename Name>
function(Name&& name, const native_function& native) function(Name&& name, const native_function& native)
: m_name(std::forward<Name>(name)), m_type(function_t::Native), m_value(native) {} : m_name(std::forward<Name>(name)), m_type(function_t::Native), m_value(native) {}
/**
* @brief Constructs an import function.
*
* @param name Name of the function.
* @param imp Import function.
*/
template <typename Name> template <typename Name>
function(Name&& name, const import_function& imp) function(Name&& name, const import_function& imp)
: m_name(std::forward<Name>(name)), m_type(function_t::Import), m_value(imp) {} : m_name(std::forward<Name>(name)), m_type(function_t::Import), m_value(imp) {}
/**
* @brief Destructs a function.
*/
~function(); ~function();
/** /**
@@ -74,7 +101,7 @@ public:
constexpr function_t type() const { return m_type; } constexpr function_t type() const { return m_type; }
public: public:
/** /**
* @brief Returns a value for normal function. * @brief Returns normal function's value.
* *
* @return The value. * @return The value.
*/ */
@@ -84,7 +111,7 @@ public:
} }
/** /**
* @brief Returns a value for native function. * @brief Returns native function's value.
* *
* @return The value. * @return The value.
*/ */
@@ -94,7 +121,7 @@ public:
} }
/** /**
* @brief Returns a name of the function's module. * @brief Returns import function's value.
* *
* @return The name. * @return The name.
*/ */
+12 -1
View File
@@ -36,11 +36,22 @@ template <typename Id>
class generic_header; class generic_header;
/** /**
* @brief Handle. * @brief Generic furvm object handle.
*
* @tparam Value Type of the handle's value.
* @tparam Header Type of the handle's header.
*/ */
template <typename Value, typename Header> template <typename Value, typename Header>
class handle; class handle;
/**
* @brief Container for the handles.
*
* @tparam Handle Type of the container's handle.
*/
template <typename Handle, typename = void>
class handle_container;
// constant.hpp // constant.hpp
/** /**
+180 -25
View File
@@ -14,30 +14,52 @@
namespace furvm { namespace furvm {
template <typename Handle, typename = void>
class handle_container;
// TODO: Implement generational indexes // TODO: Implement generational indexes
template <typename Id> template <typename Id>
class refcount_header { class refcount_header {
public: public:
using id_type = Id; using id_type = Id; /**< Id type. */
using refcount_type = std::uint32_t; using refcount_type = std::uint32_t; /**< Reference count type. */
public: public:
/**
* @brief Constructs a reference counting header.
*
* @param id Identifier of the handle's value.
* @param refCount Handle's reference count.
* @param onRelease Callback function.
*/
template <typename IdFwd, typename Func> template <typename IdFwd, typename Func>
refcount_header(IdFwd&& id, refcount_type refCount, Func&& onRelease) refcount_header(IdFwd&& id, refcount_type refCount, Func&& onRelease)
: m_id(std::forward<IdFwd>(id)), m_refCount(refCount), m_onRelease(std::forward<Func>(onRelease)) {} : m_id(std::forward<IdFwd>(id)), m_refCount(refCount), m_onRelease(std::forward<Func>(onRelease)) {}
public: public:
/**
* @brief Returns the header's reference count.
*
* @return The reference count.
*/
refcount_type reference_count() const { return m_refCount; } refcount_type reference_count() const { return m_refCount; }
/**
* @brief Increments the header's reference count.
*/
void acquire() { ++m_refCount; } void acquire() { ++m_refCount; }
/**
* @brief Decrements the header's reference count.
*
* If the reference count reaches 0, the onRelease callback passed in the constructor will be called.
*/
void release() { void release() {
--m_refCount; --m_refCount;
if (m_refCount == 0) m_onRelease(m_id); if (m_refCount == 0) m_onRelease(m_id);
} }
public: public:
/**
* @brief Returns the header's identifier.
*
* @return The identifier.
*/
id_type id() const { return m_id; } id_type id() const { return m_id; }
private: private:
id_type m_id; id_type m_id;
@@ -48,11 +70,19 @@ private:
template <typename Id> template <typename Id>
class generic_header { class generic_header {
public: public:
using id_type = Id; using id_type = Id; /**< Id type. */
public: public:
/**
* @brief Constructs a generic header.
*
* @param id Identifier of the handle.
*/
generic_header(id_type id) generic_header(id_type id)
: m_id(id) {} : m_id(id) {}
public: public:
/**
* @brief Returns the header's identifier.
*/
id_type id() const { return m_id; } id_type id() const { return m_id; }
private: private:
id_type m_id; id_type m_id;
@@ -61,18 +91,23 @@ private:
template <typename Value, typename Header = refcount_header<std::uint32_t>> template <typename Value, typename Header = refcount_header<std::uint32_t>>
class handle { class handle {
public: public:
using value_type = Value; using value_type = Value; /** Value type. */
using reference = Value&; using reference = Value&; /** Reference type. */
using const_reference = const Value&; using const_reference = const Value&; /** Constant reference type. */
using pointer = Value*; using pointer = Value*; /** Pointer type. */
using const_pointer = const Value*; using const_pointer = const Value*; /** Constant pointer type. */
public: public:
using id_type = typename Header::id_type; using id_type = typename Header::id_type; /** Id type of the header. */
public: public:
using pair_type = std::pair<Header, Value>; using pair_type = std::pair<Header, Value>; /** Type of a header-value pair. */
public: public:
handle() = default; handle() = default;
/**
* @brief Constructs a handle.
*
* @param value A pointer to the header-value pair.
*/
handle(pair_type* value) handle(pair_type* value)
: m_value(value) { : m_value(value) {
if constexpr (detail::header_has_refcount_v<Header>) { if constexpr (detail::header_has_refcount_v<Header>) {
@@ -80,6 +115,9 @@ public:
} }
} }
/**
* @brief Destructs a handle.
*/
~handle() { ~handle() {
if constexpr (detail::header_has_refcount_v<Header>) { if constexpr (detail::header_has_refcount_v<Header>) {
if (m_value != nullptr) m_value->first.release(); if (m_value != nullptr) m_value->first.release();
@@ -87,11 +125,17 @@ public:
m_value = nullptr; m_value = nullptr;
} }
/**
* @brief Move constructor.
*/
handle(handle&& other) noexcept handle(handle&& other) noexcept
: m_value(other.m_value) { : m_value(other.m_value) {
other.m_value = nullptr; other.m_value = nullptr;
} }
/**
* @brief Move constructor.
*/
handle& operator=(handle&& other) noexcept { handle& operator=(handle&& other) noexcept {
if (this == &other) return *this; if (this == &other) return *this;
m_value = other.m_value; m_value = other.m_value;
@@ -99,11 +143,17 @@ public:
return *this; return *this;
} }
/**
* @brief Copy constructor.
*/
handle(const handle& other) handle(const handle& other)
: m_value(other.m_value) { : m_value(other.m_value) {
m_value->first.acquire(); m_value->first.acquire();
} }
/**
* @brief Copy constructor.
*/
handle& operator=(const handle& other) { handle& operator=(const handle& other) {
if (this == &other) return *this; if (this == &other) return *this;
m_value = other.m_value; m_value = other.m_value;
@@ -111,22 +161,70 @@ public:
return *this; return *this;
} }
public: public:
/**
* @brief Returns an identifier of the handle's header.
*
* @return The header's identifier.
*/
id_type id() const { return m_value->first.id(); } id_type id() const { return m_value->first.id(); }
/**
* @brief Returns whether the handle is empty.
*
* @return true if the handle is empty.
*/
bool empty() const { return m_value == nullptr; } bool empty() const { return m_value == nullptr; }
/**
* @brief Returns the handle's header reference count.
*
* @return The reference count.
*/
template <typename ReferenceCount = typename Header::refcount_type> template <typename ReferenceCount = typename Header::refcount_type>
ReferenceCount reference_count() const { ReferenceCount reference_count() const {
return m_value->first.reference_count(); return m_value->first.reference_count();
} }
pointer operator->() { return &m_value->second; } /**
* @brief Returns a pointer to the handle's value.
*
* @return The value pointer.
*/
pointer operator->() { return &m_value->second; }
/**
* @brief Returns a pointer to the handle's value.
*
* @return The value pointer.
*/
const_pointer operator->() const { return &m_value->second; } const_pointer operator->() const { return &m_value->second; }
reference operator*() { return m_value->second; } /**
* @brief Returns a reference to the handle's value.
*
* @return The value reference.
*/
reference operator*() { return m_value->second; }
/**
* @brief Returns a reference to the handle's value.
*
* @return The value reference.
*/
const_reference operator*() const { return m_value->second; } const_reference operator*() const { return m_value->second; }
reference value() { return m_value->second; } /**
* @brief Returns a reference to the handle's value.
*
* @return The value reference.
*/
reference value() { return m_value->second; }
/**
* @brief Returns a reference to the handle's value.
*
* @return The value reference.
*/
const_reference value() const { return m_value->second; } const_reference value() const { return m_value->second; }
private: private:
pair_type* m_value = nullptr; pair_type* m_value = nullptr;
@@ -135,12 +233,12 @@ private:
template <typename Handle> template <typename Handle>
class handle_container<Handle, std::enable_if_t<!std::is_integral_v<typename Handle::id_type>>> { class handle_container<Handle, std::enable_if_t<!std::is_integral_v<typename Handle::id_type>>> {
private: private:
using pair_type = typename Handle::pair_type; using pair_type = typename Handle::pair_type; /**< Handle's pair type. */
public: public:
using value_type = std::remove_cv_t<std::remove_reference_t<Handle>>; using value_type = std::remove_cv_t<std::remove_reference_t<Handle>>; /**< Handle type. */
using const_value = std::add_const_t<value_type>; using const_value = std::add_const_t<value_type>; /**< Constant handle type. */
using id_type = typename Handle::id_type; using id_type = typename Handle::id_type; /**< Handle's header identifier type. */
public: public:
handle_container() = default; handle_container() = default;
~handle_container() = default; ~handle_container() = default;
@@ -151,6 +249,13 @@ public:
handle_container(const handle_container&) = delete; handle_container(const handle_container&) = delete;
handle_container& operator=(const handle_container&) = delete; handle_container& operator=(const handle_container&) = delete;
public: public:
/**
* @brief Emplaces a new value.
*
* @param id Identifier of the emplaced value.
* @param args Arguments passed to the Handle's value type constructor.
* @return A handle to the emplaced value.
*/
template <typename IdFwd, template <typename IdFwd,
typename... Args, typename... Args,
typename = std::enable_if_t<std::is_constructible_v<typename pair_type::second_type, Args...>>> typename = std::enable_if_t<std::is_constructible_v<typename pair_type::second_type, Args...>>>
@@ -164,16 +269,33 @@ public:
return { pair }; return { pair };
} }
/**
* @brief Returns a handle to the container's value.
*
* @param id Idenfifier of the value.
* @return The value.
*/
template <typename IdFwd> template <typename IdFwd>
value_type at(IdFwd&& id) { value_type at(IdFwd&& id) {
return { m_pairs.at(std::forward<IdFwd>(id)) }; return { m_pairs.at(std::forward<IdFwd>(id)) };
} }
/**
* @brief Returns a handle to the container's value.
*
* @param id Idenfifier of the value.
* @return The value.
*/
template <typename IdFwd> template <typename IdFwd>
const_value at(IdFwd&& id) const { const_value at(IdFwd&& id) const {
return { m_pairs.at(std::forward<IdFwd>(id)) }; return { m_pairs.at(std::forward<IdFwd>(id)) };
} }
/**
* @brief Erases a value from the container.
*
* @param id Identifier of the value.
*/
template <typename IdFwd> template <typename IdFwd>
void erase(IdFwd&& id) { void erase(IdFwd&& id) {
auto it = m_pairs.find(std::forward<IdFwd>(id)); auto it = m_pairs.find(std::forward<IdFwd>(id));
@@ -188,12 +310,12 @@ private:
template <typename Handle> template <typename Handle>
class handle_container<Handle, std::enable_if_t<std::is_integral_v<typename Handle::id_type>>> { class handle_container<Handle, std::enable_if_t<std::is_integral_v<typename Handle::id_type>>> {
private: private:
using pair_type = typename Handle::pair_type; using pair_type = typename Handle::pair_type; /**< Handle's pair type. */
public: public:
using value_type = std::remove_cv_t<std::remove_reference_t<Handle>>; using value_type = std::remove_cv_t<std::remove_reference_t<Handle>>; /**< Handle type. */
using const_value = std::add_const_t<value_type>; using const_value = std::add_const_t<value_type>; /**< Constant handle type. */
using id_type = typename Handle::id_type; using id_type = typename Handle::id_type; /**< Handle's header identifier type. */
public: public:
handle_container() = default; handle_container() = default;
~handle_container() = default; ~handle_container() = default;
@@ -204,6 +326,13 @@ public:
handle_container(const handle_container&) = delete; handle_container(const handle_container&) = delete;
handle_container& operator=(const handle_container&) = delete; handle_container& operator=(const handle_container&) = delete;
public: public:
/**
* @brief Emplaces a new value.
*
* @param id Identifier of the emplaced value.
* @param args Arguments passed to the Handle's value type constructor.
* @return A handle to the emplaced value.
*/
template <typename... Args, template <typename... Args,
typename = std::enable_if_t<std::is_constructible_v<typename pair_type::second_type, Args...>>> typename = std::enable_if_t<std::is_constructible_v<typename pair_type::second_type, Args...>>>
value_type emplace(id_type id, Args&&... args) { value_type emplace(id_type id, Args&&... args) {
@@ -221,15 +350,41 @@ public:
return { newPair }; return { newPair };
} }
/**
* @brief Emplaces a new value.
*
* Emplaces a new value with an automatically-assigned identifier.
*
* @param args Arguments passed to the Handle's value type constructor.
* @return A handle to the emplaced value.
*/
template <typename... Args, template <typename... Args,
typename = std::enable_if_t<std::is_constructible_v<typename Handle::pair_type::second_type, Args...>>> typename = std::enable_if_t<std::is_constructible_v<typename Handle::pair_type::second_type, Args...>>>
value_type emplace_back(Args&&... args) { value_type emplace_back(Args&&... args) {
return emplace(static_cast<id_type>(m_pairs.size()), std::forward<Args>(args)...); return emplace(static_cast<id_type>(m_pairs.size()), std::forward<Args>(args)...);
} }
value_type at(id_type id) { return { m_pairs.at(id) }; } /**
* @brief Returns a handle to a value.
*
* @param id Identifier of the value.
* @return The value.
*/
value_type at(id_type id) { return { m_pairs.at(id) }; }
/**
* @brief Returns a handle to a value.
*
* @param id Identifier of the value.
* @return The value.
*/
const_value at(id_type id) const { return { m_pairs.at(id) }; } const_value at(id_type id) const { return { m_pairs.at(id) }; }
/**
* @brief Erases a value from the container.
*
* @param id Identifier of the value.
*/
void erase(id_type id) { void erase(id_type id) {
if (id >= m_pairs.size()) return; if (id >= m_pairs.size()) return;
delete m_pairs[id]; delete m_pairs[id];
+57 -10
View File
@@ -22,10 +22,10 @@ public:
static constexpr char MAGIC[4] = { 'F', 'u', 'r', 'M' }; /** Furvm module file magic. */ static constexpr char MAGIC[4] = { 'F', 'u', 'r', 'M' }; /** Furvm module file magic. */
public: public:
/** /**
* @brief Construct a new module. * @brief Constructs a module.
* *
* @param name Name of this module. * @param name Name of the module.
* @param args Arguments to forward to bytecode's constructor. * @param args Arguments forwarded to bytecode's constructor.
*/ */
template <typename... Args, typename = std::enable_if_t<std::is_constructible_v<bytecode_t, Args...>>> template <typename... Args, typename = std::enable_if_t<std::is_constructible_v<bytecode_t, Args...>>>
mod(Args&&... args) mod(Args&&... args)
@@ -55,19 +55,25 @@ public:
constexpr byte byte(std::size_t offset) const { return m_bytecode.at(offset); } constexpr byte byte(std::size_t offset) const { return m_bytecode.at(offset); }
/** /**
* @brief Returns a reference to the module's bytecode. * @brief Returns the module's bytecode.
* *
* @return The reference to bytecode. * @return A reference to the bytecode.
*/ */
constexpr bytecode_t& bytecode() { return m_bytecode; } constexpr bytecode_t& bytecode() { return m_bytecode; }
/** /**
* @brief Returns a const reference to the module's bytecode. * @brief Returns the module's bytecode.
* *
* @return The reference to bytecode. * @return A constant reference to the bytecode.
*/ */
constexpr const bytecode_t& bytecode() const { return m_bytecode; } constexpr const bytecode_t& bytecode() const { return m_bytecode; }
public: public:
/**
* @brief Emplaces a function in the module's function container.
*
* @param args Arguments forwarded into the container's emplace_back function.
* @return A handle to the emplaced function.
*/
template <typename... Args> template <typename... Args>
function_h emplace_function(Args&&... args) { function_h emplace_function(Args&&... args) {
function_h function = m_functions.emplace_back(std::forward<Args>(args)...); function_h function = m_functions.emplace_back(std::forward<Args>(args)...);
@@ -75,26 +81,67 @@ public:
return std::move(function); return std::move(function);
} }
template <typename FunctionHandle> /**
void push_back(FunctionHandle&& handle) { * @brief Inserts a function in the module's function container.
m_functions.emplace_back(std::forward<FunctionHandle>(handle)); *
* @param function Function to insert.
*/
template <typename Function>
void push_back(Function&& function) {
m_functions.emplace_back(std::forward<Function>(function));
} }
/**
* @brief Returns a function from the module.
*
* @param id Identifier of the function.
* @return A handle to the function.
*/
auto function_at(function_id id) { return m_functions.at(id); } auto function_at(function_id id) { return m_functions.at(id); }
/**
* @brief Returns a function from the module.
*
* @param id Identifier of the function.
* @return A handle to the function.
*/
auto function_at(function_id id) const { return m_functions.at(id); } auto function_at(function_id id) const { return m_functions.at(id); }
/**
* @brief Returns a function from the module.
*
* @param name Name of the function.
* @return A handle to the function.
*/
template <typename NameFwd> template <typename NameFwd>
auto function_at(NameFwd&& name) { auto function_at(NameFwd&& name) {
return function_at(m_functionMap.at(std::forward<NameFwd>(name))); return function_at(m_functionMap.at(std::forward<NameFwd>(name)));
} }
/**
* @brief Returns a function from the module.
*
* @param name Name of the function.
* @return A handle to the function.
*/
template <typename NameFwd> template <typename NameFwd>
auto function_at(NameFwd&& name) const { auto function_at(NameFwd&& name) const {
return function_at(m_functionMap.at(std::forward<NameFwd>(name))); return function_at(m_functionMap.at(std::forward<NameFwd>(name)));
} }
/**
* @brief Erases a function from the module's function container.
*
* @param id Identifier of the function.
*/
void erase_function(function_id id) { m_functions.erase(id); } void erase_function(function_id id) { m_functions.erase(id); }
public: public:
/**
* @brief Prints the module in a bytecode form to an output stream.
*
* @param os Output stream.
* @return The output stream.
*/
std::ostream& serialize(std::ostream& os) const; std::ostream& serialize(std::ostream& os) const;
private: private:
bytecode_t m_bytecode; bytecode_t m_bytecode;
+130 -20
View File
@@ -19,10 +19,10 @@ enum class thing_t : std::uint8_t {
}; };
/** /**
* @brief Returns data size of a thing. * @brief Returns how many bytes a thing would take up.
* *
* @param type Type of the thing. * @param type Type of the thing.
* @return The data size of the thing. * @return The byte count.
*/ */
static inline std::size_t thing_type_size(thing_t type) { static inline std::size_t thing_type_size(thing_t type) {
switch (type) { switch (type) {
@@ -35,13 +35,22 @@ template <template <typename> typename Allocator>
class thing final { class thing final {
friend class executor; friend class executor;
public: public:
using allocator_type = Allocator<std::byte>; using allocator_type = Allocator<std::byte>; /**< Allocator type. */
public: public:
/**
* @brief Constructs a thing.
*
* @param type Type of the thing.
* @param allocator Allocator for the thing's data.
*/
thing(thing_t type, const allocator_type& allocator = {}) thing(thing_t type, const allocator_type& allocator = {})
: m_type(type), m_allocator(allocator) { : m_type(type), m_allocator(allocator) {
m_data = m_allocator.allocate(thing_type_size(type)); m_data = m_allocator.allocate(thing_type_size(type));
} }
/**
* @brief Destructs a thing.
*/
~thing() { ~thing() {
if (m_data != nullptr) m_allocator.deallocate(m_data, thing_type_size(thing_t::Int32)); if (m_data != nullptr) m_allocator.deallocate(m_data, thing_type_size(thing_t::Int32));
} }
@@ -74,8 +83,7 @@ public:
/** /**
* @brief Returns a clone of the thing. * @brief Returns a clone of the thing.
* *
* @param thing Thing to clone. * @return A clone of this thing.
* @return Shared pointer to a clone of the thing.
*/ */
thing clone() const { thing clone() const {
class thing res(m_type, m_allocator); class thing res(m_type, m_allocator);
@@ -88,7 +96,7 @@ public:
} }
public: public:
/** /**
* @brief Returns an int32 value from this thing. * @brief Returns the thing's int32 value.
* *
* @return The value. * @return The value.
*/ */
@@ -98,7 +106,7 @@ public:
} }
/** /**
* @brief Returns an int32 value from this thing. * @brief Returns the thing's int32 value.
* *
* @return The value. * @return The value.
*/ */
@@ -107,66 +115,132 @@ public:
return *reinterpret_cast<std::int32_t*>(m_data); return *reinterpret_cast<std::int32_t*>(m_data);
} }
public: public:
/**
* @brief Returns a sum of two things.
*
* @param rhs Thing to sum with this thing (right-hand-side).
* @return The sum.
*/
thing add(const thing& rhs) const { thing add(const thing& rhs) const {
thing res(m_type, m_allocator); thing res(m_type, m_allocator);
res.int32() = int32() + rhs.int32(); res.int32() = int32() + rhs.int32();
return res; return res;
} }
/**
* @brief Returns a difference of two things.
*
* @param rhs Thing to subtract from this thing (right-hand-side).
* @return The sum.
*/
thing sub(const thing& rhs) const { thing sub(const thing& rhs) const {
thing res(m_type, m_allocator); thing res(m_type, m_allocator);
res.int32() = int32() - rhs.int32(); res.int32() = int32() - rhs.int32();
return res; return res;
} }
/**
* @brief Returns a product of two things.
*
* @param rhs Thing to multiply with this thing (right-hand-side).
* @return The product.
*/
thing mul(const thing& rhs) const { thing mul(const thing& rhs) const {
thing res(m_type, m_allocator); thing res(m_type, m_allocator);
res.int32() = int32() * rhs.int32(); res.int32() = int32() * rhs.int32();
return res; return res;
} }
/**
* @brief Returns a quotient of two things.
*
* @param rhs Thing to divide this thing by (right-hand-side).
* @return The quotient.
*/
thing div(const thing& rhs) const { thing div(const thing& rhs) const {
thing res(m_type, m_allocator); thing res(m_type, m_allocator);
res.int32() = int32() / rhs.int32(); res.int32() = int32() / rhs.int32();
return res; return res;
} }
/**
* @brief Returns a remainder of two things.
*
* @param rhs Thing to divide this thing by (right-hand-side).
* @return The remainder.
*/
thing mod(const thing& rhs) const { thing mod(const thing& rhs) const {
thing res(m_type, m_allocator); thing res(m_type, m_allocator);
res.int32() = int32() % rhs.int32(); res.int32() = int32() % rhs.int32();
return res; return res;
} }
/**
* @brief Compares two things for equality.
*
* @param rhs Thing to compare this thing with (right-hand-side).
* @return A boolean result of the comparison in a thing form.
*/
thing equals(const thing& rhs) const { thing equals(const thing& rhs) const {
thing res(m_type, m_allocator); thing res(m_type, m_allocator);
res.int32() = int32() == rhs.int32(); res.int32() = int32() == rhs.int32();
return res; return res;
} }
/**
* @brief Compares two things for inequality.
*
* @param rhs Thing to compare this thing with (right-hand-side).
* @return A boolean result of the comparison in a thing form.
*/
thing not_equals(const thing& rhs) const { thing not_equals(const thing& rhs) const {
thing res(m_type, m_allocator); thing res(m_type, m_allocator);
res.int32() = int32() != rhs.int32(); res.int32() = int32() != rhs.int32();
return res; return res;
} }
/**
* @brief Compares if this thing is less than an another thing.
*
* @param rhs The another thing.
* @return A boolean result of the comparison in a thing form.
*/
thing less_than(const thing& rhs) const { thing less_than(const thing& rhs) const {
thing res(m_type, m_allocator); thing res(m_type, m_allocator);
res.int32() = int32() < rhs.int32(); res.int32() = int32() < rhs.int32();
return res; return res;
} }
/**
* @brief Compares if this thing is greater than an another thing.
*
* @param rhs The another thing.
* @return A boolean result of the comparison in a thing form.
*/
thing greater_than(const thing& rhs) const { thing greater_than(const thing& rhs) const {
thing res(m_type, m_allocator); thing res(m_type, m_allocator);
res.int32() = int32() > rhs.int32(); res.int32() = int32() > rhs.int32();
return res; return res;
} }
/**
* @brief Compares if this thing is less than or equal to an another thing.
*
* @param rhs The another thing.
* @return A boolean result of the comparison in a thing form.
*/
thing less_equals(const thing& rhs) const { thing less_equals(const thing& rhs) const {
thing res(m_type, m_allocator); thing res(m_type, m_allocator);
res.int32() = int32() <= rhs.int32(); res.int32() = int32() <= rhs.int32();
return res; return res;
} }
/**
* @brief Compares if this thing is greater than or equal to an another thing.
*
* @param rhs The another thing.
* @return A boolean result of the comparison in a thing form.
*/
thing greater_equals(const thing& rhs) const { thing greater_equals(const thing& rhs) const {
thing res(m_type, m_allocator); thing res(m_type, m_allocator);
res.int32() = int32() >= rhs.int32(); res.int32() = int32() >= rhs.int32();
@@ -186,27 +260,26 @@ class thing_allocator {
using dead_things = std::vector<std::pair<T*, std::size_t>>; using dead_things = std::vector<std::pair<T*, std::size_t>>;
public: public:
using value_type = T; using value_type = T; /**< Value type. */
public: public:
/**
* @brief Constructs a thing allocator.
*
* @param arena Base arena allocator.
*/
explicit thing_allocator(furlang::arena& arena) noexcept explicit thing_allocator(furlang::arena& arena) noexcept
: m_arena(&arena), m_deadThings(std::make_shared<dead_things>()) {} : m_arena(&arena), m_deadThings(std::make_shared<dead_things>()) {}
template <typename U> /**
thing_allocator(const thing_allocator<U>& other) noexcept * @brief Move constructor.
: m_arena(other.m_arena), m_deadThings(other.m_deadThings) {} */
template <typename U>
thing_allocator& operator=(const thing_allocator<U>& other) noexcept {
if (this == &other) return *this;
m_arena = other.m_arena;
m_deadThings = other.m_deadThings;
return *this;
}
template <typename U> template <typename U>
thing_allocator(thing_allocator<U>&& other) noexcept thing_allocator(thing_allocator<U>&& other) noexcept
: m_arena(std::move(other.m_arena)), m_deadThings(std::move(other.m_deadThings)) {} : m_arena(std::move(other.m_arena)), m_deadThings(std::move(other.m_deadThings)) {}
/**
* @brief Move constructor.
*/
template <typename U> template <typename U>
thing_allocator& operator=(thing_allocator<U>&& other) noexcept { thing_allocator& operator=(thing_allocator<U>&& other) noexcept {
if (this == &other) return *this; if (this == &other) return *this;
@@ -214,7 +287,31 @@ public:
m_deadThings = std::move(other.m_deadThings); m_deadThings = std::move(other.m_deadThings);
return *this; return *this;
} }
/**
* @brief Copy constructor.
*/
template <typename U>
thing_allocator(const thing_allocator<U>& other) noexcept
: m_arena(other.m_arena), m_deadThings(other.m_deadThings) {}
/**
* @brief Copy constructor.
*/
template <typename U>
thing_allocator& operator=(const thing_allocator<U>& other) noexcept {
if (this == &other) return *this;
m_arena = other.m_arena;
m_deadThings = other.m_deadThings;
return *this;
}
public: public:
/**
* @brief Returns a free chunk of memory.
*
* @param count Count of the things that must fit inside the chunk.
* @return The chunk.
*/
[[nodiscard]] T* allocate(std::size_t count = 1) { [[nodiscard]] T* allocate(std::size_t count = 1) {
for (auto it = m_deadThings->begin(); it != m_deadThings->end(); ++it) { for (auto it = m_deadThings->begin(); it != m_deadThings->end(); ++it) {
if (it->second != count) continue; if (it->second != count) continue;
@@ -224,13 +321,26 @@ public:
return m_arena->allocate<T>(count); return m_arena->allocate<T>(count);
} }
/**
* @brief Recycles the pointer.
*/
void deallocate(T* ptr, std::size_t count) noexcept { m_deadThings->emplace_back(ptr, count); } void deallocate(T* ptr, std::size_t count) noexcept { m_deadThings->emplace_back(ptr, count); }
public: public:
/**
* @brief Compares two thing allocators for equality.
*
* @return true if the two things are equal.
*/
template <typename U> template <typename U>
bool operator==(const thing_allocator<U>& other) const noexcept { bool operator==(const thing_allocator<U>& other) const noexcept {
return m_arena == other.m_arena && m_deadThings == other.m_deadThings; return m_arena == other.m_arena && m_deadThings == other.m_deadThings;
} }
/**
* @brief Compares two thing allocators for inequality.
*
* @return true if the two things are not equal.
*/
template <typename U> template <typename U>
bool operator!=(const thing_allocator<U>& other) const noexcept { bool operator!=(const thing_allocator<U>& other) const noexcept {
return m_arena != other.m_arena || m_deadThings != other.m_deadThings; return m_arena != other.m_arena || m_deadThings != other.m_deadThings;