extra/otel/opentelemetry-cpp-1.8.3/api/include/opentelemetry/nostd/shared_ptr.h (156 lines of code) (raw):

// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 #pragma once #ifdef HAVE_CPP_STDLIB # include "opentelemetry/std/shared_ptr.h" #else # include <cstdlib> # include <memory> # include <utility> # include "opentelemetry/nostd/unique_ptr.h" # include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace nostd { /** * Provide a type-erased version of std::shared_ptr that has ABI stability. */ template <class T> class shared_ptr { public: using element_type = T; using pointer = element_type *; private: static constexpr size_t kMaxSize = 32; static constexpr size_t kAlignment = 8; struct alignas(kAlignment) PlacementBuffer { char data[kMaxSize]; }; class shared_ptr_wrapper { public: shared_ptr_wrapper() noexcept = default; shared_ptr_wrapper(std::shared_ptr<T> &&ptr) noexcept : ptr_{std::move(ptr)} {} virtual ~shared_ptr_wrapper() {} virtual void CopyTo(PlacementBuffer &buffer) const noexcept { new (buffer.data) shared_ptr_wrapper{*this}; } virtual void MoveTo(PlacementBuffer &buffer) noexcept { new (buffer.data) shared_ptr_wrapper{std::move(this->ptr_)}; } template <class U, typename std::enable_if<std::is_convertible<pointer, U *>::value>::type * = nullptr> void MoveTo(typename shared_ptr<U>::PlacementBuffer &buffer) noexcept { using other_shared_ptr_wrapper = typename shared_ptr<U>::shared_ptr_wrapper; new (buffer.data) other_shared_ptr_wrapper{std::move(this->ptr_)}; } virtual pointer Get() const noexcept { return ptr_.get(); } virtual void Reset() noexcept { ptr_.reset(); } private: std::shared_ptr<T> ptr_; }; static_assert(sizeof(shared_ptr_wrapper) <= kMaxSize, "Placement buffer is too small"); static_assert(alignof(shared_ptr_wrapper) <= kAlignment, "Placement buffer not properly aligned"); public: shared_ptr() noexcept { new (buffer_.data) shared_ptr_wrapper{}; } explicit shared_ptr(pointer ptr) { std::shared_ptr<T> ptr_(ptr); new (buffer_.data) shared_ptr_wrapper{std::move(ptr_)}; } shared_ptr(std::shared_ptr<T> ptr) noexcept { new (buffer_.data) shared_ptr_wrapper{std::move(ptr)}; } shared_ptr(shared_ptr &&other) noexcept { other.wrapper().MoveTo(buffer_); } template <class U, typename std::enable_if<std::is_convertible<U *, pointer>::value>::type * = nullptr> shared_ptr(shared_ptr<U> &&other) noexcept { other.wrapper().template MoveTo<T>(buffer_); } shared_ptr(const shared_ptr &other) noexcept { other.wrapper().CopyTo(buffer_); } shared_ptr(unique_ptr<T> &&other) noexcept { std::shared_ptr<T> ptr_(other.release()); new (buffer_.data) shared_ptr_wrapper{std::move(ptr_)}; } shared_ptr(std::unique_ptr<T> &&other) noexcept { std::shared_ptr<T> ptr_(other.release()); new (buffer_.data) shared_ptr_wrapper{std::move(ptr_)}; } ~shared_ptr() { wrapper().~shared_ptr_wrapper(); } shared_ptr &operator=(shared_ptr &&other) noexcept { wrapper().~shared_ptr_wrapper(); other.wrapper().MoveTo(buffer_); return *this; } shared_ptr &operator=(std::nullptr_t) noexcept { wrapper().Reset(); return *this; } shared_ptr &operator=(const shared_ptr &other) noexcept { wrapper().~shared_ptr_wrapper(); other.wrapper().CopyTo(buffer_); return *this; } element_type &operator*() const noexcept { return *wrapper().Get(); } pointer operator->() const noexcept { return wrapper().Get(); } operator bool() const noexcept { return wrapper().Get() != nullptr; } pointer get() const noexcept { return wrapper().Get(); } void swap(shared_ptr<T> &other) noexcept { shared_ptr<T> tmp{std::move(other)}; wrapper().MoveTo(other.buffer_); tmp.wrapper().MoveTo(buffer_); } template <typename U> friend class shared_ptr; private: PlacementBuffer buffer_; shared_ptr_wrapper &wrapper() noexcept { return *reinterpret_cast<shared_ptr_wrapper *>(buffer_.data); } const shared_ptr_wrapper &wrapper() const noexcept { return *reinterpret_cast<const shared_ptr_wrapper *>(buffer_.data); } }; template <class T1, class T2> bool operator!=(const shared_ptr<T1> &lhs, const shared_ptr<T2> &rhs) noexcept { return lhs.get() != rhs.get(); } template <class T1, class T2> bool operator==(const shared_ptr<T1> &lhs, const shared_ptr<T2> &rhs) noexcept { return lhs.get() == rhs.get(); } template <class T> inline bool operator==(const shared_ptr<T> &lhs, std::nullptr_t) noexcept { return lhs.get() == nullptr; } template <class T> inline bool operator==(std::nullptr_t, const shared_ptr<T> &rhs) noexcept { return nullptr == rhs.get(); } template <class T> inline bool operator!=(const shared_ptr<T> &lhs, std::nullptr_t) noexcept { return lhs.get() != nullptr; } template <class T> inline bool operator!=(std::nullptr_t, const shared_ptr<T> &rhs) noexcept { return nullptr != rhs.get(); } } // namespace nostd OPENTELEMETRY_END_NAMESPACE #endif