39class alignas(Alignment) polymorphic_optional {
41 using base_type = BaseType;
43 using const_pointer = base_type
const *;
55 ~polymorphic_optional()
63 template<std::derived_from<base_type> Other>
65 _pointer(other.release())
69 template<std::derived_from<base_type> Other>
70 polymorphic_optional& operator=(std::unique_ptr<Other, std::default_delete<Other>>&& other)
noexcept
73 _pointer.store(
other.release(), std::memory_order::release);
76 template<std::derived_from<base_type> Other>
77 polymorphic_optional(Other&& other) noexcept : _pointer(
new Other(
std::forward<Other>(*other)))
81 template<std::derived_from<base_type> Other>
82 polymorphic_optional(Other&& other)
noexcept requires(
sizeof(Other) <= capacity and
alignof(Other) <= alignment) :
83 _pointer(new (_buffer.data()) Other(std::
forward<Other>(*
other)))
87 template<std::derived_from<base_type> Other>
88 polymorphic_optional& operator=(Other&& other)
noexcept
92 _pointer.store(new_ptr, std::memory_order::release);
96 template<std::derived_from<base_type> Other>
97 polymorphic_optional& operator=(Other&& other)
noexcept requires(
sizeof(Other) <= capacity and
alignof(Other) <= alignment)
101 _pointer.store(new_ptr, std::memory_order::release);
105 [[nodiscard]]
bool empty(std::memory_order memory_order = std::memory_order::seq_cst)
const noexcept
107 return _pointer.load(memory_order) ==
nullptr;
110 operator bool() const noexcept
115 template<
typename Value>
116 Value& value(std::memory_order memory_order = std::memory_order::seq_cst)
118 auto *ptr = _pointer.load(memory_order);
119 if (ptr ==
nullptr) {
120 throw std::bad_optional_access();
122 return down_cast<Value&>(*ptr);
125 template<
typename Value>
126 Value
const& value(std::memory_order memory_order = std::memory_order::seq_cst)
const
128 auto *ptr = _pointer.load(memory_order);
129 if (ptr ==
nullptr) {
130 throw std::bad_optional_access();
132 return down_cast<Value const&>(*ptr);
135 base_type *operator->() noexcept
137 return _pointer.load();
140 base_type
const *operator->() const noexcept
142 return _pointer.load();
145 base_type& operator*() noexcept
147 return *_pointer.load();
150 base_type
const& operator*() const noexcept
152 return *_pointer.load();
157 hi_force_inline
void reset() noexcept
159 if (
auto *ptr = _pointer.exchange(
nullptr, std::memory_order::acquire)) {
160 if (equal_ptr(ptr,
this)) {
161 std::destroy_at(ptr);
168 template<
typename Value,
typename... Args>
169 hi_force_inline Value& emplace(Args&&...args)
noexcept
173 if constexpr (
sizeof(Value) <= capacity and
alignof(Value) <=
alignment) {
178 _pointer.store(new_ptr, std::memory_order::release);
188 _pointer.store(new_ptr, std::memory_order::release);
199 template<
typename Func>
203 using result_type = std::conditional_t<std::is_same_v<func_result, void>, bool, std::optional<func_result>>;
206 if (
auto ptr = _pointer.load(std::memory_order::acquire)) {
207 if constexpr (std::is_same_v<func_result, void>) {
208 if (equal_ptr(ptr,
this)) {
210 std::destroy_at(ptr);
213 _pointer.store(
nullptr, std::memory_order::release);
218 _pointer.store(
nullptr, std::memory_order::release);
226 if (equal_ptr(ptr,
this)) {
228 std::destroy_at(ptr);
231 _pointer.store(
nullptr, std::memory_order::release);
236 _pointer.store(
nullptr, std::memory_order::release);
245 return result_type{};
256 template<
typename Value,
typename Func,
typename... Args>
265 while (_pointer.load(std::memory_order_acquire)) {
267 [[unlikely]] contended();
272 hi_assume(new_ptr !=
nullptr);
275 if constexpr (std::is_same_v<func_result, void>) {
280 _pointer.store(new_ptr, std::memory_order::release);
287 _pointer.store(new_ptr, std::memory_order::release);
301 while (_pointer.load(std::memory_order::relaxed)) {
303 [[unlikely]] contended();
306 if constexpr (std::is_same_v<func_result, void>) {
311 _pointer.store(new_ptr, std::memory_order::release);
318 _pointer.store(new_ptr, std::memory_order::release);
338 hi_no_inline
void contended() noexcept
340 using namespace std::chrono_literals;
343 ++global_counter<
"polymorphic_optional:contended">;
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hi_assert_not_null(x,...)
Assert if an expression is not nullptr.
Definition assert.hpp:238
hi_force_inline auto wait_emplace_and_invoke(Func &&func, Args &&...args) noexcept
Wait until the optional is empty, emplace a value, then invoke a function on it before committing.
Definition polymorphic_optional.hpp:257