From 271082a0dc567f4990db8f79d2fbbbcf589b1e91 Mon Sep 17 00:00:00 2001 From: Dominik Drexler Date: Sat, 14 Dec 2024 23:02:16 +0100 Subject: [PATCH] SegmentedRepository is now thread safe --- .../details/utils/segmented_repository.hpp | 59 ++++++++++++++++--- src/ast/parser.hpp | 8 --- src/ast/parser_def.hpp | 13 ---- src/ast/parser_instantiations.cpp | 2 - 4 files changed, 52 insertions(+), 30 deletions(-) diff --git a/include/loki/details/utils/segmented_repository.hpp b/include/loki/details/utils/segmented_repository.hpp index b4baea31..88eb176f 100644 --- a/include/loki/details/utils/segmented_repository.hpp +++ b/include/loki/details/utils/segmented_repository.hpp @@ -21,6 +21,7 @@ #include "loki/details/utils/segmented_vector.hpp" #include +#include #include #include #include @@ -29,7 +30,7 @@ namespace loki { -/// @brief `UniqueFactory` manages unique creation of objects +/// @brief `SegmentedRepository` is a thread-safe container for managing the unique creation of objects /// in a persistent and efficient manner, utilizing a combination of unordered_set for /// uniqueness checks and SegmentedVector for continuous and cache-efficient storage of value types. /// @tparam T is the type. @@ -45,6 +46,9 @@ class SegmentedRepository // We use pre-allocated memory to store objects persistent. SegmentedVector m_persistent_vector; + // Mutex for synchronizing write operations + mutable std::shared_mutex m_mutex; + void range_check(size_t pos) const { if (pos >= size()) @@ -61,13 +65,33 @@ class SegmentedRepository } SegmentedRepository(const SegmentedRepository& other) = delete; SegmentedRepository& operator=(const SegmentedRepository& other) = delete; - SegmentedRepository(SegmentedRepository&& other) = default; - SegmentedRepository& operator=(SegmentedRepository&& other) = default; + SegmentedRepository(SegmentedRepository&& other) noexcept : + m_uniqueness_set(std::move(other.m_uniqueness_set)), + m_persistent_vector(std::move(other.m_persistent_vector)), + m_mutex() // Create a new mutex for the moved object + { + } + + SegmentedRepository& operator=(SegmentedRepository&& other) noexcept + { + if (this != &other) + { + std::unique_lock lock_this(m_mutex, std::defer_lock); + std::unique_lock lock_other(other.m_mutex, std::defer_lock); + std::lock(lock_this, lock_other); + + m_uniqueness_set = std::move(other.m_uniqueness_set); + m_persistent_vector = std::move(other.m_persistent_vector); + } + return *this; + } /// @brief Returns a pointer to an existing object or creates it before if it does not exist. template T const* get_or_create(Args&&... args) { + std::unique_lock lock(m_mutex); // Lock only for writing + /* Construct and insert the element in persistent memory. */ // Ensure that element with identifier i is stored at position i. @@ -104,29 +128,50 @@ class SegmentedRepository */ /// @brief Returns a pointer to an existing object with the given pos. + // MT: no lock required, because elements are persistent. T const* operator[](size_t pos) const { assert(pos < size()); return &(m_persistent_vector.at(pos)); } + /// @brief Returns a pointer to an existing object with the given pos. + /// MT: no lock required, because elements are persistent. + /// @param pos + /// @return T const* at(size_t pos) const { range_check(pos); return &(m_persistent_vector.at(pos)); } - auto begin() const { return m_persistent_vector.begin(); } + auto begin() const + { + std::shared_lock lock(m_mutex); + return m_persistent_vector.begin(); + } - auto end() const { return m_persistent_vector.end(); } + auto end() const + { + std::shared_lock lock(m_mutex); + return m_persistent_vector.end(); + } - const SegmentedVector& get_storage() const { return m_persistent_vector; } + const SegmentedVector& get_storage() const + { + std::shared_lock lock(m_mutex); + return m_persistent_vector; + } /** * Capacity */ - size_t size() const { return m_persistent_vector.size(); } + size_t size() const + { + std::shared_lock lock(m_mutex); + return m_persistent_vector.size(); + } }; } diff --git a/src/ast/parser.hpp b/src/ast/parser.hpp index ecb68e8e..71b8ec28 100644 --- a/src/ast/parser.hpp +++ b/src/ast/parser.hpp @@ -162,8 +162,6 @@ struct AssignOperatorIncreaseClass; struct AssignOperatorDecreaseClass; struct AssignOperatorClass; -struct NumericTermClass; - struct EffectClass; struct EffectProductionLiteralClass; struct EffectProductionNumericClass; @@ -360,8 +358,6 @@ typedef x3::rule assig typedef x3::rule assign_operator_decrease_type; typedef x3::rule assign_operator_type; -typedef x3::rule numeric_term_type; - typedef x3::rule effect_type; typedef x3::rule effect_production_literal_type; typedef x3::rule effect_production_numeric_type; @@ -551,8 +547,6 @@ BOOST_SPIRIT_DECLARE(assign_operator_assign_type, assign_operator_decrease_type, assign_operator_type) -BOOST_SPIRIT_DECLARE(numeric_term_type) - BOOST_SPIRIT_DECLARE(effect_type, effect_production_literal_type, effect_production_numeric_type, @@ -743,8 +737,6 @@ parser::assign_operator_increase_type const& assign_operator_increase(); parser::assign_operator_decrease_type const& assign_operator_decrease(); parser::assign_operator_type const& assign_operator(); -parser::numeric_term_type const& numeric_term(); - parser::effect_type const& effect(); parser::effect_production_literal_type const& effect_production_literal(); parser::effect_production_numeric_type const& effect_production_numeric(); diff --git a/src/ast/parser_def.hpp b/src/ast/parser_def.hpp index 634d1d91..6138e402 100644 --- a/src/ast/parser_def.hpp +++ b/src/ast/parser_def.hpp @@ -178,8 +178,6 @@ assign_operator_increase_type const assign_operator_increase = "assign_operator_ assign_operator_decrease_type const assign_operator_decrease = "assign_operator_decrease"; assign_operator_type const assign_operator = "assign_operator"; -numeric_term_type const numeric_term = "numeric_term"; - effect_type const effect = "effect"; effect_production_literal_type const effect_production_literal = "effect_production_literal"; effect_production_numeric_type const effect_production_numeric = "effect_production_numeric"; @@ -393,9 +391,6 @@ const auto assign_operator_decrease_def = keyword_lit("decrease") > x3::attr(ast const auto assign_operator_def = assign_operator_assign | assign_operator_scale_up | assign_operator_scale_down | assign_operator_increase | assign_operator_decrease; -// For action cost effects only -const auto numeric_term_def = function_expression_number | function_expression_head; - const auto effect_def = ((lit('(') >> keyword_lit("and")) > *effect > lit(')')) | effect_composite | effect_production; const auto effect_production_literal_def = literal; const auto effect_production_numeric_def = (lit('(') >> assign_operator >> function_head >> function_expression) > lit(')'); @@ -588,8 +583,6 @@ BOOST_SPIRIT_DEFINE(assign_operator_assign, assign_operator_decrease, assign_operator) -BOOST_SPIRIT_DEFINE(numeric_term) - BOOST_SPIRIT_DEFINE(effect, effect_production_literal, effect_production_numeric, @@ -965,10 +958,6 @@ struct AssignOperatorClass : x3::annotate_on_success { }; -struct NumericTermClass : x3::annotate_on_success -{ -}; - struct EffectClass : x3::annotate_on_success { }; @@ -1318,8 +1307,6 @@ parser::assign_operator_increase_type const& assign_operator_increase() { return parser::assign_operator_decrease_type const& assign_operator_decrease() { return parser::assign_operator_decrease; } parser::assign_operator_type const& assign_operator() { return parser::assign_operator; } -parser::numeric_term_type const& numeric_term() { return parser::numeric_term; } - parser::effect_type const& effect() { return parser::effect; } parser::effect_production_literal_type const& effect_production_literal() { return parser::effect_production_literal; } parser::effect_production_numeric_type const& effect_production_numeric() { return parser::effect_production_numeric; } diff --git a/src/ast/parser_instantiations.cpp b/src/ast/parser_instantiations.cpp index d123c8be..74e535db 100644 --- a/src/ast/parser_instantiations.cpp +++ b/src/ast/parser_instantiations.cpp @@ -143,8 +143,6 @@ BOOST_SPIRIT_INSTANTIATE(assign_operator_increase_type, iterator_type, context_t BOOST_SPIRIT_INSTANTIATE(assign_operator_decrease_type, iterator_type, context_type) BOOST_SPIRIT_INSTANTIATE(assign_operator_type, iterator_type, context_type) -BOOST_SPIRIT_INSTANTIATE(numeric_term_type, iterator_type, context_type) - BOOST_SPIRIT_INSTANTIATE(effect_type, iterator_type, context_type) BOOST_SPIRIT_INSTANTIATE(effect_production_literal_type, iterator_type, context_type) BOOST_SPIRIT_INSTANTIATE(effect_production_numeric_type, iterator_type, context_type)