45 using base_type = BaseType;
46 using pointer = base_type *;
47 using const_pointer = base_type
const *;
67 template<std::derived_from<base_type> Other>
69 _pointer(other.release())
73 template<std::derived_from<base_type> Other>
77 _pointer.store(
other.release(), std::memory_order::release);
80 template<std::derived_from<base_type> Other>
81 polymorphic_optional(Other&& other) noexcept : _pointer(
new Other(std::forward<Other>(*other)))
85 template<std::derived_from<base_type> Other>
86 polymorphic_optional(Other&& other)
noexcept requires(
sizeof(Other) <= capacity and
alignof(Other) <= alignment) :
91 template<std::derived_from<base_type> Other>
92 polymorphic_optional& operator=(Other&& other)
noexcept
95 auto *new_ptr =
new Other(std::forward<Other>(other));
96 _pointer.store(new_ptr, std::memory_order::release);
100 template<std::derived_from<base_type> Other>
101 polymorphic_optional& operator=(Other&& other)
noexcept requires(
sizeof(Other) <= capacity and
alignof(Other) <= alignment)
104 auto *new_ptr =
new (_buffer.data()) Other(std::forward<Other>(other));
105 _pointer.store(new_ptr, std::memory_order::release);
109 [[nodiscard]]
bool empty(std::memory_order memory_order = std::memory_order::seq_cst)
const noexcept
111 return _pointer.load(memory_order) ==
nullptr;
114 operator bool() const noexcept
119 template<
typename Value>
120 Value& value(std::memory_order memory_order = std::memory_order::seq_cst)
122 auto *ptr = _pointer.load(memory_order);
123 if (ptr ==
nullptr) {
126 return down_cast<Value&>(*ptr);
129 template<
typename Value>
130 Value
const& value(std::memory_order memory_order = std::memory_order::seq_cst)
const
132 auto *ptr = _pointer.load(memory_order);
133 if (ptr ==
nullptr) {
136 return down_cast<Value const&>(*ptr);
139 base_type *operator->() noexcept
141 return _pointer.load();
144 base_type
const *operator->() const noexcept
146 return _pointer.load();
151 return *_pointer.load();
154 base_type
const&
operator*() const noexcept
156 return *_pointer.load();
161 hi_force_inline
void reset() noexcept
163 if (
auto *ptr = _pointer.exchange(
nullptr, std::memory_order::acquire)) {
164 if (equal_ptr(ptr,
this)) {
165 std::destroy_at(ptr);
172 template<
typename Value,
typename... Args>
173 hi_force_inline Value& emplace(Args&&...args)
noexcept
177 if constexpr (
sizeof(Value) <= capacity and
alignof(Value) <= alignment) {
179 auto new_ptr =
new (_buffer.data()) Value(std::forward<Args>(args)...);
180 hi_axiom(equal_ptr(new_ptr,
this));
182 _pointer.store(new_ptr, std::memory_order::release);
189 auto const new_ptr =
new Value(std::forward<Args>(args)...);
190 hi_assert_not_null(new_ptr);
192 _pointer.store(new_ptr, std::memory_order::release);
203 template<
typename Func>
206 using func_result =
decltype(std::declval<Func>()(std::declval<base_type&>()));
207 using result_type = std::conditional_t<std::is_same_v<func_result, void>, bool, std::optional<func_result>>;
210 if (
auto ptr = _pointer.load(std::memory_order::acquire)) {
211 if constexpr (std::is_same_v<func_result, void>) {
212 if (equal_ptr(ptr,
this)) {
213 std::forward<Func>(func)(*ptr);
214 std::destroy_at(ptr);
217 _pointer.store(
nullptr, std::memory_order::release);
222 _pointer.store(
nullptr, std::memory_order::release);
224 std::forward<Func>(func)(*ptr);
230 if (equal_ptr(ptr,
this)) {
231 auto result = std::forward<Func>(func)(*ptr);
232 std::destroy_at(ptr);
235 _pointer.store(
nullptr, std::memory_order::release);
240 _pointer.store(
nullptr, std::memory_order::release);
242 auto result = std::forward<Func>(func)(*ptr);
249 return result_type{};
260 template<
typename Value,
typename Func,
typename... Args>
263 using func_result =
decltype(std::declval<Func>()(std::declval<Value&>()));
265 if constexpr (
sizeof(Value) <= capacity and
alignof(Value) <= alignment) {
269 if (_pointer.load(std::memory_order_acquire) !=
nullptr) [[unlikely]] {
275 auto const new_ptr =
new (_buffer.data()) Value(std::forward<Args>(args)...);
276 hi_assume(new_ptr !=
nullptr);
277 hi_axiom(equal_ptr(new_ptr,
this));
279 if constexpr (std::is_same_v<func_result, void>) {
281 std::forward<Func>(func)(*new_ptr);
284 _pointer.store(new_ptr, std::memory_order::release);
288 auto tmp = std::forward<Func>(func)(*new_ptr);
291 _pointer.store(new_ptr, std::memory_order::release);
299 auto const new_ptr =
new Value(std::forward<Args>(args)...);
300 hi_assert_not_null(new_ptr);
305 if (_pointer.load(std::memory_order::relaxed) !=
nullptr) [[unlikely]] {
310 if constexpr (std::is_same_v<func_result, void>) {
312 std::forward<Func>(func)(*new_ptr);
315 _pointer.store(new_ptr, std::memory_order::release);
319 auto tmp = std::forward<Func>(func)(*new_ptr);
322 _pointer.store(new_ptr, std::memory_order::release);
342 hi_no_inline
void contended_read() noexcept
344 using namespace std::chrono_literals;
350 }
while (_pointer.
load(std::memory_order::relaxed) !=
nullptr);
constexpr matrix2 operator*(matrix2 const &lhs, matrix2 const &rhs) noexcept
Matrix/Matrix multiplication.
Definition transform.hpp:69
hi_force_inline void reset() noexcept
Destroys the contained value, otherwise has no effect.
Definition polymorphic_optional.hpp:161
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:261