docs(furvm): document the handle

This commit is contained in:
2026-06-21 20:08:41 +02:00
parent 1ead2f6592
commit 3759c0361f
2 changed files with 192 additions and 26 deletions
+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
/** /**
+176 -21
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();
} }
/**
* @brief Returns a pointer to the handle's value.
*
* @return The value pointer.
*/
pointer operator->() { return &m_value->second; } 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; }
/**
* @brief Returns a reference to the handle's value.
*
* @return The value reference.
*/
reference operator*() { return m_value->second; } 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; }
/**
* @brief Returns a reference to the handle's value.
*
* @return The value reference.
*/
reference value() { return m_value->second; } 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)...);
} }
/**
* @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) }; } 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];