UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
TaskArray.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#if (defined(__AUTORTFM) && __AUTORTFM)
6
7#include "HashMap.h"
8#include "Pool.h"
9#include "Stack.h"
10#include "Utils.h"
11
12#include <cstddef>
13
14namespace AutoRTFM
15{
16
17// A sequential linked-list of tasks, with the ability to tag some tasks with a
18// key. Those tagged with a key can be removed from the list in LIFO order
19// (stack-like).
20// Tasks can be traversed bi-directionally.
21//
22// Template parameters:
23// Task - the task data type
24// Key - the data type used as a key for push / pop.
25// InlineTaskCount - the number of tasks that can be allocated before a performing heap allocations.
26template<typename TaskType, typename KeyType = const void*>
27class TTaskArray
28{
29 struct FEntry
30 {
31 // The task function.
32 TaskType Task;
33 // The next sequential task.
34 FEntry* Next = nullptr;
35 // The previous sequential task.
36 FEntry* Prev = nullptr;
37
38 // Constructor using copied Task
39 FEntry(const TaskType& Task) : Task{Task} {}
40 // Constructor using moved Task
41 FEntry(TaskType&& Task) : Task{std::move(Task)} {}
42
43 // Unlinks this entry from the doubly-linked list, updating the provided
44 // head and tail pointers as necessary.
45 void Unlink(FEntry*& ListHead, FEntry*& ListTail)
46 {
47 if (ListHead == this) { ListHead = Next; }
48 if (ListTail == this) { ListTail = Prev; }
49 if (Next) { Next->Prev = Prev; }
50 if (Prev) { Prev->Next = Next; }
51 Next = nullptr;
52 Prev = nullptr;
53 }
54
55 // Links this entry to the doubly-linked list's tail pointer.
56 // This entry must be unlinked before calling.
57 void Link(FEntry*& ListHead, FEntry*& ListTail)
58 {
59 AUTORTFM_ASSERT(Next == nullptr && Prev == nullptr);
60 if (!ListHead)
61 {
62 ListHead = this;
63 }
64 Prev = ListTail;
65 if (Prev)
66 {
67 Prev->Next = this;
68 }
69 ListTail = this;
70 }
71 };
72public:
73 // The shared pool type for task arrays.
75
76 // Constructor.
77 // TaskEntryPool is used to allocate new task entries and can be shared
78 // between task arrays.
80 {}
81
82 // Destructor. Returns all allocated tasks to the pool.
84 {
85 Reset();
86 }
87
88 // Clears the array and returns all allocated tasks to the pool.
89 void Reset()
90 {
91 while (FEntry* Entry = Head)
92 {
93 Head = Head->Next;
94 EntryPool.Return(Entry);
95 }
96 Tail = nullptr;
97 Keyed.Empty();
98 Count = 0;
99 }
100
101 // Adds the unkeyed task to the end of the array.
102 template<typename TaskParamType>
103 void Add(TaskParamType&& Task)
104 {
105 FEntry* Entry = EntryPool.Take(std::forward<TaskParamType>(Task));
106 Entry->Link(Head, Tail);
107 Count++;
108 }
109
110 // Adds the keyed task to the end of the array.
111 template<typename TaskParamType>
112 void AddKeyed(KeyType Key, TaskParamType&& Task)
113 {
114 Add(std::forward<TaskParamType>(Task));
115 Keyed.FindOrAdd(Key).Push(Tail);
116 }
117
118 // Moves all the tasks from OtherArray to the end of this array, clearing
119 // OtherArray.
121 {
122 if (Head)
123 {
124 // This array has tasks in the list.
125 // Link the two task linked lists together.
126 Tail->Next = OtherArray.Head;
127 if (OtherArray.Head)
128 {
129 OtherArray.Head->Prev = Tail;
130 Tail = OtherArray.Tail;
131 }
132 }
133 else
134 {
135 // This array holds no tasks, so replace this list with OtherArray's.
136 Head = OtherArray.Head;
137 Tail = OtherArray.Tail;
138 }
139
140 // Append the keyed entries of OtherArray to this.
141 for (auto& Iterator : OtherArray.Keyed)
142 {
143 KeyType Key = Iterator.Key;
144 TEntryStack& EntryStack = Iterator.Value;
145 Keyed.FindOrAdd(Key).PushAll(std::move(EntryStack));
146 }
147
148 // Add in OtherArray's count.
149 Count += OtherArray.Count;
150
151 // Everything stolen from OtherArray. Reset it.
152 OtherArray.Head = nullptr;
153 OtherArray.Tail = nullptr;
154 OtherArray.Keyed.Reset();
155 OtherArray.Count = 0;
156 }
157
158 // Removes the last added task with the given key.
159 // Returns true if the task with the given key was removed, or false if
160 // there are no remaining tasks with the given key.
161 bool DeleteKey(KeyType Key)
162 {
163 if (TEntryStack* EntryStack = Keyed.Find(Key); EntryStack)
164 {
165 Release(EntryStack->Back());
166 EntryStack->Pop();
167 if (EntryStack->IsEmpty())
168 {
169 Keyed.Remove(Key);
170 }
171 return true;
172 }
173
174 return false;
175 }
176
177 // Removes all the tasks with the given key.
178 // Returns true if a task with the given key was removed, or false if
179 // there are no remaining tasks with the given key.
180 bool DeleteAllMatchingKeys(KeyType Key)
181 {
182 if (TEntryStack* EntryStack = Keyed.Find(Key); EntryStack)
183 {
184 while (!EntryStack->IsEmpty())
185 {
186 Release(EntryStack->Back());
187 EntryStack->Pop();
188 }
189 Keyed.Remove(Key);
190 return true;
191 }
192
193 return false;
194 }
195
196 // Traverses the tasks from least recently added to most recently added,
197 // calling Callback with each task, and removing each from the array.
198 // Callback is a function-like type with the signature: void(TASK_TYPE&)
199 template<typename CallbackType>
200 void RemoveEachForward(CallbackType&& Callback)
201 {
202 while (FEntry* Entry = Head)
203 {
204 Callback(Entry->Task);
205 Head = Entry->Next;
206 EntryPool.Return(Entry);
207 }
208 Head = nullptr;
209 Tail = nullptr;
210 Keyed.Empty();
211 Count = 0;
212 }
213
214 // Traverses the tasks from most recently added to least recently added,
215 // calling Callback with each task, and removing each from the array.
216 // Callback is a function-like type with the signature: void(TASK_TYPE&)
217 template<typename CallbackType>
218 void RemoveEachBackward(CallbackType&& Callback)
219 {
220 while (FEntry* Entry = Tail)
221 {
222 Callback(Entry->Task);
223 Tail = Entry->Prev;
224 EntryPool.Return(Entry);
225 }
226 Head = nullptr;
227 Keyed.Empty();
228 Count = 0;
229 }
230
231 // Returns the total number of tasks held by the array.
232 size_t Num() const
233 {
234 return Count;
235 }
236
237 // Returns true if there are no tasks held by the array.
238 bool IsEmpty() const
239 {
240 return Count == 0;
241 }
242
243private:
244 // An stack of pointers to entries in the linked list.
246
247 // Unlinks Entry and releases it back to the pool.
248 // Also decrements the count.
249 void Release(FEntry* Entry)
250 {
251 Entry->Unlink(Head, Tail);
252 EntryPool.Return(Entry);
253 Count--;
254 }
255
256 // The entry pool. Holds the underlying allocator.
258
259 // The doubly-linked list of tasks held by this array.
260 FEntry* Head = nullptr;
261 FEntry* Tail = nullptr;
262
263 // A map of keyed tasks keys to their ordered task entries in the linked list.
265
266 // Total number of tasks held by this array.
267 size_t Count = 0;
268};
269
270} // namespace AutoRTFM
271
272#endif // (defined(__AUTORTFM) && __AUTORTFM)
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
@ Num
Definition MetalRHIPrivate.h:234
Definition API.cpp:57