dispenso 1.6.0
A library for task parallelism
Loading...
Searching...
No Matches
once_function.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
15#pragma once
16
17#include <cstring>
18#include <utility>
19
20#include <dispenso/detail/once_callable_impl.h>
21#include <dispenso/platform.h>
22
23namespace dispenso {
24
25#if DISPENSO_HAS_CONCEPTS
34template <typename F>
35concept OnceCallableFunc = std::invocable<F>;
36#endif // DISPENSO_HAS_CONCEPTS
37
38namespace detail {
39template <typename Result>
40class FutureBase;
41template <typename Result>
42class FutureImplBase;
43} // namespace detail
44
55 public:
60#if defined DISPENSO_DEBUG
61 : invoke_(nullptr)
62#endif // DISPENSO_DEBUG
63 {
64 }
65
73 template <typename F>
74 DISPENSO_REQUIRES(OnceCallableFunc<F>)
75 OnceFunction(F&& f) {
76 auto callable = detail::createOnceCallable(std::forward<F>(f), buf_);
77 invoke_ = callable.invoke;
78 }
79
80 OnceFunction(const OnceFunction& other) = delete;
81
83 OnceFunction(OnceFunction&& other) noexcept {
84 std::memcpy(static_cast<void*>(this), &other, sizeof(OnceFunction));
85#if defined DISPENSO_DEBUG
86 other.invoke_ = nullptr;
87#endif // DISPENSO_DEBUG
88 }
89
90 OnceFunction& operator=(OnceFunction&& other) noexcept {
91 if (this != &other) {
92#if defined DISPENSO_DEBUG
93 assert(
94 invoke_ == nullptr &&
95 "OnceFunction must be invoked or cleanupNotRun() before reassignment");
96#endif // DISPENSO_DEBUG
97 std::memcpy(static_cast<void*>(this), &other, sizeof(OnceFunction));
98#if defined DISPENSO_DEBUG
99 other.invoke_ = nullptr;
100#endif // DISPENSO_DEBUG
101 }
102 return *this;
103 }
104
111#if defined DISPENSO_DEBUG
112 assert(invoke_ != nullptr && "Must not cleanup an invalid OnceFunction!");
113 invoke_(buf_, false);
114 invoke_ = nullptr;
115#else
116 invoke_(buf_, false);
117#endif // DISPENSO_DEBUG
118 }
119
124 void operator()() const {
125#if defined DISPENSO_DEBUG
126 assert(invoke_ != nullptr && "Must not use OnceFunction more than once!");
127#endif // DISPENSO_DEBUG
128
129 invoke_(buf_, true);
130
131#if defined DISPENSO_DEBUG
132 invoke_ = nullptr;
133#endif // DISPENSO_DEBUG
134 }
135
136 private:
137 // 64 bytes total (one cache line): 56 bytes inline storage + 8 bytes invoke ptr.
138 // Inline: buf_ holds the functor directly.
139 // Spill: buf_[0..7] holds a void* to pool-allocated storage.
140 // Moves are a 64-byte memcpy — no pointer fixup needed.
141 alignas(64) mutable char buf_[detail::kOnceFunctionInlineSize];
142 mutable void (*invoke_)(void*, bool);
143
144 template <typename Result>
145 friend class detail::FutureBase;
146 template <typename Result>
147 friend class detail::FutureImplBase;
148};
149
150} // namespace dispenso
OnceFunction(OnceFunction &&other) noexcept