From a8a9c11bf805c2039dc5ddbc6ce3af8870af2153 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 2 Oct 2018 23:25:12 +0300 Subject: [PATCH] typemap improvements --- Utilities/typemap.h | 159 +++++++++++++++++++++++--------------------- 1 file changed, 82 insertions(+), 77 deletions(-) diff --git a/Utilities/typemap.h b/Utilities/typemap.h index 4f0fc99df7..4034b19e6e 100644 --- a/Utilities/typemap.h +++ b/Utilities/typemap.h @@ -2,6 +2,7 @@ #include "types.h" #include "mutex.h" +#include "cond.h" #include "Atomic.h" #include "VirtualMemory.h" #include @@ -348,14 +349,17 @@ namespace utils // Free ID counter atomic_t m_sema{0}; - // Hint for next free ID - atomic_t m_hint{0}; - // Max ID ever used + 1 atomic_t m_limit{0}; // Increased on each constructor call - atomic_t m_total{0}; + atomic_t m_create_count{0}; + + // Increased on each destructor call + atomic_t m_destroy_count{0}; + + // Waitable object for the semaphore, signaled on decrease + ::notifier m_free_notifier; // Aligned size of the storage for each object uint m_ssize = 0; @@ -392,16 +396,6 @@ namespace utils void release() { - // Additional semaphore is not used for singletons - if constexpr (typeinfo_count::max_count > 1) - { - if (m_block->m_type == 0) - { - // Object deleted or not created: return semaphore - m_head->m_sema--; - } - } - if constexpr (type_const()) { m_block->m_mutex.unlock_shared(); @@ -410,6 +404,18 @@ namespace utils { m_block->m_mutex.unlock(); } + + if (m_block->m_type == 0) + { + if constexpr (typeinfo_count::max_count > 1) + { + // Return semaphore + m_head->m_sema--; + } + + // Signal free ID availability + m_head->m_free_notifier.notify_all(); + } } public: @@ -473,21 +479,23 @@ namespace utils } } - // Call the constructor + // Call the constructor, return the stamp template , typename... Args> - weak_typeptr create(Args&&... args) + ullong create(Args&&... args) { static_assert(!type_const()); - const uint this_id = this->get_id(); + const ullong result = ++m_head->m_create_count; if constexpr (typeinfo_count::max_count > 1) { // Update hints only if the object is not being recreated if (!m_block->m_type) { + const uint this_id = this->get_id(); + // Update max count - auto lim = m_head->m_limit.fetch_op([this_id](uint& limit) + m_head->m_limit.fetch_op([this_id](uint& limit) { if (limit <= this_id) { @@ -497,24 +505,6 @@ namespace utils return false; }); - - // Update hint (TODO) - m_head->m_hint.atomic_op([this_id, lim](uint& hint) - { - if (lim.first + 1 == typeinfo_count::max_count && hint <= this_id) - { - hint = this_id + 1; - } - else - { - hint++; - } - - if (hint == typeinfo_count::max_count) - { - hint = 0; - } - }); } } @@ -525,6 +515,7 @@ namespace utils if (m_block->m_type.exchange(g_typepoly.type) != 0) { (*m_block->get_ptr())->~base(); + m_head->m_destroy_count++; } *m_block->get_ptr() = new (m_block->get_ptr()) New(std::forward(args)...); @@ -538,17 +529,13 @@ namespace utils { // Destroy object if it exists m_block->get_ptr()->~T(); + m_head->m_destroy_count++; } new (m_block->get_ptr()) New(std::forward(args)...); } - // Return a weak pointer struct with a unique stamp number - weak_typeptr w; - w.id = this_id; - w.type = m_block->m_type; - w.stamp = ++m_head->m_total; - return w; + return result; } // Call the destructor if object exists @@ -570,6 +557,8 @@ namespace utils { m_block->get_ptr()->~T(); } + + m_head->m_destroy_count++; } // Get the ID @@ -618,6 +607,21 @@ namespace utils // Virtual memory size std::size_t m_total = 0; + template + typemap_head* get_head() const + { + using _type = std::decay_t; + + if constexpr (typeinfo_share::is_shared) + { + return &m_map[g_sh<_type>.type]; + } + else + { + return &m_map[g_typeinfo<_type>.type]; + } + } + public: typemap(const typemap&) = delete; @@ -681,9 +685,10 @@ namespace utils // Reset mutable fields m_map[i].m_sema.raw() = 0; - m_map[i].m_hint.raw() = 0; m_map[i].m_limit.raw() = 0; - m_map[i].m_total.raw() = 0; + + m_map[i].m_create_count.raw() = 0; + m_map[i].m_destroy_count.raw() = 0; } } @@ -748,11 +753,8 @@ namespace utils // Prepare pointers template - typeptr_base init_ptr(Arg&& id) + typeptr_base init_ptr(Arg&& id) const { - typemap_head* head; - typemap_block* block; - if constexpr (typeinfo_count::max_count == 0) { return {}; @@ -760,17 +762,11 @@ namespace utils const uint type_id = g_typeinfo>.type; - if constexpr (typeinfo_share::is_shared) - { - head = &m_map[g_sh>.type]; - } - else - { - head = &m_map[type_id]; - } - using id_tag = std::decay_t; + typemap_head* head = get_head(); + typemap_block* block; + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) { if constexpr (constexpr uint last = typeinfo_count::max_count - 1) @@ -788,7 +784,7 @@ namespace utils else { // Find empty location and lock it, starting from hint index - for (uint i = head->m_hint;; i = (i == last ? 0 : i + 1)) + for (uint lim = head->m_limit, i = (lim > last ? 0 : lim);; i = (i == last ? 0 : i + 1)) { block = reinterpret_cast(head->m_ptr + std::size_t{i} * head->m_ssize); @@ -901,7 +897,7 @@ namespace utils } template - void check_ptr(typemap_block*& block, Arg&& id) + void check_ptr(typemap_block*& block, Arg&& id) const { using id_tag = std::decay_t; @@ -1010,7 +1006,7 @@ namespace utils } template - bool lock_ptr(typemap_block* block) + bool lock_ptr(typemap_block* block) const { // Use reader lock for const access constexpr bool is_const = std::is_const_v>; @@ -1063,7 +1059,7 @@ namespace utils } template - bool try_lock(const std::array& array, uint locked, std::integer_sequence) + bool try_lock(const std::array& array, uint locked, std::integer_sequence) const { // Try to lock mutex if not locked from the previous step if (I == locked || lock_ptr(array[I].m_block)) @@ -1102,7 +1098,7 @@ namespace utils } template - uint lock_array(const std::array& array, std::integer_sequence, std::integer_sequence) + uint lock_array(const std::array& array, std::integer_sequence, std::integer_sequence) const { // Verify all mutexes are free or wait for one of them and return its index uint locked = 0; @@ -1111,14 +1107,14 @@ namespace utils } template - void check_array(std::array& array, std::integer_sequence, Args&&... ids) + void check_array(std::array& array, std::integer_sequence, Args&&... ids) const { // Check types and unlock on mismatch (check_ptr(array[I].m_block, std::forward(ids)), ...); } template - std::tuple...> array_to_tuple(const std::array& array, std::integer_sequence) + std::tuple...> array_to_tuple(const std::array& array, std::integer_sequence) const { return {array[I]...}; } @@ -1126,7 +1122,7 @@ namespace utils public: // Lock any objects by their identifiers, special tags id_new/id_any/id_always, or search predicates template > - auto lock(Args&&... ids) + auto lock(Args&&... ids) const { static_assert(((!std::is_lvalue_reference_v == !typeinfo_poly::is_poly) && ...)); static_assert(((!std::is_rvalue_reference_v) && ...)); @@ -1175,18 +1171,9 @@ namespace utils const uint type_id = g_typeinfo>.type; - typemap_head* head; + typemap_head* head = get_head(); - if constexpr (typeinfo_share::is_shared) - { - head = &m_map[g_sh>.type]; - } - else - { - head = &m_map[type_id]; - } - - const ullong ix = head->m_total; + const ullong ix = head->m_create_count; for (std::size_t j = 0; j < (typeinfo_count::max_count != 1 ? +head->m_limit : 1); j++) { @@ -1211,7 +1198,7 @@ namespace utils } // Return "unsigned negative" value if the creation index has increased - const ullong result = ix - head->m_total; + const ullong result = ix - head->m_create_count; if constexpr (sizeof...(Types) > 0) { @@ -1222,5 +1209,23 @@ namespace utils return result; } } + + template + ullong get_create_count() const + { + return get_head()->m_create_count; + } + + template + ullong get_destroy_count() const + { + return get_head()->m_destroy_count; + } + + template + std::shared_lock<::notifier> get_free_notifier() const + { + return std::shared_lock{get_head()->m_free_notifier}; + } }; } // namespace utils