16#include "pw_allocator/config.h"
19#if PW_ALLOCATOR_HAS_ATOMICS
25#include "pw_allocator/deallocator.h"
26#include "pw_allocator/internal/control_block.h"
27#include "pw_allocator/internal/managed_ptr.h"
28#include "pw_allocator/layout.h"
29#include "pw_allocator/unique_ptr.h"
39template <
typename To,
typename From>
42template <
typename To,
typename From>
64class SharedPtr final :
public ::pw::allocator::internal::ManagedPtr<T> {
66 using Base = ::pw::allocator::internal::ManagedPtr<T>;
67 using ControlBlock = ::pw::allocator::internal::ControlBlock;
68 using ControlBlockHandle = ::pw::allocator::internal::ControlBlockHandle;
71 using element_type =
typename Base::element_type;
87 template <
typename... Args>
113 constexpr
SharedPtr(element_type* value, ControlBlock* control_block)
114 : Base(value), control_block_(control_block) {}
131 template <
typename U,
132 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
142 template <
typename U,
143 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
145 *
this = std::move(other);
163 operator= <T>(other);
173 template <
typename U,
174 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
183 template <
typename U,
184 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
206 template <
typename U>
208 return static_pointer_cast<U>(*
this);
223 template <
typename To,
typename From>
237 template <
typename To,
typename From>
243 [[nodiscard]]
friend constexpr bool operator==(
const SharedPtr& lhs,
245 return lhs.Equals(
nullptr);
247 [[nodiscard]]
friend constexpr bool operator==(std::nullptr_t,
249 return rhs.Equals(
nullptr);
251 [[nodiscard]]
friend constexpr bool operator==(
const SharedPtr& lhs,
252 const SharedPtr& rhs) {
253 return lhs.Equals(rhs) && lhs.control_block_ == rhs.control_block_;
256 [[nodiscard]]
friend constexpr bool operator!=(
const SharedPtr& lhs,
258 return !lhs.Equals(
nullptr);
260 [[nodiscard]]
friend constexpr bool operator!=(std::nullptr_t,
261 const SharedPtr& rhs) {
262 return !rhs.Equals(
nullptr);
264 [[nodiscard]]
friend constexpr bool operator!=(
const SharedPtr& lhs,
265 const SharedPtr& rhs) {
266 return !(lhs == rhs);
274 constexpr size_t size()
const {
275 static_assert(std::is_array_v<T>,
276 "size() cannot be called on non-array types");
277 return control_block_ ==
nullptr
279 : (control_block_->size() /
sizeof(element_type));
285 return control_block_ ==
nullptr ? 0 : control_block_->num_shared();
290 template <
typename PtrType>
292 return std::less{}(control_block_, other.control_block_);
310 return control_block_ ==
nullptr ? nullptr : control_block_->allocator();
318 return control_block_;
332 template <
typename U,
333 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
341 template <
typename U>
342 constexpr void CheckArrayTypes();
344 ControlBlock* control_block_ =
nullptr;
353 size_t size =
sizeof(element_type);
354 if constexpr (std::is_array_v<T>) {
355 size *= owned.
size();
359 const auto& handle = ControlBlockHandle::GetInstance_DO_NOT_USE();
361 ControlBlock::Create(handle, owned.deallocator(), owned.get(), size);
363 if (control_block_ !=
nullptr) {
364 Base::CopyFrom(owned);
370template <
typename... Args>
372 static_assert(!std::is_array_v<T>);
375 const auto& handle = ControlBlockHandle::GetInstance_DO_NOT_USE();
376 auto* control_block =
377 ControlBlock::Create(handle, allocator, Layout::Of<T>());
379 if (control_block ==
nullptr) {
382 auto* t =
new (control_block->data()) T(std::forward<Args>(args)...);
383 return SharedPtr<T>(t, control_block);
390 static_assert(allocator::internal::is_unbounded_array_v<T>);
391 Layout layout = Layout::Of<T>(count).Align(alignment);
394 const auto& handle = ControlBlockHandle::GetInstance_DO_NOT_USE();
395 auto* control_block = ControlBlock::Create(handle, allocator, layout);
397 if (control_block ==
nullptr) {
400 auto* t =
new (control_block->data()) element_type[count];
405template <
typename U,
typename>
408 CheckArrayTypes<U>();
411 if (control_block_ !=
nullptr) {
412 control_block_->IncrementShared();
418template <
typename U,
typename>
420 CheckArrayTypes<U>();
433template <
typename To,
typename From>
435 using PtrType =
typename SharedPtr<To>::element_type*;
436 if (p.control_block_ !=
nullptr) {
437 p.control_block_->IncrementShared();
439 return SharedPtr<To>{
static_cast<PtrType
>(p.get()), p.control_block_};
442template <
typename To,
typename From>
444 using PtrType =
typename SharedPtr<To>::element_type*;
445 if (p.control_block_ !=
nullptr) {
446 p.control_block_->IncrementShared();
448 return SharedPtr<To>{
const_cast<PtrType
>(p.get()), p.control_block_};
453 if (*
this ==
nullptr) {
456 auto action = control_block_->DecrementShared();
457 if (action == ControlBlock::Action::kNone) {
464 Allocator* allocator = control_block_->allocator();
465 if (!Base::HasCapability(allocator, allocator::kSkipsDestroy)) {
466 if constexpr (std::is_array_v<T>) {
467 Base::Destroy(size());
473 if (action == ControlBlock::Action::kExpire) {
476 Base::Resize(allocator, control_block_,
sizeof(ControlBlock));
479 std::destroy_at(control_block_);
480 Base::Deallocate(allocator, control_block_);
489 std::swap(control_block_, other.control_block_);
493template <
typename U,
typename>
495 CheckArrayTypes<U>();
496 Base::CopyFrom(other);
497 control_block_ = other.control_block_;
501void SharedPtr<T>::Release() {
503 control_block_ =
nullptr;
508constexpr void SharedPtr<T>::CheckArrayTypes() {
509 if constexpr (std::is_array_v<T>) {
510 static_assert(std::is_array_v<U>,
511 "non-array type used with SharedPtr<T[]>");
513 static_assert(!std::is_array_v<U>,
"array type used with SharedPtr<T>");
Definition: allocator.h:42
Definition: shared_ptr.h:64
static SharedPtr Create(Allocator *allocator, size_t count, size_t alignment)
Definition: shared_ptr.h:387
bool owner_before(const PtrType &other) const noexcept
Definition: shared_ptr.h:291
SharedPtr(UniquePtr< T > &owned) noexcept
Definition: shared_ptr.h:352
constexpr SharedPtr(std::nullptr_t) noexcept
Definition: shared_ptr.h:120
friend constexpr SharedPtr< To > const_pointer_cast(const SharedPtr< From > &p) noexcept
Definition: shared_ptr.h:443
void swap(SharedPtr &other) noexcept
Swaps the managed pointer and deallocator of this and another object.
Definition: shared_ptr.h:487
constexpr int32_t use_count() const
Definition: shared_ptr.h:284
SharedPtr & operator=(std::nullptr_t) noexcept
Definition: shared_ptr.h:428
constexpr SharedPtr & operator=(const SharedPtr< U > &other) noexcept
SharedPtr & operator=(SharedPtr< U > &&other) noexcept
static SharedPtr Create(Allocator *allocator, Args &&... args)
SharedPtr(SharedPtr< U > &&other) noexcept
Definition: shared_ptr.h:144
~SharedPtr()
Releases any currently-held value.
Definition: shared_ptr.h:75
constexpr size_t size() const
Definition: shared_ptr.h:274
friend constexpr SharedPtr< To > static_pointer_cast(const SharedPtr< From > &p) noexcept
Definition: shared_ptr.h:434
ControlBlock * GetControlBlock(const ControlBlockHandle &) const
Definition: shared_ptr.h:317
constexpr SharedPtr() noexcept=default
constexpr SharedPtr(const SharedPtr &other) noexcept
Copy-constructs a SharedPtr<T> from a SharedPtr<T>.
Definition: shared_ptr.h:123
Allocator * allocator() const
Definition: shared_ptr.h:309
constexpr SharedPtr(const SharedPtr< U > &other) noexcept
Definition: shared_ptr.h:133
constexpr SharedPtr & operator=(const SharedPtr &other) noexcept
Definition: shared_ptr.h:162
void reset() noexcept
Definition: shared_ptr.h:452
Definition: unique_ptr.h:44
Definition: weak_ptr.h:37
constexpr SharedPtr< To > static_pointer_cast(const SharedPtr< From > &p) noexcept
Definition: shared_ptr.h:434
constexpr SharedPtr< To > const_pointer_cast(const SharedPtr< From > &p) noexcept
Definition: shared_ptr.h:443
The Pigweed namespace.
Definition: alignment.h:27