/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef META_BASE_SHARED_PTR_H #define META_BASE_SHARED_PTR_H #include #include "shared_ptr_internals.h" BASE_BEGIN_NAMESPACE() /** * @brief C++ standard like weak_ptr. */ template class weak_ptr final : public Internals::PtrCountedBase { public: using element_type = BASE_NS::remove_extent_t; weak_ptr() = default; ~weak_ptr() { if (this->control_) { this->control_->ReleaseWeak(); } }; weak_ptr(nullptr_t) {} weak_ptr(const shared_ptr& p) : Internals::PtrCountedBase(p) { if (this->control_) { this->control_->AddWeak(); } } weak_ptr(const weak_ptr& p) noexcept : Internals::PtrCountedBase(p) { if (this->control_) { this->control_->AddWeak(); } } weak_ptr(weak_ptr&& p) noexcept : Internals::PtrCountedBase(p) { p.InternalReset(); } // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax shared_ptr lock() const { return shared_ptr(*this); } weak_ptr& operator=(weak_ptr&& p) noexcept { if (this != &p) { reset(); this->control_ = p.control_; this->pointer_ = p.pointer_; p.InternalReset(); } return *this; } weak_ptr& operator=(const weak_ptr& p) noexcept { if (this != &p) { reset(); this->control_ = p.control_; this->pointer_ = p.pointer_; if (this->control_) { this->control_->AddWeak(); } } return *this; } weak_ptr& operator=(const shared_ptr& p) { reset(); this->control_ = p.control_; this->pointer_ = p.pointer_; if (this->control_) { this->control_->AddWeak(); } return *this; } weak_ptr& operator=(nullptr_t) noexcept { reset(); return *this; } // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax void reset() { if (this->control_) { this->control_->ReleaseWeak(); this->InternalReset(); } } /*"implicit" casting constructors */ template> weak_ptr(const shared_ptr& p) // handle casting by using functionality in shared_ptr. (creates an aliased shared_ptr to original.) : weak_ptr(shared_ptr(p)) {} template> weak_ptr(const weak_ptr& p) : weak_ptr(shared_ptr(p.lock())) {} /* "implicit" casting move */ template> weak_ptr(weak_ptr&& p) noexcept : weak_ptr(shared_ptr(p.lock())) { p.reset(); } /* "implicit" casting operators */ template> weak_ptr& operator=(const shared_ptr& p) { // handle casting by using functionality in shared_ptr. (creates an aliased shared_ptr to original.) *this = shared_ptr(p); return *this; } template> weak_ptr& operator=(const weak_ptr& p) { // first lock the given weak ptr. (to see if it has expired, and to get a pointer that can be cast) *this = shared_ptr(p.lock()); return *this; } // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax bool expired() const noexcept { return !this->control_ || this->control_->GetStrongCount() == 0; } private: friend class shared_ptr; template friend class weak_ptr; }; /** * @brief C++ standard like shared_ptr with IInterface support for reference counting. */ template class shared_ptr final : public Internals::PtrCountedBase { public: using element_type = BASE_NS::remove_extent_t; using weak_type = weak_ptr; constexpr shared_ptr() noexcept = default; constexpr shared_ptr(nullptr_t) noexcept {} shared_ptr(const shared_ptr& p) noexcept : Internals::PtrCountedBase(p) { if (this->control_) { this->control_->AddStrongCopy(); } } shared_ptr(shared_ptr&& p) noexcept : Internals::PtrCountedBase(p) { p.InternalReset(); } explicit shared_ptr(T* ptr) { if (ptr) { ConstructBlock(ptr); } } template shared_ptr(T* ptr, Deleter deleter) { if (ptr) { ConstructBlock(ptr, BASE_NS::move(deleter)); } } explicit shared_ptr(const weak_type& p) noexcept : Internals::PtrCountedBase(p) { if (this->control_) { if (!this->control_->AddStrongLock()) { this->InternalReset(); } } } template shared_ptr(const shared_ptr& r, T* ptr) noexcept : Internals::PtrCountedBase(r.control_) { if (this->control_ && ptr) { this->control_->AddStrongCopy(); this->pointer_ = const_cast(ptr); } else { this->InternalReset(); } } template> shared_ptr(shared_ptr&& p) noexcept : Internals::PtrCountedBase(p.control_) { if (this->control_) { void* ptr = nullptr; if constexpr (BASE_NS::is_same_v> || !META_NS::HasGetInterfaceMethod_v) { ptr = p.get(); } else { // make a proper interface cast here. if constexpr (BASE_NS::is_const_v) { ptr = const_cast(static_cast(p->GetInterface(T::UID))); } else { ptr = static_cast(p->GetInterface(T::UID)); } } if (ptr) { this->pointer_ = static_cast(ptr); p.InternalReset(); } else { this->InternalReset(); p.reset(); } } } template> shared_ptr(const shared_ptr& p) noexcept : shared_ptr(shared_ptr(p)) // use the above move constructor {} template> shared_ptr(unique_ptr&& p) noexcept { if (p) { ConstructBlock(p.release(), BASE_NS::move(p.get_deleter())); } } ~shared_ptr() { if (this->control_) { this->control_->Release(); } } T* operator->() const noexcept { return get(); } T& operator*() const noexcept { return *get(); } explicit operator bool() const { return get(); } bool operator==(const shared_ptr& other) const noexcept { return get() == other.get(); } bool operator!=(const shared_ptr& other) const noexcept { return !(*this == other); } // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax void reset() { if (this->control_) { this->control_->Release(); this->InternalReset(); } } // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax void reset(T* ptr) { if (ptr != this->pointer_) { reset(); if (ptr) { ConstructBlock(ptr); } } } template // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax void reset(T* ptr, Deleter deleter) { if (ptr != this->pointer_) { reset(); if (ptr) { ConstructBlock(ptr, BASE_NS::move(deleter)); } } } shared_ptr& operator=(nullptr_t) noexcept { reset(); return *this; } shared_ptr& operator=(const shared_ptr& o) { if (this != &o) { reset(); this->control_ = o.control_; this->pointer_ = o.pointer_; if (this->control_) { this->control_->AddStrongCopy(); } } return *this; } shared_ptr& operator=(shared_ptr&& o) noexcept { if (this != &o) { reset(); this->control_ = o.control_; this->pointer_ = o.pointer_; o.InternalReset(); } return *this; } // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax void swap(shared_ptr& p) { auto tp = p.pointer_; auto tc = p.control_; p.pointer_ = this->pointer_; p.control_ = this->control_; this->pointer_ = tp; this->control_ = tc; } // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax element_type* get() const noexcept { return this->pointer_; } private: using deletableType = BASE_NS::remove_const_t; void ConstructBlock(T* ptr) { static_assert(sizeof(T), "type has to be complete when constructing control block"); if constexpr (BASE_NS::is_convertible_v) { this->control_ = new Internals::RefCountedObjectStorageBlock(ptr); } else { this->control_ = new Internals::StorageBlock(ptr); } this->pointer_ = ptr; } template void ConstructBlock(T* ptr, Deleter deleter) { this->control_ = new Internals::StorageBlockWithDeleter(ptr, BASE_NS::move(deleter)); this->pointer_ = ptr; } template friend class weak_ptr; template friend class shared_ptr; }; BASE_END_NAMESPACE() // NOLINTBEGIN(readability-identifier-naming) to keep std like syntax template BASE_NS::shared_ptr static_pointer_cast(const BASE_NS::shared_ptr& ptr) { if (ptr) { return BASE_NS::shared_ptr(ptr, static_cast(ptr.get())); } return {}; } template BASE_NS::shared_ptr interface_pointer_cast(const BASE_NS::shared_ptr& ptr) { static_assert(META_NS::HasGetInterfaceMethod_v, "T::GetInterface not defined"); static_assert(META_NS::HasGetInterfaceMethod_v, "U::GetInterface not defined"); if (ptr) { if constexpr (BASE_NS::is_same_v) { // same type. return ptr; } else { return BASE_NS::shared_ptr(ptr, static_cast(static_cast(ptr->GetInterface(U::UID)))); } } return {}; } template BASE_NS::shared_ptr interface_pointer_cast(const BASE_NS::shared_ptr& ptr) { static_assert(META_NS::HasGetInterfaceMethod_v, "T::GetInterface not defined"); static_assert(META_NS::HasGetInterfaceMethod_v, "U::GetInterface not defined"); if (ptr) { if constexpr (BASE_NS::is_same_v) { // same type. return ptr; } else { return BASE_NS::shared_ptr( ptr, static_cast(static_cast(ptr->GetInterface(U::UID)))); } } return {}; } template BASE_NS::shared_ptr interface_pointer_cast(const BASE_NS::weak_ptr& weak) { return interface_pointer_cast(weak.lock()); } template BASE_NS::shared_ptr interface_pointer_cast(const BASE_NS::weak_ptr& weak) { return interface_pointer_cast(weak.lock()); } template U* interface_cast(const BASE_NS::shared_ptr& ptr) { static_assert(META_NS::HasGetInterfaceMethod_v, "T::GetInterface not defined"); static_assert(META_NS::HasGetInterfaceMethod_v, "U::GetInterface not defined"); if (ptr) { if constexpr (BASE_NS::is_same_v) { // same type. return ptr.get(); } else { return static_cast(static_cast(ptr->GetInterface(U::UID))); } } return {}; } template const U* interface_cast(const BASE_NS::shared_ptr& ptr) { static_assert(META_NS::HasGetInterfaceMethod_v, "T::GetInterface not defined"); static_assert(META_NS::HasGetInterfaceMethod_v, "U::GetInterface not defined"); if (ptr) { if constexpr (BASE_NS::is_same_v) { // same type. return ptr.get(); } else { return static_cast(static_cast(ptr->GetInterface(U::UID))); } } return {}; } template U* interface_cast(CORE_NS::IInterface* ptr) { static_assert(META_NS::HasGetInterfaceMethod_v, "U::GetInterface not defined"); if (ptr) { return static_cast(static_cast(ptr->GetInterface(U::UID))); } return {}; } template const U* interface_cast(const CORE_NS::IInterface* ptr) { static_assert(META_NS::HasGetInterfaceMethod_v, "U::GetInterface not defined"); if (ptr) { return static_cast(static_cast(ptr->GetInterface(U::UID))); } return {}; } // NOLINTEND(readability-identifier-naming) to keep std like syntax template BASE_NS::shared_ptr CreateShared(Args&&... args) { return BASE_NS::shared_ptr(new T(BASE_NS::forward(args)...)); } META_TYPE(BASE_NS::shared_ptr) META_TYPE(BASE_NS::shared_ptr) META_TYPE(BASE_NS::weak_ptr) META_TYPE(BASE_NS::weak_ptr) #endif