16#ifndef PW_ALLOCATOR_PUBLIC_PW_ALLOCATOR_SHARED_PTR_H_
17#define PW_ALLOCATOR_PUBLIC_PW_ALLOCATOR_SHARED_PTR_H_
19#include "pw_allocator/config.h"
22#if PW_ALLOCATOR_HAS_ATOMICS
28#include "pw_allocator/allocator.h"
29#include "pw_allocator/deallocator.h"
30#include "pw_allocator/internal/control_block.h"
31#include "pw_allocator/internal/managed_ptr.h"
32#include "pw_allocator/layout.h"
33#include "pw_allocator/unique_ptr.h"
34#include "pw_multibuf/v2/properties.h"
44namespace multibuf::v2 {
67class SharedPtr final : public ::pw::allocator::internal::ManagedPtr<T> {
69 using Base = ::pw::allocator::internal::ManagedPtr<T>;
70 using ControlBlock = ::pw::allocator::internal::ControlBlock;
73 using element_type =
typename Base::element_type;
100 template <
typename U,
101 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
111 template <
typename U,
112 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
114 *
this = std::move(other);
132 operator= <T>(other);
142 template <
typename U,
143 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
152 template <
typename U,
153 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
160 SharedPtr& operator=(std::nullptr_t)
noexcept;
173 template <
typename U,
174 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
177 static_cast<const allocator::internal::BaseManagedPtr&
>(*this));
180 [[nodiscard]]
friend constexpr bool operator==(
const SharedPtr& lhs,
182 return lhs.Equals(
nullptr);
184 [[nodiscard]]
friend constexpr bool operator==(std::nullptr_t,
185 const SharedPtr& rhs) {
186 return rhs.Equals(
nullptr);
188 [[nodiscard]]
friend constexpr bool operator==(
const SharedPtr& lhs,
189 const SharedPtr& rhs) {
190 return lhs.Equals(rhs) && lhs.control_block_ == rhs.control_block_;
193 [[nodiscard]]
friend constexpr bool operator!=(
const SharedPtr& lhs,
195 return !lhs.Equals(
nullptr);
197 [[nodiscard]]
friend constexpr bool operator!=(std::nullptr_t,
198 const SharedPtr& rhs) {
199 return !rhs.Equals(
nullptr);
201 [[nodiscard]]
friend constexpr bool operator!=(
const SharedPtr& lhs,
202 const SharedPtr& rhs) {
203 return !(lhs == rhs);
210 static_assert(std::is_array_v<T>,
211 "size() cannot be called on non-array types");
212 return control_block_ ==
nullptr ? 0 : control_block_->size();
218 return control_block_ ==
nullptr ? 0 : control_block_->num_shared();
226 void reset() noexcept;
233 template <typename PtrType>
234 bool owner_before(const PtrType& other) const noexcept {
235 return control_block_ < other.control_block();
241 static constexpr bool is_unbounded_array_v =
242 allocator::internal::is_unbounded_array_v<T>;
271 template <
typename... Args>
291 SharedPtr(element_type* value, ControlBlock* control_block)
292 : Base(value), control_block_(control_block) {}
294 ControlBlock* control_block()
const {
return control_block_; }
297 template <
typename U,
298 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
299 void CopyFrom(
const SharedPtr<U>& other);
306 template <
typename U>
307 constexpr void CheckArrayTypes();
309 ControlBlock* control_block_ =
nullptr;
318 if constexpr (std::is_array_v<T>) {
320 ControlBlock::Create(owned.deallocator(), owned.get(), owned.size());
322 control_block_ = ControlBlock::Create(owned.deallocator(), owned.get(), 1);
324 if (control_block_ !=
nullptr) {
325 Base::CopyFrom(owned);
331template <
typename... Args>
333 static_assert(!std::is_array_v<T>);
334 auto* control_block = ControlBlock::Create(allocator, Layout::Of<T>(), 1);
335 if (control_block ==
nullptr) {
338 auto* t =
new (control_block->data()) T(std::forward<Args>(args)...);
339 return SharedPtr<T>(t, control_block);
343SharedPtr<T> SharedPtr<T>::Create(Allocator* allocator,
346 static_assert(allocator::internal::is_unbounded_array_v<T>);
347 Layout layout = Layout::Of<T>(count).Align(alignment);
348 auto* control_block = ControlBlock::Create(allocator, layout, count);
349 if (control_block ==
nullptr) {
352 auto* t =
new (control_block->data()) std::remove_extent_t<T>[count];
353 return SharedPtr<T>(t, control_block);
357template <
typename U,
typename>
359 const SharedPtr<U>& other)
noexcept {
360 CheckArrayTypes<U>();
362 if (control_block_ !=
nullptr) {
363 control_block_->IncrementShared();
369template <
typename U,
typename>
371 CheckArrayTypes<U>();
386 if (*
this ==
nullptr) {
389 auto action = control_block_->DecrementShared();
390 if (action == ControlBlock::Action::kNone) {
397 Allocator* allocator = control_block_->allocator();
398 if (!Base::HasCapability(allocator, allocator::kSkipsDestroy)) {
399 if constexpr (std::is_array_v<T>) {
400 Base::Destroy(control_block_->size());
406 if (action == ControlBlock::Action::kExpire) {
409 Base::Resize(allocator, control_block_,
sizeof(ControlBlock));
412 std::destroy_at(control_block_);
413 Base::Deallocate(allocator, control_block_);
422 std::swap(control_block_, other.control_block_);
426template <
typename U,
typename>
428 CheckArrayTypes<U>();
429 Base::CopyFrom(other);
430 control_block_ = other.control_block_;
434void SharedPtr<T>::Release() {
436 control_block_ =
nullptr;
441constexpr void SharedPtr<T>::CheckArrayTypes() {
442 if constexpr (std::is_array_v<T>) {
443 static_assert(std::is_array_v<U>,
444 "non-array type used with SharedPtr<T[]>");
446 static_assert(!std::is_array_v<U>,
"array type used with SharedPtr<T>");
Definition: allocator.h:45
Definition: shared_ptr.h:67
size_t size() const
Definition: shared_ptr.h:209
void swap(SharedPtr &other) noexcept
Swaps the managed pointer and deallocator of this and another object.
Definition: shared_ptr.h:420
constexpr SharedPtr & operator=(const SharedPtr< U > &other) noexcept
SharedPtr & operator=(SharedPtr< U > &&other) noexcept
SharedPtr(SharedPtr< U > &&other) noexcept
Definition: shared_ptr.h:113
~SharedPtr()
Releases any currently-held value.
Definition: shared_ptr.h:77
constexpr SharedPtr() noexcept=default
constexpr SharedPtr(const SharedPtr &other) noexcept
Copy-constructs a SharedPtr<T> from a SharedPtr<T>.
Definition: shared_ptr.h:92
int32_t use_count() const
Definition: shared_ptr.h:217
constexpr SharedPtr(const SharedPtr< U > &other) noexcept
Definition: shared_ptr.h:102
constexpr SharedPtr & operator=(const SharedPtr &other) noexcept
Definition: shared_ptr.h:131
void reset() noexcept
Definition: shared_ptr.h:385
Definition: unique_ptr.h:43
Definition: weak_ptr.h:37
Definition: multibuf.h:184
Definition: multibuf.h:1021
Property
Basic properties of a MultiBuf.
Definition: properties.h:24
The Pigweed namespace.
Definition: alignment.h:27