UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
DirectedGraph.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
6
7namespace uLang
8{
9template<typename InElementType>
10struct TDiGraphTopologicalIterator_Base;
11
12template<typename InElementType>
14{
15public:
16 using NodeId = int32_t;
18
20 {
21 return _Nodes.Emplace(Item);
22 }
23
25 {
26 return _Nodes.Emplace(uLang::MoveIfPossible(Item));
27 }
28
29 bool AddDirectedEdge(const NodeId From, const NodeId To)
30 {
31 if (ULANG_ENSUREF(_Nodes.IsValidIndex(From) && _Nodes.IsValidIndex(To), "Invalid edge indices."))
32 {
33 _Nodes[From]._Successors.Add(To);
34 ++_Nodes[To]._InDegree;
35 return true;
36 }
37 return false;
38 }
39
40 bool AddDirectedEdgeUnique(const NodeId From, const NodeId To)
41 {
42 if (ULANG_ENSUREF(_Nodes.IsValidIndex(From) && _Nodes.IsValidIndex(To), "Invalid edge indices."))
43 {
46 FromSuccessors.AddUnique(To);
48 {
49 ++_Nodes[To]._InDegree;
50 return true;
51 }
52 }
53 return false;
54 }
55
57 {
58 _Nodes.Reserve(NodesSlack);
59 }
60
62 {
63 _Nodes.Empty(NodesSlack);
64 }
65
67 {
68 return _Nodes.Num();
69 }
70
72 {
73 return _Nodes[Index]._Item;
74 }
75
77 {
78 return _Nodes[Index]._Item;
79 }
80
84
86
87private:
89
90 struct SNode
91 {
92 SNode(const InElementType& Item) : _Item(Item) {}
93 SNode(InElementType&& Item) : _Item(Move(Item)) {}
94
95 InElementType _Item;
96
97 // Tracks how many incoming edges this node has
98 int32_t _InDegree = 0;
99 // Node indices for outgoing edges
101 };
102 TArray<SNode> _Nodes;
103};
104
106template<typename InElementType>
108{
110
115
116 explicit operator bool() const
117 {
118 return !_NodesToVisit.IsEmpty();
119 }
120
123 {
124 return _NodesToVisit.Pop(/*bAllowShrinking =*/false);
125 }
126
128 {
129 _NodesToVisit.Append(NodesToVisit);
130 }
131
132protected:
134 {
135 if (_NodesToVisit.Num() > 0)
136 {
137 const int32_t NodeIndex = _NodesToVisit.Pop(/*bAllowShrinking =*/false);
138
139 const typename DiGraphType::SNode& Node = Container._Nodes[NodeIndex];
140
141 for (int32_t SuccessorIndex : Node._Successors)
142 {
143 // If we've visited this Successor node for each one of it's incoming edges
144 if (++_VisitCounters[SuccessorIndex] == Container._Nodes[SuccessorIndex]._InDegree)
145 {
146 // We're ready to process it in order
147 _NodesToVisit.Push(SuccessorIndex);
148 }
149 }
150 }
151 }
152
154 {
155 return _NodesToVisit.Top();
156 }
157
159 {
160 _NodesToVisit.Empty(Container._Nodes.Num());
161 // Find all the head nodes (ones without incoming edges)
162 for (int32_t NodeIndex = 0; NodeIndex < Container._Nodes.Num(); ++NodeIndex)
163 {
164 if (Container._Nodes[NodeIndex]._InDegree == 0)
165 {
166 _NodesToVisit.Add(NodeIndex);
167 }
168 }
169
170 _VisitCounters.Reset();
171 _VisitCounters.AddDefaulted(Container._Nodes.Num());
172 }
173
174private:
176 TArray<int32_t> _VisitCounters;
177};
178
180template<typename InElementType>
182{
185
190
192 {
193 Super::Increment(_Container);
194 return *this;
195 }
196
198 {
199 return _Container[Super::CurrentNodeIndex()];
200 }
201
203 {
204 return &_Container[Super::CurrentNodeIndex()];
205 }
206
207 void Reset()
208 {
209 Super::Reset(_Container);
210 }
211
212private:
213 DiGraphType& _Container;
214};
215
217template<typename InElementType>
219{
222
227
229 {
230 Super::Increment(_Container);
231 return *this;
232 }
233
235 {
236 return _Container[Super::CurrentNodeIndex()];
237 }
238
240 {
241 return &_Container[Super::CurrentNodeIndex()];
242 }
243
244 void Reset()
245 {
246 Super::Reset(_Container);
247 }
248
249private:
250 const DiGraphType& _Container;
251};
252
253template<typename InElementType>
255{
256 const int32_t ExpectedSize = OutItems.Num() + _Nodes.Num();
257 OutItems.Reserve(ExpectedSize);
258
260 {
261 OutItems.Add(*It);
262 }
263 return OutItems.Num() == ExpectedSize;
264}
265
266template<typename InElementType>
268{
269 const int32_t ExpectedSize = OutItems.Num() + _Nodes.Num();
270 OutItems.Reserve(ExpectedSize);
271
273 {
274 OutItems.Add(&(*It));
275 }
276 return OutItems.Num() == ExpectedSize;
277}
278
279template<typename InElementType>
281{
282 const int32_t ExpectedSize = OutItems.Num() + _Nodes.Num();
283 OutItems.Reserve(ExpectedSize);
284
285 for (TDiGraphTopologicalIterator<InElementType> It(*this); It; ++It)
286 {
287 OutItems.Add(&(*It));
288 }
289 return OutItems.Num() == ExpectedSize;
290}
291
292template<typename InElementType>
294{
296 NodeVisitedMap.Reset(_Nodes.Num());
297 NodeVisitedMap.AddZeroed(_Nodes.Num());
298
299 struct SStackEntry
300 {
303 };
305
306 TArray<TArray<NodeId>> Cycles;
307
308 // Do a depth-first traversal from each node until all nodes have been visited, keeping track of
309 // the path taken and checking for cycles in it.
310 for (int32_t RootNodeIndex = 0; RootNodeIndex < _Nodes.Num(); ++RootNodeIndex)
311 {
312 if (!NodeVisitedMap[RootNodeIndex])
313 {
314 NodeVisitedMap[RootNodeIndex] = true;
315 Stack.Add(SStackEntry{RootNodeIndex,0});
316 while (Stack.Num())
317 {
318 // Pop the node from the top of the stack and check whether it has any successors
319 // left to check.
320 SStackEntry& StackTop = Stack.Top();
321 const SNode& Node = _Nodes[StackTop._NodeIndex];
322 if (StackTop._NextSuccessorIndex < Node._Successors.Num())
323 {
324 // Check the node's next successor.
325 const int32_t SuccessorNodeIndex = Node._Successors[StackTop._NextSuccessorIndex];
326 ++StackTop._NextSuccessorIndex;
327
328 // If the successor node hasn't been visited yet, push it on the stack to visit.
330 {
333 }
334 else
335 {
336 // If the successor node has already been visited, check if it's on the
337 // stack as part of the current path.
338 for (int32_t StackIndex = 0; StackIndex < Stack.Num(); ++StackIndex)
339 {
340 if (Stack[StackIndex]._NodeIndex == SuccessorNodeIndex)
341 {
342 // If the successor node was already on the stack, the path on the
343 // stack is cyclic. Extract it to the cycle list to return.
345 for (int32_t CycleStackIndex = StackIndex; CycleStackIndex < Stack.Num(); ++CycleStackIndex)
346 {
348 }
349 Cycles.Add(CycleNodeIds);
350
351 break;
352 }
353 }
354 }
355 }
356 else
357 {
358 // If all the node's successors have been visited, pop the node from the stack
359 // and continue with the new top of the stack.
360 Stack.Pop();
361 }
362 };
363 }
364 }
365
366 return Cycles;
367}
368
373template<typename InElementType>
375{
378
383
394 template<typename VisitorType>
395 bool Iterate(VisitorType Visitor)
396 {
398
399 while (_GraphIterator)
400 {
401 if (Visitor(*_GraphIterator))
402 {
404 }
405 else
406 {
407 // NOTE: This reverses the order that they were processed in before,
408 // but that's fine because they were all ready to be processed regardless
410 }
411 }
412
414 return (IsComplete());
415 }
416
417 bool IsComplete() const
418 {
419 return !(bool)_GraphIterator;
420 }
421
422 void Reset()
423 {
425 }
426
428};
429
430} // namespace uLang
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
const bool
Definition NetworkReplayStreaming.h:178
#define ULANG_ENSUREF(expr, format,...)
Definition Common.h:292
Definition Array.h:670
Definition Array.h:51
void Reset(int32_t NewSize=0)
Definition Array.h:1303
ULANG_FORCEINLINE ElementType & Top()
Definition Array.h:513
ULANG_FORCEINLINE ElementType Pop(bool bAllowShrinking=true)
Definition Array.h:476
ULANG_FORCEINLINE int32_t Add(ElementType &&Item)
Definition Array.h:1587
ULANG_FORCEINLINE int32_t Num() const
Definition Array.h:402
Definition DirectedGraph.h:14
const InElementType & operator[](NodeId Index) const
Definition DirectedGraph.h:71
NodeId AddNode(const InElementType &Item)
Definition DirectedGraph.h:19
NodeId AddNode(InElementType &&Item)
Definition DirectedGraph.h:24
bool TopologicalSort(TArray< InElementType > &OutItems) const
Definition DirectedGraph.h:254
TArray< TArray< NodeId > > FindCycles() const
Definition DirectedGraph.h:293
static constexpr NodeId InvalidNodeId
Definition DirectedGraph.h:17
void Reserve(int32_t NodesSlack, int32_t EdgesSlack=0)
Definition DirectedGraph.h:56
bool AddDirectedEdge(const NodeId From, const NodeId To)
Definition DirectedGraph.h:29
InElementType & operator[](NodeId Index)
Definition DirectedGraph.h:76
int32_t NumNodes() const
Definition DirectedGraph.h:66
bool AddDirectedEdgeUnique(const NodeId From, const NodeId To)
Definition DirectedGraph.h:40
bool TopologicalSort_Pointers(TArray< const InElementType * > &OutItems) const
Definition DirectedGraph.h:267
int32_t NodeId
Definition DirectedGraph.h:16
void Empty(int32_t NodesSlack=0, int32_t EdgesSlack=0)
Definition DirectedGraph.h:61
Definition VVMEngineEnvironment.h:23
ULANG_FORCEINLINE TRemoveReference< T >::Type && MoveIfPossible(T &&Obj)
Definition References.h:104
@ IndexNone
Definition Common.h:381
ULANG_FORCEINLINE TRemoveReference< T >::Type && Move(T &&Obj)
Definition References.h:86
U16 Index
Definition radfft.cpp:71
Definition VstNode.h:150
Definition DirectedGraph.h:219
TDiGraphConstTopologicalIterator & operator++()
Definition DirectedGraph.h:228
TDiGraphConstTopologicalIterator(const DiGraphType &InContainer)
Definition DirectedGraph.h:223
typename Super::DiGraphType DiGraphType
Definition DirectedGraph.h:221
const InElementType & operator*()
Definition DirectedGraph.h:234
void Reset()
Definition DirectedGraph.h:244
const InElementType * operator->() const
Definition DirectedGraph.h:239
Definition DirectedGraph.h:108
void Enqueue(TArray< typename DiGraphType::NodeId > &&NodesToVisit)
Definition DirectedGraph.h:127
TDiGraphTopologicalIterator_Base(const DiGraphType &InContainer)
Definition DirectedGraph.h:111
void Reset(const DiGraphType &Container)
Definition DirectedGraph.h:158
void Increment(const DiGraphType &Container)
Definition DirectedGraph.h:133
DiGraphType::NodeId CurrentNodeIndex() const
Definition DirectedGraph.h:153
DiGraphType::NodeId SkipCurrent()
Definition DirectedGraph.h:122
TDirectedGraph< InElementType > DiGraphType
Definition DirectedGraph.h:109
Definition DirectedGraph.h:182
InElementType & operator*()
Definition DirectedGraph.h:197
typename Super::DiGraphType DiGraphType
Definition DirectedGraph.h:184
TDiGraphTopologicalIterator(DiGraphType &InContainer)
Definition DirectedGraph.h:186
InElementType * operator->() const
Definition DirectedGraph.h:202
void Reset()
Definition DirectedGraph.h:207
TDiGraphTopologicalIterator & operator++()
Definition DirectedGraph.h:191
Definition DirectedGraph.h:375
bool IsComplete() const
Definition DirectedGraph.h:417
bool Iterate(VisitorType Visitor)
Definition DirectedGraph.h:395
IteratorType _GraphIterator
Definition DirectedGraph.h:427
TDiGraphVisitor(DiGraphType &DiGraph)
Definition DirectedGraph.h:379
void Reset()
Definition DirectedGraph.h:422