UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
TypedElementSorter.inl
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#include "Misc/Char.h"
5
7{
8 //
9 // FixedSizeOnly Sort
10 //
11
12 template<typename ColumnType>
18
19 template<typename ColumnType>
21 const ICoreProvider& Storage, RowHandle Row, uint32 ByteIndex) const
22 {
23 const ColumnType* Column = Storage.GetColumn<ColumnType>(Row);
24 return Column ? CalculatePrefix(*Column, ByteIndex) : FPrefixInfo{};
25 }
26
27 template<typename ColumnType>
32
33
34
35 //
36 // FixedSizeOnly Sort
37 //
38
39 template<typename ColumnType>
45
46 template<typename ColumnType>
48 const ICoreProvider& Storage, RowHandle Row, uint32 ByteIndex) const
49 {
50 const ColumnType* Column = Storage.GetColumn<ColumnType>(Row);
51 return Column ? CalculatePrefix(*Column, ByteIndex) : FPrefixInfo{};
52 }
53
54 template<typename ColumnType>
59
60
61
62 //
63 // Comparative Sort
64 //
65
66 template<typename ColumnType>
68 const ICoreProvider& Storage, RowHandle Left, RowHandle Right) const
69 {
70 const ColumnType* LeftColumn = Storage.GetColumn<ColumnType>(Left);
71 const ColumnType* RigthColumn = Storage.GetColumn<ColumnType>(Right);
72
73 return (LeftColumn && RigthColumn)
74 ? Compare(*LeftColumn, *RigthColumn)
75 : ((LeftColumn == nullptr) - (RigthColumn == nullptr));
76 }
77
78 template<typename ColumnType>
84
85 template<typename ColumnType>
90
91
92 //
93 // Hybrid Sort
94 //
95
96 template<typename ColumnType>
98 const ICoreProvider& Storage, RowHandle Left, RowHandle Right) const
99 {
100 const ColumnType* LeftColumn = Storage.GetColumn<ColumnType>(Left);
101 const ColumnType* RigthColumn = Storage.GetColumn<ColumnType>(Right);
102
103 return (LeftColumn && RigthColumn)
104 ? Compare(*LeftColumn, *RigthColumn)
105 : ((LeftColumn == nullptr) - (RigthColumn == nullptr));
106 }
107
108 template<typename ColumnType>
110 const ICoreProvider& Storage, RowHandle Row, uint32 ByteIndex) const
111 {
112 const ColumnType* Column = Storage.GetColumn<ColumnType>(Row);
113 return Column ? CalculatePrefix(*Column, ByteIndex) : FPrefixInfo{};
114 }
115
116 template<typename ColumnType>
121
122 namespace Private
123 {
124 template<typename T>
125 constexpr uint64 MoveToLocation(int32 ByteIndex, T Value)
126 {
127 constexpr int32 ByteSize = sizeof(T);
128 const uint64 Result = static_cast<uint64>(Value);
129 const int32 ByteShift = 8 - ByteIndex - ByteSize;
130 const int32 BitShift = ByteShift * 8;
131 return (BitShift >= 0) ? (Result << BitShift) : (Result >> -BitShift);
132 }
133
134 template<typename Numeric>
135 constexpr auto Rebase(Numeric Value)
136 {
137 constexpr uint64 BitShift = (sizeof(Numeric) * 8) - 1;
138
139 if constexpr (std::is_floating_point_v<Numeric>)
140 {
141 using SignedInt = std::conditional_t<sizeof(Numeric) == sizeof(double), int64, int32>;
142 using UnsignedInt = std::make_unsigned_t<SignedInt>;
143
144 union { Numeric F; UnsignedInt U; } Converter;
145 Converter.F = Value;
146
147 SignedInt mask = -static_cast<SignedInt>(Converter.U >> BitShift) | (UnsignedInt(1) << BitShift);
148 return Converter.U ^ mask;
149 }
150 else if constexpr (std::is_signed_v<Numeric>)
151 {
152 using Unsigned = std::make_unsigned_t<Numeric>;
153
154 Numeric mask = static_cast<Numeric>(-(Value >> BitShift) | (Unsigned(1) << BitShift));
155 return static_cast<Unsigned>(Value ^ mask);
156 }
157 else
158 {
159 static_assert(std::is_unsigned_v<Numeric>, "Input value to rebase for sort indexing must be a numeric value.");
160 return Value;
161 }
162 }
163
164 template<bool bCaseSensitive, typename CharType>
165 CharType ToUpper(CharType Input)
166 {
167 if constexpr (bCaseSensitive)
168 {
169 return Input;
170 }
171 else
172 {
174 }
175 }
176
177 template<typename ValueType>
178 void CalculatePrefix(FPrefixInfo& Result, int32 CurrentIndex, int32 ByteIndex, const ValueType& Value)
179 {
181 {
182 constexpr int32 ResultSize = sizeof(FPrefixInfo::Prefix);
184
186 {
187 int32 Position = CurrentIndex - ByteIndex;
188 if (Position < ResultSize)
189 {
190 Result.Prefix |= TSortTypeInfo<ValueType>::CalculatePrefix(CurrentIndex, ByteIndex, Value).Prefix;
191 Result.bHasRemainingBytes = (Position + Size) > sizeof(FPrefixInfo::Prefix);
192 }
193 }
194 else
195 {
196 constexpr uint32 ElementSize = TSortTypeInfo<ValueType>::GetElementSize();
197
198 int32 Index = CurrentIndex - ByteIndex;
199 if (ResultSize - (Index & (ResultSize - 1)) >= static_cast<int32>(ElementSize))
200 {
202 TSortTypeInfo<ValueType>::CalculatePrefix(CurrentIndex, ByteIndex, Value);
203 Result.Prefix |= Intermediate.Prefix;
204 Result.bHasRemainingBytes = Intermediate.bHasRemainingBytes;
205 }
206 }
207 }
208 }
209
210 template<typename ValueType, typename... ValueTypes>
211 void CalculatePrefix(FPrefixInfo& Result, int32 CurrentIndex, int32 ByteIndex,
212 const ValueType& Value, ValueTypes&&... Values)
213 {
215 {
216 constexpr int32 ResultSize = sizeof(FPrefixInfo::Prefix);
218 // Skip over bytes that fall out of the requested range.
219 if (CurrentIndex + Size <= ByteIndex)
220 {
221 CalculatePrefix(Result, CurrentIndex + Size, ByteIndex, Values...);
222 }
223 else
224 {
225 static_assert(TSortTypeInfo<ValueType>::bIsFixedSize, "Only the last value type can be of variable size.");
226
227 // Try to pack as many bytes into the final result as are available. This might require pulling portions of values.
228 int32 Position = CurrentIndex - ByteIndex;
229 if (Position < ResultSize)
230 {
231 // Continue while there are still bytes available.
232 Result.Prefix |= TSortTypeInfo<ValueType>::CalculatePrefix(CurrentIndex, ByteIndex, Value).Prefix;
233 CalculatePrefix(Result, CurrentIndex + Size, ByteIndex, Values...);
234 }
235 }
236 }
237 }
238 }
239
240
241
242 //
243 // TSortNameView
244 //
245
246 template<SortBy By>
248 {
249 View = &Name;
250 bIsCached = false;
251 return *this;
252 }
253
254 template<SortBy By>
256 {
257 if constexpr (bIsById)
258 {
259 return sizeof(Cache);
260 }
261 else
262 {
263 CacheCompareType();
264 return static_cast<uint32>(Cache.NumBytesWithoutNull());
265 }
266 }
267
268 template<SortBy By>
270 {
271 if constexpr (bIsById)
272 {
273 return sizeof(Cache);
274 }
275 else
276 {
277 return sizeof(typename CompareType::ElementType);
278 }
279 }
280
281 template<SortBy By>
283 {
284 CacheCompareType();
285 if constexpr (bIsById)
286 {
287 return TSortTypeInfo<CompareType>::CalculatePrefix(CurrentIndex, ByteIndex, Cache);
288 }
289 else
290 {
293 return TSortTypeInfo<SortStringView>::CalculatePrefix(CurrentIndex, ByteIndex, StringView(Cache));
294 }
295 }
296
297 template<SortBy By>
298 int32 TSortNameView<By>::Compare(const FName& Lhs, const FName& Rhs) const
299 {
300 if constexpr (bIsById)
301 {
302 return View->CompareIndexes(Rhs);
303 }
304 else
305 {
306 auto Compare = [this](const FName& To)
307 {
309 {
310 CacheCompareType();
311 FString ToString = To.ToString();
312 ToString.RemoveFromStart(TEXT("/"));
313 return Cache.Compare(ToString, ESearchCase::IgnoreCase);
314 }
315 else
316 {
317 return View->Compare(To);
318 }
319 };
320
321 if constexpr (EnumHasAllFlags(By::Flags, ESortByNameFlags::WithNone))
322 {
323 return Compare(Rhs);
324 }
325 else
326 {
327 bool LeftIsAssigned = !View->IsNone();
328 bool RightIsAssigned = !Rhs.IsNone();
330 ? Compare(Rhs)
331 // Note that this is in reversed order then elsewhere because in this case the empty value should be at the top, not the bottom.
333 }
334 }
335 }
336
337 template<SortBy By>
339 {
340 return View ? Compare(*View, Rhs) : 1;
341 }
342
343 template<SortBy By>
345 {
346 return (View && Rhs.View)
347 ? Compare(*View, *Rhs.View)
348 : static_cast<int32>(View == nullptr) - static_cast<int32>(Rhs.View == nullptr);
349 }
350
351 template<SortBy By>
353 {
354 return Compare(Rhs) == 0;
355 }
356
357 template<SortBy By>
359 {
360 return Compare(Rhs) != 0;
361 }
362
363 template<SortBy By>
365 {
366 return Compare(Rhs) < 0;
367 }
368
369 template<SortBy By>
371 {
372 return Compare(Rhs) <= 0;
373 }
374
375 template<SortBy By>
377 {
378 return Compare(Rhs) > 0;
379 }
380
381 template<SortBy By>
383 {
384 return Compare(Rhs) >= 0;
385 }
386
387 template<SortBy By>
389 {
390 if (View && !bIsCached)
391 {
392 if constexpr (bIsById)
393 {
394 Cache = View->GetNumber();
395 }
396 else
397 {
398 Cache.Reset();
399 if constexpr (EnumHasAllFlags(By::Flags, ESortByNameFlags::WithNone))
400 {
401 View->ToString(Cache);
402 }
403 else
404 {
405 if (!View->IsNone())
406 {
407 View->ToString(Cache);
408 }
409 }
410
412 {
413 Cache.RemoveFromStart(TEXT("/"));
414 }
415 }
416 bIsCached = true;
417 }
418 }
419
420
421
422 // TSortTypeInfo<TSortStringView<...>>
423
424 template<SortCase Casing, typename T>
426 {
427 return static_cast<uint32>(Value.View.NumBytes());
428 }
429
430 template<SortCase Casing, typename T>
432 {
433 return sizeof(typename T::ElementType);
434 }
435
436 template<SortCase Casing, typename T>
438 int32 CurrentIndex, int32 ByteIndex, TSortStringView<Casing, T> Value)
439 {
440 constexpr bool bIsCaseSensitive = TSortStringView<Casing, T>::bIsCaseSensitive;
441
442 uint64 Result = 0;
443 bool bHasRemainingCharacters = false;
444
445 uint32 BytesIntoResult = ByteIndex < CurrentIndex ? (CurrentIndex & 7) : 0;
446 uint32 RemainingBytes = 8 - BytesIntoResult;
447 int32 StringIndex = FMath::Clamp<int32>(ByteIndex - CurrentIndex, 0, static_cast<int32>(Value.View.NumBytes()));
448
449 if constexpr (sizeof(typename T::ElementType) == 1)
450 {
451 int32 Min = FMath::Min<int32>(Value.View.Len() - StringIndex, RemainingBytes);
452
453 switch (Min)
454 {
455 case 8:
456 Result |= (static_cast<uint64>(Private::ToUpper<bIsCaseSensitive>(Value.View[StringIndex + Min - 8])) << 56);
457 case 7:
458 Result |= (static_cast<uint64>(Private::ToUpper<bIsCaseSensitive>(Value.View[StringIndex + Min - 7])) << 48);
459 case 6:
460 Result |= (static_cast<uint64>(Private::ToUpper<bIsCaseSensitive>(Value.View[StringIndex + Min - 6])) << 40);
461 case 5:
462 Result |= (static_cast<uint64>(Private::ToUpper<bIsCaseSensitive>(Value.View[StringIndex + Min - 5])) << 32);
463 case 4:
464 Result |= (static_cast<uint64>(Private::ToUpper<bIsCaseSensitive>(Value.View[StringIndex + Min - 4])) << 24);
465 case 3:
466 Result |= (static_cast<uint64>(Private::ToUpper<bIsCaseSensitive>(Value.View[StringIndex + Min - 3])) << 16);
467 case 2:
468 Result |= (static_cast<uint64>(Private::ToUpper<bIsCaseSensitive>(Value.View[StringIndex + Min - 2])) << 8);
469 case 1:
470 Result |= (static_cast<uint64>(Private::ToUpper<bIsCaseSensitive>(Value.View[StringIndex + Min - 1])));
471 }
472 Result <<= 64 - (BytesIntoResult + Min) * 8;
474 }
475 else
476 {
477 StringIndex >>= 1;
478 int32 Min = FMath::Min<int32>(Value.View.Len() - StringIndex, RemainingBytes >> 1);
479 switch (Min)
480 {
481 case 4:
482 Result |= (static_cast<uint64>(Private::ToUpper<bIsCaseSensitive>(Value.View[StringIndex + Min - 4])) << 48);
483 case 3:
484 Result |= (static_cast<uint64>(Private::ToUpper<bIsCaseSensitive>(Value.View[StringIndex + Min - 3])) << 32);
485 case 2:
486 Result |= (static_cast<uint64>(Private::ToUpper<bIsCaseSensitive>(Value.View[StringIndex + Min - 2])) << 16);
487 case 1:
488 Result |= (static_cast<uint64>(Private::ToUpper<bIsCaseSensitive>(Value.View[StringIndex + Min - 1])));
489 }
490 Result <<= 64 - (BytesIntoResult + (Min *2)) * 8;
492 }
493
494 return FPrefixInfo
495 {
496 .Prefix = Result,
497 .bHasRemainingBytes = bHasRemainingCharacters
498 };
499 }
500
501 template<typename... ValueTypes>
502 FPrefixInfo CreateSortPrefix(uint32 ByteIndex, ValueTypes&&... Values)
503 {
504 FPrefixInfo Result
505 {
506 .Prefix = 0,
507 .bHasRemainingBytes = true
508 };
509 Private::CalculatePrefix(Result, 0, static_cast<int32>(ByteIndex), Values...);
510 return Result;
511 }
512} // namespace UE::Editor::DataStorage
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int64 int64
A 64-bit signed integer.
Definition Platform.h:1127
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
FPlatformTypes::uint64 uint64
A 64-bit unsigned integer.
Definition Platform.h:1117
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
constexpr bool EnumHasAllFlags(Enum Flags, Enum Contains)
Definition EnumClassFlags.h:28
uint32 Size
Definition VulkanMemory.cpp:4034
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition NameTypes.h:617
Definition StringView.h:107
virtual int32 Compare(const ICoreProvider &Storage, RowHandle Left, RowHandle Right) const =0
virtual ESortType GetSortType() const =0
virtual FPrefixInfo CalculatePrefix(const ICoreProvider &Storage, RowHandle Row, uint32 ByteIndex) const =0
ESortType
Definition TypedElementSorter.h:35
Definition TypedElementDataStorageInterface.h:65
ColumnType * GetColumn(RowHandle Row)
Definition TypedElementDataStorageInterface.h:802
Definition TypedElementSorter.h:95
UE_FORCEINLINE_HINT int32 Len() const
Definition UnrealString.h.inl:954
constexpr bool Compare(const InAT &InputA, const InBT &InputB, ProjectionT Projection, PredicateT Predicate)
Definition Compare.h:15
@ IgnoreCase
Definition CString.h:26
Definition OverriddenPropertySet.cpp:45
void CalculatePrefix(FPrefixInfo &Result, int32 CurrentIndex, int32 ByteIndex, const ValueType &Value)
Definition TypedElementSorter.inl:178
Definition CommonTypes.cpp:10
FPrefixInfo CreateSortPrefix(uint32 ByteIndex, ValueTypes &&... Values)
Definition TypedElementSorter.inl:502
uint64 RowHandle
Definition Handles.h:15
FORCEINLINE UE_STRING_CLASS RhsType && Rhs
Definition String.cpp.inl:718
U16 Index
Definition radfft.cpp:71
static CharType ToUpper(CharType Char)
Definition Char.h:80
Definition TypedElementSorter.h:23
uint64 Prefix
Definition TypedElementSorter.h:24
Definition TypedElementSorter.h:261
FPrefixInfo CalculatePrefix(int32 CurrentIndex, int32 ByteIndex) const
Definition TypedElementSorter.inl:282
bool operator<(const TSortNameView &Rhs) const
Definition TypedElementSorter.inl:364
bool operator==(const TSortNameView &Rhs) const
Definition TypedElementSorter.inl:352
uint32 GetByteSize() const
Definition TypedElementSorter.inl:255
bool operator>=(const TSortNameView &Rhs) const
Definition TypedElementSorter.inl:382
int32 Compare(const FName &Rhs) const
Definition TypedElementSorter.inl:338
bool operator>(const TSortNameView &Rhs) const
Definition TypedElementSorter.inl:376
TSortNameView & operator=(const FName &Name)
Definition TypedElementSorter.inl:247
bool operator!=(const TSortNameView &Rhs) const
Definition TypedElementSorter.inl:358
bool operator<=(const TSortNameView &Rhs) const
Definition TypedElementSorter.inl:370
static constexpr uint32 GetElementSize()
Definition TypedElementSorter.inl:269
Definition TypedElementSorter.h:200
Definition TypedElementSorter.h:319