From 1be291a86e15dd4b8e59a15f5038851903e82592 Mon Sep 17 00:00:00 2001 From: Justus Ranvier Date: Sun, 26 Nov 2023 20:52:33 -0600 Subject: [PATCH] Support construction with allocators for allocator-aware types Add a constructor and type trait specialization which is active if T is allocator-aware This allows a std::shared_ptr for a guarded type to be constructed with std::allocate_shared. --- src/cs_cow_guarded.h | 24 ++++++++++++++++++++++++ src/cs_deferred_guarded.h | 19 +++++++++++++++++++ src/cs_lr_guarded.h | 25 +++++++++++++++++++++++++ src/cs_ordered_guarded.h | 24 ++++++++++++++++++++++++ src/cs_plain_guarded.h | 24 ++++++++++++++++++++++++ src/cs_shared_guarded.h | 19 +++++++++++++++++++ 6 files changed, 135 insertions(+) diff --git a/src/cs_cow_guarded.h b/src/cs_cow_guarded.h index a73c31c..bafb621 100644 --- a/src/cs_cow_guarded.h +++ b/src/cs_cow_guarded.h @@ -72,6 +72,14 @@ class cow_guarded template cow_guarded(Us &&... data); + /** + Construct a cow_guarded guarded object which uses an allocator. This + constructor will accept any number of parameters, all of which + are forwarded to the constructor of T. + */ + template + cow_guarded(std::allocator_arg_t, Alloc alloc, Us &&... data); + /** Acquire a handle to the protected object. As a side effect, the protected object will be locked from access by any other @@ -220,6 +228,16 @@ cow_guarded::cow_guarded(Us &&... data) { } +template +template +cow_guarded::cow_guarded( + std::allocator_arg_t, + Alloc alloc, + Us &&... data) + : m_data(std::allocate_shared(alloc, std::forward(data)...)) +{ +} + template auto cow_guarded::lock() -> handle { @@ -338,4 +356,10 @@ auto cow_guarded::try_lock_shared_until(const TimePoint &timepoint) const } // namespace libguarded +template +struct std::uses_allocator, Alloc> + : std::uses_allocator::type +{ +}; + #endif diff --git a/src/cs_deferred_guarded.h b/src/cs_deferred_guarded.h index 8bdbda0..e9d0146 100644 --- a/src/cs_deferred_guarded.h +++ b/src/cs_deferred_guarded.h @@ -57,6 +57,9 @@ class deferred_guarded template deferred_guarded(Us &&... data); + template + deferred_guarded(std::allocator_arg_t, Alloc alloc, Us &&... data); + template void modify_detach(Func && func); @@ -112,6 +115,16 @@ deferred_guarded::deferred_guarded(Us &&... data) { } +template +template +deferred_guarded::deferred_guarded( + std::allocator_arg_t, + Alloc alloc, + Us &&... data) + : m_obj(std::forward(data)..., alloc), m_pendingWrites(false) +{ +} + template template void deferred_guarded::modify_detach(Func && func) @@ -296,4 +309,10 @@ auto deferred_guarded::try_lock_shared_until(const TimePoint & tp) const - } // namespace libguarded +template +struct std::uses_allocator, Alloc> + : std::uses_allocator::type +{ +}; + #endif diff --git a/src/cs_lr_guarded.h b/src/cs_lr_guarded.h index d33719f..ed5c58f 100644 --- a/src/cs_lr_guarded.h +++ b/src/cs_lr_guarded.h @@ -63,6 +63,14 @@ class lr_guarded template lr_guarded(Us &&... data); + /** + Construct a lr_guarded guarded object which uses an allocator. This + constructor will accept any number of parameters, all of which + are forwarded to the constructor of T. + */ + template + lr_guarded(std::allocator_arg_t, Alloc alloc, Us &&... data); + /** Modify the data by passing a functor. The functor must take exactly one argument of type T&. The functor will be called @@ -154,6 +162,17 @@ lr_guarded::lr_guarded(Us &&... data) { } +template +template +lr_guarded::lr_guarded( + std::allocator_arg_t, + Alloc alloc, + Us &&... data) + : m_left(std::forward(data)..., alloc), m_right(m_left), m_readingLeft(true), m_countingLeft(true), + m_leftReadCount(0), m_rightReadCount(0) +{ +} + template template void lr_guarded::modify(Func && func) @@ -263,4 +282,10 @@ auto lr_guarded::try_lock_shared_until(const TimePoint &) const -> shared_ } // namespace libguarded +template +struct std::uses_allocator, Alloc> + : std::uses_allocator::type +{ +}; + #endif diff --git a/src/cs_ordered_guarded.h b/src/cs_ordered_guarded.h index 1ab99b1..b0c2438 100644 --- a/src/cs_ordered_guarded.h +++ b/src/cs_ordered_guarded.h @@ -56,6 +56,14 @@ class ordered_guarded template ordered_guarded(Us &&... data); + /** + Construct a guarded object which uses an allocator. This + constructor will accept any number of parameters, all of which + are forwarded to the constructor of T. + */ + template + ordered_guarded(std::allocator_arg_t, Alloc alloc, Us &&... data); + template decltype(auto) modify(Func &&func); @@ -105,6 +113,16 @@ ordered_guarded::ordered_guarded(Us &&... data) { } +template +template +ordered_guarded::ordered_guarded( + std::allocator_arg_t, + Alloc alloc, + Us &&... data) + : m_obj(std::forward(data)..., alloc) +{ +} + template template decltype(auto) ordered_guarded::modify(Func &&func) @@ -164,4 +182,10 @@ auto ordered_guarded::try_lock_shared_until(const TimePoint &timepoint) co } // namespace libguarded +template +struct std::uses_allocator, Alloc> + : std::uses_allocator::type +{ +}; + #endif diff --git a/src/cs_plain_guarded.h b/src/cs_plain_guarded.h index 0b5d464..3af8bca 100644 --- a/src/cs_plain_guarded.h +++ b/src/cs_plain_guarded.h @@ -57,6 +57,14 @@ class plain_guarded template plain_guarded(Us &&... data); + /** + Construct a guarded object which uses an allocator. This + constructor will accept any number of parameters, all of which + are forwarded to the constructor of T. + */ + template + plain_guarded(std::allocator_arg_t, Alloc alloc, Us &&... data); + /** Acquire a handle to the protected object. As a side effect, the protected object will be locked from access by any other @@ -183,6 +191,16 @@ plain_guarded::plain_guarded(Us &&... data) { } +template +template +plain_guarded::plain_guarded( + std::allocator_arg_t, + Alloc alloc, + Us &&... data) + : m_obj(std::forward(data)..., alloc) +{ +} + template auto plain_guarded::lock() -> handle { @@ -278,4 +296,10 @@ using guarded [[deprecated("renamed to plain_guarded")]] = plain_guarded; } // namespace libguarded +template +struct std::uses_allocator, Alloc> + : std::uses_allocator::type +{ +}; + #endif diff --git a/src/cs_shared_guarded.h b/src/cs_shared_guarded.h index a491dee..5831d28 100644 --- a/src/cs_shared_guarded.h +++ b/src/cs_shared_guarded.h @@ -52,6 +52,9 @@ class shared_guarded template shared_guarded(Us &&... data); + template + shared_guarded(std::allocator_arg_t, Alloc alloc, Us &&... data); + // exclusive access [[nodiscard]] handle lock(); [[nodiscard]] handle try_lock(); @@ -142,6 +145,16 @@ shared_guarded::shared_guarded(Us &&... data) { } +template +template +shared_guarded::shared_guarded( + std::allocator_arg_t, + Alloc alloc, + Us &&... data) + : m_obj(std::forward(data)..., alloc) +{ +} + template auto shared_guarded::lock() -> handle { @@ -234,4 +247,10 @@ auto shared_guarded::try_lock_shared_until(const TimePoint &tp) const - } // namespace libguarded +template +struct std::uses_allocator, Alloc> + : std::uses_allocator::type +{ +}; + #endif