MCRO
C++23 utilities for Unreal Engine.
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages Concepts
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
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/Deque.h"
81#include "Containers/LruCache.h"
82#include "Containers/MRUArray.h"
83#include "Containers/PagedArray.h"
84#include "Containers/RingBuffer.h"
85
87
88/** @brief Bring modern declarative range operations like views and actions to the Unreal C++ arsenal */
89
92
93// TArray (pointer)
94template <typename T, typename A> auto begin(TArray<T, A>& r) -> T* { return r.GetData(); }
95template <typename T, typename A> auto begin(TArray<T, A> const& r) -> const T* { return r.GetData(); }
96template <typename T, typename A> auto end (TArray<T, A>& r) -> T* { return r.GetData() + r.Num(); }
97template <typename T, typename A> auto end (TArray<T, A> const& r) -> const T* { return r.GetData() + r.Num(); }
98template <typename T, typename A> size_t size(TArray<T, A> const& r) { return static_cast<size_t>(r.Num()); }
99
100// TArrayView (pointer)
101template <typename T, typename A> auto begin(TArrayView<T, A>& r) -> T* { return r.GetData(); }
102template <typename T, typename A> auto begin(TArrayView<T, A> const& r) -> const T* { return r.GetData(); }
103template <typename T, typename A> auto end (TArrayView<T, A>& r) -> T* { return r.GetData() + r.Num(); }
104template <typename T, typename A> auto end (TArrayView<T, A> const& r) -> const T* { return r.GetData() + r.Num(); }
105template <typename T, typename A> size_t size(TArrayView<T, A> const& r) { return static_cast<size_t>(r.Num()); }
106
107// TStaticArray (pointer)
108template <typename T, uint32 N, uint32 A> auto begin(TStaticArray<T, N, A>& r) -> T* { return r.GetData(); }
109template <typename T, uint32 N, uint32 A> auto begin(TStaticArray<T, N, A> const& r) -> const T* { return r.GetData(); }
110template <typename T, uint32 N, uint32 A> auto end (TStaticArray<T, N, A>& r) -> T* { return r.GetData() + r.Num(); }
111template <typename T, uint32 N, uint32 A> auto end (TStaticArray<T, N, A> const& r) -> const T* { return r.GetData() + r.Num(); }
112template <typename T, uint32 N, uint32 A> size_t size(TStaticArray<T, N, A> const& r) { return static_cast<size_t>(r.Num()); }
113
114// TIndirectArray (pointer)
115template <typename T>
117
118template <typename T, typename A> auto begin(TIndirectArray<T, A>& r) -> TExtendedIndirectArrayIterator< T**> { return r.GetData(); }
119template <typename T, typename A> auto begin(TIndirectArray<T, A> const& r) -> TExtendedIndirectArrayIterator<const T**> { return r.GetData(); }
120template <typename T, typename A> auto end (TIndirectArray<T, A>& r) -> TExtendedIndirectArrayIterator< T**> { return r.GetData() + r.Num(); }
121template <typename T, typename A> auto end (TIndirectArray<T, A> const& r) -> TExtendedIndirectArrayIterator<const T**> { return r.GetData() + r.Num(); }
122template <typename T, typename A> size_t size(TIndirectArray<T, A> const& r) { return static_cast<size_t>(r.Num()); }
123
124// TSet (GetIndex-able)
125template <typename T, typename K, typename A> auto begin(TSet<T, K, A>& r) -> TIteratorExtension<TSet<T, K, A>> { return r.begin(); }
126template <typename T, typename K, typename A> auto begin(TSet<T, K, A> const& r) -> TIteratorExtension<TSet<T, K, A>> { return r.begin(); }
127template <typename T, typename K, typename A> auto end (TSet<T, K, A>& r) -> TIteratorExtension<TSet<T, K, A>> { return r.end(); }
128template <typename T, typename K, typename A> auto end (TSet<T, K, A> const& r) -> TIteratorExtension<TSet<T, K, A>> { return r.end(); }
129template <typename T, typename K, typename A> size_t size(TSet<T, K, A> const& r) { return static_cast<size_t>(r.Num()); }
130
131// TMapBase
132// TMap and variants doesn't allow zero-copy view on its pairs with a capable enough iterator, however it has the
133// internal TSet stored as a protected member Pairs, and so we can access it via exploiting the fact that TMapBase
134// friends its template specializations. So we can use a dummy TMapBase to access that internal TSet.
136
138{
139public:
140
141 template <typename K, typename V, typename A, typename F>
142 static auto GetPairs(TMapBase<K, V, A, F>& map) -> TSet<TPair<K, V>, F, A>&
143 {
144 return map.Pairs;
145 }
146
147 template <typename K, typename V, typename A, typename F>
148 static auto GetPairs(TMapBase<K, V, A, F> const& map) -> TSet<TPair<K, V>, F, A> const&
149 {
150 return map.Pairs;
151 }
152};
153
154using FMapPairsAccess = TMapBase<FMapPairsAccessTag, FMapPairsAccessTag, FMapPairsAccessTag, FMapPairsAccessTag>;
155
156// TMap (map to TSet)
157template<typename K, typename V, typename A, typename F> auto begin(TMap<K, V, A, F>& map) { return begin(FMapPairsAccess::GetPairs(map)); }
158template<typename K, typename V, typename A, typename F> auto begin(TMap<K, V, A, F> const& map) { return begin(FMapPairsAccess::GetPairs(map)); }
159template<typename K, typename V, typename A, typename F> auto end (TMap<K, V, A, F>& map) { return end (FMapPairsAccess::GetPairs(map)); }
160template<typename K, typename V, typename A, typename F> auto end (TMap<K, V, A, F> const& map) { return end (FMapPairsAccess::GetPairs(map)); }
161template<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()); }
162// TMultiMap (map to TSet)
163template<typename K, typename V, typename A, typename F> auto begin(TMultiMap<K, V, A, F>& map) { return begin(FMapPairsAccess::GetPairs(map)); }
164template<typename K, typename V, typename A, typename F> auto begin(TMultiMap<K, V, A, F> const& map) { return begin(FMapPairsAccess::GetPairs(map)); }
165template<typename K, typename V, typename A, typename F> auto end (TMultiMap<K, V, A, F>& map) { return end (FMapPairsAccess::GetPairs(map)); }
166template<typename K, typename V, typename A, typename F> auto end (TMultiMap<K, V, A, F> const& map) { return end (FMapPairsAccess::GetPairs(map)); }
167template<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()); }
168
169// Strings (pointer)
170template <typename CharType> auto begin(TStringView<CharType> const& string) -> const CharType* { return string.GetData(); }
171template <typename CharType> auto end (TStringView<CharType> const& string) -> const CharType* { return string.GetData() + string.Len(); }
172template <typename CharType> size_t size(TStringView<CharType> const& string) { return static_cast<size_t>(string.Len()); }
173
174FORCEINLINE auto begin(FString& string) -> const TCHAR* { return *string; }
175FORCEINLINE auto begin(FString const& string) -> const TCHAR* { return *string; }
176FORCEINLINE auto end (FString& string) -> const TCHAR* { return *string + string.Len(); }
177FORCEINLINE auto end (FString const& string) -> const TCHAR* { return *string + string.Len(); }
178FORCEINLINE auto begin(FString&& string) -> Mcro::Range::FTempStringIterator { return {Forward<FString>(string), false}; }
179FORCEINLINE auto end (FString&& string) -> Mcro::Range::FTempStringIterator { return {Forward<FString>(string), true}; }
180FORCEINLINE size_t size(FString const& string) { return static_cast<size_t>(string.Len()); }
181
182// TBasicArray (pointer via begin/end)
183template <typename T> auto begin(TBasicArray<T>& r) -> T* { return r.begin(); }
184template <typename T> auto begin(TBasicArray<T> const& r) -> const T* { return r.begin(); }
185template <typename T> auto end (TBasicArray<T>& r) -> T* { return r.end(); }
186template <typename T> auto end (TBasicArray<T> const& r) -> const T* { return r.end(); }
187template <typename T> size_t size(TBasicArray<T> const& r) { return static_cast<size_t>(r.Num()); }
188
189// TBitArray (GetIndex-able)
190template <typename A> auto begin(TBitArray<A>& r) -> TIteratorExtension<TBitArray<A>> { return r.begin(); }
191template <typename A> auto begin(TBitArray<A> const& r) -> TIteratorExtension<TBitArray<A>> { return r.begin(); }
192template <typename A> auto end (TBitArray<A>& r) -> TIteratorExtension<TBitArray<A>> { return r.end(); }
193template <typename A> auto end (TBitArray<A> const& r) -> TIteratorExtension<TBitArray<A>> { return r.end(); }
194template <typename A> size_t size(TBitArray<A> const& r) { return static_cast<size_t>(r.Num()); }
195
196// TChunkedArray (GetIndex-able)
197template <typename T, uint32 C, typename A> auto begin(TChunkedArray<T, C, A>& r) -> TIteratorExtension<TChunkedArray<T, C, A>> { return r.begin(); }
198template <typename T, uint32 C, typename A> auto begin(TChunkedArray<T, C, A> const& r) -> TIteratorExtension<TChunkedArray<T, C, A>> { return r.begin(); }
199template <typename T, uint32 C, typename A> auto end (TChunkedArray<T, C, A>& r) -> TIteratorExtension<TChunkedArray<T, C, A>> { return r.end(); }
200template <typename T, uint32 C, typename A> auto end (TChunkedArray<T, C, A> const& r) -> TIteratorExtension<TChunkedArray<T, C, A>> { return r.end(); }
201template <typename T, uint32 C, typename A> size_t size(TChunkedArray<T, C, A> const& r) { return static_cast<size_t>(r.Num()); }
202
203// TDeque (warning, non-comparable)
204template <typename T, typename A> auto begin(TDeque<T, A>& r) -> TIteratorExtension<TDeque<T, A>> { return r.begin(); }
205template <typename T, typename A> auto begin(TDeque<T, A> const& r) -> TIteratorExtension<TDeque<T, A>> { return r.begin(); }
206template <typename T, typename A> auto end (TDeque<T, A>& r) -> TIteratorExtension<TDeque<T, A>> { return r.end(); }
207template <typename T, typename A> auto end (TDeque<T, A> const& r) -> TIteratorExtension<TDeque<T, A>> { return r.end(); }
208template <typename T, typename A> size_t size(TDeque<T, A> const& r) { return static_cast<size_t>(r.Num()); }
209
210// TResourceArray (pointer, TArray derivative)
211template <typename T, uint32 A> auto begin(TResourceArray<T, A>& r) -> T* { return r.GetData(); }
212template <typename T, uint32 A> auto begin(TResourceArray<T, A> const& r) -> const T* { return r.GetData(); }
213template <typename T, uint32 A> auto end (TResourceArray<T, A>& r) -> T* { return r.GetData() + r.Num(); }
214template <typename T, uint32 A> auto end (TResourceArray<T, A> const& r) -> const T* { return r.GetData() + r.Num(); }
215template <typename T, uint32 A> size_t size(TResourceArray<T, A> const& r) { return static_cast<size_t>(r.Num()); }
216
217// T[Double]LinkedList is not supported as it defines begin/end functions as friends, and so we cannot overload that
218// template <typename T> auto begin(TLinkedList<T>& r) -> TIteratorExtension<TLinkedList<T>> { return r.begin(); }
219// template <typename T> auto begin(TLinkedList<T> const& r) -> TIteratorExtension<TLinkedList<T>> { return r.begin(); }
220// template <typename T> auto end (TLinkedList<T>& r) -> TIteratorExtension<TLinkedList<T>> { return r.end(); }
221// template <typename T> auto end (TLinkedList<T> const& r) -> TIteratorExtension<TLinkedList<T>> { return r.end(); }
222// template <typename T> size_t size(TLinkedList<T> const& r) { return static_cast<size_t>(r.Num()); }
223
224// TLruCache (warning, non-comparable)
225template <typename K, typename V, typename C> auto begin(TLruCache<K, V, C>& r) -> TIteratorExtension<TLruCache<K, V, C>> { return r.begin(); }
226template <typename K, typename V, typename C> auto begin(TLruCache<K, V, C> const& r) -> TIteratorExtension<TLruCache<K, V, C>> { return r.begin(); }
227template <typename K, typename V, typename C> auto end (TLruCache<K, V, C>& r) -> TIteratorExtension<TLruCache<K, V, C>> { return r.end(); }
228template <typename K, typename V, typename C> auto end (TLruCache<K, V, C> const& r) -> TIteratorExtension<TLruCache<K, V, C>> { return r.end(); }
229template <typename K, typename V, typename C> size_t size(TLruCache<K, V, C> const& r) { return static_cast<size_t>(r.Num()); }
230
231// TMRUArray (pointer, TArray derivative)
232template <typename T, typename A> auto begin(TMRUArray<T, A>& r) -> T* { return r.GetData(); }
233template <typename T, typename A> auto begin(TMRUArray<T, A> const& r) -> const T* { return r.GetData(); }
234template <typename T, typename A> auto end (TMRUArray<T, A>& r) -> T* { return r.GetData() + r.Num(); }
235template <typename T, typename A> auto end (TMRUArray<T, A> const& r) -> const T* { return r.GetData() + r.Num(); }
236template <typename T, typename A> size_t size(TMRUArray<T, A> const& r) { return static_cast<size_t>(r.Num()); }
237
238// TPagedArray (warning, non-comparable)
239template <typename T, int32 P, typename A> auto begin(TPagedArray<T, P, A>& r) -> TIteratorExtension<TPagedArray<T, P, A>> { return r.begin(); }
240template <typename T, int32 P, typename A> auto begin(TPagedArray<T, P, A> const& r) -> TIteratorExtension<TPagedArray<T, P, A>> { return r.begin(); }
241template <typename T, int32 P, typename A> auto end (TPagedArray<T, P, A>& r) -> TIteratorExtension<TPagedArray<T, P, A>> { return r.end(); }
242template <typename T, int32 P, typename A> auto end (TPagedArray<T, P, A> const& r) -> TIteratorExtension<TPagedArray<T, P, A>> { return r.end(); }
243template <typename T, int32 P, typename A> size_t size(TPagedArray<T, P, A> const& r) { return static_cast<size_t>(r.Num()); }
244
245// TRingBuffer (GetIndex-able)
246template <typename T, typename A> auto begin(TRingBuffer<T, A>& r) -> TIteratorExtension<TRingBuffer<T, A>> { return r.begin(); }
247template <typename T, typename A> auto begin(TRingBuffer<T, A> const& r) -> TIteratorExtension<TRingBuffer<T, A>> { return r.begin(); }
248template <typename T, typename A> auto end (TRingBuffer<T, A>& r) -> TIteratorExtension<TRingBuffer<T, A>> { return r.end(); }
249template <typename T, typename A> auto end (TRingBuffer<T, A> const& r) -> TIteratorExtension<TRingBuffer<T, A>> { return r.end(); }
250template <typename T, typename A> size_t size(TRingBuffer<T, A> const& r) { return static_cast<size_t>(r.Num()); }
251
252// TSortedMap (warning, non-comparable)
253template <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(); }
254template <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(); }
255template <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(); }
256template <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(); }
257template <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()); }
258
259// TSparseArray (GetIndex-able)
260template <typename T, typename A> auto begin(TSparseArray<T, A>& r) -> TIteratorExtension<TSparseArray<T, A>> { return r.begin(); }
261template <typename T, typename A> auto begin(TSparseArray<T, A> const& r) -> TIteratorExtension<TSparseArray<T, A>> { return r.begin(); }
262template <typename T, typename A> auto end (TSparseArray<T, A>& r) -> TIteratorExtension<TSparseArray<T, A>> { return r.end(); }
263template <typename T, typename A> auto end (TSparseArray<T, A> const& r) -> TIteratorExtension<TSparseArray<T, A>> { return r.end(); }
264template <typename T, typename A> size_t size(TSparseArray<T, A> const& r) { return static_cast<size_t>(r.Num()); }
auto end(TArray< T, A > &r) -> T *
Definition Range.h:96
size_t size(TArray< T, A > const &r)
Definition Range.h:98
auto begin(TArray< T, A > &r) -> T *
Definition Range.h:94
static auto GetPairs(TMapBase< K, V, A, F > const &map) -> TSet< TPair< K, V >, F, A > const &
Definition Range.h:148
static auto GetPairs(TMapBase< K, V, A, F > &map) -> TSet< TPair< K, V >, F, A > &
Definition Range.h:142
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