MCRO
C++23 utilities for Unreal Engine.
Loading...
Searching...
No Matches
Range.h
Go to the documentation of this file.
1/** @noop License Comment
2 * @file
3 * @copyright
4 * This Source Code is subject to the terms of the Mozilla Public License, v2.0.
5 * If a copy of the MPL was not distributed with this file You can obtain one at
6 * https://mozilla.org/MPL/2.0/
7 *
8 * @author David Mórász
9 * @date 2025
10 */
11
12#pragma once
13
14/**
15 * @file
16 * @brief
17 * Bring modern declarative range operations like views and actions to the Unreal C++ arsenal. This header is
18 * responsible for bridging compatibility between Unreal containers and range-v3/std::ranges.
19 *
20 * The official documentation is quite barebones and doesn't go to great lengths explaining how individual features in
21 * the range-v3 library behave exactly. For a more explanatory documentation I found this website
22 * https://lukasfro.github.io/range-v3-doc/chapter_01/01_introduction.html by **PhD Lukas Fröhlich** which lists
23 * views with examples and precise descriptions. Although, as the original documentation, that is also "incomplete".
24 *
25 * Please consider the [potentials and pitfals](https://lukasfro.github.io/range-v3-doc/chapter_03/03_02_pitfalls.html)
26 * and the [tips & tricks](https://lukasfro.github.io/range-v3-doc/chapter_03/03_01_tips_tricks.html) when using
27 * range-v3 in your program.
28 *
29 * @remarks
30 * Fully supported Unreal containers:
31 * - TArray
32 * - TMap
33 * - TMultiMap
34 * - TSet
35 * - FString (`TCHAR` array)
36 * - TStringView (given char-type)
37 * - TBasicArray
38 * - TBitArray (only UE 5.5 or later)
39 * - TChunkedArray
40 * - TMRUArray
41 * - TResourceArray
42 * - TSparseArray
43 * - TStaticArray
44 * - TIndirectArray
45 * - TRingBuffer
46 * @remarks
47 * Unreal containers where some iterator features may have low-performance emulation (can be restricted with a
48 * preprocessor flag)
49 * - TDeque
50 * - TLruCache
51 * - TPagedArray
52 * - TSortedMap
53 *
54 * @warning
55 * Unsupported containers (they're not iterable or other various issues)
56 * - Most queue containers:
57 * - TQueue
58 * - TCircularQueue
59 * - TConsumeAllMpmcQueue
60 * - etc...
61 * - TCircularBuffer
62 * - TLinkedList
63 * - TDoubleLinkedList
64 * - TIntrusiveDoubleLinkedList
65 * - TDiscardableKeyValueCache
66 * - TStaticHashTable
67 * - FHashTable
68 * - TStaticBitArray
69 * - TStridedView (use `ranges::views::stride`)
70 * - TTripleBuffer
71 * @warning
72 * You may need to convert these to either a fully supported container, or write your own iterator for them. MCRO
73 * provides `Mcro::Ranges::TExtendedIterator` which can automatically make a simple bare-minimum iterator into a fully
74 * STL compliant one.
75 */
76
77#include "CoreMinimal.h"
78
79#include "Containers/BasicArray.h"
80#include "Containers/StaticArray.h"
81#include "Containers/Deque.h"
82#include "Containers/LruCache.h"
83#include "Containers/MRUArray.h"
84#include "Containers/PagedArray.h"
85#include "Containers/RingBuffer.h"
86#include "Containers/DynamicRHIResourceArray.h"
87#include "Misc/EngineVersionComparison.h"
88
90
91/** @brief Bring modern declarative range operations like views and actions to the Unreal C++ arsenal */
92
95
96// TArray (pointer)
97template <typename T, typename A> auto begin(TArray<T, A>& r) -> T* { return r.GetData(); }
98template <typename T, typename A> auto begin(TArray<T, A> const& r) -> const T* { return r.GetData(); }
99template <typename T, typename A> auto end (TArray<T, A>& r) -> T* { return r.GetData() + r.Num(); }
100template <typename T, typename A> auto end (TArray<T, A> const& r) -> const T* { return r.GetData() + r.Num(); }
101template <typename T, typename A> size_t size(TArray<T, A> const& r) { return static_cast<size_t>(r.Num()); }
102
103// TArrayView (pointer)
104template <typename T, typename A> auto begin(TArrayView<T, A>& r) -> T* { return r.GetData(); }
105template <typename T, typename A> auto begin(TArrayView<T, A> const& r) -> const T* { return r.GetData(); }
106template <typename T, typename A> auto end (TArrayView<T, A>& r) -> T* { return r.GetData() + r.Num(); }
107template <typename T, typename A> auto end (TArrayView<T, A> const& r) -> const T* { return r.GetData() + r.Num(); }
108template <typename T, typename A> size_t size(TArrayView<T, A> const& r) { return static_cast<size_t>(r.Num()); }
109
110// TStaticArray (pointer)
111template <typename T, uint32 N, uint32 A> auto begin(TStaticArray<T, N, A>& r) -> T* { return r.GetData(); }
112template <typename T, uint32 N, uint32 A> auto begin(TStaticArray<T, N, A> const& r) -> const T* { return r.GetData(); }
113template <typename T, uint32 N, uint32 A> auto end (TStaticArray<T, N, A>& r) -> T* { return r.GetData() + r.Num(); }
114template <typename T, uint32 N, uint32 A> auto end (TStaticArray<T, N, A> const& r) -> const T* { return r.GetData() + r.Num(); }
115template <typename T, uint32 N, uint32 A> size_t size(TStaticArray<T, N, A> const& r) { return static_cast<size_t>(r.Num()); }
116
117// TIndirectArray (pointer)
118template <typename T>
120
121template <typename T, typename A> auto begin(TIndirectArray<T, A>& r) -> TExtendedIndirectArrayIterator< T**> { return r.GetData(); }
122template <typename T, typename A> auto begin(TIndirectArray<T, A> const& r) -> TExtendedIndirectArrayIterator<const T**> { return r.GetData(); }
123template <typename T, typename A> auto end (TIndirectArray<T, A>& r) -> TExtendedIndirectArrayIterator< T**> { return r.GetData() + r.Num(); }
124template <typename T, typename A> auto end (TIndirectArray<T, A> const& r) -> TExtendedIndirectArrayIterator<const T**> { return r.GetData() + r.Num(); }
125template <typename T, typename A> size_t size(TIndirectArray<T, A> const& r) { return static_cast<size_t>(r.Num()); }
126
127// TSet (GetIndex-able)
128template <typename T, typename K, typename A> auto begin(TSet<T, K, A>& r) -> TIteratorExtension<TSet<T, K, A>> { return r.begin(); }
129template <typename T, typename K, typename A> auto begin(TSet<T, K, A> const& r) -> TIteratorExtension<TSet<T, K, A>> { return r.begin(); }
130template <typename T, typename K, typename A> auto end (TSet<T, K, A>& r) -> TIteratorExtension<TSet<T, K, A>> { return r.end(); }
131template <typename T, typename K, typename A> auto end (TSet<T, K, A> const& r) -> TIteratorExtension<TSet<T, K, A>> { return r.end(); }
132template <typename T, typename K, typename A> size_t size(TSet<T, K, A> const& r) { return static_cast<size_t>(r.Num()); }
133
134// TMapBase
135// TMap and variants doesn't allow zero-copy view on its pairs with a capable enough iterator, however it has the
136// internal TSet stored as a protected member Pairs, and so we can access it via exploiting the fact that TMapBase
137// friends its template specializations. So we can use a dummy TMapBase to access that internal TSet.
139
141{
142public:
143
144 template <typename K, typename V, typename A, typename F>
145 static auto GetPairs(TMapBase<K, V, A, F>& map) -> TSet<TPair<K, V>, F, A>&
146 {
147 return map.Pairs;
148 }
149
150 template <typename K, typename V, typename A, typename F>
151 static auto GetPairs(TMapBase<K, V, A, F> const& map) -> TSet<TPair<K, V>, F, A> const&
152 {
153 return map.Pairs;
154 }
155};
156
157using FMapPairsAccess = TMapBase<FMapPairsAccessTag, FMapPairsAccessTag, FMapPairsAccessTag, FMapPairsAccessTag>;
158
159// TMap (map to TSet)
160template<typename K, typename V, typename A, typename F> auto begin(TMap<K, V, A, F>& map) { return begin(FMapPairsAccess::GetPairs(map)); }
161template<typename K, typename V, typename A, typename F> auto begin(TMap<K, V, A, F> const& map) { return begin(FMapPairsAccess::GetPairs(map)); }
162template<typename K, typename V, typename A, typename F> auto end (TMap<K, V, A, F>& map) { return end (FMapPairsAccess::GetPairs(map)); }
163template<typename K, typename V, typename A, typename F> auto end (TMap<K, V, A, F> const& map) { return end (FMapPairsAccess::GetPairs(map)); }
164template<typename K, typename V, typename A, typename F> size_t size(TMap<K, V, A, F> const& map) { return static_cast<size_t>(map.Num()); }
165// TMultiMap (map to TSet)
166template<typename K, typename V, typename A, typename F> auto begin(TMultiMap<K, V, A, F>& map) { return begin(FMapPairsAccess::GetPairs(map)); }
167template<typename K, typename V, typename A, typename F> auto begin(TMultiMap<K, V, A, F> const& map) { return begin(FMapPairsAccess::GetPairs(map)); }
168template<typename K, typename V, typename A, typename F> auto end (TMultiMap<K, V, A, F>& map) { return end (FMapPairsAccess::GetPairs(map)); }
169template<typename K, typename V, typename A, typename F> auto end (TMultiMap<K, V, A, F> const& map) { return end (FMapPairsAccess::GetPairs(map)); }
170template<typename K, typename V, typename A, typename F> size_t size(TMultiMap<K, V, A, F> const& map) { return static_cast<size_t>(map.Num()); }
171
172// Strings (pointer)
173template <typename CharType> auto begin(TStringView<CharType> const& string) -> const CharType* { return string.GetData(); }
174template <typename CharType> auto end (TStringView<CharType> const& string) -> const CharType* { return string.GetData() + string.Len(); }
175template <typename CharType> size_t size(TStringView<CharType> const& string) { return static_cast<size_t>(string.Len()); }
176
177FORCEINLINE auto begin(FString& string) -> const TCHAR* { return *string; }
178FORCEINLINE auto begin(FString const& string) -> const TCHAR* { return *string; }
179FORCEINLINE auto end (FString& string) -> const TCHAR* { return *string + string.Len(); }
180FORCEINLINE auto end (FString const& string) -> const TCHAR* { return *string + string.Len(); }
181FORCEINLINE auto begin(FString&& string) -> Mcro::Range::FTempStringIterator { return {FWD(string), false}; }
182FORCEINLINE auto end (FString&& string) -> Mcro::Range::FTempStringIterator { return {FWD(string), true}; }
183FORCEINLINE size_t size(FString const& string) { return static_cast<size_t>(string.Len()); }
184
185// TBasicArray (pointer via begin/end)
186template <typename T> auto begin(TBasicArray<T>& r) -> T* { return r.begin(); }
187template <typename T> auto begin(TBasicArray<T> const& r) -> const T* { return r.begin(); }
188template <typename T> auto end (TBasicArray<T>& r) -> T* { return r.end(); }
189template <typename T> auto end (TBasicArray<T> const& r) -> const T* { return r.end(); }
190template <typename T> size_t size(TBasicArray<T> const& r) { return static_cast<size_t>(r.Num()); }
191
192#if UE_VERSION_NEWER_THAN(5, 5, -1)
193// TBitArray (GetIndex-able) (only after 5.5)
194template <typename A> auto begin(TBitArray<A>& r) -> TIteratorExtension<TBitArray<A>> { return r.begin(); }
195template <typename A> auto begin(TBitArray<A> const& r) -> TIteratorExtension<TBitArray<A>> { return r.begin(); }
196template <typename A> auto end (TBitArray<A>& r) -> TIteratorExtension<TBitArray<A>> { return r.end(); }
197template <typename A> auto end (TBitArray<A> const& r) -> TIteratorExtension<TBitArray<A>> { return r.end(); }
198template <typename A> size_t size(TBitArray<A> const& r) { return static_cast<size_t>(r.Num()); }
199#endif
200
201// TChunkedArray (GetIndex-able)
202template <typename T, uint32 C, typename A> auto begin(TChunkedArray<T, C, A>& r) -> TIteratorExtension<TChunkedArray<T, C, A>> { return r.begin(); }
203template <typename T, uint32 C, typename A> auto begin(TChunkedArray<T, C, A> const& r) -> TIteratorExtension<TChunkedArray<T, C, A>> { return r.begin(); }
204template <typename T, uint32 C, typename A> auto end (TChunkedArray<T, C, A>& r) -> TIteratorExtension<TChunkedArray<T, C, A>> { return r.end(); }
205template <typename T, uint32 C, typename A> auto end (TChunkedArray<T, C, A> const& r) -> TIteratorExtension<TChunkedArray<T, C, A>> { return r.end(); }
206template <typename T, uint32 C, typename A> size_t size(TChunkedArray<T, C, A> const& r) { return static_cast<size_t>(r.Num()); }
207
208// TDeque (warning, non-comparable)
209template <typename T, typename A> auto begin(TDeque<T, A>& r) -> TIteratorExtension<TDeque<T, A>> { return r.begin(); }
210template <typename T, typename A> auto begin(TDeque<T, A> const& r) -> TIteratorExtension<TDeque<T, A>> { return r.begin(); }
211template <typename T, typename A> auto end (TDeque<T, A>& r) -> TIteratorExtension<TDeque<T, A>> { return r.end(); }
212template <typename T, typename A> auto end (TDeque<T, A> const& r) -> TIteratorExtension<TDeque<T, A>> { return r.end(); }
213template <typename T, typename A> size_t size(TDeque<T, A> const& r) { return static_cast<size_t>(r.Num()); }
214
215// TResourceArray (pointer, TArray derivative)
216template <typename T, uint32 A> auto begin(TResourceArray<T, A>& r) -> T* { return r.GetData(); }
217template <typename T, uint32 A> auto begin(TResourceArray<T, A> const& r) -> const T* { return r.GetData(); }
218template <typename T, uint32 A> auto end (TResourceArray<T, A>& r) -> T* { return r.GetData() + r.Num(); }
219template <typename T, uint32 A> auto end (TResourceArray<T, A> const& r) -> const T* { return r.GetData() + r.Num(); }
220template <typename T, uint32 A> size_t size(TResourceArray<T, A> const& r) { return static_cast<size_t>(r.Num()); }
221
222// T[Double]LinkedList is not supported as it defines begin/end functions as friends, and so we cannot overload that
223// template <typename T> auto begin(TLinkedList<T>& r) -> TIteratorExtension<TLinkedList<T>> { return r.begin(); }
224// template <typename T> auto begin(TLinkedList<T> const& r) -> TIteratorExtension<TLinkedList<T>> { return r.begin(); }
225// template <typename T> auto end (TLinkedList<T>& r) -> TIteratorExtension<TLinkedList<T>> { return r.end(); }
226// template <typename T> auto end (TLinkedList<T> const& r) -> TIteratorExtension<TLinkedList<T>> { return r.end(); }
227// template <typename T> size_t size(TLinkedList<T> const& r) { return static_cast<size_t>(r.Num()); }
228
229// TLruCache (warning, non-comparable)
230template <typename K, typename V, typename C> auto begin(TLruCache<K, V, C>& r) -> TIteratorExtension<TLruCache<K, V, C>> { return r.begin(); }
231template <typename K, typename V, typename C> auto begin(TLruCache<K, V, C> const& r) -> TIteratorExtension<TLruCache<K, V, C>> { return r.begin(); }
232template <typename K, typename V, typename C> auto end (TLruCache<K, V, C>& r) -> TIteratorExtension<TLruCache<K, V, C>> { return r.end(); }
233template <typename K, typename V, typename C> auto end (TLruCache<K, V, C> const& r) -> TIteratorExtension<TLruCache<K, V, C>> { return r.end(); }
234template <typename K, typename V, typename C> size_t size(TLruCache<K, V, C> const& r) { return static_cast<size_t>(r.Num()); }
235
236// TMRUArray (pointer, TArray derivative)
237template <typename T, typename A> auto begin(TMRUArray<T, A>& r) -> T* { return r.GetData(); }
238template <typename T, typename A> auto begin(TMRUArray<T, A> const& r) -> const T* { return r.GetData(); }
239template <typename T, typename A> auto end (TMRUArray<T, A>& r) -> T* { return r.GetData() + r.Num(); }
240template <typename T, typename A> auto end (TMRUArray<T, A> const& r) -> const T* { return r.GetData() + r.Num(); }
241template <typename T, typename A> size_t size(TMRUArray<T, A> const& r) { return static_cast<size_t>(r.Num()); }
242
243// TPagedArray (warning, non-comparable)
244template <typename T, int32 P, typename A> auto begin(TPagedArray<T, P, A>& r) -> TIteratorExtension<TPagedArray<T, P, A>> { return r.begin(); }
245template <typename T, int32 P, typename A> auto begin(TPagedArray<T, P, A> const& r) -> TIteratorExtension<TPagedArray<T, P, A>> { return r.begin(); }
246template <typename T, int32 P, typename A> auto end (TPagedArray<T, P, A>& r) -> TIteratorExtension<TPagedArray<T, P, A>> { return r.end(); }
247template <typename T, int32 P, typename A> auto end (TPagedArray<T, P, A> const& r) -> TIteratorExtension<TPagedArray<T, P, A>> { return r.end(); }
248template <typename T, int32 P, typename A> size_t size(TPagedArray<T, P, A> const& r) { return static_cast<size_t>(r.Num()); }
249
250// TRingBuffer (GetIndex-able)
251template <typename T, typename A> auto begin(TRingBuffer<T, A>& r) -> TIteratorExtension<TRingBuffer<T, A>> { return r.begin(); }
252template <typename T, typename A> auto begin(TRingBuffer<T, A> const& r) -> TIteratorExtension<TRingBuffer<T, A>> { return r.begin(); }
253template <typename T, typename A> auto end (TRingBuffer<T, A>& r) -> TIteratorExtension<TRingBuffer<T, A>> { return r.end(); }
254template <typename T, typename A> auto end (TRingBuffer<T, A> const& r) -> TIteratorExtension<TRingBuffer<T, A>> { return r.end(); }
255template <typename T, typename A> size_t size(TRingBuffer<T, A> const& r) { return static_cast<size_t>(r.Num()); }
256
257// TSortedMap (warning, non-comparable)
258template <typename K, typename V, typename A, typename S> auto begin(TSortedMap<K, V, A, S>& r) -> TIteratorExtension<TSortedMap<K, V, A, S>> { return r.begin(); }
259template <typename K, typename V, typename A, typename S> auto begin(TSortedMap<K, V, A, S> const& r) -> TIteratorExtension<TSortedMap<K, V, A, S>> { return r.begin(); }
260template <typename K, typename V, typename A, typename S> auto end (TSortedMap<K, V, A, S>& r) -> TIteratorExtension<TSortedMap<K, V, A, S>> { return r.end(); }
261template <typename K, typename V, typename A, typename S> auto end (TSortedMap<K, V, A, S> const& r) -> TIteratorExtension<TSortedMap<K, V, A, S>> { return r.end(); }
262template <typename K, typename V, typename A, typename S> size_t size(TSortedMap<K, V, A, S> const& r) { return static_cast<size_t>(r.Num()); }
263
264// TSparseArray (GetIndex-able)
265template <typename T, typename A> auto begin(TSparseArray<T, A>& r) -> TIteratorExtension<TSparseArray<T, A>> { return r.begin(); }
266template <typename T, typename A> auto begin(TSparseArray<T, A> const& r) -> TIteratorExtension<TSparseArray<T, A>> { return r.begin(); }
267template <typename T, typename A> auto end (TSparseArray<T, A>& r) -> TIteratorExtension<TSparseArray<T, A>> { return r.end(); }
268template <typename T, typename A> auto end (TSparseArray<T, A> const& r) -> TIteratorExtension<TSparseArray<T, A>> { return r.end(); }
269template <typename T, typename A> size_t size(TSparseArray<T, A> const& r) { return static_cast<size_t>(r.Num()); }
#define FWD(...)
Shorten forwarding expression with this macro so one may not need to specify explicit type.
Definition Macros.h:100
auto end(TArray< T, A > &r) -> T *
Definition Range.h:99
size_t size(TArray< T, A > const &r)
Definition Range.h:101
auto begin(TArray< T, A > &r) -> T *
Definition Range.h:97
static auto GetPairs(TMapBase< K, V, A, F > const &map) -> TSet< TPair< K, V >, F, A > const &
Definition Range.h:151
static auto GetPairs(TMapBase< K, V, A, F > &map) -> TSet< TPair< K, V >, F, A > &
Definition Range.h:145
Extra settings for TExtendedIterator wrapper.
Definition Iterators.h:257
Allows range-v3 and std::ranges to iterate over temporary string objects and keep the string alive du...
Definition Iterators.h:411
Unreal's own iterators are not STL compliant (they are only compatible with range-for loops) so they ...
Definition Iterators.h:281