shared_ptr.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. #if defined(OPENTELEMETRY_STL_VERSION)
  5. # if OPENTELEMETRY_STL_VERSION >= 2011
  6. # include "opentelemetry/std/shared_ptr.h"
  7. # define OPENTELEMETRY_HAVE_STD_SHARED_PTR
  8. # endif
  9. #endif
  10. #if !defined(OPENTELEMETRY_HAVE_STD_SHARED_PTR)
  11. # include <cstdlib>
  12. # include <memory>
  13. # include <utility>
  14. # include "opentelemetry/nostd/unique_ptr.h"
  15. # include "opentelemetry/version.h"
  16. OPENTELEMETRY_BEGIN_NAMESPACE
  17. namespace nostd
  18. {
  19. /**
  20. * Provide a type-erased version of std::shared_ptr that has ABI stability.
  21. */
  22. template <class T>
  23. class shared_ptr
  24. {
  25. public:
  26. using element_type = T;
  27. using pointer = element_type *;
  28. private:
  29. static constexpr size_t kMaxSize = 32;
  30. static constexpr size_t kAlignment = 8;
  31. struct alignas(kAlignment) PlacementBuffer
  32. {
  33. char data[kMaxSize]{};
  34. };
  35. class shared_ptr_wrapper
  36. {
  37. public:
  38. shared_ptr_wrapper() noexcept = default;
  39. shared_ptr_wrapper(std::shared_ptr<T> &&ptr) noexcept : ptr_{std::move(ptr)} {}
  40. virtual ~shared_ptr_wrapper() {}
  41. virtual void CopyTo(PlacementBuffer &buffer) const noexcept
  42. {
  43. new (buffer.data) shared_ptr_wrapper{*this};
  44. }
  45. virtual void MoveTo(PlacementBuffer &buffer) noexcept
  46. {
  47. new (buffer.data) shared_ptr_wrapper{std::move(this->ptr_)};
  48. }
  49. template <class U,
  50. typename std::enable_if<std::is_convertible<pointer, U *>::value>::type * = nullptr>
  51. void MoveTo(typename shared_ptr<U>::PlacementBuffer &buffer) noexcept
  52. {
  53. using other_shared_ptr_wrapper = typename shared_ptr<U>::shared_ptr_wrapper;
  54. new (buffer.data) other_shared_ptr_wrapper{std::move(this->ptr_)};
  55. }
  56. virtual pointer Get() const noexcept { return ptr_.get(); }
  57. virtual void Reset() noexcept { ptr_.reset(); }
  58. private:
  59. std::shared_ptr<T> ptr_;
  60. };
  61. static_assert(sizeof(shared_ptr_wrapper) <= kMaxSize, "Placement buffer is too small");
  62. static_assert(alignof(shared_ptr_wrapper) <= kAlignment, "Placement buffer not properly aligned");
  63. public:
  64. shared_ptr() noexcept { new (buffer_.data) shared_ptr_wrapper{}; }
  65. explicit shared_ptr(pointer ptr)
  66. {
  67. std::shared_ptr<T> ptr_(ptr);
  68. new (buffer_.data) shared_ptr_wrapper{std::move(ptr_)};
  69. }
  70. shared_ptr(std::shared_ptr<T> ptr) noexcept
  71. {
  72. new (buffer_.data) shared_ptr_wrapper{std::move(ptr)};
  73. }
  74. shared_ptr(shared_ptr &&other) noexcept { other.wrapper().MoveTo(buffer_); }
  75. template <class U,
  76. typename std::enable_if<std::is_convertible<U *, pointer>::value>::type * = nullptr>
  77. shared_ptr(shared_ptr<U> &&other) noexcept
  78. {
  79. other.wrapper().template MoveTo<T>(buffer_);
  80. }
  81. shared_ptr(const shared_ptr &other) noexcept { other.wrapper().CopyTo(buffer_); }
  82. shared_ptr(unique_ptr<T> &&other) noexcept
  83. {
  84. std::shared_ptr<T> ptr_(other.release());
  85. new (buffer_.data) shared_ptr_wrapper{std::move(ptr_)};
  86. }
  87. shared_ptr(std::unique_ptr<T> &&other) noexcept
  88. {
  89. std::shared_ptr<T> ptr_(other.release());
  90. new (buffer_.data) shared_ptr_wrapper{std::move(ptr_)};
  91. }
  92. ~shared_ptr() { wrapper().~shared_ptr_wrapper(); }
  93. shared_ptr &operator=(shared_ptr &&other) noexcept
  94. {
  95. wrapper().~shared_ptr_wrapper();
  96. other.wrapper().MoveTo(buffer_);
  97. return *this;
  98. }
  99. shared_ptr &operator=(std::nullptr_t) noexcept
  100. {
  101. wrapper().Reset();
  102. return *this;
  103. }
  104. shared_ptr &operator=(const shared_ptr &other) noexcept
  105. {
  106. wrapper().~shared_ptr_wrapper();
  107. other.wrapper().CopyTo(buffer_);
  108. return *this;
  109. }
  110. element_type &operator*() const noexcept { return *wrapper().Get(); }
  111. pointer operator->() const noexcept { return wrapper().Get(); }
  112. operator bool() const noexcept { return wrapper().Get() != nullptr; }
  113. pointer get() const noexcept { return wrapper().Get(); }
  114. void swap(shared_ptr<T> &other) noexcept
  115. {
  116. shared_ptr<T> tmp{std::move(other)};
  117. wrapper().MoveTo(other.buffer_);
  118. tmp.wrapper().MoveTo(buffer_);
  119. }
  120. template <typename U>
  121. friend class shared_ptr;
  122. private:
  123. PlacementBuffer buffer_;
  124. shared_ptr_wrapper &wrapper() noexcept
  125. {
  126. return *reinterpret_cast<shared_ptr_wrapper *>(buffer_.data);
  127. }
  128. const shared_ptr_wrapper &wrapper() const noexcept
  129. {
  130. return *reinterpret_cast<const shared_ptr_wrapper *>(buffer_.data);
  131. }
  132. };
  133. template <class T1, class T2>
  134. bool operator!=(const shared_ptr<T1> &lhs, const shared_ptr<T2> &rhs) noexcept
  135. {
  136. return lhs.get() != rhs.get();
  137. }
  138. template <class T1, class T2>
  139. bool operator==(const shared_ptr<T1> &lhs, const shared_ptr<T2> &rhs) noexcept
  140. {
  141. return lhs.get() == rhs.get();
  142. }
  143. template <class T>
  144. inline bool operator==(const shared_ptr<T> &lhs, std::nullptr_t) noexcept
  145. {
  146. return lhs.get() == nullptr;
  147. }
  148. template <class T>
  149. inline bool operator==(std::nullptr_t, const shared_ptr<T> &rhs) noexcept
  150. {
  151. return nullptr == rhs.get();
  152. }
  153. template <class T>
  154. inline bool operator!=(const shared_ptr<T> &lhs, std::nullptr_t) noexcept
  155. {
  156. return lhs.get() != nullptr;
  157. }
  158. template <class T>
  159. inline bool operator!=(std::nullptr_t, const shared_ptr<T> &rhs) noexcept
  160. {
  161. return nullptr != rhs.get();
  162. }
  163. } // namespace nostd
  164. OPENTELEMETRY_END_NAMESPACE
  165. #endif /* OPENTELEMETRY_HAVE_STD_SHARED_PTR */