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"
43template <
typename To,
typename From>
46template <
typename To,
typename From>
68class SharedPtr final :
public ::pw::allocator::internal::ManagedPtr<T> {
70 using Base = ::pw::allocator::internal::ManagedPtr<T>;
71 using ControlBlock = ::pw::allocator::internal::ControlBlock;
72 using ControlBlockHandle = ::pw::allocator::internal::ControlBlockHandle;
75 using element_type =
typename Base::element_type;
91 template <
typename... Args>
117 constexpr
SharedPtr(element_type* value, ControlBlock* control_block)
118 : Base(value), control_block_(control_block) {}
135 template <
typename U,
136 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
146 template <
typename U,
147 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
149 *
this = std::move(other);
167 operator= <T>(other);
177 template <
typename U,
178 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
187 template <
typename U,
188 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
210 template <
typename U>
212 return static_pointer_cast<U>(*
this);
227 template <
typename To,
typename From>
241 template <
typename To,
typename From>
247 [[nodiscard]]
friend constexpr bool operator==(
const SharedPtr& lhs,
249 return lhs.Equals(
nullptr);
251 [[nodiscard]]
friend constexpr bool operator==(std::nullptr_t,
253 return rhs.Equals(
nullptr);
255 [[nodiscard]]
friend constexpr bool operator==(
const SharedPtr& lhs,
256 const SharedPtr& rhs) {
257 return lhs.Equals(rhs) && lhs.control_block_ == rhs.control_block_;
260 [[nodiscard]]
friend constexpr bool operator!=(
const SharedPtr& lhs,
262 return !lhs.Equals(
nullptr);
264 [[nodiscard]]
friend constexpr bool operator!=(std::nullptr_t,
265 const SharedPtr& rhs) {
266 return !rhs.Equals(
nullptr);
268 [[nodiscard]]
friend constexpr bool operator!=(
const SharedPtr& lhs,
269 const SharedPtr& rhs) {
270 return !(lhs == rhs);
278 constexpr size_t size()
const {
279 static_assert(std::is_array_v<T>,
280 "size() cannot be called on non-array types");
281 return control_block_ ==
nullptr
283 : (control_block_->size() /
sizeof(element_type));
289 return control_block_ ==
nullptr ? 0 : control_block_->num_shared();
294 template <
typename PtrType>
296 return std::less{}(control_block_, other.control_block_);
314 return control_block_ ==
nullptr ? nullptr : control_block_->allocator();
322 return control_block_;
336 template <
typename U,
337 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
345 template <
typename U>
346 constexpr void CheckArrayTypes();
348 ControlBlock* control_block_ =
nullptr;
357 size_t size =
sizeof(element_type);
358 if constexpr (std::is_array_v<T>) {
359 size *= owned.
size();
363 const auto& handle = ControlBlockHandle::GetInstance_DO_NOT_USE();
365 ControlBlock::Create(handle, owned.deallocator(), owned.get(), size);
367 if (control_block_ !=
nullptr) {
368 Base::CopyFrom(owned);
374template <
typename... Args>
376 static_assert(!std::is_array_v<T>);
379 const auto& handle = ControlBlockHandle::GetInstance_DO_NOT_USE();
380 auto* control_block =
381 ControlBlock::Create(handle, allocator, Layout::Of<T>());
383 if (control_block ==
nullptr) {
386 auto* t =
new (control_block->data()) T(std::forward<Args>(args)...);
387 return SharedPtr<T>(t, control_block);
394 static_assert(allocator::internal::is_unbounded_array_v<T>);
395 Layout layout = Layout::Of<T>(count).Align(alignment);
398 const auto& handle = ControlBlockHandle::GetInstance_DO_NOT_USE();
399 auto* control_block = ControlBlock::Create(handle, allocator, layout);
401 if (control_block ==
nullptr) {
404 auto* t =
new (control_block->data()) element_type[count];
409template <
typename U,
typename>
412 CheckArrayTypes<U>();
415 if (control_block_ !=
nullptr) {
416 control_block_->IncrementShared();
422template <
typename U,
typename>
424 CheckArrayTypes<U>();
437template <
typename To,
typename From>
439 using PtrType =
typename SharedPtr<To>::element_type*;
440 if (p.control_block_ !=
nullptr) {
441 p.control_block_->IncrementShared();
443 return SharedPtr<To>{
static_cast<PtrType
>(p.get()), p.control_block_};
446template <
typename To,
typename From>
448 using PtrType =
typename SharedPtr<To>::element_type*;
449 if (p.control_block_ !=
nullptr) {
450 p.control_block_->IncrementShared();
452 return SharedPtr<To>{
const_cast<PtrType
>(p.get()), p.control_block_};
457 if (*
this ==
nullptr) {
460 auto action = control_block_->DecrementShared();
461 if (action == ControlBlock::Action::kNone) {
468 Allocator* allocator = control_block_->allocator();
469 if (!Base::HasCapability(allocator, allocator::kSkipsDestroy)) {
470 if constexpr (std::is_array_v<T>) {
471 Base::Destroy(size());
477 if (action == ControlBlock::Action::kExpire) {
480 Base::Resize(allocator, control_block_,
sizeof(ControlBlock));
483 std::destroy_at(control_block_);
484 Base::Deallocate(allocator, control_block_);
493 std::swap(control_block_, other.control_block_);
497template <
typename U,
typename>
499 CheckArrayTypes<U>();
500 Base::CopyFrom(other);
501 control_block_ = other.control_block_;
505void SharedPtr<T>::Release() {
507 control_block_ =
nullptr;
512constexpr void SharedPtr<T>::CheckArrayTypes() {
513 if constexpr (std::is_array_v<T>) {
514 static_assert(std::is_array_v<U>,
515 "non-array type used with SharedPtr<T[]>");
517 static_assert(!std::is_array_v<U>,
"array type used with SharedPtr<T>");
Definition: allocator.h:45
Definition: shared_ptr.h:68
static SharedPtr Create(Allocator *allocator, size_t count, size_t alignment)
Definition: shared_ptr.h:391
bool owner_before(const PtrType &other) const noexcept
Definition: shared_ptr.h:295
SharedPtr(UniquePtr< T > &owned) noexcept
Definition: shared_ptr.h:356
constexpr SharedPtr(std::nullptr_t) noexcept
Definition: shared_ptr.h:124
friend constexpr SharedPtr< To > const_pointer_cast(const SharedPtr< From > &p) noexcept
Definition: shared_ptr.h:447
void swap(SharedPtr &other) noexcept
Swaps the managed pointer and deallocator of this and another object.
Definition: shared_ptr.h:491
constexpr int32_t use_count() const
Definition: shared_ptr.h:288
SharedPtr & operator=(std::nullptr_t) noexcept
Definition: shared_ptr.h:432
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:148
~SharedPtr()
Releases any currently-held value.
Definition: shared_ptr.h:79
constexpr size_t size() const
Definition: shared_ptr.h:278
friend constexpr SharedPtr< To > static_pointer_cast(const SharedPtr< From > &p) noexcept
Definition: shared_ptr.h:438
ControlBlock * GetControlBlock(const ControlBlockHandle &) const
Definition: shared_ptr.h:321
constexpr SharedPtr() noexcept=default
constexpr SharedPtr(const SharedPtr &other) noexcept
Copy-constructs a SharedPtr<T> from a SharedPtr<T>.
Definition: shared_ptr.h:127
Allocator * allocator() const
Definition: shared_ptr.h:313
constexpr SharedPtr(const SharedPtr< U > &other) noexcept
Definition: shared_ptr.h:137
constexpr SharedPtr & operator=(const SharedPtr &other) noexcept
Definition: shared_ptr.h:166
void reset() noexcept
Definition: shared_ptr.h:456
Definition: unique_ptr.h:43
Definition: weak_ptr.h:37
constexpr SharedPtr< To > static_pointer_cast(const SharedPtr< From > &p) noexcept
Definition: shared_ptr.h:438
constexpr SharedPtr< To > const_pointer_cast(const SharedPtr< From > &p) noexcept
Definition: shared_ptr.h:447
The Pigweed namespace.
Definition: alignment.h:27