UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
LruCache.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
6#include "Containers/Set.h"
8
9
15template<typename KeyType>
17{
18 [[nodiscard]] static UE_FORCEINLINE_HINT bool Matches(KeyType A, KeyType B)
19 {
20 return (A == B);
21 }
22
25 {
26 return GetTypeHash(Key);
27 }
28};
29
30
38template<typename KeyType, typename ValueType, typename KeyComp = DefaultKeyComparer<KeyType> >
40{
42 struct FCacheEntry
43 {
45 KeyType Key;
46
48 FCacheEntry* LessRecent;
49
51 FCacheEntry* MoreRecent;
52
54 ValueType Value;
55
62 [[nodiscard]] FCacheEntry(const KeyType& InKey, const ValueType& InValue)
63 : Key(InKey)
64 , LessRecent(nullptr)
65 , MoreRecent(nullptr)
66 , Value(InValue)
67 {
68 }
69
75 [[nodiscard]] FCacheEntry(const KeyType& InKey)
76 : Key(InKey)
77 , LessRecent(nullptr)
78 , MoreRecent(nullptr)
79 {
80 }
81
82
84 inline void LinkBefore(FCacheEntry* Other)
85 {
86 LessRecent = Other;
87
88 if (Other != nullptr)
89 {
90 Other->MoreRecent = this;
91 }
92 }
93
95 inline void Unlink()
96 {
97 if (LessRecent != nullptr)
98 {
99 LessRecent->MoreRecent = MoreRecent;
100 }
101
102 if (MoreRecent != nullptr)
103 {
104 MoreRecent->LessRecent = LessRecent;
105 }
106
107 LessRecent = nullptr;
108 MoreRecent = nullptr;
109 }
110 };
111
113 struct FKeyFuncs : public BaseKeyFuncs<FCacheEntry*, KeyType>
114 {
115 [[nodiscard]] UE_FORCEINLINE_HINT static const KeyType& GetSetKey(const FCacheEntry* Entry)
116 {
117 return Entry->Key;
118 }
119
120 [[nodiscard]] UE_FORCEINLINE_HINT static bool Matches(KeyType A, KeyType B)
121 {
122 return KeyComp::Matches(A, B);
123 }
124
125 [[nodiscard]] UE_FORCEINLINE_HINT static uint32 GetKeyHash(KeyType Key)
126 {
127 return KeyComp::GetKeyHash(Key);
128 }
129 };
130
131public:
132
135 : LeastRecent(nullptr)
136 , MostRecent(nullptr)
137 , MaxNumElements(0)
138 {
139 }
140
147 : LeastRecent(nullptr)
148 , MostRecent(nullptr)
149 , MaxNumElements(InMaxNumElements)
150 {
152 }
153
156 {
157 Empty();
158 }
159
160public:
161
173 void Add(const KeyType& Key, const ValueType& Value)
174 {
175 check(MaxNumElements != 0 && "Cannot add values to zero size TLruCache");
176
177 FCacheEntry** EntryPtr = LookupSet.Find(Key);
178
179 if (EntryPtr != nullptr)
180 {
181 // update existing entry
182 FCacheEntry* Entry = *EntryPtr;
183 checkSlow(Entry->Key == Key);
184
185 Entry->Value = Value;
186 MarkAsRecent(*Entry);
187 }
188 else
189 {
190 // add new entry
191 if (LookupSet.Num() == MaxNumElements)
192 {
193 Remove(LeastRecent);
194 }
195
196 FCacheEntry* NewEntry = new FCacheEntry(Key, Value);
197 NewEntry->LinkBefore(MostRecent);
198 MostRecent = NewEntry;
199
200 if (LeastRecent == nullptr)
201 {
202 LeastRecent = NewEntry;
203 }
204
205 LookupSet.Add(NewEntry);
206 }
207 }
208
220 ValueType& AddUninitialized_GetRef(const KeyType& Key)
221 {
222 check(MaxNumElements != 0 && "Cannot add values to zero size TLruCache");
223
224 FCacheEntry** EntryPtr = LookupSet.Find(Key);
225
226 if (EntryPtr != nullptr)
227 {
228 // update existing entry
229 FCacheEntry* Entry = *EntryPtr;
230 checkSlow(Entry->Key == Key);
231
232 MarkAsRecent(*Entry);
233 return Entry->Value;
234 }
235 else
236 {
237 // add new entry
238 if (LookupSet.Num() == MaxNumElements)
239 {
240 Remove(LeastRecent);
241 }
242
243 FCacheEntry* NewEntry = new FCacheEntry(Key);
244 NewEntry->LinkBefore(MostRecent);
245 MostRecent = NewEntry;
246
247 if (LeastRecent == nullptr)
248 {
249 LeastRecent = NewEntry;
250 }
251
252 LookupSet.Add(NewEntry);
253 return NewEntry->Value;
254 }
255 }
256
257
258
266 [[nodiscard]] UE_FORCEINLINE_HINT bool Contains(const KeyType& Key) const
267 {
268 return LookupSet.Contains(Key);
269 }
270
278 template<typename Predicate>
279 [[nodiscard]] inline bool ContainsByPredicate(Predicate Pred) const
280 {
281 for (const FCacheEntry* Entry : LookupSet)
282 {
283 if (Pred(Entry->Key, Entry->Value))
284 {
285 return true;
286 }
287 }
288
289 return false;
290 }
291
299 {
300 for (FCacheEntry* Entry : LookupSet)
301 {
302 delete Entry;
303 }
304
305 MaxNumElements = InMaxNumElements;
306 LookupSet.Empty(FMath::Max(MaxNumElements, 0));
307
308 MostRecent = nullptr;
309 LeastRecent = nullptr;
310 }
311
319 template<typename Predicate>
321 {
322 TArray<ValueType> Result;
323
324 for (const FCacheEntry* Entry : LookupSet)
325 {
326 if (Pred(Entry->Key, Entry->Value))
327 {
328 Result.Add(Entry->Value);
329 }
330 }
331
332 return Result;
333 }
334
342 [[nodiscard]] inline const ValueType* Find(const KeyType& Key) const
343 {
344 FCacheEntry*const * EntryPtr = LookupSet.Find(Key);
345
346 if (EntryPtr != nullptr)
347 {
348 return &(*EntryPtr)->Value;
349 }
350
351 return nullptr;
352 }
353
361 [[nodiscard]] inline ValueType* Find(const KeyType& Key)
362 {
363 FCacheEntry* const* EntryPtr = LookupSet.Find(Key);
364
365 if (EntryPtr != nullptr)
366 {
367 return &(*EntryPtr)->Value;
368 }
369
370 return nullptr;
371 }
372
379 [[nodiscard]] inline const ValueType& FindChecked(const KeyType& Key) const
380 {
381 FCacheEntry*const * EntryPtr = LookupSet.Find(Key);
382
384
385 return (*EntryPtr)->Value;
386 }
387
394 [[nodiscard]] inline ValueType& FindChecked(const KeyType& Key)
395 {
396 FCacheEntry*const * EntryPtr = LookupSet.Find(Key);
397
399
400 return (*EntryPtr)->Value;
401 }
402
409 [[nodiscard]] inline ValueType FindRef(const KeyType& Key) const
410 {
411 FCacheEntry*const * EntryPtr = LookupSet.Find(Key);
412
413 if (EntryPtr != nullptr)
414 {
415 return (*EntryPtr)->Value;
416 }
417
418 return ValueType();
419 }
420
428 [[nodiscard]] ValueType* FindAndTouch(const KeyType& Key)
429 {
430 FCacheEntry** EntryPtr = LookupSet.Find(Key);
431
432 if (EntryPtr == nullptr)
433 {
434 return nullptr;
435 }
436
438
439 return &(*EntryPtr)->Value;
440 }
441
448 [[nodiscard]] ValueType& FindAndTouchChecked(const KeyType& Key)
449 {
450 FCacheEntry** EntryPtr = LookupSet.Find(Key);
451
453
455
456 return (*EntryPtr)->Value;
457 }
458
465 [[nodiscard]] ValueType FindAndTouchRef(const KeyType& Key)
466 {
467 FCacheEntry** EntryPtr = LookupSet.Find(Key);
468
469 if (EntryPtr == nullptr)
470 {
471 return ValueType();
472 }
473
475
476 return (*EntryPtr)->Value;
477 }
478
486 template<typename Predicate>
487 [[nodiscard]] const ValueType* FindByPredicate(Predicate Pred) const
488 {
489 for (const FCacheEntry* Entry : LookupSet)
490 {
491 if (Pred(Entry->Key, Entry->Value))
492 {
493 return &Entry->Value;
494 }
495 }
496
497 return nullptr;
498 }
499
507 {
508 for (const FCacheEntry* Entry : LookupSet)
509 {
510 OutKeys.Add(Entry->Key);
511 }
512 }
513
521 {
522 return MaxNumElements;
523 }
524
531 [[nodiscard]] bool IsEmpty() const
532 {
533 return LookupSet.IsEmpty();
534 }
535
543 {
544 return LookupSet.Num();
545 }
546
553 void Remove(const KeyType& Key)
554 {
555 FCacheEntry** EntryPtr = LookupSet.Find(Key);
556
557 if (EntryPtr != nullptr)
558 {
560 }
561 }
562
570 template<typename Predicate>
572 {
573 int32 NumRemoved = 0;
574
575 for (auto It = LookupSet.CreateIterator(); It; ++It)
576 {
577 FCacheEntry* Entry = *It;
578 if (Pred(Entry->Key, Entry->Value))
579 {
580 if (Entry == LeastRecent)
581 {
582 LeastRecent = Entry->MoreRecent;
583 }
584
585 if (Entry == MostRecent)
586 {
587 MostRecent = Entry->LessRecent;
588 }
589
590 It.RemoveCurrent(); // remove before delete so hashkey doesn't change
591
592 Entry->Unlink();
593 delete Entry;
594
595 ++NumRemoved;
596 }
597 }
598
599 return NumRemoved;
600 }
601
607 inline ValueType RemoveLeastRecent()
608 {
609 check(LeastRecent);
610 ValueType LeastRecentElement = MoveTemp(LeastRecent->Value);
611 Remove(LeastRecent);
612 return LeastRecentElement;
613 }
614
620 [[nodiscard]] inline KeyType GetLeastRecentKey() const
621 {
622 check(LeastRecent);
623 return LeastRecent->Key;
624 }
625
626public:
627
633 template<bool Const>
635 {
636 public:
637
639 : CurrentEntry(nullptr)
640 {
641 }
642
644 : CurrentEntry(Cache.MostRecent)
645 {
646 }
647
648 public:
649
651 {
652 Increment();
653 return *this;
654 }
655
657 {
658 return CurrentEntry == Rhs.CurrentEntry;
659 }
660
662 {
663 return CurrentEntry != Rhs.CurrentEntry;
664 }
665
666 [[nodiscard]] ValueType& operator->() const
667 {
668 check(CurrentEntry != nullptr);
669 return CurrentEntry->Value;
670 }
671
672 [[nodiscard]] ValueType& operator*() const
673 {
674 check(CurrentEntry != nullptr);
675 return CurrentEntry->Value;
676 }
677
678 [[nodiscard]] UE_FORCEINLINE_HINT explicit operator bool() const
679 {
680 return (CurrentEntry != nullptr);
681 }
682
684 {
685 return !(bool)*this;
686 }
687
688 public:
689
690 [[nodiscard]] inline KeyType& Key() const
691 {
692 check(CurrentEntry != nullptr);
693 return CurrentEntry->Key;
694 }
695
696 [[nodiscard]] inline ValueType& Value() const
697 {
698 check(CurrentEntry != nullptr);
699 return CurrentEntry->Value;
700 }
701
702 protected:
703
704 [[nodiscard]] FCacheEntry* GetCurrentEntry()
705 {
706 return CurrentEntry;
707 }
708
710 {
711 check(CurrentEntry != nullptr);
712 CurrentEntry = CurrentEntry->LessRecent;
713 }
714
715 private:
716
717 FCacheEntry* CurrentEntry;
718 };
719
720
725 : public TBaseIterator<true>
726 {
727 public:
728
733
735 : TBaseIterator<true>(Cache)
736 {
737 }
738 };
739
740
745 : public TBaseIterator<false>
746 {
747 public:
748
749 [[nodiscard]] inline TIterator()
751 , Cache(nullptr)
752 {
753 }
754
757 , Cache(&InCache)
758 {
759 }
760
763 {
764 check(Cache != nullptr);
765
766 FCacheEntry* MoreRecentEntry = this->GetCurrentEntry();
767 this->Increment();
768 Cache->Remove(MoreRecentEntry);
769 }
770
771 private:
772
773 TLruCache* Cache;
774 };
775
776protected:
777
783 inline void MarkAsRecent(FCacheEntry& Entry)
784 {
785 check(LeastRecent != nullptr);
786 check(MostRecent != nullptr);
787
788 // if entry is least recent and not the only item in the list, make it not least recent
789 if ((&Entry == LeastRecent) && (LeastRecent->MoreRecent != nullptr))
790 {
791 LeastRecent = LeastRecent->MoreRecent;
792 }
793
794 // relink if not already the most recent item
795 if (&Entry != MostRecent)
796 {
797 Entry.Unlink();
798 Entry.LinkBefore(MostRecent);
799 MostRecent = &Entry;
800 }
801 }
802
808 inline void Remove(FCacheEntry* Entry)
809 {
810 if (Entry == nullptr)
811 {
812 return;
813 }
814
815 LookupSet.Remove(Entry->Key);
816
817 if (Entry == LeastRecent)
818 {
819 LeastRecent = Entry->MoreRecent;
820 }
821
822 if (Entry == MostRecent)
823 {
824 MostRecent = Entry->LessRecent;
825 }
826
827 Entry->Unlink();
828 delete Entry;
829 }
830
831public:
832
833 [[nodiscard]] TIterator begin() { return TIterator(*this); }
834 [[nodiscard]] TConstIterator begin() const { return TConstIterator(*this); }
835 [[nodiscard]] TIterator end() { return TIterator(); }
836 [[nodiscard]] TConstIterator end() const { return TConstIterator(); }
837
838private:
839
842
844 FCacheEntry* LeastRecent;
845
847 FCacheEntry* MostRecent;
848
850 int32 MaxNumElements;
851};
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define check(expr)
Definition AssertionMacros.h:314
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
#define UE_FORCEINLINE_HINT
Definition Platform.h:723
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
return true
Definition ExternalRpcRegistry.cpp:601
const bool
Definition NetworkReplayStreaming.h:178
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Array.h:670
Definition LruCache.h:635
void Increment()
Definition LruCache.h:709
UE_FORCEINLINE_HINT TBaseIterator()
Definition LruCache.h:638
UE_FORCEINLINE_HINT bool operator==(const TBaseIterator &Rhs) const
Definition LruCache.h:656
ValueType & Value() const
Definition LruCache.h:696
ValueType & operator*() const
Definition LruCache.h:672
UE_FORCEINLINE_HINT bool operator!=(const TBaseIterator &Rhs) const
Definition LruCache.h:661
TBaseIterator & operator++()
Definition LruCache.h:650
UE_FORCEINLINE_HINT bool operator!() const
Definition LruCache.h:683
FCacheEntry * GetCurrentEntry()
Definition LruCache.h:704
UE_FORCEINLINE_HINT TBaseIterator(const TLruCache &Cache)
Definition LruCache.h:643
KeyType & Key() const
Definition LruCache.h:690
ValueType & operator->() const
Definition LruCache.h:666
Definition LruCache.h:726
UE_FORCEINLINE_HINT TConstIterator(const TLruCache &Cache)
Definition LruCache.h:734
UE_FORCEINLINE_HINT TConstIterator()
Definition LruCache.h:729
Definition LruCache.h:746
TIterator(TLruCache &InCache)
Definition LruCache.h:755
TIterator()
Definition LruCache.h:749
void RemoveCurrentAndIncrement()
Definition LruCache.h:762
Definition LruCache.h:40
ValueType & FindAndTouchChecked(const KeyType &Key)
Definition LruCache.h:448
ValueType * Find(const KeyType &Key)
Definition LruCache.h:361
TIterator end()
Definition LruCache.h:835
UE_FORCEINLINE_HINT int32 Max() const
Definition LruCache.h:520
ValueType & FindChecked(const KeyType &Key)
Definition LruCache.h:394
const ValueType & FindChecked(const KeyType &Key) const
Definition LruCache.h:379
ValueType & AddUninitialized_GetRef(const KeyType &Key)
Definition LruCache.h:220
void Add(const KeyType &Key, const ValueType &Value)
Definition LruCache.h:173
UE_FORCEINLINE_HINT bool Contains(const KeyType &Key) const
Definition LruCache.h:266
KeyType GetLeastRecentKey() const
Definition LruCache.h:620
void Remove(FCacheEntry *Entry)
Definition LruCache.h:808
~TLruCache()
Definition LruCache.h:155
void GetKeys(TArray< KeyType > &OutKeys) const
Definition LruCache.h:506
TLruCache(int32 InMaxNumElements)
Definition LruCache.h:146
void MarkAsRecent(FCacheEntry &Entry)
Definition LruCache.h:783
void Empty(int32 InMaxNumElements=0)
Definition LruCache.h:298
const ValueType * FindByPredicate(Predicate Pred) const
Definition LruCache.h:487
int32 RemoveByPredicate(Predicate Pred)
Definition LruCache.h:571
TConstIterator end() const
Definition LruCache.h:836
TConstIterator begin() const
Definition LruCache.h:834
TLruCache()
Definition LruCache.h:134
bool ContainsByPredicate(Predicate Pred) const
Definition LruCache.h:279
ValueType FindAndTouchRef(const KeyType &Key)
Definition LruCache.h:465
ValueType * FindAndTouch(const KeyType &Key)
Definition LruCache.h:428
TArray< ValueType > FilterByPredicate(Predicate Pred) const
Definition LruCache.h:320
bool IsEmpty() const
Definition LruCache.h:531
ValueType FindRef(const KeyType &Key) const
Definition LruCache.h:409
TIterator begin()
Definition LruCache.h:833
void Remove(const KeyType &Key)
Definition LruCache.h:553
const ValueType * Find(const KeyType &Key) const
Definition LruCache.h:342
ValueType RemoveLeastRecent()
Definition LruCache.h:607
UE_FORCEINLINE_HINT int32 Num() const
Definition LruCache.h:542
@ false
Definition radaudio_common.h:23
Definition SetUtilities.h:23
KeyType KeyType
Definition SetUtilities.h:24
Definition LruCache.h:17
static UE_FORCEINLINE_HINT bool Matches(KeyType A, KeyType B)
Definition LruCache.h:18
static UE_FORCEINLINE_HINT uint32 GetKeyHash(KeyType Key)
Definition LruCache.h:24