UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
IntervalTree.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 "BitStack.h"
9#include "Stack.h"
10#include "Utils.h"
11
12namespace AutoRTFM
13{
14
15struct FIntervalTree final
16{
17 FIntervalTree() = default;
18
19 FIntervalTree(const FIntervalTree&) = delete;
20 FIntervalTree& operator=(const FIntervalTree&) = delete;
21
22 UE_AUTORTFM_FORCENOINLINE bool Insert(const void* const Address, const size_t Size)
23 {
24 FRange NewRange(Address, Size);
25 return Insert(std::move(NewRange));
26 }
27
28 UE_AUTORTFM_FORCENOINLINE bool Contains(const void* const Address, const size_t Size) const
29 {
30 const FRange NewRange(Address, Size);
31
33 {
34 return false;
35 }
36
38
39 do
40 {
41 const FRange Range = NodeRanges[Current];
42
43 // This check does not need to prove that NewRange is entirely
44 // enclosed within Range, because if any byte of NewRange was in the
45 // original Range then it **must** already have been new memory.
46 if ((NewRange.Start < Range.End) && (Range.Start < NewRange.End))
47 {
48 return true;
49 }
50
54
55 return false;
56 }
57
58 bool IsEmpty() const
59 {
61 }
62
63 void Reset()
64 {
66 NodeRanges.Reset();
67 NodeLefts.Reset();
68 NodeRights.Reset();
69 NodeParents.Reset();
70 NodeColors.Reset();
71 }
72
73 void Merge(const FIntervalTree& Other)
74 {
75 if (Other.IsEmpty())
76 {
77 return;
78 }
79
81
82 ToProcess.Push(Other.Root);
83
84 do
85 {
87 ToProcess.Pop();
88
89 FRange Range = Other.NodeRanges[Current];
90
91 Insert(std::move(Range));
92
93 const FIntervalTreeNodeIndex Left = Other.NodeLefts[Current];
94 const FIntervalTreeNodeIndex Right = Other.NodeRights[Current];
95
97 {
98 ToProcess.Push(Left);
99 }
100
102 {
103 ToProcess.Push(Right);
104 }
105 } while (!ToProcess.IsEmpty());
106 }
107
108 // Calls Callback with each interval in the tree, in order of address.
109 // Callback must have the signature: Callback(uintptr_t Start, uintptr_t End)
110 template<typename CALLBACK>
111 void ForEach(CALLBACK&& Callback) const
112 {
114 {
115 ForEach(Root, Callback);
116 }
117 }
118
119private:
120 static constexpr size_t InlineArraySize = 8;
123
124 struct FRange final
125 {
126 FRange(const void* const Address, const size_t Size) :
128
131 };
132
134
136
137 enum EColor : bool
138 {
139 Red = false,
140 Black = true
141 };
142
149
150 static constexpr bool bExtraDebugging = false;
151
152 template<typename CALLBACK>
153 void ForEach(FIntervalTreeNodeIndex Index, CALLBACK&& Callback) const
154 {
156 {
157 ForEach(Left, Callback);
158 }
159 Callback(NodeRanges[Index].Start, NodeRanges[Index].End);
161 {
162 ForEach(Right, Callback);
163 }
164 }
165
167 {
169 NodeRanges.Push(NewRange);
173 NodeColors.Push(EColor::Black);
174 return Index;
175 }
176
178 {
180 NodeRanges.Push(NewRange);
183 NodeParents.Push(Parent);
184 NodeColors.Push(EColor::Red);
185 return Index;
186 }
187
189 {
191 {
192 AUTORTFM_ASSERT(NodeRanges.IsEmpty());
193 Root = AddNode(std::move(NewRange));
194 return true;
195 }
196
198
199 for(;;)
200 {
201 const FRange Range = NodeRanges[Current];
202
203 if (AUTORTFM_UNLIKELY((NewRange.Start < Range.End) && (Range.Start < NewRange.End)))
204 {
205 return false;
206 }
207
208 if (NewRange.Start < Range.Start)
209 {
210 if (AUTORTFM_UNLIKELY(NewRange.End == Range.Start))
211 {
212 AUTORTFM_ASSERT(NewRange.Start < Range.Start);
213
214 // We can just modify the existing node in place.
215 NodeRanges[Current].Start = NewRange.Start;
216 return true;
217 }
219 {
220 const FIntervalTreeNodeIndex Index = AddNode(std::move(NewRange), Current);
222 Current = Index;
223 break;
224 }
225
227 }
228 else
229 {
230 if (AUTORTFM_UNLIKELY(NewRange.Start == Range.End))
231 {
232 AUTORTFM_ASSERT(NewRange.End > Range.End);
233
234 // We can just modify the existing node in place.
235 NodeRanges[Current].End = NewRange.End;
236 return true;
237 }
239 {
240 const FIntervalTreeNodeIndex Index = AddNode(std::move(NewRange), Current);
242 Current = Index;
243 break;
244 }
245
247 }
248
250 }
251
253 {
254 return (IntervalTreeNodeIndexNone == Index) || (EColor::Black == NodeColors[Index]);
255 };
256
257 for(;;)
258 {
260
262
263 // The root will always have a black parent, so this check covers both.
264 if (Parent == Root)
265 {
266 NodeColors[Parent] = EColor::Black;
267 break;
268 }
269 else if (IsBlack(Parent))
270 {
271 break;
272 }
273
275
277
278 const bool bParentIsLeft = NodeLefts[GrandParent] == Parent;
279
280 // The uncle is the other node of our parent.
282
284
285 if (!IsBlack(Uncle))
286 {
288 NodeColors[Parent] = EColor::Black;
289 NodeColors[Uncle] = EColor::Black;
290
291 if (GrandParent == Root)
292 {
293 break;
294 }
295 else
296 {
297 NodeColors[GrandParent] = EColor::Red;
298 }
299
301 continue;
302 }
303
304 // Our uncle is black, so we need to swizzle around.
305 const bool bCurrentIsLeft = NodeLefts[Parent] == Current;
306
307 if (bParentIsLeft)
308 {
309 if (!bCurrentIsLeft)
310 {
312
314 {
316 }
317
322 std::swap(Parent, Current);
323 }
324
327
329 {
331 }
332
335
339 }
340 else
341 {
342 if (bCurrentIsLeft)
343 {
345
347 {
349 }
350
355 std::swap(Parent, Current);
356 }
357
360
362 {
364 }
365
368
372 }
373
375 {
376 Root = Parent;
377 }
378 else
379 {
381
383 {
385 }
386 else
387 {
389 }
390 }
391
392 break;
393 }
394
396
397 return true;
398 }
399
401 {
402 if constexpr (bExtraDebugging)
403 {
405 {
407 }
408 }
409 }
410
412 {
413 // We need to use recursion to check because we cannot have any
414 // allocations within the checker itself!
415 if constexpr (bExtraDebugging)
416 {
419
423
425 {
427 }
428 else
429 {
432 }
433
436
438 {
440 }
441
443 {
445 }
446 }
447 }
448};
449
450} // namespace AutoRTFM
451
452#endif // (defined(__AUTORTFM) && __AUTORTFM)
EForEachResult ForEach(T &Array, const PREDICATE_CLASS &Predicate)
Definition AISense_Sight.cpp:60
#define UE_AUTORTFM_FORCENOINLINE
Definition AutoRTFMDefines.h:173
#define UE_AUTORTFM_FORCEINLINE
Definition AutoRTFMDefines.h:171
#define UE_AUTORTFM_ASSUME(x)
Definition AutoRTFMDefines.h:174
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
uint32 Size
Definition VulkanMemory.cpp:4034
Definition API.cpp:57
void Insert(ResidencySet &Set, FD3D12ResidencyHandle &Object)
Definition D3D12Residency.h:164
@ Contains
Definition AutomationTest.h:160
@ Range
Definition EnvQueryTypes.h:81
@ Start
Definition GeoEnum.h:100
U16 Index
Definition radfft.cpp:71