UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
AutoRTFMTask.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include <cstddef>
6#include <type_traits>
7#include <utility>
8
9#include "AutoRTFMDefines.h"
10
11namespace AutoRTFM
12{
13
14// TTask is a small std::function like class that can wrap a functor (lambda, etc).
15// TTask is used by AutoRTFM for callbacks such as OnCommit and OnAbort
16// handlers, which there may be many accumulating throughout a transaction.
17// For this reason TTask is designed to be compact in size (smaller than
18// TFunction), but large enough to fit the most common functors used by AutoRTFM
19// tasks.
20// Note: to prevent generating closed-variants of task-wrapped functions,
21// operator() cannot be called from the closed. All other operations on
22// the task can be called from the open or closed.
23template<typename Signature>
24class TTask;
25
26template<typename ReturnType, typename... ParameterTypes>
27class TTask<ReturnType(ParameterTypes...)>
28{
29public:
30 static constexpr size_t InlineDataSize = 16;
31 static constexpr size_t InlineDataAlignment = 8;
32
33private:
34 // The payload holds either the inline function data, or a pointer to the
35 // data in a heap allocation.
36 union FPayload
37 {
38 std::byte Inline[InlineDataSize];
39 void* External;
40 };
41
42 // Holds the function pointers for operating on the payload.
43 struct FPayloadMethods
44 {
45 using CallFn = ReturnType(FPayload& Payload, ParameterTypes...);
46 using CopyFn = void(FPayload& Dst, const FPayload& Src);
47 using MoveFn = void(FPayload& Dst, FPayload& Src);
48 using DestructFn = void(FPayload& Payload);
49
50 CallFn* Call = nullptr; // Calls the function held by the payload.
51 CopyFn* Copy = nullptr; // Copies the payload.
52 MoveFn* Move = nullptr; // Moves the payload.
53 DestructFn* Destruct = nullptr; // Destructs the payload.
54 };
55
56 // Traits helper for a functor (T).
57 template<typename T>
58 struct TTraits
59 {
60 // True iff T can fit within the inline payload, and does not require
61 // courser alignment than provided by the inline payload.
62 static constexpr bool bCanUseInline = sizeof(T) <= InlineDataSize && alignof(T) <= InlineDataAlignment;
63
64 // Returns the functor from the payload.
65 static T* FunctionFrom(FPayload& Payload)
66 {
67 return bCanUseInline ? reinterpret_cast<T*>(Payload.Inline) : reinterpret_cast<T*>(Payload.External);
68 }
69
70 // Returns the functor from the payload.
71 static const T* FunctionFrom(const FPayload& Payload)
72 {
73 return bCanUseInline ? reinterpret_cast<const T*>(Payload.Inline) : reinterpret_cast<const T*>(Payload.External);
74 }
75
76 // Calls the function held by the payload. Cannot be called from the closed.
77 AUTORTFM_DISABLE static ReturnType Call(FPayload& Payload, ParameterTypes... Arguments)
78 {
79 return (*FunctionFrom(Payload))(std::forward<ParameterTypes>(Arguments)...);
80 }
81
82 // Copies the payload.
83 static void Copy(FPayload& Dst, const FPayload& Src)
84 {
85 if constexpr (bCanUseInline)
86 {
87 new(Dst.Inline) T(*FunctionFrom(Src));
88 }
89 else
90 {
91 Dst.External = new T(*FunctionFrom(Src));
92 }
93 }
94
95 // Moves the payload.
96 static void Move(FPayload& Dst, FPayload& Src)
97 {
98 if constexpr (bCanUseInline)
99 {
100 new(Dst.Inline) T(std::move(*FunctionFrom(Src)));
101 }
102 else
103 {
104 Dst.External = Src.External;
105 }
106 }
107
108 // Destructs the payload.
109 static void Destruct(FPayload& Payload)
110 {
111 if constexpr (bCanUseInline)
112 {
113 FunctionFrom(Payload)->~T();
114 }
115 else
116 {
117 delete FunctionFrom(Payload);
118 }
119 }
120
121 // The methods to operate on a payload for a functor of type T.
122 static constexpr FPayloadMethods PayloadMethods { &Call, &Copy, &Move, &Destruct };
123 };
124public:
125 // Constructor.
126 // The TTask is constructed in a non-set state.
127 TTask() = default;
128
129 // Destructor.
131 {
132 Reset();
133 }
134
135 // Copy constructor
137 {
138 if (Other.IsSet())
139 {
140 PayloadMethods = Other.PayloadMethods;
141 PayloadMethods->Copy(Payload, Other.Payload);
142 }
143 }
144
145 // Move constructor
147 {
148 if (Other.IsSet())
149 {
150 PayloadMethods = Other.PayloadMethods;
151 PayloadMethods->Move(Payload, Other.Payload);
152 Other.PayloadMethods = nullptr;
153 }
154 }
155
156 // Constructor from functor.
157 template
158 <
159 typename FunctorType,
160 typename = std::enable_if_t
161 <
162 // Use the explicit TTask copy / move constructors instead of this constructor
163 !std::is_same_v<std::decay_t<FunctorType>, TTask> &&
164 // The templated argument must be a functor with the correct signature
165 std::is_invocable_r_v<ReturnType, std::decay_t<FunctorType>, ParameterTypes...>
166 >
167 >
168 TTask(FunctorType&& Other)
169 {
170 using Decayed = std::decay_t<FunctorType>;
171 using Traits = TTraits<Decayed>;
172 PayloadMethods = &Traits::PayloadMethods;
173 if (Traits::bCanUseInline)
174 {
175 new(Payload.Inline) Decayed(std::forward<FunctorType>(Other));
176 }
177 else
178 {
179 Payload.External = new Decayed(std::forward<FunctorType>(Other));
180 }
181 }
182
183 // Copy assignment operator
184 TTask& operator = (const TTask& Other)
185 {
186 if (&Other != this)
187 {
188 Reset();
189 if (Other.IsSet())
190 {
191 PayloadMethods = Other.PayloadMethods;
192 PayloadMethods->Copy(Payload, Other.Payload);
193 }
194 }
195 return *this;
196 }
197
198 // Move assignment operator
199 TTask& operator = (TTask&& Other)
200 {
201 if (&Other != this)
202 {
203 Reset();
204 if (Other.IsSet())
205 {
206 PayloadMethods = Other.PayloadMethods;
207 PayloadMethods->Move(Payload, Other.Payload);
208 Other.PayloadMethods = nullptr;
209 }
210 }
211 return *this;
212 }
213
214 // Call operator. Cannot be called from the closed.
215 template<typename... ArgumentTypes>
216 AUTORTFM_DISABLE ReturnType operator()(ArgumentTypes&&... Arguments) const
217 {
218 return PayloadMethods->Call(Payload, std::forward<ArgumentTypes>(Arguments)...);
219 }
220
221 // Reset the task to an unset state.
222 void Reset()
223 {
224 if (PayloadMethods)
225 {
226 PayloadMethods->Destruct(Payload);
227 PayloadMethods = nullptr;
228 }
229 }
230
231 // Returns true if the task holds a functor.
232 bool IsSet() const
233 {
234 return PayloadMethods != nullptr;
235 }
236
237 // Returns the address of the functor.
238 void* FunctionAddress() const
239 {
240 return reinterpret_cast<void*>(PayloadMethods->Call);
241 }
242
243private:
244 // mutable as the functor might be mutable.
245 alignas(InlineDataAlignment) mutable FPayload Payload;
246 FPayloadMethods const* PayloadMethods = nullptr;
247};
248
249// Tasks are designed to be compact.
250static_assert(sizeof(TTask<void()>) <= 24);
251
252} // namespace AutoRTFM
OODEFFUNC typedef void(OODLE_CALLBACK t_fp_OodleCore_Plugin_Free)(void *ptr)
#define AUTORTFM_DISABLE
Definition AutoRTFMDefines.h:116
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
void Move(T &A, typename TMoveSupportTraits< T >::Copy B)
Definition UnrealTemplate.h:24
bool IsSet() const
Definition AutoRTFMTask.h:232
void Reset()
Definition AutoRTFMTask.h:222
TTask(TTask &&Other)
Definition AutoRTFMTask.h:146
TTask(const TTask &Other)
Definition AutoRTFMTask.h:136
~TTask()
Definition AutoRTFMTask.h:130
AUTORTFM_DISABLE ReturnType operator()(ArgumentTypes &&... Arguments) const
Definition AutoRTFMTask.h:216
TTask(FunctorType &&Other)
Definition AutoRTFMTask.h:168
void * FunctionAddress() const
Definition AutoRTFMTask.h:238
Definition AutoRTFMTask.h:24
Definition API.cpp:57
void Destruct(void *Dest)
Definition Class.h:1265