From fe7c4ddd93d1e2f4513c5ae88c09ea0d70b8331d Mon Sep 17 00:00:00 2001 From: wvpm <24685035+wvpm@users.noreply.github.com> Date: Fri, 22 May 2026 23:40:57 +0200 Subject: [PATCH] IdentifierRegistry replacement types --- .../types/registries/OwningRegistry.hpp | 100 ++++++++++++++ .../registries/OwningRegistry_Modify.hpp | 122 ++++++++++++++++++ .../registries/OwningRegistry_Search.hpp | 90 +++++++++++++ .../types/registries/RegistryView.hpp | 114 ++++++++++++++++ .../types/registries/RegistryView_Modify.hpp | 42 ++++++ 5 files changed, 468 insertions(+) create mode 100644 src/openvic-simulation/types/registries/OwningRegistry.hpp create mode 100644 src/openvic-simulation/types/registries/OwningRegistry_Modify.hpp create mode 100644 src/openvic-simulation/types/registries/OwningRegistry_Search.hpp create mode 100644 src/openvic-simulation/types/registries/RegistryView.hpp create mode 100644 src/openvic-simulation/types/registries/RegistryView_Modify.hpp diff --git a/src/openvic-simulation/types/registries/OwningRegistry.hpp b/src/openvic-simulation/types/registries/OwningRegistry.hpp new file mode 100644 index 00000000..28e6a671 --- /dev/null +++ b/src/openvic-simulation/types/registries/OwningRegistry.hpp @@ -0,0 +1,100 @@ +#pragma once + +#include "openvic-simulation/core/Assert.hpp" +#include "openvic-simulation/core/memory/Vector.hpp" +#include "openvic-simulation/core/template/Concepts.hpp" + +namespace OpenVic { + struct owning_registry_internal_tag {}; + + template< + typename ValueType, + typename SizeType, + typename Allocator + > + struct OwningRegistry { + private: + bool _is_locked { false }; + memory::vector _values; + + public: + [[nodiscard]] constexpr bool& is_locked_internal(owning_registry_internal_tag) { return _is_locked; } + [[nodiscard]] constexpr memory::vector& values_internal(owning_registry_internal_tag) { return _values; } + + [[nodiscard]] constexpr bool is_locked() const { return _is_locked; } + + // Member types based on std::vector + using value_type = typename decltype(_values)::value_type; + using allocator_type = typename decltype(_values)::allocator_type; + using size_type = SizeType; + using difference_type = typename decltype(_values)::difference_type; + using reference = typename decltype(_values)::reference; + using const_reference = typename decltype(_values)::const_reference; + using pointer = typename decltype(_values)::pointer; + using const_pointer = typename decltype(_values)::const_pointer; + using iterator = typename decltype(_values)::iterator; + using const_iterator = typename decltype(_values)::const_iterator; + using reverse_iterator = typename decltype(_values)::reverse_iterator; + using const_reverse_iterator = typename decltype(_values)::const_reverse_iterator; + + [[nodiscard]] constexpr allocator_type get_allocator() const { return _values.get_allocator(); } + + // Element access based on std::vector + [[nodiscard]] constexpr reference operator[](const size_type pos) { + OV_HARDEN_ASSERT_ACCESS(pos, "operator[]"); + return _values[get_index_as_size_t(pos)]; + } + [[nodiscard]] constexpr const_reference operator[](const size_type pos) const { + OV_HARDEN_ASSERT_ACCESS(pos, "operator[]"); + return _values[get_index_as_size_t(pos)]; + } + + [[nodiscard]] constexpr reference front() { + OV_HARDEN_ASSERT_NONEMPTY("front"); + return _values[0]; + } + [[nodiscard]] constexpr const_reference front() const { + OV_HARDEN_ASSERT_NONEMPTY("front"); + return _values[0]; + } + + [[nodiscard]] constexpr reference back() { + OV_HARDEN_ASSERT_NONEMPTY("back"); + return _values[_values.size()-1]; + } + [[nodiscard]] constexpr const_reference back() const { + OV_HARDEN_ASSERT_NONEMPTY("back"); + return _values[_values.size()-1]; + } + + [[nodiscard]] constexpr value_type* data() noexcept { return _values.data(); } + [[nodiscard]] constexpr value_type const* data() const noexcept { return _values.data(); } + + // Iterators based on std::vector + [[nodiscard]] constexpr iterator begin() noexcept { return _values.begin(); } + [[nodiscard]] constexpr const_iterator begin() const noexcept { return _values.begin(); } + [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return _values.cbegin(); } + + [[nodiscard]] constexpr iterator end() noexcept { return _values.end(); } + [[nodiscard]] constexpr const_iterator end() const noexcept { return _values.end(); } + [[nodiscard]] constexpr const_iterator cend() const noexcept { return _values.cend(); } + + [[nodiscard]] constexpr reverse_iterator rbegin() noexcept { return _values.rbegin(); } + [[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept { return _values.rbegin(); } + [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return _values.crbegin(); } + + [[nodiscard]] constexpr reverse_iterator rend() noexcept { return _values.rend(); } + [[nodiscard]] constexpr const_reverse_iterator rend() const noexcept { return _values.rend(); } + [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return _values.crend(); } + + // Capacity based on std::vector + [[nodiscard]] constexpr bool empty() const noexcept { return _values.empty(); } + [[nodiscard]] constexpr size_type size() const noexcept { return _values.size(); } + [[nodiscard]] constexpr size_type max_size() const noexcept { return _values.max_size(); } + constexpr void reserve(const size_type new_cap) { _values.reserve(new_cap); } + [[nodiscard]] constexpr size_type capacity() const noexcept { return _values.capacity(); } + constexpr void shrink_to_fit() { _values.shrink_to_fit(); } + + // Modifiers omitted on purpose + }; +} \ No newline at end of file diff --git a/src/openvic-simulation/types/registries/OwningRegistry_Modify.hpp b/src/openvic-simulation/types/registries/OwningRegistry_Modify.hpp new file mode 100644 index 00000000..7493a4fc --- /dev/null +++ b/src/openvic-simulation/types/registries/OwningRegistry_Modify.hpp @@ -0,0 +1,122 @@ +#pragma once + +#include + +#include "OwningRegistry.hpp" +#include "OwningRegistry_Search.hpp" + +#include "openvic-simulation/core/template/FunctionalConcepts.hpp" +#include "openvic-simulation/core/Typedefs.hpp" +#include "openvic-simulation/utility/Logger.hpp" + +namespace OpenVic { + inline bool duplicate_fail_callback(std::string_view registry_name, std::string_view duplicate_identifier) { + spdlog::error_s( + "Failure adding item to the {} registry - an item with the identifier \"{}\" already exists!", + registry_name, duplicate_identifier + ); + return false; + } + inline bool duplicate_warning_callback(std::string_view registry_name, std::string_view duplicate_identifier) { + spdlog::warn_s( + "Warning adding item to the {} registry - an item with the identifier \"{}\" already exists!", + registry_name, duplicate_identifier + ); + return true; + } + + template< + typename ValueType, + typename SizeType, + typename Allocator + > + inline void lock_registry( + OwningRegistry& registry, + const bool should_log = false + ) { + if (registry.is_locked()) { + spdlog::error_s("Failed to lock {} registry - already locked!", OpenVic::type_name); + } else { + registry.is_locked_internal(owning_registry_internal_tag{}) = true; + if (should_log) { + SPDLOG_INFO("Locked {} registry after registering {} items", OpenVic::type_name, registry.size()); + } + } + } + + template< + typename ValueType, + typename SizeType, + typename Allocator, + typename... Args + > + inline constexpr bool emplace_item( + OwningRegistry& registry, + const std::string_view identifier, + Callback auto duplicate_callback, + Args&&... args + ) { + if (registry.is_locked()) { + spdlog::error_s("Cannot emplace_item to the {} registry - locked!", OpenVic::type_name); + return false; + } + + if (has_identifier(registry, identifier)) { + return duplicate_callback(OpenVic::type_name, identifier); + } + + registry.values_internal(owning_registry_internal_tag{}).emplace_back(std::forward(args)...); + return true; + } + + template< + typename ValueType, + typename SizeType, + typename Allocator, + typename... Args + > + inline constexpr bool emplace_item( + OwningRegistry& registry, + std::string_view identifier, + Args&&... args + ) { + return emplace_item(registry, identifier, duplicate_fail_callback, std::forward(args)...); + } + + template< + typename ValueType, + typename SizeType, + typename Allocator + > + inline constexpr bool emplace_via_move( + OwningRegistry& registry, + std::string_view identifier, + Callback auto duplicate_callback, + ValueType&& item + ) { + if (registry.is_locked()) { + spdlog::error_s("Cannot emplace_via_move to the {} registry - locked!", OpenVic::type_name); + return false; + } + + if (has_identifier(registry, identifier)) { + return duplicate_callback(OpenVic::type_name, identifier); + } + + registry.values_internal(owning_registry_internal_tag{}).emplace_back(std::move(item)); + return true; + } + + template< + typename ValueType, + typename SizeType, + typename Allocator + > + inline constexpr bool emplace_via_move( + OwningRegistry& registry, + std::string_view identifier, + ValueType&& item + ) { + return emplace_via_move(registry, identifier, duplicate_fail_callback, std::move(item)); + } +} \ No newline at end of file diff --git a/src/openvic-simulation/types/registries/OwningRegistry_Search.hpp b/src/openvic-simulation/types/registries/OwningRegistry_Search.hpp new file mode 100644 index 00000000..4c02ac1f --- /dev/null +++ b/src/openvic-simulation/types/registries/OwningRegistry_Search.hpp @@ -0,0 +1,90 @@ +#pragma once + +#include +#include +#include + +#include "OwningRegistry.hpp" + +#include "openvic-simulation/core/template/Concepts.hpp" +#include "openvic-simulation/types/TypedSpan.hpp" + +namespace OpenVic { + template< + typename ValueType, + typename SizeType, + typename Allocator + > requires is_strongly_typed + [[nodiscard]] inline TypedSpan get_values(OwningRegistry& registry) { + return { registry.data(), registry.size() }; + } + + template< + typename ValueType, + typename SizeType, + typename Allocator + > requires is_strongly_typed + [[nodiscard]] inline TypedSpan get_values(OwningRegistry const& registry) { + return { registry.data(), registry.size() }; + } + + template< + typename ValueType, + typename SizeType, + typename Allocator + > requires (!is_strongly_typed) + [[nodiscard]] inline std::span get_values(OwningRegistry& registry) { + return { registry.data(), registry.size() }; + } + + template< + typename ValueType, + typename SizeType, + typename Allocator + > requires (!is_strongly_typed) + [[nodiscard]] inline std::span get_values(OwningRegistry const& registry) { + return { registry.data(), registry.size() }; + } + + template< + typename ValueType, + typename SizeType, + typename Allocator + > requires has_get_identifier + [[nodiscard]] inline bool has_identifier( + OwningRegistry const& registry, + std::string_view identifier + ) { + return std::ranges::any_of(registry.begin(), registry.end(), [&](ValueType const& value) { + return value.get_identifier() == identifier; + }); + } + + template< + typename ValueType, + typename SizeType, + typename Allocator + > requires has_get_identifier + [[nodiscard]] inline auto find( + OwningRegistry& registry, + std::string_view identifier + ) { + return std::find_if(registry.begin(), registry.end(), [&](ValueType const& value) { + return value.get_identifier() == identifier; + }); + } + + template< + typename ValueType, + typename SizeType, + typename Allocator + > requires has_get_identifier + [[nodiscard]] inline auto find( + OwningRegistry const& registry, + std::string_view identifier + ) { + return std::find_if(registry.begin(), registry.end(), [&](ValueType const& value) { + return value.get_identifier() == identifier; + }); + } +} \ No newline at end of file diff --git a/src/openvic-simulation/types/registries/RegistryView.hpp b/src/openvic-simulation/types/registries/RegistryView.hpp new file mode 100644 index 00000000..1daeb996 --- /dev/null +++ b/src/openvic-simulation/types/registries/RegistryView.hpp @@ -0,0 +1,114 @@ +#pragma once + +#include +#include +#include +#include + +#include "openvic-simulation/core/Typedefs.hpp" + +namespace OpenVic { + struct registry_view_internal_tag {}; + + template< + typename ValueType, + std::size_t N_Spans + > + struct RegistryView { + static_assert(N_Spans > 0); + private: + bool _is_locked; + std::array, N_Spans> _views; + + public: + constexpr RegistryView() : _is_locked(false) { } + + template + constexpr RegistryView(Args&&... args) : _is_locked(true), _views(std::forward(args)...) {} + + [[nodiscard]] constexpr bool& is_locked_internal(registry_view_internal_tag) { return _is_locked; } + [[nodiscard]] constexpr std::span, N_Spans> get_views_internal(registry_view_internal_tag) { return _views; } + + [[nodiscard]] constexpr bool is_locked() const { return _is_locked; } + + // Member types based on std::vector + using value_type = ValueType; + using size_type = std::size_t; + using reference = ValueType&; + using const_reference = ValueType const&; + + // Element access based on std::vector + [[nodiscard]] constexpr reference operator[](const size_type pos) { + size_type remaining = pos; + for (std::size_t i = 0; i < N_Spans; ++i) { + if (remaining < _views[i].size()) { + return _views[i][remaining]; + } + remaining -= size_type(_views[i].size()); + } + unreachable(); + } + [[nodiscard]] constexpr const_reference operator[](const size_type pos) const { + size_type remaining = pos; + for (std::size_t i = 0; i < N_Spans; ++i) { + if (remaining < _views[i].size()) { + return _views[i][remaining]; + } + remaining -= size_type(_views[i].size()); + } + unreachable(); + } + + [[nodiscard]] constexpr reference front() { + for (std::size_t i = 0; i < N_Spans; ++i) { + if (!_views[i].empty()) { + return _views[i].front(); + } + } + unreachable(); + } + [[nodiscard]] constexpr const_reference front() const { + for (std::size_t i = 0; i < N_Spans; ++i) { + if (!_views[i].empty()) { + return _views[i].front(); + } + } + unreachable(); + } + + [[nodiscard]] constexpr reference back() { + for (std::size_t i = N_Spans; i > 0; --i) { + if (!_views[i - 1].empty()) { + return _views[i - 1].back(); + } + } + unreachable(); + } + [[nodiscard]] constexpr const_reference back() const { + for (std::size_t i = N_Spans; i > 0; --i) { + if (!_views[i - 1].empty()) { + return _views[i - 1].back(); + } + } + unreachable(); + } + + // Capacity based on std::vector + [[nodiscard]] constexpr bool empty() const noexcept { + for (std::size_t i = 0; i < N_Spans; ++i) { + if (!_views[i].empty()) { + return false; + } + } + + return true; + } + [[nodiscard]] constexpr size_type size() const noexcept { + size_type total_size {}; + for (std::size_t i = 0; i < N_Spans; ++i) { + total_size += size_type(_views[i].size()); + } + return total_size; + } + }; +} \ No newline at end of file diff --git a/src/openvic-simulation/types/registries/RegistryView_Modify.hpp b/src/openvic-simulation/types/registries/RegistryView_Modify.hpp new file mode 100644 index 00000000..1fddb4d5 --- /dev/null +++ b/src/openvic-simulation/types/registries/RegistryView_Modify.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "RegistryView.hpp" + +#include "openvic-simulation/utility/Logger.hpp" + +namespace OpenVic { + template + requires (sizeof...(Args) > 0) && (std::convertible_to> && ... ) + [[nodiscard]] inline constexpr auto combine_into_view(Args&&... args){ + using FirstArg = std::tuple_element_t<0, std::tuple...>>; + using SizeType = typename FirstArg::size_type; + + return RegistryView( + std::forward(args)... + ); + } + + template< + typename ValueType, + std::size_t N_Spans + > + inline void lock_registry( + RegistryView& registry, + const bool should_log = false + ) { + if (registry.is_locked()) { + spdlog::error_s("Failed to lock {} registry - already locked!", OpenVic::type_name); + } else { + registry.is_locked_internal(registry_view_internal_tag{}) = true; + if (should_log) { + SPDLOG_INFO("Locked {} registry after registering {} items", OpenVic::type_name, registry.size()); + } + } + } +} \ No newline at end of file