UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
ObservableArray.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "Concepts/Integral.h"
6#include "Containers/Array.h"
10#include "HAL/UnrealMemory.h"
12#include "Misc/MemStack.h"
13
15{
16
17template <typename InElementType>
18struct TObservableArray;
19
22{
24 Reset,
26 Add,
28 Remove,
32 Swap,
33};
34
38template<typename InElementType>
40{
41private:
43 using SizeType = typename ArrayViewType::SizeType;
44 using ElementType = typename ArrayViewType::ElementType;
46
47private:
48 static TObservableArrayChangedArgs MakeResetAction()
49 {
52 return Result;
53 }
54
56 {
58 Result.Array = InAddedItems;
59 Result.StartIndex = InNewIndex;
61 check(Result.Array.Num() > 0 && Result.StartIndex >= 0);
62 return Result;
63 }
64
66 {
68 Result.Array = InRemovedItems;
69 Result.StartIndex = InRemoveStartedIndex;
71 check(Result.Array.Num() > 0 && Result.StartIndex >= 0);
72 return Result;
73 }
74
76 {
78 Result.Array = InRemovedItems;
79 Result.StartIndex = InRemoveStartedIndex;
80 Result.MoveIndex = InPreviousMovedItemLocation;
82 // The move index can be invalid if the array is now empty.
83 check(Result.Array.Num() > 0 && (Result.MoveIndex > 0 || Result.MoveIndex == INDEX_NONE) && Result.StartIndex >= 0);
84 return Result;
85 }
86
88 {
90 Result.StartIndex = InFirstIndex;
91 Result.MoveIndex = InSecondIndex;
93 check(Result.Array.Num() == 0 && Result.MoveIndex >= 0 && Result.StartIndex >= 0 && Result.MoveIndex != Result.StartIndex);
94 return Result;
95 }
96
97public:
100 {
101 return Action;
102 }
103
112 SizeType GetActionIndex() const
113 {
114 return StartIndex;
115 }
116
138
147
149 {
153 {
154
155 }
156 SizeType FirstIndex;
157 SizeType SecondIndex;
158 };
159
164 {
165 return (Action == EObservableArrayChangedAction::Swap) ? FSwapIndex(MoveIndex, StartIndex): FSwapIndex(INDEX_NONE, INDEX_NONE);
166 }
167
170 {
171 return Array;
172 }
173
174private:
175 ArrayViewType Array;
176 SizeType StartIndex = INDEX_NONE;
177 SizeType MoveIndex = INDEX_NONE;
179};
180
181
185template <typename InElementType>
187{
188public:
196
198
199public:
200 TObservableArray() = default;
202 : Array(Ptr, Count)
203 {
204
205 }
206
207 TObservableArray(std::initializer_list<ElementType> InitList)
208 : Array(InitList)
209 {
210
211 }
212
213 template<typename InOtherAllocatorType>
215 : Array(Other)
216 {
217
218 }
219
220 template <typename InOtherAllocatorType>
226
227 // Non-copyable for now, but this could be made copyable in future if needed.
232
234 {
235 }
236
237public:
239 {
240 return ArrayChangedDelegate;
241 }
242
243public:
245 {
246 SizeType NewIndex = Array.Add(Item);
247 ArrayChangedDelegate.Broadcast(ObservableArrayChangedArgsType::MakeAddAction({ GetData() + NewIndex, 1 }, NewIndex));
248 return NewIndex;
249 }
250
252 {
253 int32 NewIndex = Array.Add(MoveTempIfPossible(Item));
254 ArrayChangedDelegate.Broadcast(ObservableArrayChangedArgsType::MakeAddAction({ GetData() + NewIndex, 1 }, NewIndex));
255 return NewIndex;
256 }
257
258 template <typename... InArgTypes>
260 {
261 SizeType NewIndex = Array.Emplace(Forward<InArgTypes>(Args)...);
262 ArrayChangedDelegate.Broadcast(ObservableArrayChangedArgsType::MakeAddAction({ GetData() + NewIndex, 1 }, NewIndex));
263 return NewIndex;
264 }
265
266 template <typename... InArgTypes>
268 {
269 Array.EmplaceAt(Index, Forward<InArgTypes>(Args)...);
270 ArrayChangedDelegate.Broadcast(ObservableArrayChangedArgsType::MakeAddAction({ GetData() + Index, 1 }, Index));
271 }
272
273 template <typename OtherElementType>
275 {
276 Append(Source.Array);
277 }
278
279 template <typename OtherElementType, typename OtherAllocatorType>
281 {
282 if (Source.Num() > 0)
283 {
284 SizeType PreviousNum = Array.Num();
285 Array.Append(Source);
286 SizeType NewNum = Array.Num();
287 ArrayChangedDelegate.Broadcast(ObservableArrayChangedArgsType::MakeAddAction({ GetData() + PreviousNum, NewNum - PreviousNum }, PreviousNum));
288 }
289 }
290
291 template <typename OtherElementType, typename OtherAllocator>
293 {
294 if (Source.Num() > 0)
295 {
296 SizeType PreviousNum = Array.Num();
297 Array.Append(MoveTempIfPossible(Source));
298 SizeType NewNum = Array.Num();
299 ArrayChangedDelegate.Broadcast(ObservableArrayChangedArgsType::MakeAddAction({ GetData() + PreviousNum, NewNum - PreviousNum }, PreviousNum));
300 }
301 }
302
304 {
305 SizeType Index = Array.Find(Item);
306 if (Index == INDEX_NONE)
307 {
308 return 0;
309 }
311 return 1;
312 }
314 inline SizeType RemoveSingle(const ElementType& Item, bool bAllowShrinking)
315 {
316 return RemoveSingle(Item, bAllowShrinking ? EAllowShrinking::Yes : EAllowShrinking::No);
317 }
318
320 {
321 SizeType Index = Array.Find(Item);
322 if (Index == INDEX_NONE)
323 {
324 return 0;
325 }
327 return 1;
328 }
329 UE_ALLOWSHRINKING_BOOL_DEPRECATED("RemoveSingleSwap")
330 inline SizeType RemoveSingleSwap(const ElementType& Item, bool bAllowShrinking)
331 {
332 return RemoveSingleSwap(Item, bAllowShrinking ? EAllowShrinking::Yes : EAllowShrinking::No);
333 }
334
336 {
337 check((Index >= 0) & (Index < Num()));
338
340
342 ArrayChangedDelegate.Broadcast(ObservableArrayChangedArgsType::MakeRemoveAction({ &RemovedElement, 1 }, Index));
343 }
344 template <UE::CIntegral CountType>
346 {
347 static_assert(!std::is_same_v<CountType, bool>, "TObservableArray::RemoveAt: unexpected bool passed as the Count argument");
348 check((NumToRemove > 0) & (Index >= 0) & (Index + NumToRemove <= Num()));
349 if (NumToRemove > 0)
350 {
351 if (NumToRemove == 1)
352 {
355 ArrayChangedDelegate.Broadcast(ObservableArrayChangedArgsType::MakeRemoveAction({ &RemovedElement, 1 }, Index));
356 }
357 else
358 {
359 // Copy the items to a temporary array to call the delegate
360 FMemMark Mark(FMemStack::Get());
363 for (SizeType RemoveIndex = 0; RemoveIndex < NumToRemove; ++RemoveIndex)
364 {
365 RemovedElements.Add(MoveTemp(Array[RemoveIndex + Index]));
366 }
367
369 ArrayChangedDelegate.Broadcast(ObservableArrayChangedArgsType::MakeRemoveAction({ RemovedElements.GetData(), NumToRemove }, Index));
370 }
371 }
372 }
374 inline void RemoveAt(SizeType Index, SizeType NumToRemove, bool bAllowShrinking)
375 {
377 }
378
380 {
381 SizeType PreviousNum = Array.Num();
382 SizeType SwapAmount = FPlatformMath::Min(1, PreviousNum - (Index + 1));
383
385
387 ArrayChangedDelegate.Broadcast(ObservableArrayChangedArgsType::MakeRemoveSwapAction({ &RemovedElement, 1 }, Index, PreviousNum - SwapAmount));
388 }
389 template <UE::CIntegral CountType>
391 {
392 static_assert(!std::is_same_v<CountType, bool>, "TObservableArray::RemoveAtSwap: unexpected bool passed as the Count argument");
393 check((NumToRemove > 0) & (Index >= 0) & (Index + NumToRemove <= Num()));
394 if (NumToRemove > 0)
395 {
396 SizeType PreviousNum = Array.Num();
397 SizeType SwapAmount = FPlatformMath::Min(NumToRemove, PreviousNum - (Index + NumToRemove));
398 if (NumToRemove == 1)
399 {
401
403 ArrayChangedDelegate.Broadcast(ObservableArrayChangedArgsType::MakeRemoveSwapAction({ &RemovedElement, 1 }, Index, PreviousNum - SwapAmount));
404 }
405 else
406 {
407 // Copy the items to a temporary array to call the delegate
408 FMemMark Mark(FMemStack::Get());
411 for (SizeType RemoveIndex = 0; RemoveIndex < NumToRemove; ++RemoveIndex)
412 {
413 RemovedElements.Add(MoveTemp(Array[RemoveIndex + Index]));
414 }
415
417 ArrayChangedDelegate.Broadcast(ObservableArrayChangedArgsType::MakeRemoveSwapAction({ RemovedElements.GetData(), NumToRemove }, Index, PreviousNum - SwapAmount));
418 }
419 }
420 }
423 {
425 }
426
428 {
431 {
433 ArrayChangedDelegate.Broadcast(ObservableArrayChangedArgsType::MakeSwapAction(FirstIndexToSwap, SecondIndexToSwap));
434 }
435 }
436
437 void Reset(SizeType NewSize = 0)
438 {
439 SizeType PreviousNum = Array.Num();
440 Array.Reset(NewSize);
441 if (PreviousNum > 0)
442 {
443 ArrayChangedDelegate.Broadcast(ObservableArrayChangedArgsType::MakeResetAction());
444 }
445 }
446
448 {
449 Array.Reserve(Number);
450 }
451
452 bool IsEmpty() const
453 {
454 return Array.IsEmpty();
455 }
456
457 int32 Num() const
458 {
459 return Array.Num();
460 }
461
463 {
464 return Array.IsValidIndex(Index);
465 }
466
468 {
469 return GetData()[Index];
470 }
471
473 {
474 return GetData()[Index];
475 }
476
478 {
479 return Array.GetData();
480 }
481
482 const ElementType* GetData() const
483 {
484 return Array.GetData();
485 }
486
487 template <typename ComparisonType>
488 bool Contains(const ComparisonType& Item) const
489 {
490 return Array.Contains(Item);
491 }
492
493 template <typename InPredicate>
498
499 SizeType Find(const ElementType& Item) const
500 {
501 return Array.Find(Item);
502 }
503
504 template <typename InPredicate>
509
510 template <typename InPredicate>
512 {
513 return Array.FindByPredicate(Pred);
514 }
515
516 template <typename InPredicate>
517 UE_DEPRECATED(5.4, "IndexByPredicate is deprecated. Use IndexOfByPredicate instead")
519 {
520 return Array.IndexOfByPredicate(Pred);
521 }
522
523 template <typename InPredicate>
525 {
526 return Array.IndexOfByPredicate(Pred);
527 }
528
529public:
530 template <typename InOtherAllocatorType>
532 {
533 return Array.operator==(OtherArray);
534 }
535
537 {
538 return Array.operator==(OtherArray.Array);
539 }
540
541 template <typename InOtherAllocatorType>
543 {
544 return Self.Array.operator==(OtherArray);
545 }
546
547public:
549 {
550 return Array.begin();
551 }
552
554 {
555 return Array.begin();
556 }
557
559 {
560 return Array.end();
561 }
562
564 {
565 return Array.end();
566 }
567
568private:
569 ArrayType Array;
570 FArrayChangedDelegate ArrayChangedDelegate;
571};
572
573 } //namespace
EAllowShrinking
Definition AllowShrinking.h:10
#define UE_ALLOWSHRINKING_BOOL_DEPRECATED(FunctionName)
Definition AllowShrinking.h:31
#define check(expr)
Definition AssertionMacros.h:314
return Self
Definition CocoaThread.cpp:337
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define UE_DEPRECATED(Version, Message)
Definition CoreMiscDefines.h:302
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTempIfPossible(T &&Obj) noexcept
Definition UnrealTemplate.h:538
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
uint8_t uint8
Definition binka_ue_file_header.h:8
Definition MemStack.h:506
InSizeType SizeType
Definition ArrayView.h:142
InElementType ElementType
Definition ArrayView.h:141
InAllocatorType AllocatorType
Definition Array.h:677
ElementType * FindByPredicate(Predicate Pred)
Definition Array.h:1471
UE_REWRITE SizeType Num() const
Definition Array.h:1144
void RemoveAt(SizeType Index, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2083
TCheckedPointerIterator< const ElementType, SizeType, false > RangedForConstIteratorType
Definition Array.h:3372
void Reset(SizeType NewSize=0)
Definition Array.h:2246
UE_NODEBUG UE_FORCEINLINE_HINT ElementType * GetData() UE_LIFETIMEBOUND
Definition Array.h:1027
InElementType ElementType
Definition Array.h:676
UE_FORCEINLINE_HINT void RemoveAtSwap(SizeType Index, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2185
UE_FORCEINLINE_HINT void SwapMemory(SizeType FirstIndexToSwap, SizeType SecondIndexToSwap)
Definition Array.h:3284
UE_NODEBUG UE_FORCEINLINE_HINT RangedForIteratorType end()
Definition Array.h:3391
bool Contains(const ComparisonType &Item) const
Definition Array.h:1518
typename InAllocatorType::SizeType SizeType
Definition Array.h:675
UE_REWRITE bool IsEmpty() const
Definition Array.h:1133
UE_FORCEINLINE_HINT SizeType Emplace(ArgsType &&... Args)
Definition Array.h:2561
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
UE_NODEBUG UE_FORCEINLINE_HINT bool IsValidIndex(SizeType Index) const
Definition Array.h:1122
void Append(const TArray< OtherElementType, OtherAllocatorType > &Source)
Definition Array.h:2412
UE_NODEBUG UE_FORCEINLINE_HINT RangedForIteratorType begin()
Definition Array.h:3389
UE_NODEBUG UE_FORCEINLINE_HINT bool Find(const ElementType &Item, SizeType &Index) const
Definition Array.h:1302
SizeType IndexOfByPredicate(Predicate Pred) const
Definition Array.h:1423
UE_FORCEINLINE_HINT void EmplaceAt(SizeType Index, ArgsType &&... Args)
Definition Array.h:2665
UE_FORCEINLINE_HINT void Reserve(SizeType Number)
Definition Array.h:3016
UE_NODEBUG UE_FORCEINLINE_HINT bool ContainsByPredicate(Predicate Pred) const
Definition Array.h:1538
TCheckedPointerIterator< ElementType, SizeType, false > RangedForIteratorType
Definition Array.h:3371
static FORCEINLINE FMemStack & Get()
Definition ThreadSingleton.h:101
Definition ObservableArray.h:15
EObservableArrayChangedAction
Definition ObservableArray.h:22
U16 Index
Definition radfft.cpp:71
SizeType PreviousMovedElmenentIndex
Definition ObservableArray.h:136
FRemoveSwapIndex(SizeType InRemoveIndex, SizeType InPreviousMovedElmenentIndex)
Definition ObservableArray.h:119
SizeType SecondIndex
Definition ObservableArray.h:157
SizeType FirstIndex
Definition ObservableArray.h:156
FSwapIndex(SizeType InFirstIndex, SizeType InSecondIndex)
Definition ObservableArray.h:150
ArrayViewType GetItems() const
Definition ObservableArray.h:169
EObservableArrayChangedAction GetAction() const
Definition ObservableArray.h:99
SizeType GetActionIndex() const
Definition ObservableArray.h:112
FSwapIndex GetSwapIndex() const
Definition ObservableArray.h:163
FRemoveSwapIndex GetRemovedSwapIndexes() const
Definition ObservableArray.h:143
Definition ObservableArray.h:187
void Swap(SizeType FirstIndexToSwap, SizeType SecondIndexToSwap)
Definition ObservableArray.h:427
bool Contains(const ComparisonType &Item) const
Definition ObservableArray.h:488
friend bool operator==(TArray< ElementType, InOtherAllocatorType > &OtherArray, const TObservableArray &Self)
Definition ObservableArray.h:542
TObservableArray & operator=(TObservableArray &&Other)=delete
bool operator==(const TObservableArray &OtherArray) const
Definition ObservableArray.h:536
bool IsEmpty() const
Definition ObservableArray.h:452
FArrayChangedDelegate & OnArrayChanged()
Definition ObservableArray.h:238
ElementType * FindByPredicate(InPredicate Pred)
Definition ObservableArray.h:505
const ElementType * GetData() const
Definition ObservableArray.h:482
ElementType & operator[](SizeType Index)
Definition ObservableArray.h:467
SizeType IndexByPredicate(InPredicate Pred) const
Definition ObservableArray.h:518
const ElementType * FindByPredicate(InPredicate Pred) const
Definition ObservableArray.h:511
typename ArrayType::SizeType SizeType
Definition ObservableArray.h:190
~TObservableArray()
Definition ObservableArray.h:233
RangedForConstIteratorType end() const
Definition ObservableArray.h:563
SizeType ContainsByPredicate(InPredicate Pred) const
Definition ObservableArray.h:494
SizeType Add(const ElementType &Item)
Definition ObservableArray.h:244
SizeType Add(ElementType &&Item)
Definition ObservableArray.h:251
void EmplaceAt(SizeType Index, InArgTypes &&... Args)
Definition ObservableArray.h:267
SizeType Emplace(InArgTypes &&... Args)
Definition ObservableArray.h:259
void Reset(SizeType NewSize=0)
Definition ObservableArray.h:437
SizeType Find(const ElementType &Item) const
Definition ObservableArray.h:499
void Append(const TObservableArray< OtherElementType > &Source)
Definition ObservableArray.h:274
SizeType RemoveSingle(const ElementType &Item, EAllowShrinking AllowShrinking=EAllowShrinking::Default)
Definition ObservableArray.h:303
RangedForConstIteratorType begin() const
Definition ObservableArray.h:553
void RemoveAt(SizeType Index, EAllowShrinking AllowShrinking=EAllowShrinking::Default)
Definition ObservableArray.h:335
SizeType RemoveSingleSwap(const ElementType &Item, EAllowShrinking AllowShrinking=EAllowShrinking::Default)
Definition ObservableArray.h:319
RangedForIteratorType begin()
Definition ObservableArray.h:548
TObservableArray(const TObservableArray &)=delete
void RemoveAtSwap(SizeType Index, EAllowShrinking AllowShrinking=EAllowShrinking::Default)
Definition ObservableArray.h:379
TArray< InElementType > ArrayType
Definition ObservableArray.h:189
typename ArrayType::ElementType ElementType
Definition ObservableArray.h:191
int32 Num() const
Definition ObservableArray.h:457
typename ArrayType::RangedForIteratorType RangedForIteratorType
Definition ObservableArray.h:193
TObservableArray(std::initializer_list< ElementType > InitList)
Definition ObservableArray.h:207
bool operator==(TArray< ElementType, InOtherAllocatorType > &OtherArray) const
Definition ObservableArray.h:531
bool IsValidIndex(SizeType Index) const
Definition ObservableArray.h:462
SizeType IndexOfByPredicate(InPredicate Pred) const
Definition ObservableArray.h:524
typename ArrayType::AllocatorType AllocatorType
Definition ObservableArray.h:192
void Reserve(SizeType Number)
Definition ObservableArray.h:447
RangedForIteratorType end()
Definition ObservableArray.h:558
const ElementType & operator[](SizeType Index) const
Definition ObservableArray.h:472
ElementType * GetData()
Definition ObservableArray.h:477
void Append(const TArray< OtherElementType, OtherAllocatorType > &Source)
Definition ObservableArray.h:280
DECLARE_MULTICAST_DELEGATE_OneParam(FArrayChangedDelegate, ObservableArrayChangedArgsType)
void RemoveAtSwap(SizeType Index, CountType NumToRemove, EAllowShrinking AllowShrinking=EAllowShrinking::Default)
Definition ObservableArray.h:390
typename ArrayType::RangedForConstIteratorType RangedForConstIteratorType
Definition ObservableArray.h:194
TObservableArray & operator=(const TObservableArray &)=delete
TObservableArray(const TArray< ElementType, InOtherAllocatorType > &Other)
Definition ObservableArray.h:214
void Append(TArray< OtherElementType, OtherAllocator > &&Source)
Definition ObservableArray.h:292
TObservableArray(const ElementType *Ptr, SizeType Count)
Definition ObservableArray.h:201
TObservableArray(TObservableArray &&Other)=delete
void RemoveAt(SizeType Index, CountType NumToRemove, EAllowShrinking AllowShrinking=EAllowShrinking::Default)
Definition ObservableArray.h:345
TObservableArray(TArray< ElementType, InOtherAllocatorType > &&Other)
Definition ObservableArray.h:221