MCRO
C++23 utilities for Unreal Engine.
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages Concepts
Iterators.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#include "CoreMinimal.h"
15
16#include "Mcro/Concepts.h"
17#include "Mcro/TypeName.h"
18#include "Mcro/TextMacros.h"
19#include "Mcro/SharedObjects.h"
20#include "Mcro/Void.h"
21#include "Mcro/Range/Concepts.h"
22
23#ifndef MCRO_RANGE_ALLOW_BASIC_ITERATOR_FEATURE_EMULATION
24/**
25 * @brief
26 * Iterators which can only step one item at a time, and/or doesn't expose difference computation can have the jump
27 * and difference features emulated at the cost of expensive O(N) time operations. Turning this feature off ensures
28 * stricter policy about this when working with Unreal containers and range-v3
29 *
30 * When this flag is on, a runtime ensure is still triggered.
31 */
32#define MCRO_RANGE_ALLOW_BASIC_ITERATOR_FEATURE_EMULATION 1
33#endif
34
35namespace Mcro::Range
36{
37 using namespace Mcro::Concepts;
38 using namespace Mcro::SharedObjects;
39 using namespace Mcro::TypeName;
40
41 template <typename T>
43
44 template <CIsIteratorStep<EIteratorStep::Single> T>
46 {
47#if MCRO_RANGE_ALLOW_BASIC_ITERATOR_FEATURE_EMULATION
48 T& operator () (T& iterator, size_t steps) const
49 {
50 ensureAlwaysMsgf(false, TEXT_
51 "Given iterator %s can only be incremented in single steps, and therefore can only be incremented in"
52 " O(N) time!",
53 TTypeName<T>.GetData()
54 );
55 for (size_t i=0; i<steps; ++i)
56 ++iterator;
57 return iterator;
58 }
59#endif
60 };
61
62 template <CIsIteratorStep<EIteratorStep::Jump> T>
64 {
65 T& operator () (T& iterator, size_t steps) const
66 {
67 return iterator += steps;
68 }
69 };
70
71 template <typename T>
73
74 template <typename T>
76
77 template <CIteratorFeature<EIteratorDirection::Bidirectional, EIteratorStep::Single> T>
79 {
80#if MCRO_RANGE_ALLOW_BASIC_ITERATOR_FEATURE_EMULATION
81 T& operator () (T& iterator, size_t steps) const
82 {
83 ensureAlwaysMsgf(false, TEXT_
84 "Given iterator %s can only be decremented in single steps, and therefore can only be decremented in"
85 " O(N) time!",
86 TTypeName<T>.GetData()
87 );
88 for (size_t i=0; i<steps; ++i)
89 --iterator;
90 return iterator;
91 }
92#endif
93 };
94
95 template <CIteratorFeature<EIteratorDirection::Bidirectional, EIteratorStep::Jump> T>
97 {
98 T& operator () (T& iterator, size_t steps) const
99 {
100 return iterator -= steps;
101 }
102 };
103
104 template <typename T>
106
107 template <typename T>
109 {
110 using Type = void;
111 };
112
113 template <CBasicForwardIterator T>
115 {
116 using Type = int64;
117 };
118
119 /*
120 template <CPointer T>
121 struct TIteratorDifference_Struct<T>
122 {
123 using Type = std::ptrdiff_t;
124 };
125
126 template <CHasGetIndex T>
127 struct TIteratorDifference_Struct<T>
128 {
129 using Type = decltype(DeclVal<T>().GetIndex());
130 };
131
132 template <CHasElementIndex T>
133 struct TIteratorDifference_Struct<T>
134 {
135 using Type = decltype(DeclVal<T>().ElementIndex);
136 };
137 */
138
139 /** @brief return a difference type for given iterator. */
140 template <typename T>
142
143 template <typename T>
145
146 template <CBasicForwardIterator T>
147 requires CTotallyOrdered<T>
149 {
150 auto operator () (T const& l, T const& r) const
151 {
152 return l <=> r;
153 }
154 };
155
156 template <CBasicForwardIterator T>
157 requires CHasElementIndex<T>
159 {
160 auto operator () (T const& l, T const& r) const
161 {
162 return l.ElementIndex <=> r.ElementIndex;
163 }
164 };
165
166 template <CBasicForwardIterator T>
167 requires CHasGetIndex<T>
169 {
170 auto operator () (T const& l, T const& r) const
171 {
172 return l.GetIndex() <=> r.GetIndex();
173 }
174 };
175
176 template <typename T>
178
179 template <typename T>
181
182 template <CBasicForwardIterator T>
184 {
185#if MCRO_RANGE_ALLOW_BASIC_ITERATOR_FEATURE_EMULATION
186 int64 operator () (T const& l, T const& r) const
187 {
188 ensureAlwaysMsgf(false, TEXT_
189 "Given iterator %s doesn't expose public state about its logical position within the range. Computing"
190 " the distance between two may take O(N) time, where N is the singular steps between the two actual"
191 " positions.",
192 TTypeName<T>.GetData()
193 );
194
195 ensureAlwaysMsgf(CTotallyOrdered<T>, TEXT_
196 "Given iterator %s wasn't relationally comparable. It is assumed that the right iterator is bigger than"
197 " the left one. The program may freeze otherwise!",
198 TTypeName<T>.GetData()
199 );
200
201 T left = l;
202 T right = r;
203 if constexpr (CTotallyOrdered<T>) if (l > r)
204 {
205 left = r;
206 right = l;
207 }
208
209 int64 i = 0;
210 for (;;)
211 {
212 if (!IteratorEquals(left, right)) return i;
213 ensureAlwaysMsgf(i < 1000000, TEXT_
214 "Computing distance between two minimal iterators %s took longer than a million steps."
215 " Maybe use a different container type which can provide iterator distance in O(1) time, or heed"
216 " the above warnings and make sure the right iterator is bigger than the left one.",
217 TTypeName<T>.GetData()
218 );
219 ++i;
220 }
221 }
222#endif
223 };
224
225 template <CStdDistanceCompatible T>
227 {
228 auto operator () (T const& l, T const& r) const
229 {
230 return std::distance(l, r);
231 }
232 };
233
234 template <CHasElementIndex T>
236 {
237 auto operator () (T const& l, T const& r) const
238 {
239 return r.ElementIndex - l.ElementIndex;
240 }
241 };
242
243 template <CHasGetIndex T>
245 {
246 auto operator () (T const& l, T const& r) const
247 {
248 return r.GetIndex() - l.GetIndex();
249 }
250 };
251
252 template <typename T>
254
255 /** @brief Extra settings for `TExtendedIterator` wrapper */
257 {
258 /**
259 * @brief
260 * This is originally meant for `TIndirectArray` where the given operator is extremely minimal but it still
261 * holds a contiguous memory block of pointers. `TExtendedIterator` can then dereference those pointers
262 * instead.
263 */
265 };
266
267 /**
268 * @brief
269 * Unreal's own iterators are not STL compliant (they are only compatible with range-for loops) so they cannot be
270 * used with more advanced STL algorithms or other third-party libraries which may expect the full iterator
271 * interface compatibility. For that TExtendedIterator fills in the missing components and wraps Unreal iterators
272 * to be fully STL iterator compliant.
273 *
274 * TExtendedIterator makes a copy of the Unreal iterator it wraps for internal storage, which should not have
275 * significant side effects, but emphasis is on SHOULD.
276 */
277 template <CBasicForwardIterator Iterator, FExtendedIteratorPolicy Policy = {}>
279 : TIteratorCategory<Iterator>
280 , std::conditional_t<CConstType<Iterator>, FVoid, std::output_iterator_tag>
281 {
287
289
290 template <CConvertibleToDecayed<Iterator> InputIterator>
291 TExtendedIterator(InputIterator&& input) : BaseIterator(input) {}
292
294 : BaseIterator(other.BaseIterator) {}
295
297 : BaseIterator(MoveTemp(other.BaseIterator)) {}
298
300 {
301 using std::swap;
302 swap(*this, other);
303 return *this;
304 }
305
307 {
308 ++BaseIterator;
309 return *this;
310 }
311
313 {
314 TExtendedIterator previous = *this;
315 ++BaseIterator;
316 return previous;
317 }
318
319 template <CBasicBidirectionalIterator = Iterator>
321 {
322 --BaseIterator;
323 return *this;
324 }
325
326 template <CBasicBidirectionalIterator = Iterator>
328 {
329 TExtendedIterator previous = *this;
330 --BaseIterator;
331 return previous;
332 }
333
334 template <CHasMemberAccessOperator = Iterator>
335 auto operator -> () { return BaseIterator.operator->(); }
336
337 template <CHasMemberAccessOperator = Iterator>
338 auto operator -> () const { return BaseIterator.operator->(); }
339
340 auto operator * () -> value_type const&
341 {
342 if constexpr (Policy.DereferencePointerToPointer)
343 return *static_cast<value_type*>(*BaseIterator);
344 return *BaseIterator;
345 }
346
347 auto operator * () const -> value_type const&
348 {
349 if constexpr (Policy.DereferencePointerToPointer)
350 return *static_cast<const value_type*>(*BaseIterator);
351 return *BaseIterator;
352 }
353
354 auto operator += (int steps) -> TExtendedIterator&
355 {
356 return TIteratorJumpForward<Iterator>(*this, steps);
357 }
358
359 auto operator + (int steps) const -> TExtendedIterator
360 {
361 TExtendedIterator result = *this;
362 result += steps;
363 return result;
364 }
365
366 template <CBasicBidirectionalIterator = Iterator>
367 auto operator -= (int steps) -> TExtendedIterator&
368 {
369 return TIteratorJumpBackward<Iterator>(*this, steps);
370 }
371
372 template <CBasicBidirectionalIterator = Iterator>
373 auto operator - (int steps) const -> TExtendedIterator
374 {
375 TExtendedIterator result = *this;
376 result -= steps;
377 return result;
378 }
379
381 {
382 return TIteratorComputeDistance<Iterator>(l.BaseIterator, r.BaseIterator);
383 }
384
385 friend bool operator == (TExtendedIterator const& l, TExtendedIterator const& r)
386 {
387 return IteratorEquals(l.BaseIterator, r.BaseIterator);
388 }
389
390 friend bool operator != (TExtendedIterator const& l, TExtendedIterator const& r)
391 {
392 return !IteratorEquals(l.BaseIterator, r.BaseIterator);
393 }
394
395 template <CIteratorComparable = Iterator>
396 friend auto operator <=> (TExtendedIterator const& l, TExtendedIterator const& r)
397 {
398 return TIteratorCompare<Iterator>(l.BaseIterator, r.BaseIterator);
399 }
400
401 private:
402 Iterator BaseIterator;
403 };
404
405 /**
406 * @brief
407 * Allows range-v3 and std::ranges to iterate over temporary string objects and keep the string alive during view
408 * and action operators.
409 */
410 struct MCRO_API FTempStringIterator : std::random_access_iterator_tag
411 {
412 using value_type = TCHAR;
413 using iterator_category = std::random_access_iterator_tag;
414 using difference_type = std::ptrdiff_t;
417
418 FTempStringIterator() : Current(nullptr) {}
419 FTempStringIterator(FString&& string, bool end);
420
422 : String(other.String)
423 , Current(other.Current)
424 {}
425
427 : String(MoveTemp(other.String))
428 , Current(other.Current)
429 {}
430
431 auto operator ++ () -> FTempStringIterator&;
432 auto operator ++ (int) -> FTempStringIterator;
433 auto operator -- () -> FTempStringIterator&;
434 auto operator -- (int) -> FTempStringIterator;
435 auto operator * () -> TCHAR const&;
436 auto operator * () const -> TCHAR const&;
437 auto operator += (int steps) -> FTempStringIterator&;
438 auto operator -= (int steps) -> FTempStringIterator&;
439 auto operator + (int steps) const -> FTempStringIterator;
440 auto operator - (int steps) const -> FTempStringIterator;
441
442 friend MCRO_API auto operator - (FTempStringIterator const& l, FTempStringIterator const& r) -> difference_type;
443 friend FORCEINLINE auto operator <=> (FTempStringIterator const& l, FTempStringIterator const& r)
444 {
445 return l.Current <=> r.Current;
446 }
447
448 private:
450 const TCHAR* Current;
451 };
452}
This header exists because STL headers in Android doesn't define STL concepts (other than same_as whi...
auto end(TArray< T, A > &r) -> T *
Definition Range.h:96
Use leading TEXT_ without parenthesis for Unreal compatible text literals.
#define TEXT_
A convenience alternative to Unreal's own TEXT macro but this one doesn't require parenthesis around ...
Definition TextMacros.h:51
Convert types to string.
These two are the most useful types in the arsenal of the C++ developer. Use these for dummy types or...
typename TIteratorDifference_Struct< T >::Type TIteratorDifference
return a difference type for given iterator.
Definition Iterators.h:141
std::decay_t< decltype(*DeclVal< T >())> TIteratorElementType
return the iterator's associated content type when they're dereferenced.
Definition Concepts.h:159
bool IteratorEquals(L const &l, R const &r)
Definition Concepts.h:47
constexpr TIteratorCompare_Struct< T > TIteratorCompare
Definition Iterators.h:177
constexpr TIteratorJumpForward_Struct< T > TIteratorJumpForward
Definition Iterators.h:72
constexpr TIteratorJumpBackward_Struct< T > TIteratorJumpBackward
Definition Iterators.h:105
std::conditional_t< CRandomAccessIterator< T >, std::random_access_iterator_tag, std::conditional_t< CBasicBidirectionalIterator< T >, std::bidirectional_iterator_tag, std::conditional_t< CBasicForwardIterator< T >, std::forward_iterator_tag, std::input_iterator_tag > > > TIteratorCategory
Assume an STL iterator category from input iterator.
Definition Concepts.h:121
constexpr TIteratorComputeDistance_Struct< T > TIteratorComputeDistance
Definition Iterators.h:253
Utilities for TSharedPtr/Ref and related.
TSharedPtr< TSharedStorage< T > > TSharedStoragePtr
constexpr FStringView TTypeName
Get a friendly string of an input type without using typeid(T).name().
Definition TypeName.h:195
Extra settings for TExtendedIterator wrapper.
Definition Iterators.h:257
bool DereferencePointerToPointer
This is originally meant for TIndirectArray where the given operator is extremely minimal but it stil...
Definition Iterators.h:264
Allows range-v3 and std::ranges to iterate over temporary string objects and keep the string alive du...
Definition Iterators.h:411
FTempStringIterator(FTempStringIterator &&other) noexcept
Definition Iterators.h:426
FTempStringIterator(FString &&string, bool end)
FTempStringIterator(FTempStringIterator const &other)
Definition Iterators.h:421
std::random_access_iterator_tag iterator_category
Definition Iterators.h:413
Unreal's own iterators are not STL compliant (they are only compatible with range-for loops) so they ...
Definition Iterators.h:281
auto operator*() -> value_type const &
Definition Iterators.h:340
auto operator+(int steps) const -> TExtendedIterator
Definition Iterators.h:359
TIteratorDifference< Iterator > difference_type
Definition Iterators.h:284
friend auto operator<=>(TExtendedIterator const &l, TExtendedIterator const &r)
Definition Iterators.h:396
auto operator+=(int steps) -> TExtendedIterator &
Definition Iterators.h:354
TExtendedIterator(TExtendedIterator const &other)
Definition Iterators.h:293
auto operator++() -> TExtendedIterator &
Definition Iterators.h:306
auto operator--() -> TExtendedIterator &
Definition Iterators.h:320
friend auto operator-(TExtendedIterator const &l, TExtendedIterator const &r) -> difference_type
Definition Iterators.h:380
auto operator-=(int steps) -> TExtendedIterator &
Definition Iterators.h:367
friend bool operator!=(TExtendedIterator const &l, TExtendedIterator const &r)
Definition Iterators.h:390
TIteratorElementType< Iterator > value_type
Definition Iterators.h:282
auto operator=(TExtendedIterator other) -> TExtendedIterator &
Definition Iterators.h:299
TIteratorCategory< Iterator > iterator_category
Definition Iterators.h:283
friend bool operator==(TExtendedIterator const &l, TExtendedIterator const &r)
Definition Iterators.h:385
TExtendedIterator(InputIterator &&input)
Definition Iterators.h:291
TExtendedIterator(TExtendedIterator &&other) noexcept
Definition Iterators.h:296