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"
60class SharedPtr final : public ::pw::allocator::internal::ManagedPtr<T> {
62 using Base = ::pw::allocator::internal::ManagedPtr<T>;
63 using ControlBlock = ::pw::allocator::internal::ControlBlock;
66 using element_type =
typename Base::element_type;
94 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
104 template <
typename U,
105 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
107 *
this = std::move(other);
125 operator= <T>(other);
135 template <
typename U,
136 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
145 template <
typename U,
146 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
153 SharedPtr& operator=(std::nullptr_t)
noexcept;
166 template <
typename U,
167 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
170 static_cast<const allocator::internal::BaseManagedPtr&
>(*this));
173 [[nodiscard]]
friend constexpr bool operator==(
const SharedPtr& lhs,
175 return lhs.Equals(
nullptr);
177 [[nodiscard]]
friend constexpr bool operator==(std::nullptr_t,
178 const SharedPtr& rhs) {
179 return rhs.Equals(
nullptr);
181 [[nodiscard]]
friend constexpr bool operator==(
const SharedPtr& lhs,
182 const SharedPtr& rhs) {
183 return lhs.Equals(rhs) && lhs.control_block_ == rhs.control_block_;
186 [[nodiscard]]
friend constexpr bool operator!=(
const SharedPtr& lhs,
188 return !lhs.Equals(
nullptr);
190 [[nodiscard]]
friend constexpr bool operator!=(std::nullptr_t,
191 const SharedPtr& rhs) {
192 return !rhs.Equals(
nullptr);
194 [[nodiscard]]
friend constexpr bool operator!=(
const SharedPtr& lhs,
195 const SharedPtr& rhs) {
196 return !(lhs == rhs);
203 static_assert(std::is_array_v<T>,
204 "size() cannot be called on non-array types");
205 return control_block_ ==
nullptr ? 0 : control_block_->size();
211 return control_block_ ==
nullptr ? 0 : control_block_->num_shared();
219 void reset() noexcept;
226 template <typename PtrType>
227 bool owner_before(const PtrType& other) const noexcept {
228 return control_block_ < other.control_block();
234 static constexpr bool is_unbounded_array_v =
235 allocator::internal::is_unbounded_array_v<T>;
262 template <
typename... Args>
282 SharedPtr(element_type* value, ControlBlock* control_block)
283 : Base(value), control_block_(control_block) {}
285 ControlBlock* control_block()
const {
return control_block_; }
288 template <
typename U,
289 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
290 void CopyFrom(
const SharedPtr<U>& other);
297 template <
typename U>
298 constexpr void CheckArrayTypes();
300 ControlBlock* control_block_ =
nullptr;
309 if constexpr (std::is_array_v<T>) {
311 ControlBlock::Create(owned.deallocator(), owned.get(), owned.size());
313 control_block_ = ControlBlock::Create(owned.deallocator(), owned.get(), 1);
315 if (control_block_ !=
nullptr) {
316 Base::CopyFrom(owned);
322template <
typename... Args>
324 static_assert(!std::is_array_v<T>);
325 auto* control_block = ControlBlock::Create(allocator, Layout::Of<T>(), 1);
326 if (control_block ==
nullptr) {
329 auto* t =
new (control_block->data()) T(std::forward<Args>(args)...);
330 return SharedPtr<T>(t, control_block);
334SharedPtr<T> SharedPtr<T>::Create(Allocator* allocator,
337 static_assert(allocator::internal::is_unbounded_array_v<T>);
338 Layout layout = Layout::Of<T>(count).Align(alignment);
339 auto* control_block = ControlBlock::Create(allocator, layout, count);
340 if (control_block ==
nullptr) {
343 auto* t =
new (control_block->data()) std::remove_extent_t<T>[count];
344 return SharedPtr<T>(t, control_block);
348template <
typename U,
typename>
350 const SharedPtr<U>& other)
noexcept {
351 CheckArrayTypes<U>();
353 if (control_block_ !=
nullptr) {
354 control_block_->IncrementShared();
360template <
typename U,
typename>
362 CheckArrayTypes<U>();
377 if (*
this ==
nullptr) {
380 auto action = control_block_->DecrementShared();
381 if (action == ControlBlock::Action::kNone) {
388 Allocator* allocator = control_block_->allocator();
389 if (!Base::HasCapability(allocator, allocator::kSkipsDestroy)) {
390 if constexpr (std::is_array_v<T>) {
391 Base::Destroy(control_block_->size());
397 if (action == ControlBlock::Action::kExpire) {
400 Base::Resize(allocator, control_block_,
sizeof(ControlBlock));
403 Base::Deallocate(allocator, control_block_);
412 std::swap(control_block_, other.control_block_);
416template <
typename U,
typename>
418 CheckArrayTypes<U>();
419 Base::CopyFrom(other);
420 control_block_ = other.control_block_;
424void SharedPtr<T>::Release() {
426 control_block_ =
nullptr;
431constexpr void SharedPtr<T>::CheckArrayTypes() {
432 if constexpr (std::is_array_v<T>) {
433 static_assert(std::is_array_v<U>,
434 "non-array type used with SharedPtr<T[]>");
436 static_assert(!std::is_array_v<U>,
"array type used with SharedPtr<T>");
Definition: allocator.h:36
Definition: multibuf_v2.h:184
Definition: shared_ptr.h:60
size_t size() const
Definition: shared_ptr.h:202
void swap(SharedPtr &other) noexcept
Swaps the managed pointer and deallocator of this and another object.
Definition: shared_ptr.h:410
constexpr SharedPtr & operator=(const SharedPtr< U > &other) noexcept
SharedPtr & operator=(SharedPtr< U > &&other) noexcept
SharedPtr(SharedPtr< U > &&other) noexcept
Definition: shared_ptr.h:106
~SharedPtr()
Releases any currently-held value.
Definition: shared_ptr.h:70
constexpr SharedPtr() noexcept=default
constexpr SharedPtr(const SharedPtr &other) noexcept
Copy-constructs a SharedPtr<T> from a SharedPtr<T>.
Definition: shared_ptr.h:85
int32_t use_count() const
Definition: shared_ptr.h:210
constexpr SharedPtr(const SharedPtr< U > &other) noexcept
Definition: shared_ptr.h:95
constexpr SharedPtr & operator=(const SharedPtr &other) noexcept
Definition: shared_ptr.h:124
void reset() noexcept
Definition: shared_ptr.h:376
Definition: unique_ptr.h:43
Definition: weak_ptr.h:37
MultiBufProperty
Basic properties of a MultiBuf.
Definition: properties.h:24
The Pigweed namespace.
Definition: alignment.h:27