From 2d0a567e9c0b29729e6fb7e45682f055e5ca1c70 Mon Sep 17 00:00:00 2001 From: Valentin Palade Date: Thu, 30 Jan 2025 12:53:46 +0200 Subject: [PATCH 1/8] created experimental branch --- solid/reflection/v1/dispatch.hpp | 11 +++++------ solid/serialization/v3/binarybase.hpp | 2 +- solid/serialization/v3/binarybasic.hpp | 2 +- solid/serialization/v3/binarydeserializer.hpp | 12 +++++++++++- solid/serialization/v3/binaryserializer.hpp | 6 +++++- solid/serialization/v3/error.hpp | 2 +- solid/serialization/v3/serialization.hpp | 7 ------- solid/serialization/v3/test/CMakeLists.txt | 1 + solid/serialization/v3/test/test_binary.cpp | 8 +++++++- solid/utility/test/test_function_perf.cpp | 2 +- 10 files changed, 33 insertions(+), 20 deletions(-) diff --git a/solid/reflection/v1/dispatch.hpp b/solid/reflection/v1/dispatch.hpp index adde8129..162d9311 100644 --- a/solid/reflection/v1/dispatch.hpp +++ b/solid/reflection/v1/dispatch.hpp @@ -43,20 +43,19 @@ constexpr TypeGroupE type_group() { if constexpr (solid::is_shared_ptr_v) { return TypeGroupE::SharedPtr; - } - if constexpr (solid::is_intrusive_ptr_v) { + } else if constexpr (solid::is_intrusive_ptr_v) { return TypeGroupE::IntrusivePtr; - } - if constexpr (solid::is_unique_ptr_v) { + } else if constexpr (solid::is_unique_ptr_v) { return TypeGroupE::UniquePtr; } else { static_assert(!std::is_pointer_v, "Naked pointer are not supported - use std::shared_ptr or std::unique_ptr"); } + if constexpr (std::is_same_v) return TypeGroupE::Basic; - if constexpr (std::is_enum_v) + else if constexpr (std::is_enum_v) return TypeGroupE::Enum; - if constexpr (is_bitset_v) + else if constexpr (is_bitset_v) return TypeGroupE::Bitset; else if constexpr (is_std_vector_bool_v) return TypeGroupE::VectorBool; diff --git a/solid/serialization/v3/binarybase.hpp b/solid/serialization/v3/binarybase.hpp index 7638bbb4..11a7c030 100644 --- a/solid/serialization/v3/binarybase.hpp +++ b/solid/serialization/v3/binarybase.hpp @@ -22,7 +22,7 @@ namespace solid { namespace serialization { -namespace v3 { +inline namespace v3 { extern const LoggerT logger; diff --git a/solid/serialization/v3/binarybasic.hpp b/solid/serialization/v3/binarybasic.hpp index 369efa59..6f365f75 100644 --- a/solid/serialization/v3/binarybasic.hpp +++ b/solid/serialization/v3/binarybasic.hpp @@ -18,7 +18,7 @@ namespace solid { namespace serialization { -namespace v3 { +inline namespace v3 { namespace binary { namespace impl { diff --git a/solid/serialization/v3/binarydeserializer.hpp b/solid/serialization/v3/binarydeserializer.hpp index 01e7e4ab..cd9b7cda 100644 --- a/solid/serialization/v3/binarydeserializer.hpp +++ b/solid/serialization/v3/binarydeserializer.hpp @@ -23,7 +23,7 @@ namespace solid { namespace serialization { -namespace v3 { +inline namespace v3 { namespace binary { class DeserializerBase : public Base { @@ -1088,14 +1088,24 @@ class Deserializer : public DeserializerBase { } } +#if 0 template +#else + template >> +#endif +#if 0 + requires( + !std::is_base_of_v && !std::is_floating_point_v || (std::is_pointer_v && (is_shared_ptr_v || is_unique_ptr_v || is_intrusive_ptr_v))) +#endif void addDispatch(const Meta& _meta, T& _rt, ContextT& _rctx, const size_t _id, const char* const _name) { +#if 0 static_assert(!std::is_base_of_v, "Cannot use std::istream with Deserializer"); if constexpr (!is_shared_ptr_v && !is_unique_ptr_v && !is_intrusive_ptr_v) { static_assert(!std::is_pointer_v, "Naked pointer are not supported - use std::shared_ptr or std::unique_ptr"); } static_assert(!std::is_floating_point_v, "Floating point values not supported"); +#endif if constexpr (std::is_base_of_v) { addStream(const_cast(_rt), _meta.max_size_, _meta.progress_function_, _rctx, _id, _name); diff --git a/solid/serialization/v3/binaryserializer.hpp b/solid/serialization/v3/binaryserializer.hpp index 82a4e20b..985eb354 100644 --- a/solid/serialization/v3/binaryserializer.hpp +++ b/solid/serialization/v3/binaryserializer.hpp @@ -29,7 +29,7 @@ namespace solid { namespace serialization { -namespace v3 { +inline namespace v3 { namespace binary { class SerializerBase : public Base { @@ -912,14 +912,18 @@ class Serializer : public SerializerBase { } template + requires( + !std::is_base_of_v && !std::is_floating_point_v || (std::is_pointer_v && (is_shared_ptr_v || is_unique_ptr_v || is_intrusive_ptr_v))) void addDispatch(const Meta& _meta, const T& _rt, ContextT& _rctx, const size_t _id, const char* const _name) { +#if 0 static_assert(!std::is_base_of_v, "Cannot use std::ostream with Serializer"); if constexpr (!is_shared_ptr_v && !is_unique_ptr_v && !is_intrusive_ptr_v) { static_assert(!std::is_pointer_v, "Naked pointer are not supported - use std::shared_ptr or std::unique_ptr"); } static_assert(!std::is_floating_point_v, "Floating point values not supported"); +#endif if constexpr (std::is_base_of_v) { solid_assert(_meta.progress_function_); diff --git a/solid/serialization/v3/error.hpp b/solid/serialization/v3/error.hpp index ded37f60..d5ab8d61 100644 --- a/solid/serialization/v3/error.hpp +++ b/solid/serialization/v3/error.hpp @@ -14,7 +14,7 @@ namespace solid { namespace serialization { -namespace v3 { +inline namespace v3 { extern const ErrorConditionT error_limit_container; extern const ErrorConditionT error_limit_string; diff --git a/solid/serialization/v3/serialization.hpp b/solid/serialization/v3/serialization.hpp index fcc170f2..deafc189 100644 --- a/solid/serialization/v3/serialization.hpp +++ b/solid/serialization/v3/serialization.hpp @@ -14,10 +14,3 @@ #include "solid/serialization/v3/binarybasic.hpp" #include "solid/serialization/v3/binarydeserializer.hpp" #include "solid/serialization/v3/binaryserializer.hpp" -namespace solid { -namespace serialization { - -using namespace v3; - -} // namespace serialization -} // namespace solid diff --git a/solid/serialization/v3/test/CMakeLists.txt b/solid/serialization/v3/test/CMakeLists.txt index e41b4116..7d78500c 100644 --- a/solid/serialization/v3/test/CMakeLists.txt +++ b/solid/serialization/v3/test/CMakeLists.txt @@ -9,6 +9,7 @@ set( SerializationV3TestSuite create_test_sourcelist( SerializationV3Tests test_serialization.cpp ${SerializationV3TestSuite}) add_executable(test_serialization_v3 ${SerializationV3Tests}) +target_compile_options(test_serialization_v3 PUBLIC "SHELL: -fconcepts-diagnostics-depth=2") target_link_libraries(test_serialization_v3 solid_serialization_v3 diff --git a/solid/serialization/v3/test/test_binary.cpp b/solid/serialization/v3/test/test_binary.cpp index 32d901d0..24f5088d 100644 --- a/solid/serialization/v3/test/test_binary.cpp +++ b/solid/serialization/v3/test/test_binary.cpp @@ -76,6 +76,8 @@ class Test { char blob64[sizeof(uint64_t)]; std::ostringstream oss; + std::istringstream iss; + string* pstr = nullptr; void populate(bool _b) { @@ -209,7 +211,9 @@ class Test { return b == _rt.b && a == _rt.a && v == _rt.v && d == _rt.d && s1 == s2 && m == _rt.m && s == _rt.s && um == _rt.um && us == _rt.us && vb == _rt.vb && bs == _rt.bs && vc == _rt.vc; } - SOLID_REFLECT_V1(_rs, _rthis, _rctx) + // SOLID_REFLECT_V1(_rs, _rthis, _rctx) + template + void solidReflectV1(this Self& _rthis, Reflector& _rs, Context& _rctx) { _rs.add(_rthis.p, _rctx, 1, "p", [](auto& _rmeta) { _rmeta.maxSize(100); }); _rs @@ -271,6 +275,8 @@ class Test { _rctx); _rs.add(_rthis.a3, _rctx, 16, "a3"); + //_rs.add(_rthis.iss, _rctx, 17, "iss"); + //_rs.add(_rthis.pstr, _rctx, 18, "pstr"); //_rs.add(blob, blob_sz, BlobCapacity, _rctx, "blob"); //_rs.add(blob32, blob32_sz, sizeof(uint32_t), _rctx, "blob32"); diff --git a/solid/utility/test/test_function_perf.cpp b/solid/utility/test/test_function_perf.cpp index 4538604e..25dd574b 100644 --- a/solid/utility/test/test_function_perf.cpp +++ b/solid/utility/test/test_function_perf.cpp @@ -111,7 +111,7 @@ TestBase* create_test(const FunctionChoice _fnc_choice, const size_t _closure_si { switch (_fnc_choice) { case FunctionChoice::Solid: - return create_test>(_closure_size); + return create_test>(_closure_size); case FunctionChoice::Standard: return create_test>(_closure_size); } From 87288d131b2d2b2dc1dac8be257534cc22089688 Mon Sep 17 00:00:00 2001 From: Valentin Palade Date: Mon, 24 Feb 2025 12:46:31 +0200 Subject: [PATCH 2/8] start experimenting with ConstSharedBuffer --- solid/frame/mprpc/mprpcconfiguration.hpp | 10 +- solid/system/common.hpp | 4 +- solid/system/spinlock.hpp | 8 +- solid/utility/collapse.hpp | 7 +- solid/utility/intrusiveptr.hpp | 11 +- solid/utility/sharedbuffer.hpp | 235 +++++++++++++++++----- solid/utility/src/sharedbuffer.cpp | 44 ++-- solid/utility/test/test_collapse.cpp | 12 +- solid/utility/test/test_shared_buffer.cpp | 72 ++++--- 9 files changed, 281 insertions(+), 122 deletions(-) diff --git a/solid/frame/mprpc/mprpcconfiguration.hpp b/solid/frame/mprpc/mprpcconfiguration.hpp index 19866071..32577b14 100644 --- a/solid/frame/mprpc/mprpcconfiguration.hpp +++ b/solid/frame/mprpc/mprpcconfiguration.hpp @@ -63,7 +63,7 @@ using RelayDataFlagsT = Flags; std::ostream& operator<<(std::ostream& _ros, const RelayDataFlagsT& _flags); struct RelayData { - SharedBuffer buffer_; + ConstSharedBuffer buffer_; const char* pdata_ = nullptr; size_t data_size_ = 0; RelayData* pnext_ = nullptr; @@ -140,10 +140,10 @@ struct RelayData { private: friend class RelayConnection; RelayData( - const SharedBuffer& _buffer, - const char* _pdata, - size_t _data_size, - const bool _is_last) + const ConstSharedBuffer& _buffer, + const char* _pdata, + size_t _data_size, + const bool _is_last) : buffer_(_buffer) , pdata_(_pdata) , data_size_(_data_size) diff --git a/solid/system/common.hpp b/solid/system/common.hpp index c8b849db..4601d612 100644 --- a/solid/system/common.hpp +++ b/solid/system/common.hpp @@ -27,13 +27,13 @@ using longlong = long long; using ulonglong = unsigned long long; #ifdef __cpp_lib_hardware_interference_size -#ifndef _MSC_VER +#if !defined(_MSC_VER) && !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Winterference-size" #endif constexpr std::size_t hardware_constructive_interference_size = std::hardware_constructive_interference_size; constexpr std::size_t hardware_destructive_interference_size = std::hardware_destructive_interference_size; -#ifndef _MSC_VER +#if !defined(_MSC_VER) && !defined(__clang__) #pragma GCC diagnostic pop #endif #else diff --git a/solid/system/spinlock.hpp b/solid/system/spinlock.hpp index 703aa7b7..37fc0f9c 100644 --- a/solid/system/spinlock.hpp +++ b/solid/system/spinlock.hpp @@ -11,6 +11,10 @@ #include "solid/system/common.hpp" +#if (defined(__i386__) || defined(__x86_64__)) && defined(__clang__) +#include +#endif + #ifdef SOLID_USE_PTHREAD_SPINLOCK #include @@ -26,10 +30,6 @@ #define _WINSOCKAPI_ #include -#elif defined(__i386__) || defined(__x86_64__) -#if defined(__clang__) -#include -#endif #endif #endif diff --git a/solid/utility/collapse.hpp b/solid/utility/collapse.hpp index fe56c6db..40d3f9d3 100644 --- a/solid/utility/collapse.hpp +++ b/solid/utility/collapse.hpp @@ -16,7 +16,7 @@ namespace solid { #ifdef __cpp_concepts template -concept Collapsable = std::is_same_v || is_intrusive_ptr_v; +concept Collapsable = std::is_same_v || is_intrusive_ptr_v; template #else @@ -24,10 +24,7 @@ template #endif inline auto collapse(Ptr& _rptr) { - if (_rptr.collapse()) { - return Ptr(std::move(_rptr)); - } - return Ptr(); + return _rptr.collapse(); } } // namespace solid \ No newline at end of file diff --git a/solid/utility/intrusiveptr.hpp b/solid/utility/intrusiveptr.hpp index 3d08df98..d2087b70 100644 --- a/solid/utility/intrusiveptr.hpp +++ b/solid/utility/intrusiveptr.hpp @@ -65,7 +65,9 @@ class IntrusivePtr : public Policy { public: using element_type = T; - IntrusivePtr() = default; + using ThisT = IntrusivePtr; + + IntrusivePtr() = default; IntrusivePtr(const IntrusivePtr& _other) : ptr_(_other.ptr_) @@ -181,16 +183,16 @@ class IntrusivePtr : public Policy { return 0; } - bool collapse() + ThisT collapse() { if (ptr_) { if (Policy::release(*ptr_)) { Policy::acquire(*ptr_); - return true; + return ThisT{std::move(*this)}; } ptr_ = nullptr; } - return false; + return {}; } private: @@ -234,6 +236,7 @@ auto make_policy_intrusive(const P& _policy, Args&&... _args) return IntrusivePtr(_policy, new T(std::forward(_args)...)); } } // namespace impl + template auto make_intrusive(Args&&... _args) { diff --git a/solid/utility/sharedbuffer.hpp b/solid/utility/sharedbuffer.hpp index 7d4df75d..e160e98c 100644 --- a/solid/utility/sharedbuffer.hpp +++ b/solid/utility/sharedbuffer.hpp @@ -9,7 +9,14 @@ namespace solid { -class SharedBuffer { +class BufferManager; + +namespace detail { + +class SharedBufferBase { + friend class BufferManager; + +protected: struct Data { std::atomic use_count_; std::thread::id make_thread_id_; @@ -44,50 +51,68 @@ class SharedBuffer { } }; - static Data sentinel; + static inline Data sentinel{}; + static Data* allocate_data(const std::size_t _cap); Data* pdata_; - friend SharedBuffer make_shared_buffer(const std::size_t); - friend class BufferManager; - - static Data* allocate_data(const std::size_t _cap); +protected: + SharedBufferBase() + : pdata_(&sentinel) + { + } - SharedBuffer(const std::size_t _cap) + SharedBufferBase(const std::size_t _cap) : pdata_(allocate_data(_cap)) { } - SharedBuffer(const std::size_t _cap, const std::thread::id& _thr_id); + SharedBufferBase(const std::size_t _cap, const std::thread::id& _thr_id); -public: - explicit operator bool() const noexcept + SharedBufferBase(const SharedBufferBase& _other) + : pdata_(_other ? &_other.pdata_->acquire() : _other.pdata_) { - return pdata_ != &sentinel; } - SharedBuffer() - : pdata_(&sentinel) + SharedBufferBase(SharedBufferBase&& _other) + : pdata_(_other.pdata_) { + _other.pdata_ = &sentinel; } - SharedBuffer(const SharedBuffer& _other) - : pdata_(_other ? &_other.pdata_->acquire() : _other.pdata_) + + char* data() const { + return pdata_->data(); } - SharedBuffer(SharedBuffer&& _other) - : pdata_(_other.pdata_) + + void doCopy(const SharedBufferBase& _other) { - _other.pdata_ = &sentinel; + if (pdata_ != _other.pdata_) { + reset(); + + if (_other) { + pdata_ = &_other.pdata_->acquire(); + } + } } - ~SharedBuffer() + void doMove(SharedBufferBase&& _other) { - reset(); + if (pdata_ != _other.pdata_) { + reset(); + pdata_ = _other.pdata_; + _other.pdata_ = &sentinel; + } } - char* data() const +public: + explicit operator bool() const noexcept { - return pdata_->data(); + return pdata_ != &sentinel; + } + ~SharedBufferBase() + { + reset(); } std::size_t size() const @@ -107,16 +132,6 @@ class SharedBuffer { return pdata_->make_thread_id_; } - void append(const std::size_t _size) - { - pdata_->size_ += _size; - } - - void resize(const std::size_t _size = 0) - { - pdata_->size_ = _size; - } - bool empty() const { return pdata_->size_ == 0; @@ -137,56 +152,168 @@ class SharedBuffer { } return previous_use_count; } +}; + +} // namespace detail + +class ConstSharedBuffer; + +//----------------------------------------------------------------------------- +// Mutable - SharedBuffer +//----------------------------------------------------------------------------- +class SharedBuffer : public detail::SharedBufferBase { - bool collapse() + friend class BufferManager; + friend SharedBuffer make_shared_buffer(const std::size_t); + friend class ConstSharedBuffer; + + SharedBuffer(const std::size_t _cap) + : SharedBufferBase(_cap) + { + } + + SharedBuffer(const std::size_t _cap, const std::thread::id& _thr_id) + : SharedBufferBase(_cap, _thr_id) + { + } + + SharedBuffer(ConstSharedBuffer&& _other); + +public: + SharedBuffer() = default; + + SharedBuffer(const SharedBuffer& _other) = delete; + + SharedBuffer(SharedBuffer&& _other) + : SharedBufferBase(std::move(_other)) + { + } + + ~SharedBuffer() + { + reset(); + } + + char* data() + { + return detail::SharedBufferBase::data(); + } + + void append(const std::size_t _size) + { + pdata_->size_ += _size; + } + + void resize(const std::size_t _size = 0) + { + pdata_->size_ = _size; + } + + SharedBuffer& operator=(const SharedBuffer& _other) = delete; + + SharedBuffer& operator=(SharedBuffer&& _other) + { + doMove(std::move(_other)); + return *this; + } +}; + +inline SharedBuffer make_shared_buffer(const std::size_t _cap) +{ + return SharedBuffer(_cap); +} + +//----------------------------------------------------------------------------- +// ConstSharedBuffer +//----------------------------------------------------------------------------- + +class ConstSharedBuffer : public detail::SharedBufferBase { +public: + ConstSharedBuffer() = default; + + ConstSharedBuffer(const ConstSharedBuffer& _other) + : SharedBufferBase(std::move(_other)) + { + } + + ConstSharedBuffer(ConstSharedBuffer&& _other) + : SharedBufferBase(std::move(_other)) + { + } + + ConstSharedBuffer(SharedBuffer&& _other) + : SharedBufferBase(std::move(_other)) + { + } + + ~ConstSharedBuffer() + { + reset(); + } + + const char* data() const + { + return detail::SharedBufferBase::data(); + } + + SharedBuffer collapse() { if (*this) { size_t previous_use_count = 0; auto buf = pdata_->release(previous_use_count); if (buf) { pdata_->acquire(); - return true; + return SharedBuffer(std::move(*this)); } else { pdata_ = &sentinel; } } - return false; + return {}; } - SharedBuffer& operator=(const SharedBuffer& _other) + SharedBuffer mutate() { - if (pdata_ != _other.pdata_) { - reset(); - - if (_other) { - pdata_ = &_other.pdata_->acquire(); - } + if (useCount() == 1) { + return SharedBuffer(std::move(*this)); + } else { + return {}; } + } + + ConstSharedBuffer& operator=(const ConstSharedBuffer& _other) + { + doCopy(_other); return *this; } - SharedBuffer& operator=(SharedBuffer&& _other) + ConstSharedBuffer& operator=(ConstSharedBuffer&& _other) { - if (pdata_ != _other.pdata_) { - reset(); - pdata_ = _other.pdata_; - _other.pdata_ = &sentinel; - } + doMove(std::move(_other)); + return *this; + } + + ConstSharedBuffer& operator=(SharedBuffer&& _other) + { + doMove(std::move(_other)); return *this; } }; -inline SharedBuffer make_shared_buffer(const std::size_t _cap) +inline SharedBuffer::SharedBuffer(ConstSharedBuffer&& _other) + : SharedBufferBase(std::move(_other)) { - return SharedBuffer(_cap); } +//----------------------------------------------------------------------------- +// BufferManager +//----------------------------------------------------------------------------- + class BufferManager : NonCopyable { - friend class SharedBuffer; + friend class detail::SharedBufferBase; struct Data; - PimplT pimpl_; - static char* release(SharedBuffer::Data* _pdata); - static SharedBuffer::Data* allocate(const size_t _cap); + PimplT pimpl_; + static char* release(detail::SharedBufferBase::Data* _pdata); + static detail::SharedBufferBase::Data* allocate(const size_t _cap); public: struct LocalData; diff --git a/solid/utility/src/sharedbuffer.cpp b/solid/utility/src/sharedbuffer.cpp index 3a3e06ef..439ec95a 100644 --- a/solid/utility/src/sharedbuffer.cpp +++ b/solid/utility/src/sharedbuffer.cpp @@ -5,19 +5,8 @@ namespace solid { -SharedBuffer::Data SharedBuffer::sentinel; +// SharedBuffer::Data SharedBuffer::sentinel; -char* SharedBuffer::Data::release(size_t& _previous_use_count) -{ - if ((_previous_use_count = use_count_.fetch_sub(1)) == 1) { - if (make_thread_id_ == std::thread::id{}) { - return buffer_; - } else { - return BufferManager::release(this); - } - } - return nullptr; -} namespace { template inline constexpr std::size_t compute_capacity(const std::size_t _cap) @@ -35,7 +24,20 @@ inline constexpr std::size_t compute_capacity(const std::size_t _cap) } } // namespace -/* static */ SharedBuffer::Data* SharedBuffer::allocate_data(const std::size_t _cap) +namespace detail { +char* SharedBufferBase::Data::release(size_t& _previous_use_count) +{ + if ((_previous_use_count = use_count_.fetch_sub(1)) == 1) { + if (make_thread_id_ == std::thread::id{}) { + return buffer_; + } else { + return BufferManager::release(this); + } + } + return nullptr; +} + +/* static */ SharedBufferBase::Data* SharedBufferBase::allocate_data(const std::size_t _cap) { const std::size_t new_cap = compute_capacity(_cap); auto pbuf = new char[new_cap]; @@ -45,7 +47,7 @@ inline constexpr std::size_t compute_capacity(const std::size_t _cap) return pdata; } -SharedBuffer::SharedBuffer(const std::size_t _cap, const std::thread::id& _thr_id) +SharedBufferBase::SharedBufferBase(const std::size_t _cap, const std::thread::id& _thr_id) { pdata_ = BufferManager::allocate(_cap); if (pdata_ == nullptr) [[unlikely]] { @@ -57,12 +59,18 @@ SharedBuffer::SharedBuffer(const std::size_t _cap, const std::thread::id& _thr_i pdata_->make_thread_id_ = _thr_id; } -std::size_t SharedBuffer::actualCapacity() const +std::size_t SharedBufferBase::actualCapacity() const { - const std::size_t new_cap = compute_capacity(pdata_->capacity_); - return (pdata_->buffer_ + new_cap) - pdata_->data(); + if (*this) { + const std::size_t new_cap = compute_capacity(pdata_->capacity_); + return (pdata_->buffer_ + new_cap) - pdata_->data(); + } else { + return 0; + } } +} // namespace detail + //----------------------------------------------------------------------------- struct BufferManager::LocalData { @@ -139,7 +147,7 @@ BufferManager::~BufferManager() {} { if (_pdata) { if (_pdata->make_thread_id_ == std::this_thread::get_id()) { - const std::size_t new_cap = compute_capacity(_pdata->capacity_); + const std::size_t new_cap = compute_capacity(_pdata->capacity_); auto& entry = local_data.entry_map_[new_cap]; if (!entry.full()) { diff --git a/solid/utility/test/test_collapse.cpp b/solid/utility/test/test_collapse.cpp index 2af573ab..33ff65c4 100644 --- a/solid/utility/test/test_collapse.cpp +++ b/solid/utility/test/test_collapse.cpp @@ -148,17 +148,17 @@ int test_collapse(int argc, char* argv[]) const auto stop_time = chrono::high_resolution_clock::now(); cout << "Duration: " << chrono::duration_cast(stop_time - start_time).count() << "us" << endl; } else if (choice == 'b') { - CallPoolT wp{{thread_count, 10000, 100}, + CallPoolT wp{{thread_count, 10000, 100}, [](const size_t) { set_current_thread_affinity(); }, [](const size_t) {}}; - auto sm = make_shared_buffer(100); - const auto start_time = chrono::high_resolution_clock::now(); + ConstSharedBuffer sm = make_shared_buffer(100); + const auto start_time = chrono::high_resolution_clock::now(); for (size_t i = 0; i < repeat_count; ++i) { - std::promise p; - auto f = p.get_future(); - auto sm_lock{std::move(sm)}; + std::promise p; + auto f = p.get_future(); + auto sm_lock{std::move(sm)}; wp.pushAll( [&p, sm_lock]() mutable { if (auto tmp_sm = collapse(sm_lock)) { diff --git a/solid/utility/test/test_shared_buffer.cpp b/solid/utility/test/test_shared_buffer.cpp index 679c52d0..85220c90 100644 --- a/solid/utility/test/test_shared_buffer.cpp +++ b/solid/utility/test/test_shared_buffer.cpp @@ -15,49 +15,66 @@ int test_shared_buffer(int argc, char* argv[]) cout << sb.capacity() << endl; cout << sb.size() << endl; + string_view pangram = "the quick brown fox jumps over the lazy dog"; + strncpy(sb.data(), pangram.data(), sb.capacity()); - sb.resize(100); + sb.resize(pangram.size()); - solid_check(sb.size() == 100); + sb.data()[0] = 'T'; - SharedBuffer sb2 = sb; + solid_check(sb.size() == pangram.size()); - solid_check(sb2.size() == 100); + // SharedBuffer sbx{sb};//will not compile - SharedBuffer sb3 = sb2; // sb3 == sb2 + SharedBuffer sbx{std::move(sb)}; - solid_check(!sb2.collapse()); - solid_check(!sb.collapse()); + solid_check(sbx.size() == pangram.size()); + solid_check(!sb); - solid_check(sb3.collapse()); - solid_check(sb3); + ConstSharedBuffer csb = move(sbx); + + solid_check(csb.size() == pangram.size()); + + // csb.data()[0] = 't';//will not compile + + ConstSharedBuffer csb2 = csb; // sb3 == sb2 + + solid_check(csb.size() == pangram.size()); + auto sbc = csb.collapse(); + solid_check(!sbc); + sbc = csb2.collapse(); + solid_check(sbc); + solid_check(!csb2); + solid_check(sbc.size() == pangram.size()); + cout << "Data: " << sbc.data() << endl; } { std::promise p; std::future f = p.get_future(); vector thr_vec; - void* psb1 = nullptr; + const void* psb1 = nullptr; { - SharedBuffer sb1 = BufferManager::make(1000); - SharedBuffer sb2 = BufferManager::make(2000); + ConstSharedBuffer csb1 = BufferManager::make(1000); + ConstSharedBuffer csb2 = BufferManager::make(2000); - cout << static_cast(sb1.data()) << endl; - cout << static_cast(sb2.data()) << endl; + cout << static_cast(csb1.data()) << endl; + cout << static_cast(csb2.data()) << endl; - psb1 = sb1.data(); + psb1 = csb1.data(); solid_check(psb1); - auto lambda = [&p, sb1, sb2]() mutable { + auto lambda = [&p, csb1, csb2]() mutable { this_thread::sleep_for(chrono::milliseconds(200)); - if (sb1.collapse()) { - p.set_value(std::move(sb1)); + auto sbc = csb1.collapse(); + if (sbc) { + p.set_value(std::move(sbc)); } - if (sb2.collapse()) { - sb2.reset(); - solid_check(!sb2); + sbc = csb2.collapse(); + if (sbc) { + solid_check(!csb2); solid_check(BufferManager::localCount(2000) == 0); } }; @@ -65,9 +82,9 @@ int test_shared_buffer(int argc, char* argv[]) for (size_t i = 0; i < 4; ++i) { thr_vec.emplace_back(lambda); } - - if (sb1.collapse()) { - p.set_value(std::move(sb1)); + auto sbc = csb1.collapse(); + if (sbc) { + p.set_value(std::move(sbc)); } } @@ -102,6 +119,13 @@ int test_shared_buffer(int argc, char* argv[]) SharedBuffer empty_buf; solid_check(empty_buf.capacity() == 0); cout << "Empty buffer actualCapacity = " << empty_buf.actualCapacity() << endl; + solid_check(empty_buf.actualCapacity() == 0); + } + { + SharedBuffer zero_buf = make_shared_buffer(0); + solid_check(zero_buf.capacity() == 0); + cout << "Zero buffer actualCapacity = " << zero_buf.actualCapacity() << endl; + solid_check(zero_buf.actualCapacity() != 0 && zero_buf.actualCapacity() < 0xffffffff); } return 0; } \ No newline at end of file From 2bb8ec92ed5e26fd734bd19cc8d4ae358ae39dae Mon Sep 17 00:00:00 2001 From: Valentin Palade Date: Sat, 1 Mar 2025 19:32:36 +0200 Subject: [PATCH 3/8] experimenting with new intrusive_ptr design --- solid/frame/mprpc/mprpcconfiguration.hpp | 10 +- solid/serialization/v3/test/test_binary.cpp | 6 +- solid/utility/cacheable.hpp | 2 +- solid/utility/intrusiveptr.hpp | 530 +++++++++++++++++++- solid/utility/sharedbuffer.hpp | 148 +++++- solid/utility/src/sharedbuffer.cpp | 6 +- solid/utility/test/CMakeLists.txt | 4 +- solid/utility/test/test_intrusiveptr.cpp | 132 ++++- solid/utility/test/test_shared_buffer.cpp | 26 +- 9 files changed, 804 insertions(+), 60 deletions(-) diff --git a/solid/frame/mprpc/mprpcconfiguration.hpp b/solid/frame/mprpc/mprpcconfiguration.hpp index 32577b14..19866071 100644 --- a/solid/frame/mprpc/mprpcconfiguration.hpp +++ b/solid/frame/mprpc/mprpcconfiguration.hpp @@ -63,7 +63,7 @@ using RelayDataFlagsT = Flags; std::ostream& operator<<(std::ostream& _ros, const RelayDataFlagsT& _flags); struct RelayData { - ConstSharedBuffer buffer_; + SharedBuffer buffer_; const char* pdata_ = nullptr; size_t data_size_ = 0; RelayData* pnext_ = nullptr; @@ -140,10 +140,10 @@ struct RelayData { private: friend class RelayConnection; RelayData( - const ConstSharedBuffer& _buffer, - const char* _pdata, - size_t _data_size, - const bool _is_last) + const SharedBuffer& _buffer, + const char* _pdata, + size_t _data_size, + const bool _is_last) : buffer_(_buffer) , pdata_(_pdata) , data_size_(_data_size) diff --git a/solid/serialization/v3/test/test_binary.cpp b/solid/serialization/v3/test/test_binary.cpp index 24f5088d..d8221b66 100644 --- a/solid/serialization/v3/test/test_binary.cpp +++ b/solid/serialization/v3/test/test_binary.cpp @@ -210,10 +210,12 @@ class Test { #endif return b == _rt.b && a == _rt.a && v == _rt.v && d == _rt.d && s1 == s2 && m == _rt.m && s == _rt.s && um == _rt.um && us == _rt.us && vb == _rt.vb && bs == _rt.bs && vc == _rt.vc; } - - // SOLID_REFLECT_V1(_rs, _rthis, _rctx) +#ifndef __cpp_explicit_this_parameter + SOLID_REFLECT_V1(_rs, _rthis, _rctx) +#else template void solidReflectV1(this Self& _rthis, Reflector& _rs, Context& _rctx) +#endif { _rs.add(_rthis.p, _rctx, 1, "p", [](auto& _rmeta) { _rmeta.maxSize(100); }); _rs diff --git a/solid/utility/cacheable.hpp b/solid/utility/cacheable.hpp index aaeb892b..448857c7 100644 --- a/solid/utility/cacheable.hpp +++ b/solid/utility/cacheable.hpp @@ -175,7 +175,7 @@ class EnableCacheable : public What { void doCache() override { if constexpr (std::is_base_of_v) { - Cache::store(IntrusivePtr(static_cast(this))); + Cache::store(IntrusivePtr(static_cast(this), true)); } else { static_assert(std::is_base_of_v, "Type must be derived from SharedCacheable"); Cache::store(std::static_pointer_cast(this->shared_from_this())); diff --git a/solid/utility/intrusiveptr.hpp b/solid/utility/intrusiveptr.hpp index d2087b70..d05c538a 100644 --- a/solid/utility/intrusiveptr.hpp +++ b/solid/utility/intrusiveptr.hpp @@ -14,6 +14,364 @@ namespace solid { +#if true + +struct IntrusiveThreadSafePolicy; + +class IntrusiveThreadSafeBase { + friend struct IntrusiveThreadSafePolicy; + mutable std::atomic_size_t use_count_{0}; +}; + +struct IntrusiveThreadSafePolicy { + + static void acquire(const IntrusiveThreadSafeBase& _r) noexcept + { + ++_r.use_count_; + } + static bool release(const IntrusiveThreadSafeBase& _r) noexcept + { + return _r.use_count_.fetch_sub(1) == 1; + } + + template + static void destroy(const T& _r) + { + static_assert(!std::is_same_v, "cannot destroy object from non virtual base class IntrusiveThreadSafeBase"); + delete &_r; + } + + static auto use_count(const IntrusiveThreadSafeBase& _r) noexcept + { + return _r.use_count_.load(std::memory_order_relaxed); + } + + template + static T* create(Args&&... _args) + { + return new T(std::forward(_args)...); + } +}; + +template +struct intrusive_policy_dispatch; + +template +concept DefaultIntrusiveC = std::is_base_of_v; + +template +struct intrusive_policy_dispatch { + using type = IntrusiveThreadSafePolicy; +}; + +template +using intrusive_policy_dispatch_t = typename intrusive_policy_dispatch::type; + +namespace impl { +template > +bool intrusive_ptr_release(const T& _r) +{ + return PolicyT::release(_r); +} + +template > +void intrusive_ptr_destroy(const T& _r) +{ + return PolicyT::destroy(_r); +} + +template > +void intrusive_ptr_acquire(const T& _r) +{ + PolicyT::acquire(_r); +} + +template > +size_t intrusive_ptr_use_count(const T& _r) +{ + return PolicyT::use_count(_r); +} + +template > +T* intrusive_ptr_create(Args&&... _args) +{ + return PolicyT::template create(std::forward(_args)...); +} + +template +class IntrusivePtrBase { + using ThisT = IntrusivePtrBase; + template + friend class IntrusivePtrBase; + +protected: + T* ptr_ = nullptr; + +protected: + IntrusivePtrBase() = default; + + IntrusivePtrBase(const IntrusivePtrBase& _other) + : ptr_(_other.ptr_) + { + if (ptr_) { + intrusive_ptr_acquire(*ptr_); + } + } + + IntrusivePtrBase(IntrusivePtrBase&& _other) + : ptr_(_other.detach()) + { + } + + template + IntrusivePtrBase(const IntrusivePtrBase& _other) + : ptr_(static_cast(_other.ptr_)) + { + if (ptr_) { + intrusive_ptr_acquire(*ptr_); + } + } + + template + IntrusivePtrBase(IntrusivePtrBase&& _other) + : ptr_(static_cast(_other.detach())) + { + } + + ~IntrusivePtrBase() + { + if (ptr_ && intrusive_ptr_release(*ptr_)) { + intrusive_ptr_destroy(*ptr_); + } + } + + void doCopy(const IntrusivePtrBase& _other) noexcept + { + IntrusivePtrBase{_other}.swap(*this); + } + void doMove(IntrusivePtrBase&& _other) noexcept + { + IntrusivePtrBase{std::move(_other)}.swap(*this); + } + + template + void doCopy(const IntrusivePtrBase& _other) noexcept + { + IntrusivePtrBase{_other}.swap(*this); + } + + template + void doMove(IntrusivePtrBase&& _other) noexcept + { + IntrusivePtrBase{std::move(_other)}.swap(*this); + } + + IntrusivePtrBase(T* _ptr) + : ptr_(_ptr) + { + if (_ptr) { + intrusive_ptr_acquire(*_ptr); + } + } + + IntrusivePtrBase(T* _ptr, const bool _do_acquire) + : ptr_(_ptr) + { + if (_ptr && _do_acquire) { + intrusive_ptr_acquire(*_ptr); + } + } + + T* detach() noexcept + { + T* ret = ptr_; + ptr_ = nullptr; + return ret; + } + + void swap(IntrusivePtrBase& _other) noexcept + { + T* tmp = ptr_; + ptr_ = _other.ptr_; + _other.ptr_ = tmp; + } + +public: + using element_type = T; + + explicit operator bool() const noexcept + { + return ptr_ != nullptr; + } + + void reset() + { + if (ptr_) { + if (intrusive_ptr_release(*ptr_)) { + intrusive_ptr_destroy(*ptr_); + } + ptr_ = nullptr; + } + } + + size_t useCount() const noexcept + { + if (ptr_ != nullptr) [[likely]] { + return intrusive_ptr_use_count(*ptr_); + } + return 0; + } +#if 0 + ThisT collapse() + { + if (ptr_) { + if (intrusive_ptr_release(*ptr_)) { + intrusive_ptr_acquire(*ptr_); + return ThisT{std::move(*this)}; + } + ptr_ = nullptr; + } + return {}; + } + +#endif +}; + +} // namespace impl + +template +class IntrusivePtr : public impl::IntrusivePtrBase { + using BaseT = impl::IntrusivePtrBase; + using ThisT = IntrusivePtr; + template + friend class IntrusivePtr; + +public: + IntrusivePtr() = default; + + IntrusivePtr(T* _ptr, const bool _do_acquire) + : BaseT(_ptr, _do_acquire) + { + } + + IntrusivePtr(const IntrusivePtr& _other) + : BaseT(_other) + { + } + + IntrusivePtr(IntrusivePtr&& _other) + : BaseT(std::move(_other)) + { + } + + template + IntrusivePtr(const IntrusivePtr& _other) + : BaseT(_other) + { + } + + template + IntrusivePtr(IntrusivePtr&& _other) + : BaseT(std::move(_other)) + { + } + + ~IntrusivePtr() = default; + + IntrusivePtr& operator=(const IntrusivePtr& _other) noexcept + { + BaseT::doCopy(_other); + return *this; + } + + IntrusivePtr& operator=(IntrusivePtr&& _other) noexcept + { + BaseT::doMove(std::move(_other)); + return *this; + } + + template + IntrusivePtr& operator=(const IntrusivePtr& _other) noexcept + { + BaseT::doCopy(_other); + return *this; + } + + template + IntrusivePtr& operator=(IntrusivePtr&& _other) noexcept + { + BaseT::doMove(std::move(_other)); + return *this; + } + + T* get() const noexcept + { + return BaseT::ptr_; + } + + T& operator*() const noexcept + { + return *BaseT::ptr_; + } + + T* operator->() const noexcept + { + return BaseT::ptr_; + } + +private: + template + friend IntrusivePtr make_intrusive(Args&&... _args); + template + friend IntrusivePtr static_pointer_cast(const IntrusivePtr& _rp) noexcept; + template + friend IntrusivePtr dynamic_pointer_cast(const IntrusivePtr& _rp) noexcept; + template + friend IntrusivePtr static_pointer_cast(IntrusivePtr&& _rp) noexcept; + template + friend IntrusivePtr dynamic_pointer_cast(IntrusivePtr&& _rp) noexcept; + + IntrusivePtr(T* _ptr) + : BaseT(_ptr) + { + } +}; + +template +inline IntrusivePtr make_intrusive(Args&&... _args) +{ + // return IntrusivePtr(new TT(std::forward(_args)...)); + return IntrusivePtr(impl::intrusive_ptr_create(std::forward(_args)...)); +} +template +inline IntrusivePtr static_pointer_cast(const IntrusivePtr& _rp) noexcept +{ + return IntrusivePtr(static_cast(_rp.get())); +} +template +inline IntrusivePtr dynamic_pointer_cast(const IntrusivePtr& _rp) noexcept +{ + return IntrusivePtr(dynamic_cast(_rp.get())); +} + +template +inline IntrusivePtr static_pointer_cast(IntrusivePtr&& _rp) noexcept +{ + return IntrusivePtr(static_cast(_rp.detach())); +} + +template +inline IntrusivePtr dynamic_pointer_cast(IntrusivePtr&& _rp) noexcept +{ + auto* pt = dynamic_cast(_rp.get()); + if (pt) { + _rp.detach(); + return IntrusivePtr(pt); + } + return IntrusivePtr(); +} + +#else class IntrusiveThreadSafePolicy; class IntrusiveThreadSafeBase { @@ -37,11 +395,6 @@ class IntrusiveThreadSafeBase { } }; -namespace impl { -template -auto make_policy_intrusive(const P& _policy, Args&&... _args); -} - class IntrusiveThreadSafePolicy { protected: void acquire(const IntrusiveThreadSafeBase& _rt) const noexcept @@ -59,17 +412,22 @@ class IntrusiveThreadSafePolicy { } }; +namespace impl { +template +auto make_policy_intrusive(const P& _policy, Args&&... _args); + template -class IntrusivePtr : public Policy { +class IntrusivePtrBase : public Policy { +protected: T* ptr_ = nullptr; -public: +protected: using element_type = T; - using ThisT = IntrusivePtr; + using ThisT = IntrusivePtrBase; - IntrusivePtr() = default; + IntrusivePtrBase() = default; - IntrusivePtr(const IntrusivePtr& _other) + IntrusivePtrBase(const IntrusivePtrBase& _other) : ptr_(_other.ptr_) { if (ptr_) { @@ -77,13 +435,13 @@ class IntrusivePtr : public Policy { } } - IntrusivePtr(IntrusivePtr&& _other) + IntrusivePtrBase(IntrusivePtrBase&& _other) : ptr_(_other.detach()) { } template - IntrusivePtr(const IntrusivePtr& _other) + IntrusivePtrBase(const IntrusivePtrBase& _other) : ptr_(_other.get()) { if (ptr_) { @@ -92,24 +450,24 @@ class IntrusivePtr : public Policy { } template - IntrusivePtr(IntrusivePtr&& _other) + IntrusivePtrBase(IntrusivePtrBase&& _other) : ptr_(_other.detach()) { } template - friend class IntrusivePtr; + friend class IntrusivePtrBase; - ~IntrusivePtr() + ~IntrusivePtrBase() { if (ptr_ && Policy::release(*ptr_)) { delete ptr_; } } - IntrusivePtr& operator=(const IntrusivePtr& _other) noexcept + IntrusivePtrBase& operator=(const IntrusivePtrBase& _other) noexcept { - IntrusivePtr{_other}.swap(*this); + IntrusivePtrBase{_other}.swap(*this); return *this; } IntrusivePtr& operator=(IntrusivePtr&& _other) noexcept @@ -229,6 +587,142 @@ class IntrusivePtr : public Policy { } }; +} // namespace impl + +template +class IntrusivePtr : public impl::IntrusivePtrBase { +public: + using element_type = T; + using BaseT = impl::IntrusivePtrBase; + using ThisT = IntrusivePtr; + + IntrusivePtr() = default; + + IntrusivePtr(const IntrusivePtr& _other) + : BaseT(_other) + { + } + + IntrusivePtr(IntrusivePtr&& _other) + : BaseT(std::move(_other)) + { + } + + template + IntrusivePtr(const IntrusivePtr& _other) + : BaseT(_other) + { + } + + template + IntrusivePtr(IntrusivePtr&& _other) + : BaseT(std::move(_other)) + { + } + + template + friend class IntrusivePtr; + + ~IntrusivePtr() + { + } + + IntrusivePtr& operator=(const IntrusivePtr& _other) noexcept + { + IntrusivePtr{_other}.swap(*this); + return *this; + } + + IntrusivePtr& operator=(IntrusivePtr&& _other) noexcept + { + IntrusivePtr{std::move(_other)}.swap(*this); + return *this; + } + + template + IntrusivePtr& operator=(const IntrusivePtr& _other) noexcept + { + IntrusivePtr{_other}.swap(*this); + return *this; + } + template + IntrusivePtr& operator=(IntrusivePtr&& _other) noexcept + { + IntrusivePtr{std::move(_other)}.swap(*this); + return *this; + } + + void reset() + { + if (ptr_) { + if (Policy::release(*ptr_)) { + delete ptr_; + } + ptr_ = nullptr; + } + } + + void swap(IntrusivePtr& _other) noexcept + { + T* tmp = ptr_; + ptr_ = _other.ptr_; + _other.ptr_ = tmp; + } + + size_t useCount() const noexcept + { + if (ptr_ != nullptr) [[likely]] { + return Policy::useCount(*ptr_); + } + return 0; + } + + ThisT collapse() + { + if (ptr_) { + if (Policy::release(*ptr_)) { + Policy::acquire(*ptr_); + return ThisT{std::move(*this)}; + } + ptr_ = nullptr; + } + return {}; + } + +private: + template + friend auto make_intrusive(Args&&... _args); + template + friend auto impl::make_policy_intrusive(const PP&, Args&&... _args); + template + friend IntrusivePtr static_pointer_cast(const IntrusivePtr& _rp) noexcept; + template + friend IntrusivePtr dynamic_pointer_cast(const IntrusivePtr& _rp) noexcept; + template + friend IntrusivePtr static_pointer_cast(IntrusivePtr&& _rp) noexcept; + template + friend IntrusivePtr dynamic_pointer_cast(IntrusivePtr&& _rp) noexcept; + template + friend class EnableCacheable; + + IntrusivePtr(T* _ptr) + : ptr_(_ptr) + { + if (_ptr) { + Policy::acquire(*_ptr); + } + } + + IntrusivePtr(const Policy& _policy, T* _ptr) + : Policy(_policy) + , ptr_(_ptr) + { + if (_ptr) { + Policy::acquire(*_ptr); + } + } +}; + namespace impl { template auto make_policy_intrusive(const P& _policy, Args&&... _args) @@ -275,5 +769,5 @@ IntrusivePtr dynamic_pointer_cast(IntrusivePtr&& _rp) noexcept } return IntrusivePtr(); } - +#endif } // namespace solid \ No newline at end of file diff --git a/solid/utility/sharedbuffer.hpp b/solid/utility/sharedbuffer.hpp index e160e98c..ab364f91 100644 --- a/solid/utility/sharedbuffer.hpp +++ b/solid/utility/sharedbuffer.hpp @@ -11,7 +11,7 @@ namespace solid { class BufferManager; -namespace detail { +namespace impl { class SharedBufferBase { friend class BufferManager; @@ -154,18 +154,17 @@ class SharedBufferBase { } }; -} // namespace detail +} // namespace impl -class ConstSharedBuffer; +class MutableSharedBuffer; //----------------------------------------------------------------------------- -// Mutable - SharedBuffer +// SharedBuffer //----------------------------------------------------------------------------- -class SharedBuffer : public detail::SharedBufferBase { +class SharedBuffer : public impl::SharedBufferBase { friend class BufferManager; friend SharedBuffer make_shared_buffer(const std::size_t); - friend class ConstSharedBuffer; SharedBuffer(const std::size_t _cap) : SharedBufferBase(_cap) @@ -177,26 +176,29 @@ class SharedBuffer : public detail::SharedBufferBase { { } - SharedBuffer(ConstSharedBuffer&& _other); - public: SharedBuffer() = default; - SharedBuffer(const SharedBuffer& _other) = delete; + SharedBuffer(const SharedBuffer& _other) + : SharedBufferBase(_other) + { + } SharedBuffer(SharedBuffer&& _other) : SharedBufferBase(std::move(_other)) { } + SharedBuffer(MutableSharedBuffer&& _other); + ~SharedBuffer() { reset(); } - char* data() + char* data() const { - return detail::SharedBufferBase::data(); + return pdata_->data(); } void append(const std::size_t _size) @@ -209,13 +211,19 @@ class SharedBuffer : public detail::SharedBufferBase { pdata_->size_ = _size; } - SharedBuffer& operator=(const SharedBuffer& _other) = delete; + SharedBuffer& operator=(const SharedBuffer& _other) + { + doCopy(_other); + return *this; + } SharedBuffer& operator=(SharedBuffer&& _other) { doMove(std::move(_other)); return *this; } + + SharedBuffer& operator=(MutableSharedBuffer&& _other); }; inline SharedBuffer make_shared_buffer(const std::size_t _cap) @@ -223,16 +231,86 @@ inline SharedBuffer make_shared_buffer(const std::size_t _cap) return SharedBuffer(_cap); } +class ConstSharedBuffer; + +//----------------------------------------------------------------------------- +// MutableSharedBuffer +//----------------------------------------------------------------------------- + +class MutableSharedBuffer : public impl::SharedBufferBase { + friend class ConstSharedBuffer; + + MutableSharedBuffer(const std::size_t _cap) + : SharedBufferBase(_cap) + { + } + + MutableSharedBuffer(const std::size_t _cap, const std::thread::id& _thr_id) + : SharedBufferBase(_cap, _thr_id) + { + } + + MutableSharedBuffer(ConstSharedBuffer&& _other); + +public: + MutableSharedBuffer() = default; + + MutableSharedBuffer(const MutableSharedBuffer& _other) = delete; + + MutableSharedBuffer(MutableSharedBuffer&& _other) + : SharedBufferBase(std::move(_other)) + { + } + + MutableSharedBuffer(SharedBuffer&& _other) + : SharedBufferBase(std::move(_other)) + { + } + + ~MutableSharedBuffer() + { + reset(); + } + + char* data() + { + return impl::SharedBufferBase::data(); + } + + void append(const std::size_t _size) + { + pdata_->size_ += _size; + } + + void resize(const std::size_t _size = 0) + { + pdata_->size_ = _size; + } + + MutableSharedBuffer& operator=(const MutableSharedBuffer& _other) = delete; + + MutableSharedBuffer& operator=(MutableSharedBuffer&& _other) + { + doMove(std::move(_other)); + return *this; + } + MutableSharedBuffer& operator=(SharedBuffer&& _other) + { + doMove(std::move(_other)); + return *this; + } +}; + //----------------------------------------------------------------------------- // ConstSharedBuffer //----------------------------------------------------------------------------- -class ConstSharedBuffer : public detail::SharedBufferBase { +class ConstSharedBuffer : public impl::SharedBufferBase { public: ConstSharedBuffer() = default; ConstSharedBuffer(const ConstSharedBuffer& _other) - : SharedBufferBase(std::move(_other)) + : SharedBufferBase(_other) { } @@ -246,6 +324,11 @@ class ConstSharedBuffer : public detail::SharedBufferBase { { } + ConstSharedBuffer(MutableSharedBuffer&& _other) + : SharedBufferBase(std::move(_other)) + { + } + ~ConstSharedBuffer() { reset(); @@ -253,17 +336,17 @@ class ConstSharedBuffer : public detail::SharedBufferBase { const char* data() const { - return detail::SharedBufferBase::data(); + return impl::SharedBufferBase::data(); } - SharedBuffer collapse() + MutableSharedBuffer collapse() { if (*this) { size_t previous_use_count = 0; auto buf = pdata_->release(previous_use_count); if (buf) { pdata_->acquire(); - return SharedBuffer(std::move(*this)); + return MutableSharedBuffer(std::move(*this)); } else { pdata_ = &sentinel; } @@ -271,10 +354,10 @@ class ConstSharedBuffer : public detail::SharedBufferBase { return {}; } - SharedBuffer mutate() + MutableSharedBuffer mutate() { if (useCount() == 1) { - return SharedBuffer(std::move(*this)); + return MutableSharedBuffer(std::move(*this)); } else { return {}; } @@ -297,9 +380,26 @@ class ConstSharedBuffer : public detail::SharedBufferBase { doMove(std::move(_other)); return *this; } + + ConstSharedBuffer& operator=(MutableSharedBuffer&& _other) + { + doMove(std::move(_other)); + return *this; + } }; -inline SharedBuffer::SharedBuffer(ConstSharedBuffer&& _other) +inline MutableSharedBuffer::MutableSharedBuffer(ConstSharedBuffer&& _other) + : SharedBufferBase(std::move(_other)) +{ +} + +inline SharedBuffer& SharedBuffer::operator=(MutableSharedBuffer&& _other) +{ + doMove(std::move(_other)); + return *this; +} + +inline SharedBuffer::SharedBuffer(MutableSharedBuffer&& _other) : SharedBufferBase(std::move(_other)) { } @@ -309,11 +409,11 @@ inline SharedBuffer::SharedBuffer(ConstSharedBuffer&& _other) //----------------------------------------------------------------------------- class BufferManager : NonCopyable { - friend class detail::SharedBufferBase; + friend class impl::SharedBufferBase; struct Data; - PimplT pimpl_; - static char* release(detail::SharedBufferBase::Data* _pdata); - static detail::SharedBufferBase::Data* allocate(const size_t _cap); + PimplT pimpl_; + static char* release(impl::SharedBufferBase::Data* _pdata); + static impl::SharedBufferBase::Data* allocate(const size_t _cap); public: struct LocalData; diff --git a/solid/utility/src/sharedbuffer.cpp b/solid/utility/src/sharedbuffer.cpp index 439ec95a..e8695cc4 100644 --- a/solid/utility/src/sharedbuffer.cpp +++ b/solid/utility/src/sharedbuffer.cpp @@ -24,7 +24,7 @@ inline constexpr std::size_t compute_capacity(const std::size_t _cap) } } // namespace -namespace detail { +namespace impl { char* SharedBufferBase::Data::release(size_t& _previous_use_count) { if ((_previous_use_count = use_count_.fetch_sub(1)) == 1) { @@ -69,7 +69,7 @@ std::size_t SharedBufferBase::actualCapacity() const } } -} // namespace detail +} // namespace impl //----------------------------------------------------------------------------- @@ -147,7 +147,7 @@ BufferManager::~BufferManager() {} { if (_pdata) { if (_pdata->make_thread_id_ == std::this_thread::get_id()) { - const std::size_t new_cap = compute_capacity(_pdata->capacity_); + const std::size_t new_cap = compute_capacity(_pdata->capacity_); auto& entry = local_data.entry_map_[new_cap]; if (!entry.full()) { diff --git a/solid/utility/test/CMakeLists.txt b/solid/utility/test/CMakeLists.txt index 4ea4dd4e..48cedec9 100644 --- a/solid/utility/test/CMakeLists.txt +++ b/solid/utility/test/CMakeLists.txt @@ -1,5 +1,6 @@ #============================================================================== set( UtilityTestSuite + test_intrusiveptr.cpp test_invalid_index.cpp test_innerlist.cpp test_any.cpp @@ -20,8 +21,7 @@ set( UtilityTestSuite test_function_any_speed_full_solid.cpp test_function_any_speed_full_stl.cpp test_shared_buffer.cpp - test_collapse.cpp - test_intrusiveptr.cpp + #test_collapse.cpp ) set( ThreadPoolTestSuite diff --git a/solid/utility/test/test_intrusiveptr.cpp b/solid/utility/test/test_intrusiveptr.cpp index 6858a3e7..8eb8263d 100644 --- a/solid/utility/test/test_intrusiveptr.cpp +++ b/solid/utility/test/test_intrusiveptr.cpp @@ -5,7 +5,136 @@ using namespace solid; using namespace std; +#if true +namespace { +class Test : public IntrusiveThreadSafeBase { + string s_; + int i_ = 0; + +public: + Test(const string_view _s, const int _i) + : s_(_s) + , i_(_i) + { + } +}; + +struct TestFirst : Test { + size_t sz_ = 0; + + TestFirst(const size_t _sz, const string_view _s, const int _i) + : Test(_s, _i) + , sz_(_sz) + { + } +}; + +struct TestWithCounter { + string s_; + int i_ = 0; + + TestWithCounter(const string_view _s, const int _i) + : s_(_s) + , i_(_i) + { + } + + virtual ~TestWithCounter() {} + +private: + friend class TestIntrusivePolicy; + mutable atomic use_count_{0}; +}; + +template +concept TestIntrusiveC = std::is_base_of_v; + +struct TestIntrusivePolicy { + static void acquire(const TestWithCounter& _p) noexcept + { + ++_p.use_count_; + } + static bool release(const TestWithCounter& _p) noexcept + { + return _p.use_count_.fetch_sub(1) == 1; + } + static size_t useCount(const TestWithCounter& _p) noexcept + { + return _p.use_count_.load(std::memory_order_relaxed); + } + + template + static void destroy(const T& _r) + { + delete &_r; + } + + template + static T* create(Args&&... _args) + { + return new T(std::forward(_args)...); + } +}; + +} // namespace + +template +struct solid::intrusive_policy_dispatch { + using type = TestIntrusivePolicy; +}; + +int test_intrusiveptr(int argc, char* argvp[]) +{ + Test t{"ceva", 10}; + auto test_ptr = make_intrusive("ceva", 10); + auto twc_ptr = make_intrusive("ceva2", 11); + + cout << "sizeof(test_ptr): " << sizeof(test_ptr) << endl; + cout << "sizeof(twc_ptr): " << sizeof(twc_ptr) << endl; + + { + IntrusivePtr ptr; + + ptr = test_ptr; + solid_check(ptr.useCount() == 2); + } + solid_check(test_ptr.useCount() == 1); + { + IntrusivePtr ptr{test_ptr}; + + solid_check(ptr.useCount() == 2); + } + solid_check(test_ptr.useCount() == 1); + { + IntrusivePtr ptr{std::move(test_ptr)}; + + solid_check(ptr.useCount() == 1); + test_ptr = std::move(ptr); + } + solid_check(test_ptr.useCount() == 1); + { + IntrusivePtr ptr; + ptr = std::move(test_ptr); + + solid_check(ptr.useCount() == 1); + test_ptr = std::move(ptr); + } + solid_check(test_ptr.useCount() == 1); + + auto first_ptr = make_intrusive(111UL, "ceva", 10); + + { + IntrusivePtr ptr{static_pointer_cast(first_ptr)}; + + solid_check(ptr && ptr.useCount() == 2); + + // auto base_ptr = static_pointer_cast(ptr);//must not compile + } + + return 0; +} +#else namespace { struct Test : IntrusiveThreadSafeBase { @@ -108,4 +237,5 @@ int test_intrusiveptr(int argc, char* argvp[]) solid_check(ptr && ptr.useCount() == 2); } return 0; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/solid/utility/test/test_shared_buffer.cpp b/solid/utility/test/test_shared_buffer.cpp index 85220c90..86f0f49b 100644 --- a/solid/utility/test/test_shared_buffer.cpp +++ b/solid/utility/test/test_shared_buffer.cpp @@ -13,6 +13,24 @@ int test_shared_buffer(int argc, char* argv[]) { SharedBuffer sb = make_shared_buffer(1000); + cout << sb.capacity() << endl; + cout << sb.size() << endl; + + sb.resize(100); + + solid_check(sb.size() == 100); + + SharedBuffer sb2 = sb; + + solid_check(sb2.size() == 100); + + SharedBuffer sb3 = sb2; // sb3 == sb2 + + solid_check(sb3); + } + { + MutableSharedBuffer sb = make_shared_buffer(1000); + cout << sb.capacity() << endl; cout << sb.size() << endl; string_view pangram = "the quick brown fox jumps over the lazy dog"; @@ -24,9 +42,9 @@ int test_shared_buffer(int argc, char* argv[]) solid_check(sb.size() == pangram.size()); - // SharedBuffer sbx{sb};//will not compile + // MutableSharedBuffer sbxx{sb};//will not compile - SharedBuffer sbx{std::move(sb)}; + MutableSharedBuffer sbx{std::move(sb)}; solid_check(sbx.size() == pangram.size()); solid_check(!sb); @@ -49,8 +67,8 @@ int test_shared_buffer(int argc, char* argv[]) cout << "Data: " << sbc.data() << endl; } { - std::promise p; - std::future f = p.get_future(); + std::promise p; + std::future f = p.get_future(); vector thr_vec; const void* psb1 = nullptr; From aaff487374844beed00cdb22d703ffb399b57cf9 Mon Sep 17 00:00:00 2001 From: Valentin Palade Date: Tue, 4 Mar 2025 11:16:19 +0200 Subject: [PATCH 4/8] csharedbuffer: mutable/const instrusive_ptr and shared_buffer --- solid/utility/collapse.hpp | 2 +- solid/utility/intrusiveptr.hpp | 313 ++++++++++++++++++++++ solid/utility/sharedbuffer.hpp | 27 +- solid/utility/test/CMakeLists.txt | 2 +- solid/utility/test/test_collapse.cpp | 20 +- solid/utility/test/test_shared_buffer.cpp | 7 +- solid/utility/typetraits.hpp | 11 + 7 files changed, 359 insertions(+), 23 deletions(-) diff --git a/solid/utility/collapse.hpp b/solid/utility/collapse.hpp index 40d3f9d3..6d3fbc0f 100644 --- a/solid/utility/collapse.hpp +++ b/solid/utility/collapse.hpp @@ -16,7 +16,7 @@ namespace solid { #ifdef __cpp_concepts template -concept Collapsable = std::is_same_v || is_intrusive_ptr_v; +concept Collapsable = std::is_same_v || is_const_intrusive_ptr_v; template #else diff --git a/solid/utility/intrusiveptr.hpp b/solid/utility/intrusiveptr.hpp index d05c538a..ae8e384f 100644 --- a/solid/utility/intrusiveptr.hpp +++ b/solid/utility/intrusiveptr.hpp @@ -21,6 +21,12 @@ struct IntrusiveThreadSafePolicy; class IntrusiveThreadSafeBase { friend struct IntrusiveThreadSafePolicy; mutable std::atomic_size_t use_count_{0}; + +protected: + auto useCount() const + { + return use_count_.load(std::memory_order_relaxed); + } }; struct IntrusiveThreadSafePolicy { @@ -56,6 +62,7 @@ struct IntrusiveThreadSafePolicy { template struct intrusive_policy_dispatch; +#ifdef __cpp_concepts template concept DefaultIntrusiveC = std::is_base_of_v; @@ -66,6 +73,7 @@ struct intrusive_policy_dispatch { template using intrusive_policy_dispatch_t = typename intrusive_policy_dispatch::type; +#endif namespace impl { template > @@ -98,6 +106,8 @@ T* intrusive_ptr_create(Args&&... _args) return PolicyT::template create(std::forward(_args)...); } +// + template class IntrusivePtrBase { using ThisT = IntrusivePtrBase; @@ -337,6 +347,239 @@ class IntrusivePtr : public impl::IntrusivePtrBase { } }; +//----------------------------------------------------------------------------- +// MutableIntrusivePtr +//----------------------------------------------------------------------------- +template +class ConstIntrusivePtr; + +template +class MutableIntrusivePtr : public impl::IntrusivePtrBase { + using BaseT = impl::IntrusivePtrBase; + using ThisT = MutableIntrusivePtr; + template + friend class MutableIntrusivePtr; + template + friend class ConstIntrusivePtr; + + MutableIntrusivePtr(IntrusivePtr&& _other) + : BaseT(std::move(_other)) + { + } + +public: + MutableIntrusivePtr() = default; + + MutableIntrusivePtr(T* _ptr, const bool _do_acquire) + : BaseT(_ptr, _do_acquire) + { + } + + MutableIntrusivePtr(const MutableIntrusivePtr& _other) = delete; + + template + MutableIntrusivePtr(const MutableIntrusivePtr& _other) = delete; + + MutableIntrusivePtr(MutableIntrusivePtr&& _other) + : BaseT(std::move(_other)) + { + } + template + MutableIntrusivePtr(MutableIntrusivePtr&& _other) + : BaseT(std::move(_other)) + { + } + + ~MutableIntrusivePtr() = default; + + MutableIntrusivePtr& operator=(const MutableIntrusivePtr& _other) noexcept = delete; + + template + MutableIntrusivePtr& operator=(const MutableIntrusivePtr& _other) noexcept = delete; + + MutableIntrusivePtr& operator=(MutableIntrusivePtr&& _other) noexcept + { + BaseT::doMove(std::move(_other)); + return *this; + } + template + MutableIntrusivePtr& operator=(MutableIntrusivePtr&& _other) noexcept + { + BaseT::doMove(std::move(_other)); + return *this; + } + + T* get() const noexcept + { + return BaseT::ptr_; + } + + T& operator*() const noexcept + { + return *BaseT::ptr_; + } + + T* operator->() const noexcept + { + return BaseT::ptr_; + } + +private: + template + friend MutableIntrusivePtr make_mutable_intrusive(Args&&... _args); + template + friend MutableIntrusivePtr static_pointer_cast(const MutableIntrusivePtr& _rp) noexcept; + template + friend MutableIntrusivePtr dynamic_pointer_cast(const MutableIntrusivePtr& _rp) noexcept; + template + friend MutableIntrusivePtr static_pointer_cast(MutableIntrusivePtr&& _rp) noexcept; + template + friend MutableIntrusivePtr dynamic_pointer_cast(MutableIntrusivePtr&& _rp) noexcept; + + MutableIntrusivePtr(T* _ptr) + : BaseT(_ptr) + { + } + + MutableIntrusivePtr(ConstIntrusivePtr&& _other) + : BaseT(std::move(_other)) + { + } + + template + MutableIntrusivePtr(ConstIntrusivePtr&& _other) + : BaseT(std::move(_other)) + { + } +}; + +//----------------------------------------------------------------------------- +// ConstIntrusivePtr +//----------------------------------------------------------------------------- + +template +class ConstIntrusivePtr : public impl::IntrusivePtrBase { + using BaseT = impl::IntrusivePtrBase; + using ThisT = ConstIntrusivePtr; + template + friend class ConstIntrusivePtr; + +public: + ConstIntrusivePtr() = default; + + ConstIntrusivePtr(T* _ptr, const bool _do_acquire) + : BaseT(_ptr, _do_acquire) + { + } + + ConstIntrusivePtr(MutableIntrusivePtr&& _other) + : BaseT(_other) + { + } + + template + ConstIntrusivePtr(MutableIntrusivePtr&& _other) + : BaseT(std::move(_other)) + { + } + + ConstIntrusivePtr(ConstIntrusivePtr const& _other) + : BaseT(_other) + { + } + + ConstIntrusivePtr(ConstIntrusivePtr&& _other) + : BaseT(std::move(_other)) + { + } + + template + ConstIntrusivePtr(const ConstIntrusivePtr& _other) + : BaseT(_other) + { + } + + template + ConstIntrusivePtr(ConstIntrusivePtr&& _other) + : BaseT(std::move(_other)) + { + } + + ~ConstIntrusivePtr() = default; + + ConstIntrusivePtr& operator=(const ConstIntrusivePtr& _other) noexcept + { + BaseT::doCopy(_other); + return *this; + } + + ConstIntrusivePtr& operator=(ConstIntrusivePtr&& _other) noexcept + { + BaseT::doMove(std::move(_other)); + return *this; + } + + template + ConstIntrusivePtr& operator=(const ConstIntrusivePtr& _other) noexcept + { + BaseT::doCopy(_other); + return *this; + } + + template + ConstIntrusivePtr& operator=(ConstIntrusivePtr&& _other) noexcept + { + BaseT::doMove(std::move(_other)); + return *this; + } + + const T* get() const noexcept + { + return BaseT::ptr_; + } + + T const& operator*() const noexcept + { + return *BaseT::ptr_; + } + + const T* operator->() const noexcept + { + return BaseT::ptr_; + } + + MutableIntrusivePtr collapse() + { + if (BaseT::ptr_) { + if (impl::intrusive_ptr_release(*BaseT::ptr_)) { + impl::intrusive_ptr_acquire(*BaseT::ptr_); + return MutableIntrusivePtr{std::move(*this)}; + } + BaseT::ptr_ = nullptr; + } + return {}; + } + +private: + template + friend ConstIntrusivePtr static_pointer_cast(const ConstIntrusivePtr& _rp) noexcept; + template + friend ConstIntrusivePtr dynamic_pointer_cast(const ConstIntrusivePtr& _rp) noexcept; + template + friend ConstIntrusivePtr static_pointer_cast(ConstIntrusivePtr&& _rp) noexcept; + template + friend ConstIntrusivePtr dynamic_pointer_cast(ConstIntrusivePtr&& _rp) noexcept; + + ConstIntrusivePtr(T* _ptr) + : BaseT(_ptr) + { + } +}; + +//----------------------------------------------------------------------------- +// IntrusivePtr +//----------------------------------------------------------------------------- + template inline IntrusivePtr make_intrusive(Args&&... _args) { @@ -371,6 +614,76 @@ inline IntrusivePtr dynamic_pointer_cast(IntrusivePtr&& _rp) noexcept return IntrusivePtr(); } +//----------------------------------------------------------------------------- +// MutableIntrusivePtr +//----------------------------------------------------------------------------- + +template +inline MutableIntrusivePtr make_mutable_intrusive(Args&&... _args) +{ + // return IntrusivePtr(new TT(std::forward(_args)...)); + return MutableIntrusivePtr(make_intrusive(std::forward(_args)...)); +} +template +inline MutableIntrusivePtr static_pointer_cast(const MutableIntrusivePtr& _rp) noexcept +{ + return MutableIntrusivePtr(static_cast(_rp.get())); +} +template +inline MutableIntrusivePtr dynamic_pointer_cast(const MutableIntrusivePtr& _rp) noexcept +{ + return MutableIntrusivePtr(dynamic_cast(_rp.get())); +} + +template +inline MutableIntrusivePtr static_pointer_cast(MutableIntrusivePtr&& _rp) noexcept +{ + return MutableIntrusivePtr(static_cast(_rp.detach())); +} + +template +inline MutableIntrusivePtr dynamic_pointer_cast(MutableIntrusivePtr&& _rp) noexcept +{ + auto* pt = dynamic_cast(_rp.get()); + if (pt) { + _rp.detach(); + return MutableIntrusivePtr(pt); + } + return MutableIntrusivePtr(); +} + +//----------------------------------------------------------------------------- +// ConstIntrusivePtr +//----------------------------------------------------------------------------- + +template +inline ConstIntrusivePtr static_pointer_cast(const ConstIntrusivePtr& _rp) noexcept +{ + return ConstIntrusivePtr(static_cast(_rp.get())); +} +template +inline ConstIntrusivePtr dynamic_pointer_cast(const ConstIntrusivePtr& _rp) noexcept +{ + return ConstIntrusivePtr(dynamic_cast(_rp.get())); +} + +template +inline ConstIntrusivePtr static_pointer_cast(ConstIntrusivePtr&& _rp) noexcept +{ + return ConstIntrusivePtr(static_cast(_rp.detach())); +} + +template +inline ConstIntrusivePtr dynamic_pointer_cast(ConstIntrusivePtr&& _rp) noexcept +{ + auto* pt = dynamic_cast(_rp.get()); + if (pt) { + _rp.detach(); + return ConstIntrusivePtr(pt); + } + return ConstIntrusivePtr(); +} +//----------------------------------------------------------------------------- #else class IntrusiveThreadSafePolicy; diff --git a/solid/utility/sharedbuffer.hpp b/solid/utility/sharedbuffer.hpp index ab364f91..4d4b100e 100644 --- a/solid/utility/sharedbuffer.hpp +++ b/solid/utility/sharedbuffer.hpp @@ -239,6 +239,8 @@ class ConstSharedBuffer; class MutableSharedBuffer : public impl::SharedBufferBase { friend class ConstSharedBuffer; + friend class BufferManager; + friend MutableSharedBuffer make_mutable_buffer(const std::size_t); MutableSharedBuffer(const std::size_t _cap) : SharedBufferBase(_cap) @@ -252,6 +254,11 @@ class MutableSharedBuffer : public impl::SharedBufferBase { MutableSharedBuffer(ConstSharedBuffer&& _other); + MutableSharedBuffer(SharedBuffer&& _other) + : SharedBufferBase(std::move(_other)) + { + } + public: MutableSharedBuffer() = default; @@ -262,11 +269,6 @@ class MutableSharedBuffer : public impl::SharedBufferBase { { } - MutableSharedBuffer(SharedBuffer&& _other) - : SharedBufferBase(std::move(_other)) - { - } - ~MutableSharedBuffer() { reset(); @@ -301,6 +303,11 @@ class MutableSharedBuffer : public impl::SharedBufferBase { } }; +inline MutableSharedBuffer make_mutable_buffer(const std::size_t _cap) +{ + return MutableSharedBuffer(make_shared_buffer(_cap)); +} + //----------------------------------------------------------------------------- // ConstSharedBuffer //----------------------------------------------------------------------------- @@ -319,11 +326,6 @@ class ConstSharedBuffer : public impl::SharedBufferBase { { } - ConstSharedBuffer(SharedBuffer&& _other) - : SharedBufferBase(std::move(_other)) - { - } - ConstSharedBuffer(MutableSharedBuffer&& _other) : SharedBufferBase(std::move(_other)) { @@ -429,6 +431,11 @@ class BufferManager : NonCopyable { return SharedBuffer{_cap, std::this_thread::get_id()}; } + inline static MutableSharedBuffer makeMutable(const size_t _cap) + { + return MutableSharedBuffer{make(_cap)}; + } + static void localMaxCount(const size_t _cap, const size_t _count); static size_t localMaxCount(const size_t _cap); static size_t localCount(const size_t _cap); diff --git a/solid/utility/test/CMakeLists.txt b/solid/utility/test/CMakeLists.txt index 48cedec9..2dd8220d 100644 --- a/solid/utility/test/CMakeLists.txt +++ b/solid/utility/test/CMakeLists.txt @@ -1,6 +1,7 @@ #============================================================================== set( UtilityTestSuite test_intrusiveptr.cpp + test_collapse.cpp test_invalid_index.cpp test_innerlist.cpp test_any.cpp @@ -21,7 +22,6 @@ set( UtilityTestSuite test_function_any_speed_full_solid.cpp test_function_any_speed_full_stl.cpp test_shared_buffer.cpp - #test_collapse.cpp ) set( ThreadPoolTestSuite diff --git a/solid/utility/test/test_collapse.cpp b/solid/utility/test/test_collapse.cpp index 33ff65c4..34741732 100644 --- a/solid/utility/test/test_collapse.cpp +++ b/solid/utility/test/test_collapse.cpp @@ -49,7 +49,7 @@ struct Message : IntrusiveThreadSafeBase { }; using CallPoolT = ThreadPool, Function>; -using SharedMessageT = IntrusivePtr; +using SharedMessageT = ConstIntrusivePtr; } // namespace int test_collapse(int argc, char* argv[]) @@ -78,7 +78,7 @@ int test_collapse(int argc, char* argv[]) std::shared_future ready_future(ready_promise.get_future()); std::promise p; auto f = p.get_future(); - auto sm = make_intrusive(); + SharedMessageT sm = make_mutable_intrusive(); vector thr_vec; { auto lambda = [&p, ready_future](SharedMessageT _sm) mutable { @@ -114,17 +114,20 @@ int test_collapse(int argc, char* argv[]) } } } else if (choice == 'p') { - CallPoolT wp{{thread_count, 10000, 100}, + CallPoolT wp{{thread_count, 10000, 100}, [](const size_t) { set_current_thread_affinity(); }, [](const size_t) {}}; - auto sm = make_intrusive(); - const auto start_time = chrono::high_resolution_clock::now(); + SharedMessageT sm = make_mutable_intrusive(); + const auto start_time = chrono::high_resolution_clock::now(); for (size_t i = 0; i < repeat_count; ++i) { std::promise p; auto f = p.get_future(); - auto sm_lock{std::move(sm)}; + SharedMessageT sm_lock{std::move(sm)}; + + solid_check(sm_lock); + wp.pushAll( [&p, sm_lock]() mutable { if (auto tmp_sm = collapse(sm_lock)) { @@ -138,7 +141,7 @@ int test_collapse(int argc, char* argv[]) p.set_value(std::move(tmp_sm)); } { - if (f.wait_for(chrono::seconds(5000)) != future_status::ready) { + if (f.wait_for(chrono::seconds(5)) != future_status::ready) { solid_throw("Waited for too long"); } sm = f.get(); @@ -153,12 +156,13 @@ int test_collapse(int argc, char* argv[]) set_current_thread_affinity(); }, [](const size_t) {}}; - ConstSharedBuffer sm = make_shared_buffer(100); + ConstSharedBuffer sm = make_mutable_buffer(100); const auto start_time = chrono::high_resolution_clock::now(); for (size_t i = 0; i < repeat_count; ++i) { std::promise p; auto f = p.get_future(); auto sm_lock{std::move(sm)}; + solid_check(sm_lock); wp.pushAll( [&p, sm_lock]() mutable { if (auto tmp_sm = collapse(sm_lock)) { diff --git a/solid/utility/test/test_shared_buffer.cpp b/solid/utility/test/test_shared_buffer.cpp index 86f0f49b..660c3e50 100644 --- a/solid/utility/test/test_shared_buffer.cpp +++ b/solid/utility/test/test_shared_buffer.cpp @@ -29,7 +29,7 @@ int test_shared_buffer(int argc, char* argv[]) solid_check(sb3); } { - MutableSharedBuffer sb = make_shared_buffer(1000); + MutableSharedBuffer sb = make_mutable_buffer(1000); cout << sb.capacity() << endl; cout << sb.size() << endl; @@ -74,8 +74,8 @@ int test_shared_buffer(int argc, char* argv[]) const void* psb1 = nullptr; { - ConstSharedBuffer csb1 = BufferManager::make(1000); - ConstSharedBuffer csb2 = BufferManager::make(2000); + ConstSharedBuffer csb1 = BufferManager::makeMutable(1000); + ConstSharedBuffer csb2 = BufferManager::makeMutable(2000); cout << static_cast(csb1.data()) << endl; cout << static_cast(csb2.data()) << endl; @@ -90,6 +90,7 @@ int test_shared_buffer(int argc, char* argv[]) if (sbc) { p.set_value(std::move(sbc)); } + solid_check(!sbc); sbc = csb2.collapse(); if (sbc) { solid_check(!csb2); diff --git a/solid/utility/typetraits.hpp b/solid/utility/typetraits.hpp index c2942af2..4d701019 100644 --- a/solid/utility/typetraits.hpp +++ b/solid/utility/typetraits.hpp @@ -110,6 +110,14 @@ template struct is_intrusive_ptr> : std::true_type { }; +template +struct is_const_intrusive_ptr : std::false_type { +}; + +template +struct is_const_intrusive_ptr> : std::true_type { +}; + template inline constexpr bool is_unique_ptr_v = is_unique_ptr::value; @@ -119,6 +127,9 @@ inline constexpr bool is_shared_ptr_v = is_shared_ptr::value; template inline constexpr bool is_intrusive_ptr_v = is_intrusive_ptr::value; +template +inline constexpr bool is_const_intrusive_ptr_v = is_const_intrusive_ptr::value; + template struct is_bitset : std::false_type { }; From ef011fdf584639d3727b04b0a8db5b0692d645c3 Mon Sep 17 00:00:00 2001 From: Valentin Palade Date: Tue, 4 Mar 2025 23:19:46 +0200 Subject: [PATCH 5/8] csharedbuffer: make compile on macos --- solid/serialization/v3/src/binarybasic.cpp | 2 +- .../v3/src/binarydeserializer.cpp | 2 +- .../serialization/v3/src/binaryserializer.cpp | 2 +- solid/serialization/v3/src/error.cpp | 2 +- solid/serialization/v3/test/CMakeLists.txt | 2 +- solid/utility/sharedbuffer.hpp | 80 ++++++++++--------- solid/utility/src/sharedbuffer.cpp | 38 ++++----- solid/utility/test/test_shared_buffer.cpp | 2 +- 8 files changed, 68 insertions(+), 62 deletions(-) diff --git a/solid/serialization/v3/src/binarybasic.cpp b/solid/serialization/v3/src/binarybasic.cpp index f079854d..a23ee9a3 100644 --- a/solid/serialization/v3/src/binarybasic.cpp +++ b/solid/serialization/v3/src/binarybasic.cpp @@ -14,7 +14,7 @@ namespace solid { namespace serialization { -namespace v3 { +inline namespace v3 { const LoggerT logger{"solid::serialization"}; diff --git a/solid/serialization/v3/src/binarydeserializer.cpp b/solid/serialization/v3/src/binarydeserializer.cpp index c7ac30d8..91269a2c 100644 --- a/solid/serialization/v3/src/binarydeserializer.cpp +++ b/solid/serialization/v3/src/binarydeserializer.cpp @@ -14,7 +14,7 @@ namespace solid { namespace serialization { -namespace v3 { +inline namespace v3 { namespace binary { //== Deserializer ============================================================== diff --git a/solid/serialization/v3/src/binaryserializer.cpp b/solid/serialization/v3/src/binaryserializer.cpp index b0075005..02697e2a 100644 --- a/solid/serialization/v3/src/binaryserializer.cpp +++ b/solid/serialization/v3/src/binaryserializer.cpp @@ -14,7 +14,7 @@ namespace solid { namespace serialization { -namespace v3 { +inline namespace v3 { namespace binary { //== Serializer ============================================================== diff --git a/solid/serialization/v3/src/error.cpp b/solid/serialization/v3/src/error.cpp index 8196729f..0850c6eb 100644 --- a/solid/serialization/v3/src/error.cpp +++ b/solid/serialization/v3/src/error.cpp @@ -14,7 +14,7 @@ namespace solid { namespace serialization { -namespace v3 { +inline namespace v3 { namespace { diff --git a/solid/serialization/v3/test/CMakeLists.txt b/solid/serialization/v3/test/CMakeLists.txt index 7d78500c..92eab2da 100644 --- a/solid/serialization/v3/test/CMakeLists.txt +++ b/solid/serialization/v3/test/CMakeLists.txt @@ -9,7 +9,7 @@ set( SerializationV3TestSuite create_test_sourcelist( SerializationV3Tests test_serialization.cpp ${SerializationV3TestSuite}) add_executable(test_serialization_v3 ${SerializationV3Tests}) -target_compile_options(test_serialization_v3 PUBLIC "SHELL: -fconcepts-diagnostics-depth=2") +#target_compile_options(test_serialization_v3 PUBLIC "SHELL: -fconcepts-diagnostics-depth=2") target_link_libraries(test_serialization_v3 solid_serialization_v3 diff --git a/solid/utility/sharedbuffer.hpp b/solid/utility/sharedbuffer.hpp index 4d4b100e..c01ba59f 100644 --- a/solid/utility/sharedbuffer.hpp +++ b/solid/utility/sharedbuffer.hpp @@ -13,48 +13,50 @@ class BufferManager; namespace impl { -class SharedBufferBase { +struct SharedBufferData { friend class BufferManager; -protected: - struct Data { - std::atomic use_count_; - std::thread::id make_thread_id_; - Data* pnext_ = nullptr; - std::size_t size_ = 0; - std::size_t capacity_ = 0; - char* buffer_ = nullptr; - char data_[8]; - - Data() - : use_count_(1) - { - } + std::atomic use_count_; + std::thread::id make_thread_id_; + SharedBufferData* pnext_ = nullptr; + std::size_t size_ = 0; + std::size_t capacity_ = 0; + char* buffer_ = nullptr; + char data_[8]; - Data(char* _buffer) - : use_count_(1) - , buffer_(_buffer) - { - } + SharedBufferData() + : use_count_(1) + { + } - Data& acquire() - { - use_count_.fetch_add(1); - return *this; - } + SharedBufferData(char* _buffer) + : use_count_(1) + , buffer_(_buffer) + { + } - char* release(size_t& _previous_use_count); + SharedBufferData& acquire() + { + use_count_.fetch_add(1); + return *this; + } - char* data() - { - return data_; - } - }; + char* release(size_t& _previous_use_count); + + char* data() + { + return data_; + } +}; - static inline Data sentinel{}; - static Data* allocate_data(const std::size_t _cap); +class SharedBufferBase { +protected: + friend class BufferManager; - Data* pdata_; + static inline SharedBufferData sentinel{}; + static SharedBufferData* allocate_data(const std::size_t _cap); + + SharedBufferData* pdata_; protected: SharedBufferBase() @@ -411,11 +413,15 @@ inline SharedBuffer::SharedBuffer(MutableSharedBuffer&& _other) //----------------------------------------------------------------------------- class BufferManager : NonCopyable { + friend class impl::SharedBufferData; friend class impl::SharedBufferBase; struct Data; - PimplT pimpl_; - static char* release(impl::SharedBufferBase::Data* _pdata); - static impl::SharedBufferBase::Data* allocate(const size_t _cap); + PimplT pimpl_; + + using DataT = impl::SharedBufferData; + + static char* release(DataT* _pdata); + static DataT* allocate(const size_t _cap); public: struct LocalData; diff --git a/solid/utility/src/sharedbuffer.cpp b/solid/utility/src/sharedbuffer.cpp index e8695cc4..c17785e3 100644 --- a/solid/utility/src/sharedbuffer.cpp +++ b/solid/utility/src/sharedbuffer.cpp @@ -25,7 +25,7 @@ inline constexpr std::size_t compute_capacity(const std::size_t _cap) } // namespace namespace impl { -char* SharedBufferBase::Data::release(size_t& _previous_use_count) +char* SharedBufferData::release(size_t& _previous_use_count) { if ((_previous_use_count = use_count_.fetch_sub(1)) == 1) { if (make_thread_id_ == std::thread::id{}) { @@ -37,12 +37,12 @@ char* SharedBufferBase::Data::release(size_t& _previous_use_count) return nullptr; } -/* static */ SharedBufferBase::Data* SharedBufferBase::allocate_data(const std::size_t _cap) +/* static */ SharedBufferData* SharedBufferBase::allocate_data(const std::size_t _cap) { - const std::size_t new_cap = compute_capacity(_cap); + const std::size_t new_cap = compute_capacity(_cap); auto pbuf = new char[new_cap]; - auto pdata = new (pbuf) Data{pbuf}; + auto pdata = new (pbuf) SharedBufferData{pbuf}; pdata->capacity_ = _cap; //(pbuf + new_cap) - pdata->data(); return pdata; } @@ -51,9 +51,9 @@ SharedBufferBase::SharedBufferBase(const std::size_t _cap, const std::thread::id { pdata_ = BufferManager::allocate(_cap); if (pdata_ == nullptr) [[unlikely]] { - const std::size_t new_cap = compute_capacity(_cap); + const std::size_t new_cap = compute_capacity(_cap); char* pbuf = new char[new_cap]; - pdata_ = new (pbuf) Data{pbuf}; + pdata_ = new (pbuf) SharedBufferData{pbuf}; pdata_->capacity_ = _cap; //(pbuf + new_cap) - pdata_->data(); } pdata_->make_thread_id_ = _thr_id; @@ -62,7 +62,7 @@ SharedBufferBase::SharedBufferBase(const std::size_t _cap, const std::thread::id std::size_t SharedBufferBase::actualCapacity() const { if (*this) { - const std::size_t new_cap = compute_capacity(pdata_->capacity_); + const std::size_t new_cap = compute_capacity(pdata_->capacity_); return (pdata_->buffer_ + new_cap) - pdata_->data(); } else { return 0; @@ -75,9 +75,9 @@ std::size_t SharedBufferBase::actualCapacity() const struct BufferManager::LocalData { struct Entry { - SharedBuffer::Data* ptop_ = nullptr; - size_t max_count_ = BufferManager::configuration().default_local_max_count_; - size_t count_ = 0; + impl::SharedBufferData* ptop_ = nullptr; + size_t max_count_ = BufferManager::configuration().default_local_max_count_; + size_t count_ = 0; inline bool empty() const noexcept { @@ -89,7 +89,7 @@ struct BufferManager::LocalData { return max_count_ != 0 && count_ >= max_count_; } - inline SharedBuffer::Data* pop() noexcept + inline impl::SharedBufferData* pop() noexcept { if (!empty()) { auto* ptmp = ptop_; @@ -100,7 +100,7 @@ struct BufferManager::LocalData { return nullptr; } - inline void push(SharedBuffer::Data* _pnode) noexcept + inline void push(impl::SharedBufferData* _pnode) noexcept { if (_pnode) { _pnode->pnext_ = ptop_; @@ -143,11 +143,11 @@ BufferManager::~BufferManager() {} return ins; } -/* static */ char* BufferManager::release(SharedBuffer::Data* _pdata) +/* static */ char* BufferManager::release(DataT* _pdata) { if (_pdata) { if (_pdata->make_thread_id_ == std::this_thread::get_id()) { - const std::size_t new_cap = compute_capacity(_pdata->capacity_); + const std::size_t new_cap = compute_capacity(_pdata->capacity_); auto& entry = local_data.entry_map_[new_cap]; if (!entry.full()) { @@ -160,9 +160,9 @@ BufferManager::~BufferManager() {} return nullptr; } -/* static */ SharedBuffer::Data* BufferManager::allocate(const size_t _cap) +/* static */ BufferManager::DataT* BufferManager::allocate(const size_t _cap) { - const std::size_t new_cap = compute_capacity(_cap); + const std::size_t new_cap = compute_capacity(_cap); auto& entry = local_data.entry_map_[new_cap]; auto* pdata = entry.pop(); if (pdata) { @@ -176,19 +176,19 @@ BufferManager::~BufferManager() {} /* static */ void BufferManager::localMaxCount(const size_t _cap, const size_t _count) { - const std::size_t new_cap = compute_capacity(_cap); + const std::size_t new_cap = compute_capacity(_cap); local_data.entry_map_[new_cap].max_count_ = _count; } /* static */ size_t BufferManager::localMaxCount(const size_t _cap) { - const std::size_t new_cap = compute_capacity(_cap); + const std::size_t new_cap = compute_capacity(_cap); return local_data.entry_map_[new_cap].max_count_; } /* static */ size_t BufferManager::localCount(const size_t _cap) { - const std::size_t new_cap = compute_capacity(_cap); + const std::size_t new_cap = compute_capacity(_cap); return local_data.entry_map_[new_cap].count_; } diff --git a/solid/utility/test/test_shared_buffer.cpp b/solid/utility/test/test_shared_buffer.cpp index 660c3e50..69c40b23 100644 --- a/solid/utility/test/test_shared_buffer.cpp +++ b/solid/utility/test/test_shared_buffer.cpp @@ -49,7 +49,7 @@ int test_shared_buffer(int argc, char* argv[]) solid_check(sbx.size() == pangram.size()); solid_check(!sb); - ConstSharedBuffer csb = move(sbx); + ConstSharedBuffer csb = std::move(sbx); solid_check(csb.size() == pangram.size()); From 94ebd271ea02bbbbd49a5ae07b13916a950b8e71 Mon Sep 17 00:00:00 2001 From: Valentin Palade Date: Thu, 6 Mar 2025 23:26:08 +0200 Subject: [PATCH 6/8] csharedbuffer: cleanup and more concepts --- solid/frame/manager.hpp | 39 -- solid/frame/mprpc/mprpcservice.hpp | 179 -------- solid/frame/mprpc/src/mprpcconfiguration.cpp | 30 -- solid/frame/mprpc/src/mprpcconnection.hpp | 2 +- .../test/test_clientserver_idempotent.cpp | 2 +- solid/serialization/v3/binarydeserializer.hpp | 16 +- solid/serialization/v3/binaryserializer.hpp | 8 - solid/utility/intrusiveptr.hpp | 415 ------------------ solid/utility/test/test_intrusiveptr.cpp | 110 +---- 9 files changed, 6 insertions(+), 795 deletions(-) diff --git a/solid/frame/manager.hpp b/solid/frame/manager.hpp index 9e7d7bb2..d13a550f 100644 --- a/solid/frame/manager.hpp +++ b/solid/frame/manager.hpp @@ -101,14 +101,6 @@ class Manager final : NonCopyable { template bool visit(ActorIdT const& _ruid, F _f); -#if false // TODO:vapa:delete - template - bool visitDynamicCast(ActorIdT const& _ruid, F _f); - - template - bool visitExplicitCast(ActorIdT const& _ruid, F _f); -#endif - ActorIdT id(const ActorBase& _ractor) const; Service& service(const ActorBase& _ractor) const; @@ -189,37 +181,6 @@ inline bool Manager::visit(ActorIdT const& _ruid, F _f) { return doVisit(_ruid, ActorVisitFunctionT{_f}); } -#if false -template -inline bool Manager::visitDynamicCast(ActorIdT const& _ruid, F _f) -{ - auto lambda = [&_f](VisitContext& _rctx) { - T* pt = dynamic_cast(&_rctx.actor()); - if (pt) { - return _f(_rctx, *pt); - } - return false; - }; - ActorVisitFunctionT fct(std::ref(lambda)); - return doVisit(_ruid, fct); -} - -template -inline bool Manager::visitExplicitCast(ActorIdT const& _ruid, F _f) -{ - auto lambda = [&_f](VisitContext& _rctx) { - const std::type_info& req_type = typeid(T); - const std::type_info& val_type = doGetTypeId(*(&_rctx.actor())); - - if (std::type_index(req_type) == std::type_index(val_type)) { - return _f(_rctx, static_cast(_rctx.actor())); - } - return false; - }; - - return doVisit(_ruid, ActorVisitFunctionT{lambda}); -} -#endif template inline size_t Manager::forEachServiceActor(const Service& _rservice, F _f) diff --git a/solid/frame/mprpc/mprpcservice.hpp b/solid/frame/mprpc/mprpcservice.hpp index cfe72777..4b2e8155 100644 --- a/solid/frame/mprpc/mprpcservice.hpp +++ b/solid/frame/mprpc/mprpcservice.hpp @@ -348,13 +348,6 @@ class Service : public frame::Service { const MessageFlagsT& _flags = 0); // send message using connection uid ------------------------------------- -#if 0 - template - ErrorConditionT sendMessage( - RecipientId const& _rrecipient_id, - MessagePointerT const& _rmsgptr, - const MessageFlagsT& _flags = 0); -#endif template ErrorConditionT sendMessage( const RecipientUrl& _recipient_url, @@ -401,23 +394,6 @@ class Service : public frame::Service { MessagePointerT const& _rmsgptr, MessageId& _rmsg_id, const MessageFlagsT& _flags = 0); - // send request using connection uid -------------------------------------- -#if 0 - template - ErrorConditionT sendRequest( - RecipientId const& _rrecipient_id, - MessagePointerT const& _rmsgptr, - Fnc _complete_fnc, - const MessageFlagsT& _flags = 0); - - template - ErrorConditionT sendRequest( - RecipientId const& _rrecipient_id, - MessagePointerT const& _rmsgptr, - Fnc _complete_fnc, - MessageId& _rmsguid, - const MessageFlagsT& _flags = 0); -#endif // send message with complete using recipient name ------------------------ template @@ -444,23 +420,6 @@ class Service : public frame::Service { MessageId& _rmsguid, const MessageFlagsT& _flags); - // send message with complete using connection uid ------------------------ -#if 0 - template - ErrorConditionT sendMessage( - RecipientId const& _rrecipient_id, - MessagePointerT const& _rmsgptr, - Fnc _complete_fnc, - const MessageFlagsT& _flags); - - template - ErrorConditionT sendMessage( - RecipientId const& _rrecipient_id, - MessagePointerT const& _rmsgptr, - Fnc _complete_fnc, - MessageId& _rmsguid, - const MessageFlagsT& _flags); -#endif // send message using ConnectionContext ---------------------------------- template @@ -468,21 +427,6 @@ class Service : public frame::Service { ConnectionContext& _rctx, MessagePointerT const& _rmsgptr, const MessageFlagsT& _flags = 0); -#if 0 - template - ErrorConditionT sendMessage( - ConnectionContext& _rctx, - MessagePointerT const& _rmsgptr, - const MessageFlagsT& _flags = 0); - - template - ErrorConditionT sendMessage( - ConnectionContext& _rctx, - MessagePointerT const& _rmsgptr, - Fnc _complete_fnc, - const MessageFlagsT& _flags = 0); - -#endif //------------------------------------------------------------------------- ErrorConditionT sendRelay(const ActorIdT& _rconid, RelayData&& _urelmsg); ErrorConditionT sendRelayCancel(RelayData&& _urelmsg); @@ -741,19 +685,6 @@ ErrorConditionT Service::sendMessage( MessageCompleteFunctionT complete_handler; return doSendMessage(_recipient_url, msgptr, complete_handler, &_rrecipient_id, &_rmsg_id, _flags); } -// send message using connection uid ------------------------------------- -#if 0 -template -ErrorConditionT Service::sendMessage( - RecipientId const& _rrecipient_id, - MessagePointerT const& _rmsgptr, - const MessageFlagsT& _flags) -{ - auto msgptr(solid::static_pointer_cast(_rmsgptr)); - MessageCompleteFunctionT complete_handler; - return doSendMessage(nullptr, _rrecipient_id, msgptr, complete_handler, nullptr, nullptr, _flags); -} -#endif //------------------------------------------------------------------------- template ErrorConditionT Service::sendMessage( @@ -825,46 +756,6 @@ ErrorConditionT Service::sendRequest( return doSendMessage(_recipient_url, msgptr, complete_handler, &_rrecipient_id, &_rmsguid, _flags | MessageFlagsE::AwaitResponse); } //------------------------------------------------------------------------- -#if 0 -// send request using connection uid -------------------------------------- -template -ErrorConditionT Service::sendRequest( - RecipientId const& _rrecipient_id, - MessagePointerT const& _rmsgptr, - Fnc _complete_fnc, - const MessageFlagsT& _flags) -{ - using CompleteHandlerT = CompleteHandler::send_type, - typename message_complete_traits::recv_type>; - - auto msgptr(solid::static_pointer_cast(_rmsgptr)); - CompleteHandlerT fnc(std::forward(_complete_fnc)); - MessageCompleteFunctionT complete_handler(std::move(fnc)); - - return doSendMessage(nullptr, _rrecipient_id, msgptr, complete_handler, nullptr, nullptr, _flags | MessageFlagsE::AwaitResponse); -} -//------------------------------------------------------------------------- -template -ErrorConditionT Service::sendRequest( - RecipientId const& _rrecipient_id, - MessagePointerT const& _rmsgptr, - Fnc _complete_fnc, - MessageId& _rmsguid, - const MessageFlagsT& _flags) -{ - using CompleteHandlerT = CompleteHandler::send_type, - typename message_complete_traits::recv_type>; - - auto msgptr(solid::static_pointer_cast(_rmsgptr)); - CompleteHandlerT fnc(std::forward(_complete_fnc)); - MessageCompleteFunctionT complete_handler(std::move(fnc)); - - return doSendMessage(nullptr, _rrecipient_id, msgptr, complete_handler, nullptr, &_rmsguid, _flags | MessageFlagsE::AwaitResponse); -} -#endif -//------------------------------------------------------------------------- // send response using recipient id --------------------------------------- template @@ -951,46 +842,6 @@ ErrorConditionT Service::sendMessage( return doSendMessage(_recipient_url, msgptr, complete_handler, &_rrecipient_id, &_rmsguid, _flags); } //------------------------------------------------------------------------- -// send message with complete using connection uid ------------------------ -#if 0 -template -ErrorConditionT Service::sendMessage( - RecipientId const& _rrecipient_id, - MessagePointerT const& _rmsgptr, - Fnc _complete_fnc, - const MessageFlagsT& _flags) -{ - using CompleteHandlerT = CompleteHandler::send_type, - typename message_complete_traits::recv_type>; - - auto msgptr(solid::static_pointer_cast(_rmsgptr)); - CompleteHandlerT fnc(std::forward(_complete_fnc)); - MessageCompleteFunctionT complete_handler(std::move(fnc)); - - return doSendMessage(nullptr, _rrecipient_id, msgptr, complete_handler, nullptr, nullptr, _flags); -} -//------------------------------------------------------------------------- -template -ErrorConditionT Service::sendMessage( - RecipientId const& _rrecipient_id, - MessagePointerT const& _rmsgptr, - Fnc _complete_fnc, - MessageId& _rmsguid, - const MessageFlagsT& _flags) -{ - using CompleteHandlerT = CompleteHandler::send_type, - typename message_complete_traits::recv_type>; - - auto msgptr(solid::static_pointer_cast(_rmsgptr)); - CompleteHandlerT fnc(std::forward(_complete_fnc)); - MessageCompleteFunctionT complete_handler(std::move(fnc)); - - return doSendMessage(nullptr, _rrecipient_id, msgptr, complete_handler, nullptr, &_rmsguid, _flags); -} -#endif -//------------------------------------------------------------------------- // send message using ConnectionContext ---------------------------------- template @@ -1003,36 +854,6 @@ ErrorConditionT Service::sendResponse( MessageCompleteFunctionT complete_handler; return doSendMessage(_rctx, msgptr, complete_handler, nullptr, nullptr, _flags | MessageFlagsE::Response); } -#if 0 -template -ErrorConditionT Service::sendMessage( - ConnectionContext& _rctx, - MessagePointerT const& _rmsgptr, - const MessageFlagsT& _flags) -{ - auto msgptr(solid::static_pointer_cast(_rmsgptr)); - MessageCompleteFunctionT complete_handler; - return doSendMessage(_rctx, msgptr, complete_handler, nullptr, nullptr, _flags); -} - -template -ErrorConditionT Service::sendMessage( - ConnectionContext& _rctx, - MessagePointerT const& _rmsgptr, - Fnc _complete_fnc, - const MessageFlagsT& _flags) -{ - using CompleteHandlerT = CompleteHandler::send_type, - typename message_complete_traits::recv_type>; - - auto msgptr(solid::static_pointer_cast(_rmsgptr)); - CompleteHandlerT fnc(std::forward(_complete_fnc)); - MessageCompleteFunctionT complete_handler(std::move(fnc)); - - return doSendMessage(_rctx, msgptr, complete_handler, nullptr, nullptr, _flags); -} -#endif //------------------------------------------------------------------------- template diff --git a/solid/frame/mprpc/src/mprpcconfiguration.cpp b/solid/frame/mprpc/src/mprpcconfiguration.cpp index bff022ef..a3a30d38 100644 --- a/solid/frame/mprpc/src/mprpcconfiguration.cpp +++ b/solid/frame/mprpc/src/mprpcconfiguration.cpp @@ -39,36 +39,6 @@ std::ostream& operator<<(std::ostream& _ros, const RelayDataFlagsT& _flags) return _ros; } -#if false -/*virtual*/ BufferBase::~BufferBase() -{ -} - -RecvBufferPointerT make_recv_buffer(const size_t _cp) -{ - switch (_cp) { - case 512: - return std::dynamic_pointer_cast(std::make_shared>()); - case 1 * 1024: - return std::dynamic_pointer_cast(std::make_shared>()); - case 2 * 1024: - return std::dynamic_pointer_cast(std::make_shared>()); - case 4 * 1024: - return std::dynamic_pointer_cast(std::make_shared>()); - case 8 * 1024: - return std::dynamic_pointer_cast(std::make_shared>()); - case 16 * 1024: - return std::dynamic_pointer_cast(std::make_shared>()); - case 32 * 1024: - return std::dynamic_pointer_cast(std::make_shared>()); - case 64 * 1024: - return std::dynamic_pointer_cast(std::make_shared>()); - default: - return std::make_shared>(_cp); - } -} -#endif - namespace { SharedBuffer default_allocate_recv_buffer(const uint32_t _cp) { diff --git a/solid/frame/mprpc/src/mprpcconnection.hpp b/solid/frame/mprpc/src/mprpcconnection.hpp index adacab0c..27bbb59a 100644 --- a/solid/frame/mprpc/src/mprpcconnection.hpp +++ b/solid/frame/mprpc/src/mprpcconnection.hpp @@ -380,7 +380,7 @@ class Connection : public frame::aio::Actor { bool poll_pool_more_ = true; bool send_posted_ = false; Any<> any_data_; - char socket_emplace_buf_[static_cast(ConnectionValues::SocketEmplacementSize)]; + char socket_emplace_buf_[static_cast(ConnectionValues::SocketEmplacementSize)] = {}; SocketStubPtrT sock_ptr_; NanoTime timeout_recv_ = NanoTime::max(); // client and server NanoTime timeout_send_soft_ = NanoTime::max(); // client and server diff --git a/solid/frame/mprpc/test/test_clientserver_idempotent.cpp b/solid/frame/mprpc/test/test_clientserver_idempotent.cpp index 1f17c871..b8762b17 100644 --- a/solid/frame/mprpc/test/test_clientserver_idempotent.cpp +++ b/solid/frame/mprpc/test/test_clientserver_idempotent.cpp @@ -389,7 +389,7 @@ int test_clientserver_idempotent(int argc, char* argv[]) cfg.pool_max_active_connection_count = max_per_pool_connection_count; - cfg.client.name_resolve_fnc = frame::mprpc::InternetResolverF(resolver, server_port.c_str(), {"localhost"}, SocketInfo::Inet4); + cfg.client.name_resolve_fnc = frame::mprpc::InternetResolverF(resolver, server_port.c_str(), "localhost", SocketInfo::Inet4); if (secure) { solid_dbg(generic_logger, Info, "Configure SSL client ------------------------------------"); diff --git a/solid/serialization/v3/binarydeserializer.hpp b/solid/serialization/v3/binarydeserializer.hpp index cd9b7cda..7edd9b8d 100644 --- a/solid/serialization/v3/binarydeserializer.hpp +++ b/solid/serialization/v3/binarydeserializer.hpp @@ -1088,25 +1088,13 @@ class Deserializer : public DeserializerBase { } } -#if 0 - template -#else - template >> -#endif -#if 0 + template >*/> +#if 1 requires( !std::is_base_of_v && !std::is_floating_point_v || (std::is_pointer_v && (is_shared_ptr_v || is_unique_ptr_v || is_intrusive_ptr_v))) #endif void addDispatch(const Meta& _meta, T& _rt, ContextT& _rctx, const size_t _id, const char* const _name) { -#if 0 - static_assert(!std::is_base_of_v, "Cannot use std::istream with Deserializer"); - if constexpr (!is_shared_ptr_v && !is_unique_ptr_v && !is_intrusive_ptr_v) { - static_assert(!std::is_pointer_v, "Naked pointer are not supported - use std::shared_ptr or std::unique_ptr"); - } - static_assert(!std::is_floating_point_v, "Floating point values not supported"); -#endif - if constexpr (std::is_base_of_v) { addStream(const_cast(_rt), _meta.max_size_, _meta.progress_function_, _rctx, _id, _name); } else if constexpr (std::is_integral_v) { diff --git a/solid/serialization/v3/binaryserializer.hpp b/solid/serialization/v3/binaryserializer.hpp index 985eb354..0148a362 100644 --- a/solid/serialization/v3/binaryserializer.hpp +++ b/solid/serialization/v3/binaryserializer.hpp @@ -916,14 +916,6 @@ class Serializer : public SerializerBase { !std::is_base_of_v && !std::is_floating_point_v || (std::is_pointer_v && (is_shared_ptr_v || is_unique_ptr_v || is_intrusive_ptr_v))) void addDispatch(const Meta& _meta, const T& _rt, ContextT& _rctx, const size_t _id, const char* const _name) { -#if 0 - static_assert(!std::is_base_of_v, "Cannot use std::ostream with Serializer"); - if constexpr (!is_shared_ptr_v && !is_unique_ptr_v && !is_intrusive_ptr_v) { - static_assert(!std::is_pointer_v, "Naked pointer are not supported - use std::shared_ptr or std::unique_ptr"); - } - - static_assert(!std::is_floating_point_v, "Floating point values not supported"); -#endif if constexpr (std::is_base_of_v) { solid_assert(_meta.progress_function_); diff --git a/solid/utility/intrusiveptr.hpp b/solid/utility/intrusiveptr.hpp index ae8e384f..675d23d3 100644 --- a/solid/utility/intrusiveptr.hpp +++ b/solid/utility/intrusiveptr.hpp @@ -14,8 +14,6 @@ namespace solid { -#if true - struct IntrusiveThreadSafePolicy; class IntrusiveThreadSafeBase { @@ -231,20 +229,6 @@ class IntrusivePtrBase { } return 0; } -#if 0 - ThisT collapse() - { - if (ptr_) { - if (intrusive_ptr_release(*ptr_)) { - intrusive_ptr_acquire(*ptr_); - return ThisT{std::move(*this)}; - } - ptr_ = nullptr; - } - return {}; - } - -#endif }; } // namespace impl @@ -684,403 +668,4 @@ inline ConstIntrusivePtr dynamic_pointer_cast(ConstIntrusivePtr&& _rp) n return ConstIntrusivePtr(); } //----------------------------------------------------------------------------- -#else -class IntrusiveThreadSafePolicy; - -class IntrusiveThreadSafeBase { - mutable std::atomic_size_t use_count_{0}; - -public: - size_t useCount() const noexcept - { - return use_count_.load(std::memory_order_relaxed); - } - -private: - friend class IntrusiveThreadSafePolicy; - void acquire() const noexcept - { - ++use_count_; - } - bool release() const noexcept - { - return use_count_.fetch_sub(1) == 1; - } -}; - -class IntrusiveThreadSafePolicy { -protected: - void acquire(const IntrusiveThreadSafeBase& _rt) const noexcept - { - _rt.acquire(); - } - - auto release(const IntrusiveThreadSafeBase& _rt) const noexcept - { - return _rt.release(); - } - auto useCount(const IntrusiveThreadSafeBase& _rt) const noexcept - { - return _rt.useCount(); - } -}; - -namespace impl { -template -auto make_policy_intrusive(const P& _policy, Args&&... _args); - -template -class IntrusivePtrBase : public Policy { -protected: - T* ptr_ = nullptr; - -protected: - using element_type = T; - using ThisT = IntrusivePtrBase; - - IntrusivePtrBase() = default; - - IntrusivePtrBase(const IntrusivePtrBase& _other) - : ptr_(_other.ptr_) - { - if (ptr_) { - Policy::acquire(*ptr_); - } - } - - IntrusivePtrBase(IntrusivePtrBase&& _other) - : ptr_(_other.detach()) - { - } - - template - IntrusivePtrBase(const IntrusivePtrBase& _other) - : ptr_(_other.get()) - { - if (ptr_) { - Policy::acquire(*ptr_); - } - } - - template - IntrusivePtrBase(IntrusivePtrBase&& _other) - : ptr_(_other.detach()) - { - } - - template - friend class IntrusivePtrBase; - - ~IntrusivePtrBase() - { - if (ptr_ && Policy::release(*ptr_)) { - delete ptr_; - } - } - - IntrusivePtrBase& operator=(const IntrusivePtrBase& _other) noexcept - { - IntrusivePtrBase{_other}.swap(*this); - return *this; - } - IntrusivePtr& operator=(IntrusivePtr&& _other) noexcept - { - IntrusivePtr{std::move(_other)}.swap(*this); - return *this; - } - - template - IntrusivePtr& operator=(const IntrusivePtr& _other) noexcept - { - IntrusivePtr{_other}.swap(*this); - return *this; - } - template - IntrusivePtr& operator=(IntrusivePtr&& _other) noexcept - { - IntrusivePtr{std::move(_other)}.swap(*this); - return *this; - } - - T* get() const noexcept - { - return ptr_; - } - - T* detach() noexcept - { - T* ret = ptr_; - ptr_ = nullptr; - return ret; - } - - T& operator*() const noexcept - { - return *ptr_; - } - - T* operator->() const noexcept - { - return ptr_; - } - - explicit operator bool() const noexcept - { - return ptr_ != nullptr; - } - - void reset() - { - if (ptr_) { - if (Policy::release(*ptr_)) { - delete ptr_; - } - ptr_ = nullptr; - } - } - - void swap(IntrusivePtr& _other) noexcept - { - T* tmp = ptr_; - ptr_ = _other.ptr_; - _other.ptr_ = tmp; - } - - size_t useCount() const noexcept - { - if (ptr_ != nullptr) [[likely]] { - return Policy::useCount(*ptr_); - } - return 0; - } - - ThisT collapse() - { - if (ptr_) { - if (Policy::release(*ptr_)) { - Policy::acquire(*ptr_); - return ThisT{std::move(*this)}; - } - ptr_ = nullptr; - } - return {}; - } - -private: - template - friend auto make_intrusive(Args&&... _args); - template - friend auto impl::make_policy_intrusive(const PP&, Args&&... _args); - template - friend IntrusivePtr static_pointer_cast(const IntrusivePtr& _rp) noexcept; - template - friend IntrusivePtr dynamic_pointer_cast(const IntrusivePtr& _rp) noexcept; - template - friend IntrusivePtr static_pointer_cast(IntrusivePtr&& _rp) noexcept; - template - friend IntrusivePtr dynamic_pointer_cast(IntrusivePtr&& _rp) noexcept; - template - friend class EnableCacheable; - - IntrusivePtr(T* _ptr) - : ptr_(_ptr) - { - if (_ptr) { - Policy::acquire(*_ptr); - } - } - - IntrusivePtr(const Policy& _policy, T* _ptr) - : Policy(_policy) - , ptr_(_ptr) - { - if (_ptr) { - Policy::acquire(*_ptr); - } - } -}; - -} // namespace impl - -template -class IntrusivePtr : public impl::IntrusivePtrBase { -public: - using element_type = T; - using BaseT = impl::IntrusivePtrBase; - using ThisT = IntrusivePtr; - - IntrusivePtr() = default; - - IntrusivePtr(const IntrusivePtr& _other) - : BaseT(_other) - { - } - - IntrusivePtr(IntrusivePtr&& _other) - : BaseT(std::move(_other)) - { - } - - template - IntrusivePtr(const IntrusivePtr& _other) - : BaseT(_other) - { - } - - template - IntrusivePtr(IntrusivePtr&& _other) - : BaseT(std::move(_other)) - { - } - - template - friend class IntrusivePtr; - - ~IntrusivePtr() - { - } - - IntrusivePtr& operator=(const IntrusivePtr& _other) noexcept - { - IntrusivePtr{_other}.swap(*this); - return *this; - } - - IntrusivePtr& operator=(IntrusivePtr&& _other) noexcept - { - IntrusivePtr{std::move(_other)}.swap(*this); - return *this; - } - - template - IntrusivePtr& operator=(const IntrusivePtr& _other) noexcept - { - IntrusivePtr{_other}.swap(*this); - return *this; - } - template - IntrusivePtr& operator=(IntrusivePtr&& _other) noexcept - { - IntrusivePtr{std::move(_other)}.swap(*this); - return *this; - } - - void reset() - { - if (ptr_) { - if (Policy::release(*ptr_)) { - delete ptr_; - } - ptr_ = nullptr; - } - } - - void swap(IntrusivePtr& _other) noexcept - { - T* tmp = ptr_; - ptr_ = _other.ptr_; - _other.ptr_ = tmp; - } - - size_t useCount() const noexcept - { - if (ptr_ != nullptr) [[likely]] { - return Policy::useCount(*ptr_); - } - return 0; - } - - ThisT collapse() - { - if (ptr_) { - if (Policy::release(*ptr_)) { - Policy::acquire(*ptr_); - return ThisT{std::move(*this)}; - } - ptr_ = nullptr; - } - return {}; - } - -private: - template - friend auto make_intrusive(Args&&... _args); - template - friend auto impl::make_policy_intrusive(const PP&, Args&&... _args); - template - friend IntrusivePtr static_pointer_cast(const IntrusivePtr& _rp) noexcept; - template - friend IntrusivePtr dynamic_pointer_cast(const IntrusivePtr& _rp) noexcept; - template - friend IntrusivePtr static_pointer_cast(IntrusivePtr&& _rp) noexcept; - template - friend IntrusivePtr dynamic_pointer_cast(IntrusivePtr&& _rp) noexcept; - template - friend class EnableCacheable; - - IntrusivePtr(T* _ptr) - : ptr_(_ptr) - { - if (_ptr) { - Policy::acquire(*_ptr); - } - } - - IntrusivePtr(const Policy& _policy, T* _ptr) - : Policy(_policy) - , ptr_(_ptr) - { - if (_ptr) { - Policy::acquire(*_ptr); - } - } -}; - -namespace impl { -template -auto make_policy_intrusive(const P& _policy, Args&&... _args) -{ - return IntrusivePtr(_policy, new T(std::forward(_args)...)); -} -} // namespace impl - -template -auto make_intrusive(Args&&... _args) -{ - if constexpr (std::is_base_of_v) { - return IntrusivePtr(new T(std::forward(_args)...)); - } else { - return impl::make_policy_intrusive(std::forward(_args)...); - } -} - -template -IntrusivePtr static_pointer_cast(const IntrusivePtr& _rp) noexcept -{ - return IntrusivePtr(static_cast(_rp.get())); -} - -template -IntrusivePtr static_pointer_cast(IntrusivePtr&& _rp) noexcept -{ - return IntrusivePtr(static_cast(_rp.detach())); -} - -template -IntrusivePtr dynamic_pointer_cast(const IntrusivePtr& _rp) noexcept -{ - return IntrusivePtr(dynamic_cast(_rp.get())); -} - -template -IntrusivePtr dynamic_pointer_cast(IntrusivePtr&& _rp) noexcept -{ - auto* pt = dynamic_cast(_rp.get()); - if (pt) { - _rp.detach(); - return IntrusivePtr(pt); - } - return IntrusivePtr(); -} -#endif } // namespace solid \ No newline at end of file diff --git a/solid/utility/test/test_intrusiveptr.cpp b/solid/utility/test/test_intrusiveptr.cpp index 8eb8263d..cf87f81e 100644 --- a/solid/utility/test/test_intrusiveptr.cpp +++ b/solid/utility/test/test_intrusiveptr.cpp @@ -5,7 +5,7 @@ using namespace solid; using namespace std; -#if true + namespace { class Test : public IntrusiveThreadSafeBase { string s_; @@ -132,110 +132,4 @@ int test_intrusiveptr(int argc, char* argvp[]) } return 0; -} - -#else -namespace { - -struct Test : IntrusiveThreadSafeBase { - string s_; - int i_ = 0; - - Test(const string_view _s, const int _i) - : s_(_s) - , i_(_i) - { - } -}; - -struct TestFirst : Test { - size_t sz_ = 0; - - TestFirst(const size_t _sz, const string_view _s, const int _i) - : Test(_s, _i) - , sz_(_sz) - { - } -}; - -struct TestWithCounter { - string s_; - int i_ = 0; - - TestWithCounter(const string_view _s, const int _i) - : s_(_s) - , i_(_i) - { - } - -private: - friend class TestIntrusivePolicy; - mutable atomic use_count_{0}; -}; - -class TestIntrusivePolicy { -protected: - void acquire(const TestWithCounter& _p) noexcept - { - ++_p.use_count_; - } - bool release(const TestWithCounter& _p) noexcept - { - return _p.use_count_.fetch_sub(1) == 1; - } - size_t useCount(const TestWithCounter& _p) const noexcept - { - return _p.use_count_.load(std::memory_order_relaxed); - } -}; - -} // namespace - -int test_intrusiveptr(int argc, char* argvp[]) -{ - Test t{"ceva", 10}; - auto test_ptr = make_intrusive("ceva", 10); - auto twc_ptr = make_intrusive(TestIntrusivePolicy{}, "ceva2", 11); - - cout << "sizeof(test_ptr): " << sizeof(test_ptr) << endl; - cout << "sizeof(twc_ptr): " << sizeof(twc_ptr) << endl; - - { - IntrusivePtr ptr; - - ptr = test_ptr; - solid_check(ptr.useCount() == 2); - } - solid_check(test_ptr.useCount() == 1); - { - IntrusivePtr ptr{test_ptr}; - - solid_check(ptr.useCount() == 2); - } - solid_check(test_ptr.useCount() == 1); - { - IntrusivePtr ptr{std::move(test_ptr)}; - - solid_check(ptr.useCount() == 1); - test_ptr = std::move(ptr); - } - solid_check(test_ptr.useCount() == 1); - { - IntrusivePtr ptr; - ptr = std::move(test_ptr); - - solid_check(ptr.useCount() == 1); - test_ptr = std::move(ptr); - } - solid_check(test_ptr.useCount() == 1); - - auto first_ptr = make_intrusive(111UL, "ceva", 10); - - { - IntrusivePtr ptr{static_pointer_cast(first_ptr)}; - - solid_check(ptr && ptr.useCount() == 2); - } - return 0; -} -#endif \ No newline at end of file +} \ No newline at end of file From 2d8a5dda1e9467cddbbd877254f7dc6aa7bcebc9 Mon Sep 17 00:00:00 2001 From: Valentin Palade Date: Sat, 15 Mar 2025 18:00:59 +0200 Subject: [PATCH 7/8] csharedbuffer: fixing FreeBSD build --- solid/utility/atomic_wait | 518 ++++++++++++----------- solid/utility/intrusiveptr.hpp | 2 +- solid/utility/test/test_intrusiveptr.cpp | 9 + tutorials/mprpc_file/CMakeLists.txt | 12 +- 4 files changed, 283 insertions(+), 258 deletions(-) diff --git a/solid/utility/atomic_wait b/solid/utility/atomic_wait index 117a807b..fc9fdd75 100644 --- a/solid/utility/atomic_wait +++ b/solid/utility/atomic_wait @@ -44,326 +44,348 @@ The strategy is chosen this way, by platform: */ -//#define __NO_TABLE -//#define __NO_FUTEX -//#define __NO_CONDVAR -//#define __NO_SLEEP -//#define __NO_IDENT +// #define __NO_TABLE +// #define __NO_FUTEX +// #define __NO_CONDVAR +// #define __NO_SLEEP +// #define __NO_IDENT // To benchmark against spinning -//#define __NO_SPIN -//#define __NO_WAIT +// #define __NO_SPIN +// #define __NO_WAIT #ifndef __ATOMIC_WAIT_INCLUDED #define __ATOMIC_WAIT_INCLUDED -#include -#include #include +#include +#include #include #if defined(__NO_IDENT) - #include - #include +#include +#include - #define __ABI - #define __YIELD() std::this_thread::yield() - #define __SLEEP(x) std::this_thread::sleep_for(std::chrono::microseconds(x)) - #define __YIELD_PROCESSOR() +#define __ABI +#define __YIELD() std::this_thread::yield() +#define __SLEEP(x) std::this_thread::sleep_for(std::chrono::microseconds(x)) +#define __YIELD_PROCESSOR() #else #if defined(__CUSTD__) - #define __NO_FUTEX - #define __NO_CONDVAR - #ifndef __CUDACC__ - #define __host__ - #define __device__ - #endif - #define __ABI __host__ __device__ +#define __NO_FUTEX +#define __NO_CONDVAR +#ifndef __CUDACC__ +#define __host__ +#define __device__ +#endif +#define __ABI __host__ __device__ #else - #define __ABI +#define __ABI #endif -#if defined(__APPLE__) || defined(__linux__) +#if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) - #include - #include - #define __YIELD() sched_yield() - #define __SLEEP(x) usleep(x) +#include +#include +#define __YIELD() sched_yield() +#define __SLEEP(x) usleep(x) - #if defined(__aarch64__) - # define __YIELD_PROCESSOR() asm volatile ("yield" ::: "memory") - #elif defined(__x86_64__) - # define __YIELD_PROCESSOR() asm volatile ("pause" ::: "memory") - #elif defined (__powerpc__) - # define __YIELD_PROCESSOR() asm volatile ("or 27,27,27" ::: "memory") - #endif +#if defined(__aarch64__) +#define __YIELD_PROCESSOR() asm volatile("yield" ::: "memory") +#elif defined(__x86_64__) +#define __YIELD_PROCESSOR() asm volatile("pause" ::: "memory") +#elif defined(__powerpc__) +#define __YIELD_PROCESSOR() asm volatile("or 27,27,27" ::: "memory") +#endif #endif #if defined(__linux__) && !defined(__NO_FUTEX) - #if !defined(__NO_TABLE) - #define __TABLE - #endif - - #include - #include - #include - #include - - #define __FUTEX - #define __FUTEX_TIMED - #define __type_used_directly(_T) (std::is_same::type>::type, __futex_preferred_t>::value) - using __futex_preferred_t = std::int32_t; - template ::type = 1> - void __do_direct_wait(_Tp const* ptr, _Tp val, void const* timeout) { - syscall(SYS_futex, ptr, FUTEX_WAIT_PRIVATE, val, timeout, 0, 0); - } - template ::type = 1> - void __do_direct_wake(_Tp const* ptr, bool all) { - syscall(SYS_futex, ptr, FUTEX_WAKE_PRIVATE, all ? INT_MAX : 1, 0, 0, 0); - } +#if !defined(__NO_TABLE) +#define __TABLE +#endif + +#include +#include +#include +#include + +#define __FUTEX +#define __FUTEX_TIMED +#define __type_used_directly(_T) (std::is_same::type>::type, \ + __futex_preferred_t>::value) +using __futex_preferred_t = std::int32_t; +template ::type = 1> +void __do_direct_wait(_Tp const* ptr, _Tp val, void const* timeout) +{ + syscall(SYS_futex, ptr, FUTEX_WAIT_PRIVATE, val, timeout, 0, 0); +} +template ::type = 1> +void __do_direct_wake(_Tp const* ptr, bool all) +{ + syscall(SYS_futex, ptr, FUTEX_WAKE_PRIVATE, all ? INT_MAX : 1, 0, 0, 0); +} #elif defined(_WIN32) && !defined(__CUSTD__) - #define __NO_CONDVAR - #define __NO_TABLE - - #ifndef NOMINMAX - #define NOMINMAX - #endif - - #define _WINSOCKAPI_ - #include - #define __YIELD() Sleep(0) - #define __SLEEP(x) Sleep(x) - #define __YIELD_PROCESSOR() YieldProcessor() - - #include - template - auto __atomic_load_n(_Tp const* a, int) -> typename std::remove_reference::type { - auto const t = *a; - _ReadWriteBarrier(); - return t; - } - #define __builtin_expect(e, v) (e) - - #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= _WIN32_WINNT_WIN8) && !defined(__NO_FUTEX) - - #define __FUTEX - #define __type_used_directly(_T) (sizeof(_T) <= 8) - using __futex_preferred_t = std::int64_t; - template ::type = 1> - void __do_direct_wait(_Tp const* ptr, _Tp val, void const*) { - WaitOnAddress((PVOID)ptr, (PVOID)&val, sizeof(_Tp), INFINITE); - } - template ::type = 1> - void __do_direct_wake(_Tp const* ptr, bool all) { - if (all) - WakeByAddressAll((PVOID)ptr); - else - WakeByAddressSingle((PVOID)ptr); - } - - #endif +#define __NO_CONDVAR +#define __NO_TABLE + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#define _WINSOCKAPI_ +#include +#define __YIELD() Sleep(0) +#define __SLEEP(x) Sleep(x) +#define __YIELD_PROCESSOR() YieldProcessor() + +#include +template +auto __atomic_load_n(_Tp const* a, int) -> typename std::remove_reference::type +{ + auto const t = *a; + _ReadWriteBarrier(); + return t; +} +#define __builtin_expect(e, v) (e) + +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= _WIN32_WINNT_WIN8) && !defined(__NO_FUTEX) + +#define __FUTEX +#define __type_used_directly(_T) (sizeof(_T) <= 8) +using __futex_preferred_t = std::int64_t; +template ::type = 1> +void __do_direct_wait(_Tp const* ptr, _Tp val, void const*) +{ + WaitOnAddress((PVOID)ptr, (PVOID)&val, sizeof(_Tp), INFINITE); +} +template ::type = 1> +void __do_direct_wake(_Tp const* ptr, bool all) +{ + if (all) + WakeByAddressAll((PVOID)ptr); + else + WakeByAddressSingle((PVOID)ptr); +} + +#endif #endif // _WIN32 #if !defined(__FUTEX) && !defined(__NO_CONDVAR) - #if defined(__NO_TABLE) - #warning "Condvars always generate a table (ignoring __NO_TABLE)." - #endif - #include - #define __CONDVAR - #define __TABLE +#if defined(__NO_TABLE) +#warning "Condvars always generate a table (ignoring __NO_TABLE)." +#endif +#include +#define __CONDVAR +#define __TABLE #endif #endif // __NO_IDENT #ifdef __TABLE - struct alignas(64) contended_t { - #if defined(__FUTEX) - int waiters = 0; - __futex_preferred_t version = 0; - #elif defined(__CONDVAR) - int credit = 0; - pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - pthread_cond_t condvar = PTHREAD_COND_INITIALIZER; - #else - #error "" - #endif - }; - contended_t * __contention(volatile void const * p); +struct alignas(64) contended_t { +#if defined(__FUTEX) + int waiters = 0; + __futex_preferred_t version = 0; +#elif defined(__CONDVAR) + int credit = 0; + pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_cond_t condvar = PTHREAD_COND_INITIALIZER; #else - template - __ABI void __cxx_atomic_try_wait_slow_fallback(_Tp const* ptr, _Tp val, int order) { - #ifndef __NO_SLEEP - long history = 10; - do { - __SLEEP(history >> 2); - history += history >> 2; - if (history > (1 << 10)) - history = 1 << 10; - } while (__atomic_load_n(ptr, order) == val); - #else - __YIELD(); - #endif - } +#error "" +#endif +}; +contended_t* __contention(volatile void const* p); +#else +template +__ABI void __cxx_atomic_try_wait_slow_fallback(_Tp const* ptr, _Tp val, int order) +{ +#ifndef __NO_SLEEP + long history = 10; + do { + __SLEEP(history >> 2); + history += history >> 2; + if (history > (1 << 10)) + history = 1 << 10; + } while (__atomic_load_n(ptr, order) == val); +#else + __YIELD(); +#endif +} #endif // __TABLE #if defined(__CONDVAR) - template - void __cxx_atomic_notify_all(volatile _Tp const* ptr) { - auto * const c = __contention(ptr); - __atomic_thread_fence(__ATOMIC_SEQ_CST); - if(__builtin_expect(0 == __atomic_load_n(&c->credit, __ATOMIC_RELAXED), 1)) - return; - if(0 != __atomic_exchange_n(&c->credit, 0, __ATOMIC_RELAXED)) { - pthread_mutex_lock(&c->mutex); - pthread_mutex_unlock(&c->mutex); - pthread_cond_broadcast(&c->condvar); - } - } - template - void __cxx_atomic_notify_one(volatile _Tp const* ptr) { - __cxx_atomic_notify_all(ptr); - } - template - void __cxx_atomic_try_wait_slow(volatile _Tp const* ptr, _Tp const val, int order) { - auto * const c = __contention(ptr); +template +void __cxx_atomic_notify_all(volatile _Tp const* ptr) +{ + auto* const c = __contention(ptr); + __atomic_thread_fence(__ATOMIC_SEQ_CST); + if (__builtin_expect(0 == __atomic_load_n(&c->credit, __ATOMIC_RELAXED), 1)) + return; + if (0 != __atomic_exchange_n(&c->credit, 0, __ATOMIC_RELAXED)) { pthread_mutex_lock(&c->mutex); - __atomic_store_n(&c->credit, 1, __ATOMIC_RELAXED); - __atomic_thread_fence(__ATOMIC_SEQ_CST); - if (val == __atomic_load_n(ptr, order)) - pthread_cond_wait(&c->condvar, &c->mutex); pthread_mutex_unlock(&c->mutex); + pthread_cond_broadcast(&c->condvar); } +} +template +void __cxx_atomic_notify_one(volatile _Tp const* ptr) +{ + __cxx_atomic_notify_all(ptr); +} +template +void __cxx_atomic_try_wait_slow(volatile _Tp const* ptr, _Tp const val, int order) +{ + auto* const c = __contention(ptr); + pthread_mutex_lock(&c->mutex); + __atomic_store_n(&c->credit, 1, __ATOMIC_RELAXED); + __atomic_thread_fence(__ATOMIC_SEQ_CST); + if (val == __atomic_load_n(ptr, order)) + pthread_cond_wait(&c->condvar, &c->mutex); + pthread_mutex_unlock(&c->mutex); +} #elif defined(__FUTEX) - template ::type = 1> - void __cxx_atomic_notify_all(_Tp const* ptr) { - #if defined(__TABLE) - auto * const c = __contention(ptr); - __atomic_fetch_add(&c->version, 1, __ATOMIC_RELAXED); - __atomic_thread_fence(__ATOMIC_SEQ_CST); - if (0 != __atomic_exchange_n(&c->waiters, 0, __ATOMIC_RELAXED)) - __do_direct_wake(&c->version, true); - #endif - } - template ::type = 1> - void __cxx_atomic_notify_one(_Tp const* ptr) { - __cxx_atomic_notify_all(ptr); - } - template ::type = 1> - void __cxx_atomic_try_wait_slow(_Tp const* ptr, _Tp const val, int order) { - #if defined(__TABLE) - auto * const c = __contention(ptr); - __atomic_store_n(&c->waiters, 1, __ATOMIC_RELAXED); - __atomic_thread_fence(__ATOMIC_SEQ_CST); - auto const version = __atomic_load_n(&c->version, __ATOMIC_RELAXED); - if (__builtin_expect(val != __atomic_load_n(ptr, order), 1)) - return; - #ifdef __FUTEX_TIMED - constexpr timespec timeout = { 2, 0 }; // Hedge on rare 'int version' aliasing. - __do_direct_wait(&c->version, version, &timeout); - #else - __do_direct_wait(&c->version, version, nullptr); - #endif - #else - __cxx_atomic_try_wait_slow_fallback(ptr, val, order); - #endif // __TABLE - } - - template ::type = 1> - void __cxx_atomic_try_wait_slow(_Tp const* ptr, _Tp val, int order) { - #ifdef __TABLE - auto * const c = __contention(ptr); - __atomic_fetch_add(&c->waiters, 1, __ATOMIC_RELAXED); - __atomic_thread_fence(__ATOMIC_SEQ_CST); - #endif - __do_direct_wait(ptr, val, nullptr); - #ifdef __TABLE - __atomic_fetch_sub(&c->waiters, 1, __ATOMIC_RELAXED); - #endif - } - template ::type = 1> - void __cxx_atomic_notify_all(_Tp const* ptr) { - #ifdef __TABLE - auto * const c = __contention(ptr); - __atomic_thread_fence(__ATOMIC_SEQ_CST); - if (0 != __atomic_load_n(&c->waiters, __ATOMIC_RELAXED)) - #endif - __do_direct_wake(ptr, true); - } - template ::type = 1> - void __cxx_atomic_notify_one(_Tp const* ptr) { - #ifdef __TABLE - auto * const c = __contention(ptr); - __atomic_thread_fence(__ATOMIC_SEQ_CST); - if (0 != __atomic_load_n(&c->waiters, __ATOMIC_RELAXED)) - #endif - __do_direct_wake(ptr, false); - } +template ::type = 1> +void __cxx_atomic_notify_all(_Tp const* ptr) +{ +#if defined(__TABLE) + auto* const c = __contention(ptr); + __atomic_fetch_add(&c->version, 1, __ATOMIC_RELAXED); + __atomic_thread_fence(__ATOMIC_SEQ_CST); + if (0 != __atomic_exchange_n(&c->waiters, 0, __ATOMIC_RELAXED)) + __do_direct_wake(&c->version, true); +#endif +} +template ::type = 1> +void __cxx_atomic_notify_one(_Tp const* ptr) +{ + __cxx_atomic_notify_all(ptr); +} +template ::type = 1> +void __cxx_atomic_try_wait_slow(_Tp const* ptr, _Tp const val, int order) +{ +#if defined(__TABLE) + auto* const c = __contention(ptr); + __atomic_store_n(&c->waiters, 1, __ATOMIC_RELAXED); + __atomic_thread_fence(__ATOMIC_SEQ_CST); + auto const version = __atomic_load_n(&c->version, __ATOMIC_RELAXED); + if (__builtin_expect(val != __atomic_load_n(ptr, order), 1)) + return; +#ifdef __FUTEX_TIMED + constexpr timespec timeout = {2, 0}; // Hedge on rare 'int version' aliasing. + __do_direct_wait(&c->version, version, &timeout); +#else + __do_direct_wait(&c->version, version, nullptr); +#endif +#else + __cxx_atomic_try_wait_slow_fallback(ptr, val, order); +#endif // __TABLE +} + +template ::type = 1> +void __cxx_atomic_try_wait_slow(_Tp const* ptr, _Tp val, int order) +{ +#ifdef __TABLE + auto* const c = __contention(ptr); + __atomic_fetch_add(&c->waiters, 1, __ATOMIC_RELAXED); + __atomic_thread_fence(__ATOMIC_SEQ_CST); +#endif + __do_direct_wait(ptr, val, nullptr); +#ifdef __TABLE + __atomic_fetch_sub(&c->waiters, 1, __ATOMIC_RELAXED); +#endif +} +template ::type = 1> +void __cxx_atomic_notify_all(_Tp const* ptr) +{ +#ifdef __TABLE + auto* const c = __contention(ptr); + __atomic_thread_fence(__ATOMIC_SEQ_CST); + if (0 != __atomic_load_n(&c->waiters, __ATOMIC_RELAXED)) +#endif + __do_direct_wake(ptr, true); +} +template ::type = 1> +void __cxx_atomic_notify_one(_Tp const* ptr) +{ +#ifdef __TABLE + auto* const c = __contention(ptr); + __atomic_thread_fence(__ATOMIC_SEQ_CST); + if (0 != __atomic_load_n(&c->waiters, __ATOMIC_RELAXED)) +#endif + __do_direct_wake(ptr, false); +} #else // __FUTEX || __CONDVAR - template - __ABI void __cxx_atomic_try_wait_slow(_Tp const* ptr, _Tp val, int order) { - __cxx_atomic_try_wait_slow_fallback(ptr, val, order); - } - template - __ABI void __cxx_atomic_notify_one(_Tp const* ptr) { } - template - __ABI void __cxx_atomic_notify_all(_Tp const* ptr) { } +template +__ABI void __cxx_atomic_try_wait_slow(_Tp const* ptr, _Tp val, int order) +{ + __cxx_atomic_try_wait_slow_fallback(ptr, val, order); +} +template +__ABI void __cxx_atomic_notify_one(_Tp const* ptr) {} +template +__ABI void __cxx_atomic_notify_all(_Tp const* ptr) {} #endif // __FUTEX || __CONDVAR template -__ABI void __cxx_atomic_wait(_Tp const* ptr, _Tp const val, int order) { +__ABI void __cxx_atomic_wait(_Tp const* ptr, _Tp const val, int order) +{ #ifndef __NO_SPIN - if(__builtin_expect(__atomic_load_n(ptr, order) != val,1)) + if (__builtin_expect(__atomic_load_n(ptr, order) != val, 1)) return; - for(int i = 0; i < 16; ++i) { - if(__atomic_load_n(ptr, order) != val) + for (int i = 0; i < 16; ++i) { + if (__atomic_load_n(ptr, order) != val) return; - if(i < 12) + if (i < 12) __YIELD_PROCESSOR(); else __YIELD(); } #endif - while(val == __atomic_load_n(ptr, order)) + while (val == __atomic_load_n(ptr, order)) #ifndef __NO_WAIT __cxx_atomic_try_wait_slow(ptr, val, order) #endif - ; + ; } #include namespace std { - template - __ABI void atomic_wait_explicit(atomic<_Tp> const* a, _Tv val, std::memory_order order) { - __cxx_atomic_wait((const _Tp*)a, (_Tp)val, (int)order); - } - template - __ABI void atomic_wait(atomic<_Tp> const* a, _Tv val) { - atomic_wait_explicit(a, val, std::memory_order_seq_cst); - } - template - __ABI void atomic_notify_one(atomic<_Tp> const* a) { - __cxx_atomic_notify_one((const _Tp*)a); - } - template - __ABI void atomic_notify_all(atomic<_Tp> const* a) { - __cxx_atomic_notify_all((const _Tp*)a); - } +template +__ABI void atomic_wait_explicit(atomic<_Tp> const* a, _Tv val, std::memory_order order) +{ + __cxx_atomic_wait((const _Tp*)a, (_Tp)val, (int)order); +} +template +__ABI void atomic_wait(atomic<_Tp> const* a, _Tv val) +{ + atomic_wait_explicit(a, val, std::memory_order_seq_cst); +} +template +__ABI void atomic_notify_one(atomic<_Tp> const* a) +{ + __cxx_atomic_notify_one((const _Tp*)a); +} +template +__ABI void atomic_notify_all(atomic<_Tp> const* a) +{ + __cxx_atomic_notify_all((const _Tp*)a); } +} // namespace std #endif //__ATOMIC_WAIT_INCLUDED \ No newline at end of file diff --git a/solid/utility/intrusiveptr.hpp b/solid/utility/intrusiveptr.hpp index 675d23d3..3204a8b9 100644 --- a/solid/utility/intrusiveptr.hpp +++ b/solid/utility/intrusiveptr.hpp @@ -457,7 +457,7 @@ class ConstIntrusivePtr : public impl::IntrusivePtrBase { } ConstIntrusivePtr(MutableIntrusivePtr&& _other) - : BaseT(_other) + : BaseT(std::move(_other)) { } diff --git a/solid/utility/test/test_intrusiveptr.cpp b/solid/utility/test/test_intrusiveptr.cpp index cf87f81e..4ca3e40c 100644 --- a/solid/utility/test/test_intrusiveptr.cpp +++ b/solid/utility/test/test_intrusiveptr.cpp @@ -131,5 +131,14 @@ int test_intrusiveptr(int argc, char* argvp[]) // auto base_ptr = static_pointer_cast(ptr);//must not compile } + { + MutableIntrusivePtr p1 = make_mutable_intrusive("ceva", 10); + + ConstIntrusivePtr p2 = std::move(p1); + + solid_check(p2); + solid_check(!p1); + } + return 0; } \ No newline at end of file diff --git a/tutorials/mprpc_file/CMakeLists.txt b/tutorials/mprpc_file/CMakeLists.txt index 58f88cd8..5618145d 100644 --- a/tutorials/mprpc_file/CMakeLists.txt +++ b/tutorials/mprpc_file/CMakeLists.txt @@ -1,12 +1,7 @@ -if(APPLE OR WIN32) -else() - set(STDFS_LIB stdc++fs) -endif() - include(CheckCXXSymbolExists) -CHECK_CXX_SYMBOL_EXISTS(std::filesystem::path::preferred_separator filesystem cxx17fs) +CHECK_CXX_SYMBOL_EXISTS(std::filesystem::path::preferred_separator filesystem cxx_fs) -if(cxx17fs) +if(cxx_fs) add_executable (tutorial_mprpc_file_server mprpc_file_server.cpp mprpc_file_messages.hpp) target_link_libraries (tutorial_mprpc_file_server @@ -17,7 +12,6 @@ if(cxx17fs) solid_utility solid_system ${SYSTEM_BASIC_LIBRARIES} - ${STDFS_LIB} ) add_executable (tutorial_mprpc_file_client mprpc_file_client.cpp mprpc_file_messages.hpp) @@ -32,5 +26,5 @@ if(cxx17fs) ${SYSTEM_BASIC_LIBRARIES} ) else() - message("C++17 filesystem not found - mprpc_file tutorial not available") + message("C++ filesystem not found - mprpc_file tutorial not available") endif() From c1202f1b59471709b058bc23096e3dbc8c35cb35 Mon Sep 17 00:00:00 2001 From: Valentin Palade Date: Fri, 21 Mar 2025 22:56:57 +0200 Subject: [PATCH 8/8] csharedbuffer: fix freebsd tests --- CMakeLists.txt | 8 ++++---- solid/frame/aio/src/aioreactor.cpp | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e95116c2..fb33d647 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,8 +125,8 @@ if((NOT CMAKE_SYSTEM MATCHES "Windows*") AND CMAKE_BUILD_TYPE STREQUAL "coverage #force a single configuration type on Windows builds set(CMAKE_CONFIGURATION_TYPES "debug") set(CONFIGURATION_TYPE "debug") - add_compile_options("SHELL: -coverage -fprofile-arcs -ftest-coverage") - add_link_options("SHELL: -fprofile-arcs -ftest-coverage") + add_compile_options("SHELL: --coverage") + add_link_options("SHELL: --coverage") elseif(CMAKE_SYSTEM MATCHES "Windows*" AND CMAKE_BUILD_TYPE STREQUAL "coverage") message(FATAL_ERROR "\r\n === Coverage not yet supported for Windows systems ===\r\n") endif() @@ -382,9 +382,9 @@ if(NOT ON_CROSS) find_program( MEMORYCHECK_COMMAND valgrind ) set( MEMORYCHECK_COMMAND_OPTIONS "--trace-children=yes --leak-check=full" ) set( MEMORYCHECK_SUPPRESSIONS_FILE "${PROJECT_SOURCE_DIR}/cmake/valgrind_suppress.txt" ) - + set(SOLID_TEST_ALL TRUE CACHE BOOL "Enable/Disable all tests") - + enable_testing() include(CTest) else() diff --git a/solid/frame/aio/src/aioreactor.cpp b/solid/frame/aio/src/aioreactor.cpp index 852aa28e..d74d6e16 100644 --- a/solid/frame/aio/src/aioreactor.cpp +++ b/solid/frame/aio/src/aioreactor.cpp @@ -567,10 +567,10 @@ inline ReactorEventE systemEventsToReactorEvents(const uint32_t _events) inline constexpr ReactorEventE systemEventsToReactorEvents(const unsigned short _flags, const short _filter) { - ReactorEventE retval = ReactorEventE::None; - if (_flags & (EV_EOF | EV_ERROR)) { + if (_flags & (EV_ERROR)) { return ReactorEventE::Hangup; } + if (_filter == EVFILT_READ) { return ReactorEventE::Recv; } else if (_filter == EVFILT_WRITE) { @@ -579,7 +579,7 @@ inline constexpr ReactorEventE systemEventsToReactorEvents(const unsigned short return ReactorEventE::Recv; } - return retval; + return ReactorEventE::None; } #elif defined(SOLID_USE_WSAPOLL) inline ReactorEventE systemEventsToReactorEvents(const uint32_t _events, decltype(WSAPOLLFD::events)& _revs)