31 MoveOnly(MoveOnly&&) =
default;
32 MoveOnly& operator=(MoveOnly&&) =
default;
33 MoveOnly(
const MoveOnly&) =
delete;
34 MoveOnly& operator=(
const MoveOnly&) =
delete;
39 NonCopyable() =
default;
40 NonCopyable(
const NonCopyable&) =
delete;
41 NonCopyable& operator=(
const NonCopyable&) =
delete;
51template <
bool Const,
typename R,
typename... Args>
52class MoveOnlyCallable {
53 static constexpr std::size_t kStorageSize = 3 *
sizeof(
void*);
54 static constexpr std::size_t kStorageAlign =
alignof(std::max_align_t);
57 using TargetRef = std::conditional_t<Const, const D&, D&>;
60 static constexpr bool kInline =
sizeof(D) <= kStorageSize &&
alignof(D) <= kStorageAlign &&
61 std::is_nothrow_move_constructible_v<D>;
64 R (*invoke)(
void* storage, Args&&... args);
65 void (*relocate)(
void* dst,
void* src)
noexcept;
66 void (*destroy)(
void* storage)
noexcept;
70 static D* Target(
void* storage)
noexcept {
71 if constexpr (kInline<D>) {
72 return std::launder(
static_cast<D*
>(storage));
74 return *std::launder(
static_cast<D**
>(storage));
79 static R Invoke(
void* storage, Args&&... args) {
80 TargetRef<D> target = *Target<D>(storage);
81 if constexpr (std::is_void_v<R>) {
82 static_cast<void>(std::invoke(target, std::forward<Args>(args)...));
84 return std::invoke(target, std::forward<Args>(args)...);
89 static void Relocate(
void* dst,
void* src)
noexcept {
90 if constexpr (kInline<D>) {
91 D* from = Target<D>(src);
92 ::new (dst) D(std::move(*from));
95 ::new (dst) D*(Target<D>(src));
100 static void Destroy(
void* storage)
noexcept {
101 if constexpr (kInline<D>) {
102 Target<D>(storage)->~D();
104 delete Target<D>(storage);
108 template <
typename D>
109 static constexpr Ops kOps{&Invoke<D>, &Relocate<D>, &Destroy<D>};
113 template <
typename F>
114 static constexpr bool kAccepts =
115 std::conjunction_v<std::negation<std::is_same<std::remove_cvref_t<F>, MoveOnlyCallable>>,
116 std::is_invocable_r<R, TargetRef<std::decay_t<F>>, Args...>,
117 std::is_constructible<std::decay_t<F>, F>>;
120 MoveOnlyCallable() noexcept = default;
122 MoveOnlyCallable(std::nullptr_t) noexcept {}
124 template <
typename F>
126 MoveOnlyCallable(F&& f) {
127 using D = std::decay_t<F>;
128 if constexpr (std::is_pointer_v<D> || std::is_member_pointer_v<D>) {
133 if constexpr (kInline<D>) {
134 ::new (
static_cast<void*
>(storage_)) D(std::forward<F>(f));
136 ::new (
static_cast<void*
>(storage_)) D*(
new D(std::forward<F>(f)));
141 MoveOnlyCallable(MoveOnlyCallable&& other)
noexcept { TakeFrom(other); }
143 MoveOnlyCallable(
const MoveOnlyCallable&) =
delete;
144 MoveOnlyCallable& operator=(
const MoveOnlyCallable&) =
delete;
146 ~MoveOnlyCallable() { Reset(); }
148 MoveOnlyCallable& operator=(MoveOnlyCallable&& other)
noexcept {
149 if (
this != &other) {
156 MoveOnlyCallable& operator=(std::nullptr_t)
noexcept {
161 template <
typename F>
163 MoveOnlyCallable& operator=(F&& f) {
164 *
this = MoveOnlyCallable(std::forward<F>(f));
168 void swap(MoveOnlyCallable& other)
noexcept {
169 MoveOnlyCallable held(std::move(other));
170 other = std::move(*
this);
171 *
this = std::move(held);
174 friend void swap(MoveOnlyCallable& a, MoveOnlyCallable& b)
noexcept { a.swap(b); }
176 explicit operator bool() const noexcept {
return ops_ !=
nullptr; }
178 friend bool operator==(
const MoveOnlyCallable& f, std::nullptr_t)
noexcept {
179 return f.ops_ ==
nullptr;
182 R operator()(Args... args)
186 return ops_->invoke(storage_, std::forward<Args>(args)...);
189 R operator()(Args... args)
const
193 return ops_->invoke(
const_cast<std::byte*
>(storage_), std::forward<Args>(args)...);
197 void TakeFrom(MoveOnlyCallable& other)
noexcept {
198 if (other.ops_ !=
nullptr) {
199 other.ops_->relocate(storage_, other.storage_);
200 ops_ = std::exchange(other.ops_,
nullptr);
204 void Reset() noexcept {
205 if (
const Ops* ops = std::exchange(ops_,
nullptr)) {
206 ops->destroy(storage_);
210 alignas(kStorageAlign) std::byte storage_[kStorageSize]{};
211 const Ops* ops_ =
nullptr;
219template <
typename Signature>
220struct MoveOnlyFunctionFor;
223template <
typename R,
typename... Args>
224struct MoveOnlyFunctionFor<R(Args...)> {
225 using type = MoveOnlyCallable<
false, R, Args...>;
229template <
typename R,
typename... Args>
230struct MoveOnlyFunctionFor<R(Args...) const> {
231 using type = MoveOnlyCallable<
true, R, Args...>;
236#if defined(__cpp_lib_move_only_function) && __cpp_lib_move_only_function >= 202110L
243template <
typename Signature>
253template <
typename Signature>
264class PropagateConst :
public MoveOnly {
266 using element_type = std::remove_reference_t<decltype(*std::declval<T&>())>;
268 PropagateConst() =
default;
270 PropagateConst(T pointer)
noexcept(std::is_nothrow_move_constructible_v<T>)
271 : pointer_(std::move(pointer)) {}
273 PropagateConst(PropagateConst&& other)
noexcept =
default;
275 PropagateConst& operator=(PropagateConst&& other)
noexcept =
default;
277 PropagateConst& operator=(T pointer)
noexcept(std::is_nothrow_move_assignable_v<T>) {
278 pointer_ = std::move(pointer);
282 element_type* get()
noexcept {
return std::to_address(pointer_); }
284 const element_type* get()
const noexcept {
return std::to_address(pointer_); }
286 element_type* operator->()
noexcept {
return get(); }
288 const element_type* operator->()
const noexcept {
return get(); }
290 element_type& operator*()
noexcept {
return *get(); }
292 const element_type& operator*()
const noexcept {
return *get(); }
294 explicit operator bool()
const noexcept {
return get() !=
nullptr; }
296 friend bool operator==(
const PropagateConst& value, std::nullptr_t)
noexcept {
297 return value.get() ==
nullptr;
307 ScopeGuard() =
default;
#define REX_ASSERT(cond,...)
Definition assert.h:84
ScopeGuard(MoveOnlyFunction< void()> release)
ScopeGuard & operator=(ScopeGuard &&other) noexcept
ScopeGuard(ScopeGuard &&other) noexcept
typename detail::MoveOnlyFunctionFor< Signature >::type MoveOnlyFunction
Definition utility.h:254
Integer types, byte order wrappers and size literals.