UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
String.cpp.inl
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3/*********************************************************************************************************************
4 * NOTICE *
5 * *
6 * This file is not intended to be included directly - it will be included by other .cpp files which have predefined *
7 * some macros to be expanded within this file. As such, it does not have a #pragma once as it is intended to be *
8 * included multiple times with different macro definitions. *
9 * *
10 * #includes needed to compile this file need to be specified in StringIncludes.cpp.inl file rather than here. *
11 *********************************************************************************************************************/
12#define UE_INCLUDETOOL_IGNORE_INCONSISTENT_STATE
13
14#ifndef UE_STRING_CLASS
15 #error "String.cpp.inl should only be included after defining UE_STRING_CLASS"
16#endif
17#ifndef UE_STRING_CHARTYPE
18 #error "String.cpp.inl should only be included after defining UE_STRING_CHARTYPE"
19#endif
20#ifndef UE_STRING_CHARTYPE_IS_TCHAR
21 #error "String.cpp.inl should only be included after defining UE_STRING_CHARTYPE_IS_TCHAR"
22#endif
23
24 /* String implementation
25 *****************************************************************************/
26
27namespace UE::Core::Private
28{
29 template <typename CompareType>
31 {
32 // Skip over common initial non-wildcard-char sequence of Target and Wildcard
33 for (;;)
34 {
35 if (WildcardLength == 0)
36 {
37 return TargetLength == 0;
38 }
39
42 {
43 break;
44 }
45
46 if (!Compare(*Target, WCh))
47 {
48 return false;
49 }
50
51 ++Target;
52 ++Wildcard;
55 }
56
57 // Test for common suffix
58 const UE_STRING_CHARTYPE* TPtr = Target + TargetLength;
60 for (;;)
61 {
62 --TPtr;
63 --WPtr;
64
67 {
68 break;
69 }
70
71 if (!Compare(*TPtr, WCh))
72 {
73 return false;
74 }
75
78
79 if (TargetLength == 0)
80 {
81 break;
82 }
83 }
84
85 // Match * against anything and ? against single (and zero?) chars
88 {
89 return true;
90 }
91 ++Wildcard;
93
94 // This routine is very slow, though it does ok with one wildcard
95 int32 MaxNum = TargetLength;
96 if (FirstWild == CHARTEXT(UE_STRING_CHARTYPE, '?') && MaxNum > 1)
97 {
98 MaxNum = 1;
99 }
100
101 for (int32 Index = 0; Index <= MaxNum; ++Index)
102 {
104 {
105 return true;
106 }
107 }
108 return false;
109 }
110
111 template <typename SrcCharType>
113 {
114 check(Count >= 0);
115
116 if (!Count)
117 {
118 return;
119 }
120
121 checkSlow(Str);
122
123 int32 OldEnd = Out.Num();
124
125 // Try to reserve enough space by guessing that the new length will be the same as the input length.
126 // Include an extra gap for a null terminator if we don't already have a string allocated
127 Out.AddUninitialized(Count + (OldEnd ? 0 : 1));
128 OldEnd -= OldEnd ? 1 : 0;
129
130 UE_STRING_CHARTYPE* Dest = Out.GetData() + OldEnd;
131
132 // Try copying characters to end of string, overwriting null terminator if we already have one
133 UE_STRING_CHARTYPE* NewEnd = FPlatformString::Convert(Dest, Count, Str, Count);
134 if (!NewEnd)
135 {
136 // If that failed, it will have meant that conversion likely contained multi-code unit characters
137 // and so the buffer wasn't long enough, so calculate it properly.
138 int32 Length = FPlatformString::ConvertedLength<UE_STRING_CHARTYPE>(Str, Count);
139
140 // Add the extra bytes that we need
142
143 // Restablish destination pointer in case a realloc happened
144 Dest = Out.GetData() + OldEnd;
145
146 NewEnd = FPlatformString::Convert(Dest, Length, Str, Count);
148 }
149 else
150 {
151 int32 NewEndIndex = (int32)(NewEnd - Dest);
152 if (NewEndIndex < Count)
153 {
155 }
156 }
157
158 // (Re-)establish the null terminator
160 }
161
162 template <typename SrcCharType>
164 {
165 checkf(Src, TEXT("Unable to construct string from a null pointer"));
166 checkf(ExtraSlack >= 0, TEXT("Unable to construct string with negative slack"));
167
168 if (*Src)
169 {
170 int32 SrcLen = TCString<SrcCharType>::Strlen(Src) + 1;
171 int32 DestLen = FPlatformString::ConvertedLength<UE_STRING_CHARTYPE>(Src, SrcLen);
172 Data.Reserve(DestLen + ExtraSlack);
173 Data.AddUninitialized(DestLen);
174
175 FPlatformString::Convert(Data.GetData(), DestLen, Src, SrcLen);
176 }
177 else if (ExtraSlack > 0)
178 {
179 Data.Reserve(ExtraSlack + 1);
180 }
181 }
182
183 template <typename SrcCharType>
185 {
186 checkf(InSrc || InCount == 0, TEXT("Unable to construct string from a null pointer"));
187 checkf(InCount >= 0, TEXT("Unable to construct string with a negative size"));
188 checkf(ExtraSlack >= 0, TEXT("Unable to construct string with negative slack"));
189
190 int32 DestLen = FPlatformString::ConvertedLength<UE_STRING_CHARTYPE>(InSrc, InCount);
191 if (DestLen > 0)
192 {
193 Data.Reserve(DestLen + ExtraSlack + 1);
194 Data.AddUninitialized(DestLen + 1);
195
196 UE_STRING_CHARTYPE* DataPtr = Data.GetData();
197
198 FPlatformString::Convert(DataPtr, DestLen, InSrc, InCount);
199 DataPtr[DestLen] = CHARTEXT(UE_STRING_CHARTYPE, '\0');
200 }
201 else if (ExtraSlack > 0)
202 {
203 Data.Reserve(ExtraSlack + 1);
204 }
205 }
206
207 template <typename SrcCharType>
208 FORCEINLINE void ConstructWithSlack(/* Out */ TArray<UE_STRING_CHARTYPE>& Data, const SrcCharType* Src, int32 ExtraSlack)
209 {
210 checkf(Src, TEXT("Unable to construct string from a null pointer"));
211 checkf(ExtraSlack >= 0, TEXT("Unable to construct string with negative slack"));
212
213 if (*Src)
214 {
215 int32 SrcLen = TCString<SrcCharType>::Strlen(Src) + 1;
216 int32 DestLen = FPlatformString::ConvertedLength<UE_STRING_CHARTYPE>(Src, SrcLen);
217 Data.Reserve(DestLen + ExtraSlack);
218 Data.AddUninitialized(DestLen);
219
220 FPlatformString::Convert(Data.GetData(), DestLen, Src, SrcLen);
221 }
222 else if (ExtraSlack > 0)
223 {
224 Data.Reserve(ExtraSlack + 1);
225 }
226 }
227} // namespace UE::Core::Private
228
234
235// Deprecated
236UE_STRING_CLASS::UE_STRING_CLASS(int32 Len, const ANSICHAR* Str) { if (Str && *Str) { UE::Core::Private::ConstructWithLength(Data, Str, Len, 0); } }
237UE_STRING_CLASS::UE_STRING_CLASS(int32 Len, const WIDECHAR* Str) { if (Str && *Str) { UE::Core::Private::ConstructWithLength(Data, Str, Len, 0); } }
238UE_STRING_CLASS::UE_STRING_CLASS(int32 Len, const UTF8CHAR* Str) { if (Str && *Str) { UE::Core::Private::ConstructWithLength(Data, Str, Len, 0); } }
239UE_STRING_CLASS::UE_STRING_CLASS(int32 Len, const UCS2CHAR* Str) { if (Str && *Str) { UE::Core::Private::ConstructWithLength(Data, Str, Len, 0); } }
240UE_STRING_CLASS::UE_STRING_CLASS(const ANSICHAR* Str, int32 ExtraSlack) { if (Str) { UE::Core::Private::ConstructFromCString(Data, Str, ExtraSlack); } else if (ExtraSlack > 0) { Data.Reserve(ExtraSlack + 1); } }
241UE_STRING_CLASS::UE_STRING_CLASS(const WIDECHAR* Str, int32 ExtraSlack) { if (Str) { UE::Core::Private::ConstructFromCString(Data, Str, ExtraSlack); } else if (ExtraSlack > 0) { Data.Reserve(ExtraSlack + 1); } }
242UE_STRING_CLASS::UE_STRING_CLASS(const UTF8CHAR* Str, int32 ExtraSlack) { if (Str) { UE::Core::Private::ConstructFromCString(Data, Str, ExtraSlack); } else if (ExtraSlack > 0) { Data.Reserve(ExtraSlack + 1); } }
243UE_STRING_CLASS::UE_STRING_CLASS(const UCS2CHAR* Str, int32 ExtraSlack) { if (Str) { UE::Core::Private::ConstructFromCString(Data, Str, ExtraSlack); } else if (ExtraSlack > 0) { Data.Reserve(ExtraSlack + 1); } }
244// Deprecated
245
251UE_STRING_CLASS UE_STRING_CLASS::ConstructWithSlack(const ANSICHAR* Str, int32 ExtraSlack) { UE_STRING_CLASS Result; UE::Core::Private::ConstructFromCString(Result.Data, Str, ExtraSlack); return Result; }
252UE_STRING_CLASS UE_STRING_CLASS::ConstructWithSlack(const WIDECHAR* Str, int32 ExtraSlack) { UE_STRING_CLASS Result; UE::Core::Private::ConstructFromCString(Result.Data, Str, ExtraSlack); return Result; }
253UE_STRING_CLASS UE_STRING_CLASS::ConstructWithSlack(const UTF8CHAR* Str, int32 ExtraSlack) { UE_STRING_CLASS Result; UE::Core::Private::ConstructFromCString(Result.Data, Str, ExtraSlack); return Result; }
254UE_STRING_CLASS UE_STRING_CLASS::ConstructWithSlack(const UCS2CHAR* Str, int32 ExtraSlack) { UE_STRING_CLASS Result; UE::Core::Private::ConstructFromCString(Result.Data, Str, ExtraSlack); return Result; }
255UE_STRING_CLASS UE_STRING_CLASS::ConstructWithSlack(const UTF32CHAR* Str, int32 ExtraSlack) { UE_STRING_CLASS Result; UE::Core::Private::ConstructFromCString(Result.Data, Str, ExtraSlack); return Result; }
256UE_STRING_CLASS UE_STRING_CLASS::ConstructFromPtrSizeWithSlack(const ANSICHAR* Str, int32 Len, int32 ExtraSlack) { UE_STRING_CLASS Result; UE::Core::Private::ConstructWithLength(Result.Data, Str, Len, ExtraSlack); return Result; }
257UE_STRING_CLASS UE_STRING_CLASS::ConstructFromPtrSizeWithSlack(const WIDECHAR* Str, int32 Len, int32 ExtraSlack) { UE_STRING_CLASS Result; UE::Core::Private::ConstructWithLength(Result.Data, Str, Len, ExtraSlack); return Result; }
258UE_STRING_CLASS UE_STRING_CLASS::ConstructFromPtrSizeWithSlack(const UTF8CHAR* Str, int32 Len, int32 ExtraSlack) { UE_STRING_CLASS Result; UE::Core::Private::ConstructWithLength(Result.Data, Str, Len, ExtraSlack); return Result; }
259UE_STRING_CLASS UE_STRING_CLASS::ConstructFromPtrSizeWithSlack(const UCS2CHAR* Str, int32 Len, int32 ExtraSlack) { UE_STRING_CLASS Result; UE::Core::Private::ConstructWithLength(Result.Data, Str, Len, ExtraSlack); return Result; }
260UE_STRING_CLASS UE_STRING_CLASS::ConstructFromPtrSizeWithSlack(const UTF32CHAR* Str, int32 Len, int32 ExtraSlack) { UE_STRING_CLASS Result; UE::Core::Private::ConstructWithLength(Result.Data, Str, Len, ExtraSlack); return Result; }
261
263{
264 if (Data.GetData() != Other)
265 {
266 int32 Len = (Other && *Other) ? TCString<ElementType>::Strlen(Other) + 1 : 0;
267 Data.Empty(Len);
268 Data.AddUninitialized(Len);
269
270 if (Len)
271 {
272 FMemory::Memcpy(Data.GetData(), Other, Len * sizeof(ElementType));
273 }
274 }
275 return *this;
276}
277
278
279void UE_STRING_CLASS::AssignRange(const ElementType* OtherData, int32 OtherLen)
280{
281 if (OtherLen == 0)
282 {
283 Empty();
284 }
285 else
286 {
287 const int32 ThisLen = Len();
288 if (OtherLen <= ThisLen)
289 {
290 // Unless the input is longer, this might be assigned from a view of itself.
291 ElementType* DataPtr = Data.GetData();
292 FMemory::Memmove(DataPtr, OtherData, OtherLen * sizeof(ElementType));
293 DataPtr[OtherLen] = CHARTEXT(ElementType, '\0');
294 Data.RemoveAt(OtherLen + 1, ThisLen - OtherLen);
295 }
296 else
297 {
298 Data.Empty(OtherLen + 1);
299 Data.AddUninitialized(OtherLen + 1);
300 ElementType* DataPtr = Data.GetData();
301 FMemory::Memcpy(DataPtr, OtherData, OtherLen * sizeof(ElementType));
302 DataPtr[OtherLen] = CHARTEXT(ElementType, '\0');
303 }
304 }
305}
306
307void UE_STRING_CLASS::Reserve(int32 CharacterCount)
308{
309 checkSlow(CharacterCount >= 0 && CharacterCount < MAX_int32);
310 if (CharacterCount > 0)
311 {
312 Data.Reserve(CharacterCount + 1);
313 }
314}
315
317{
318 Data.Empty(Slack ? Slack + 1 : 0);
319}
320
322{
323 Data.Empty(0);
324}
325
327{
330 if (ElementType* DataPtr = Data.GetData())
331 {
332 *DataPtr = CHARTEXT(ElementType, '\0');
333 }
334}
335
337{
338 Data.Shrink();
339}
340
341#ifdef __OBJC__
343NSString* UE_STRING_CLASS::GetNSString() const
344{
345 NSString* OutString = (NSString*)GetCFString();
346 [OutString autorelease];
347
348 return OutString;
349}
350#endif
351
352#if PLATFORM_APPLE
354CFStringRef UE_STRING_CLASS::GetCFString() const
355{
356 CFStringRef OutString;
357
358#if PLATFORM_TCHAR_IS_4_BYTES
359 OutString = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8*)Data.GetData(), Len() * sizeof(ElementType), kCFStringEncodingUTF32LE, false);
360#else
361 OutString = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8*)Data.GetData(), Len() * sizeof(ElementType), kCFStringEncodingUTF16LE, false);
362#endif
363
364 return OutString;
365}
366#endif
367
369{
371
372 if (InChar != 0)
373 {
374 // position to insert the character.
375 // At the end of the string if we have existing characters, otherwise at the 0 position
376 int32 InsertIndex = (Data.Num() > 0) ? Data.Num()-1 : 0;
377
378 // number of characters to add. If we don't have any existing characters,
379 // we'll need to append the terminating zero as well.
380 int32 InsertCount = (Data.Num() > 0) ? 1 : 2;
381
383 Data[InsertIndex] = InChar;
384 Data[InsertIndex+1] = CHARTEXT(ElementType, '\0');
385 }
386 return *this;
387}
388
394
400
406
412
418
420{
421 if (Data.Num())
422 {
424 check(DataLen == 0 || DataLen < Data.Num());
425 int32 Len = DataLen > 0 ? DataLen+1 : 0;
426
427 check(Len <= Data.Num());
428 Data.RemoveAt(Len, Data.Num()-Len);
429 }
430}
431
432
434{
435 checkf(SubStrLen >= 0, TEXT("Invalid SubStrLen: %d"), SubStrLen);
436
438 {
439 const ElementType* Start = **this;
440 int32 RemainingLength = Len();
441 if (StartPosition != INDEX_NONE && RemainingLength > 0)
442 {
443 const ElementType* End = Start + RemainingLength;
444 Start += FMath::Clamp(StartPosition, 0, RemainingLength - 1);
446 }
447 const ElementType* Tmp = SearchCase == ESearchCase::IgnoreCase
450
451 return Tmp ? UE_PTRDIFF_TO_INT32(Tmp-**this) : INDEX_NONE;
452 }
453 else
454 {
455 // if ignoring, do a onetime ToUpper on both strings, to avoid ToUppering multiple
456 // times in the loop below
457 if (SearchCase == ESearchCase::IgnoreCase)
458 {
460 }
461 else
462 {
463 const int32 SearchStringLength=FMath::Max(1, SubStrLen);
464
465 if (StartPosition == INDEX_NONE || StartPosition >= Len())
466 {
467 StartPosition = Len();
468 }
469
470 for (int32 i = StartPosition - SearchStringLength; i >= 0; i--)
471 {
472 int32 j;
473 for (j=0; j != SubStrLen; j++)
474 {
475 if ((*this)[i+j]!=SubStr[j])
476 {
477 break;
478 }
479 }
480
481 if (j == SubStrLen)
482 {
483 return i;
484 }
485 }
486 return INDEX_NONE;
487 }
488 }
489}
490
492{
493 check(LeftStr != RightStr || LeftStr == nullptr);
494
495 int32 InPos = Find(InStr, SearchCase, SearchDir);
496
497 if (InPos < 0)
498 {
499 return false;
500 }
501
502 if (LeftStr)
503 {
504 if (LeftStr != this)
505 {
506 *LeftStr = Left(InPos);
507 if (RightStr)
508 {
509 *RightStr = Mid(InPos + InStr.Len());
510 }
511 }
512 else
513 {
514 // we know that RightStr can't be this so we can safely modify it before we deal with LeftStr
515 if (RightStr)
516 {
517 *RightStr = Mid(InPos + InStr.Len());
518 }
519 *LeftStr = Left(InPos);
520 }
521 }
522 else if (RightStr)
523 {
524 *RightStr = Mid(InPos + InStr.Len());
525 }
526
527 return true;
528}
529
534
536{
537 UE_STRING_CLASS New = *this;
539 return New;
540}
541
543{
544 this->ToUpperInline();
545 return MoveTemp(*this);
546}
547
549{
550 const int32 StringLength = Len();
551 ElementType* RawData = Data.GetData();
552 for (int32 i = 0; i < StringLength; ++i)
553 {
555 }
556}
557
558
560{
561 UE_STRING_CLASS New = *this;
563 return New;
564}
565
567{
568 this->ToLowerInline();
569 return MoveTemp(*this);
570}
571
573{
574 const int32 StringLength = Len();
575 ElementType* RawData = Data.GetData();
576 for (int32 i = 0; i < StringLength; ++i)
577 {
579 }
580}
581
583{
584 const int32 StringLength = Len();
585 if (StringLength == 0)
586 {
587 return;
588 }
589
590 ElementType* RawData = Data.GetData();
591 int32 CopyToIndex = 0;
592 for (int32 CopyFromIndex = 0; CopyFromIndex < StringLength; ++CopyFromIndex)
593 {
594 if (RawData[CopyFromIndex] != ' ')
595 { // Copy any character OTHER than space.
597 ++CopyToIndex;
598 }
599 }
600
601 // Copy null-terminating character.
602 if (CopyToIndex <= StringLength)
603 {
606 }
607}
608
610{
611 if (SearchCase == ESearchCase::IgnoreCase)
612 {
614 }
615 else
616 {
618 }
619}
620
622{
623 if (SearchCase == ESearchCase::IgnoreCase)
624 {
625 return InSuffixLen > 0 &&
626 Len() >= InSuffixLen &&
628 }
629 else
630 {
631 return InSuffixLen > 0 &&
632 Len() >= InSuffixLen &&
634 }
635}
636
638{
639 if (Character != 0)
640 {
641 if (Data.Num() == 0)
642 {
643 *this += Character;
644 }
645 else
646 {
647 Data.Insert(Character, Index);
648 }
649 }
650}
651
653{
654 if (Characters.Len())
655 {
656 if (Data.Num() == 0)
657 {
658 *this += Characters;
659 }
660 else
661 {
662 Data.Insert(Characters.Data.GetData(), Characters.Len(), Index);
663 }
664 }
665}
666
668{
669 // The clamping behavior below that we are inheriting from the (Index, Count, AllowShrinking) overload is unfortunate, as it pessimizes this call.
670 if (FMath::Clamp(1, 0, Len()-Index) == 1)
671 {
673 }
674}
675
680
682{
683 if (InPrefixLen == 0)
684 {
685 return false;
686 }
687
688 if (StartsWith(InPrefix, InPrefixLen, SearchCase))
689 {
691 return true;
692 }
693
694 return false;
695}
696
698{
699 if (InSuffixLen == 0)
700 {
701 return false;
702 }
703
704 if (EndsWith(InSuffix, InSuffixLen, SearchCase))
705 {
707 return true;
708 }
709
710 return false;
711}
712
714{
715
716template <typename LhsType, typename RhsType>
718{
719 Lhs.CheckInvariants();
721
722 if (Lhs.IsEmpty())
723 {
724 return Forward<RhsType>(Rhs);
725 }
726
728
729 UE_STRING_CLASS Result(Forward<LhsType>(Lhs), /* extra slack */ RhsLen);
731
732 return Result;
733}
734
735template <typename LhsCharType, typename RhsType>
737{
738 using ElementType = UE_STRING_CLASS::ElementType;
739
742 if (LhsLen == 0)
743 {
744 return Forward<RhsType>(Rhs);
745 }
746
747 int32 RhsLen = Rhs.Len();
748
749 // This is not entirely optimal, as if the Rhs is an rvalue and has enough slack space to hold Lhs, then
750 // the memory could be reused here without constructing a new object. However, until there is proof otherwise,
751 // I believe this will be relatively rare and isn't worth making the code a lot more complex right now.
755
759 *(ResultData + LhsLen + RhsLen) = CHARTEXT(ElementType, '\0');
760
761 return Result;
762}
763
764template <typename LhsType, typename RhsCharType>
766{
767 Lhs.CheckInvariants();
769 if (RhsLen == 0)
770 {
771 return Forward<LhsType>(Lhs);
772 }
773
774 UE_STRING_CLASS Result(Forward<LhsType>(Lhs), /* extra slack */ RhsLen);
776
777 return Result;
778}
779
780template <typename LhsCharType, typename RhsType>
782{
783 checkSlow(Lhs);
784 if (!Lhs)
785 {
786 return Forward<RhsType>(Rhs);
787 }
788
790}
791
792template <typename LhsType, typename RhsCharType>
794{
795 checkSlow(Rhs);
796 if (!Rhs)
797 {
798 return Forward<LhsType>(Lhs);
799 }
801}
802
803} // namespace UE::String::Private
804
805UE_STRING_CLASS UE_STRING_CLASS::ConcatFF(const UE_STRING_CLASS& Lhs, const UE_STRING_CLASS& Rhs) { return UE::String::Private::PREPROCESSOR_JOIN(ConcatStrings_, UE_STRING_CLASS)(Lhs, Rhs); }
806UE_STRING_CLASS UE_STRING_CLASS::ConcatFF(UE_STRING_CLASS&& Lhs, const UE_STRING_CLASS& Rhs) { return UE::String::Private::PREPROCESSOR_JOIN(ConcatStrings_, UE_STRING_CLASS)(MoveTemp(Lhs), Rhs); }
807UE_STRING_CLASS UE_STRING_CLASS::ConcatFF(const UE_STRING_CLASS& Lhs, UE_STRING_CLASS&& Rhs) { return UE::String::Private::PREPROCESSOR_JOIN(ConcatStrings_, UE_STRING_CLASS)(Lhs, MoveTemp(Rhs)); }
809UE_STRING_CLASS UE_STRING_CLASS::ConcatFC(const UE_STRING_CLASS& Lhs, const ElementType* Rhs) { return UE::String::Private::PREPROCESSOR_JOIN(ConcatStringPtr_, UE_STRING_CLASS)(Lhs, Rhs); }
810UE_STRING_CLASS UE_STRING_CLASS::ConcatFC(UE_STRING_CLASS&& Lhs, const ElementType* Rhs) { return UE::String::Private::PREPROCESSOR_JOIN(ConcatStringPtr_, UE_STRING_CLASS)(MoveTemp(Lhs), Rhs); }
811UE_STRING_CLASS UE_STRING_CLASS::ConcatCF(const ElementType* Lhs, const UE_STRING_CLASS& Rhs) { return UE::String::Private::PREPROCESSOR_JOIN(ConcatPtrString_, UE_STRING_CLASS)(Lhs, Rhs); }
812UE_STRING_CLASS UE_STRING_CLASS::ConcatCF(const ElementType* Lhs, UE_STRING_CLASS&& Rhs) { return UE::String::Private::PREPROCESSOR_JOIN(ConcatPtrString_, UE_STRING_CLASS)(Lhs, MoveTemp(Rhs)); }
813UE_STRING_CLASS UE_STRING_CLASS::ConcatFR(const UE_STRING_CLASS& Lhs, const ElementType* Rhs, int32 RhsLen) { return UE::String::Private::PREPROCESSOR_JOIN(ConcatStringRange_, UE_STRING_CLASS)(Lhs, Rhs, RhsLen); }
814UE_STRING_CLASS UE_STRING_CLASS::ConcatFR(UE_STRING_CLASS&& Lhs, const ElementType* Rhs, int32 RhsLen) { return UE::String::Private::PREPROCESSOR_JOIN(ConcatStringRange_, UE_STRING_CLASS)(MoveTemp(Lhs), Rhs, RhsLen); }
815UE_STRING_CLASS UE_STRING_CLASS::ConcatRF(const ElementType* Lhs, int32 LhsLen, const UE_STRING_CLASS& Rhs) { return UE::String::Private::PREPROCESSOR_JOIN(ConcatRangeString_, UE_STRING_CLASS)(Lhs, LhsLen, Rhs); }
816UE_STRING_CLASS UE_STRING_CLASS::ConcatRF(const ElementType* Lhs, int32 LhsLen, UE_STRING_CLASS&& Rhs) { return UE::String::Private::PREPROCESSOR_JOIN(ConcatRangeString_, UE_STRING_CLASS)(Lhs, LhsLen, MoveTemp(Rhs)); }
817
825{
826 int32 DataNum = Data.Num();
827 if (StrLength == 0)
828 {
829 if (DataNum > 1 && Data[DataNum - 2] != CHARTEXT(ElementType, '/') && Data[DataNum - 2] != CHARTEXT(ElementType, '\\'))
830 {
831 Data[DataNum - 1] = CHARTEXT(ElementType, '/');
832 Data.Add(CHARTEXT(ElementType, '\0'));
833 }
834 }
835 else
836 {
837 if (DataNum > 0)
838 {
839 if (DataNum > 1 && Data[DataNum - 2] != CHARTEXT(ElementType, '/') && Data[DataNum - 2] != CHARTEXT(ElementType, '\\') && *Str != CHARTEXT(ElementType, '/'))
840 {
841 Data[DataNum - 1] = CHARTEXT(ElementType, '/');
842 }
843 else
844 {
846 --DataNum;
847 }
848 }
849
851 Data.Append(Str, StrLength);
852 Data.Add(CHARTEXT(ElementType, '\0'));
853 }
854}
855
862
864{
865 if (Count >= 0)
866 {
867 const int32 Length = Len();
868 const int32 RequestedStart = Start;
869 Start = FMath::Clamp(Start, 0, Length);
871 return UE_STRING_CLASS::ConstructFromPtrSize(**this + Start, End-Start);
872 }
873
874 return UE_STRING_CLASS();
875}
876
878{
879 MidInline(Start, Count, EAllowShrinking::No);
880 return MoveTemp(*this);
881}
882
883void UE_STRING_CLASS::ReplaceCharInlineCaseSensitive(const ElementType From, const ElementType To)
884{
885 for (ElementType& Character : Data)
886 {
887 Character = Character == From ? To : Character;
888 }
889}
890
891void UE_STRING_CLASS::ReplaceCharInlineIgnoreCase(const ElementType From, const ElementType To)
892{
894 ReplaceCharInlineCaseSensitive(OtherCaseFrom, To);
895 ReplaceCharInlineCaseSensitive(From, To);
896}
897
903
905{
906 UE_STRING_CLASS Result(*this);
907 Result.TrimStartAndEndInline();
908 return Result;
909}
910
912{
913 TrimStartAndEndInline();
914 return MoveTemp(*this);
915}
916
918{
919 int32 Pos = 0;
920 while(Pos < Len() && TChar<ElementType>::IsWhitespace((*this)[Pos]))
921 {
922 Pos++;
923 }
924 RemoveAt(0, Pos);
925}
926
928{
929 UE_STRING_CLASS Result(*this);
930 Result.TrimStartInline();
931 return Result;
932}
933
935{
936 TrimStartInline();
937 return MoveTemp(*this);
938}
939
941{
942 int32 End = Len();
943 while(End > 0 && TChar<ElementType>::IsWhitespace((*this)[End - 1]))
944 {
945 End--;
946 }
947 RemoveAt(End, Len() - End);
948}
949
951{
952 UE_STRING_CLASS Result(*this);
953 Result.TrimEndInline();
954 return Result;
955}
956
958{
959 TrimEndInline();
960 return MoveTemp(*this);
961}
962
964{
965 bool bQuotesWereRemoved=false;
966 int32 Start = 0, Count = Len();
967 if (Count > 0)
968 {
969 if ((*this)[0] == CharacterToTrim)
970 {
971 Start++;
972 Count--;
974 }
975
976 if (Len() > 1 && (*this)[Len() - 1] == CharacterToTrim)
977 {
978 Count--;
980 }
981 }
982
983 if (bCharRemoved != nullptr)
984 {
986 }
988}
989
994
996{
997 UE_STRING_CLASS Result(*this);
999 return Result;
1000}
1001
1003{
1004 TrimQuotesInline(bQuotesRemoved);
1005 return MoveTemp(*this);
1006}
1007
1009{
1010 UE_STRING_CLASS Result(*this);
1012 return Result;
1013}
1014
1016{
1017 TrimCharInline(CharacterToTrim, bCharRemoved);
1018 return MoveTemp(*this);
1019}
1020
1028
1030{
1031 UE_STRING_CLASS New(*this);
1032 New.ReverseString();
1033 return New;
1034}
1035
1037{
1038 ReverseString();
1039 return MoveTemp(*this);
1040}
1041
1043{
1044 if (Len() > 0)
1045 {
1046 ElementType* StartChar = &(*this)[0];
1047 ElementType* EndChar = &(*this)[Len()-1];
1049 do
1050 {
1051 TempChar = *StartChar; // store the current value of StartChar
1052 *StartChar = *EndChar; // change the value of StartChar to the value of EndChar
1053 *EndChar = TempChar; // change the value of EndChar to the character that was previously at StartChar
1054
1055 StartChar++;
1056 EndChar--;
1057
1058 } while (StartChar < EndChar); // repeat until we've reached the midpoint of the string
1059 }
1060}
1061
1063{
1065
1066 int32 Dec = 0;
1067 for (int32 x = Number.Len()-1 ; x > -1 ; --x)
1068 {
1069 Result += Number.Mid(x,1);
1070
1071 Dec++;
1072 if (Dec == 3 && x > 0)
1073 {
1074 Result += CHARTEXT(ElementType, ',');
1075 Dec = 0;
1076 }
1077 }
1078
1079 return Result.Reverse();
1080}
1081
1090{
1091 int32 Length = FMath::Max(Len(), MinCharacters);
1092 Ar << Length;
1093
1094 for (int32 CharIndex=0; CharIndex<Len(); CharIndex++)
1095 {
1097 Ar << AnsiChar;
1098 }
1099
1100 // Zero pad till minimum number of characters are written.
1101 for (int32 i = Len(); i < Length; i++)
1102 {
1103 ANSICHAR NullChar = 0;
1104 Ar << NullChar;
1105 }
1106}
1107
1109{
1110 const ElementType* DigitToChar = CHARTEXT(ElementType, "9876543210123456789");
1111 constexpr int32 ZeroDigitIndex = 9;
1112 bool bIsNumberNegative = Num < 0;
1113 const int32 TempBufferSize = 16; // 16 is big enough
1114 ElementType TempNum[TempBufferSize];
1115 int32 TempAt = TempBufferSize; // fill the temp string from the top down.
1116
1117 // Convert to string assuming base ten.
1118 do
1119 {
1121 Num /= 10;
1122 } while (Num);
1123
1125 {
1127 }
1128
1129 const ElementType* CharPtr = TempNum + TempAt;
1130 const int32 NumChars = TempBufferSize - TempAt;
1132}
1133
1134
1136{
1137 return TCString<ElementType>::ToBool(**this);
1138}
1139
1141{
1142 UE_STRING_CLASS Result;
1143 Result.Reserve(SrcSize * 3);
1144 // Convert and append each byte in the buffer
1145 for (uint32 Count = 0; Count < SrcSize; Count++)
1146 {
1147 Result += UE_STRING_CLASS::Printf(CHARTEXT(FmtCharType, "%03d"),(uint8)SrcBuffer[Count]);
1148 }
1149 return Result;
1150}
1151
1152bool UE_STRING_CLASS::ToBlob(const UE_STRING_CLASS& Source, uint8* DestBuffer, const uint32 DestSize)
1153{
1154 // Make sure the buffer is at least half the size and that the string is an
1155 // even number of characters long
1156 if (DestSize >= (uint32)(Source.Len() / 3) &&
1157 (Source.Len() % 3) == 0)
1158 {
1160 ConvBuffer[3] = CHARTEXT(ElementType, '\0');
1161 int32 WriteIndex = 0;
1162 // Walk the string 3 chars at a time
1163 for (int32 Index = 0; Index < Source.Len(); Index += 3, WriteIndex++)
1164 {
1165 ConvBuffer[0] = Source[Index];
1166 ConvBuffer[1] = Source[Index + 1];
1167 ConvBuffer[2] = Source[Index + 2];
1168 DestBuffer[WriteIndex] = (uint8)TCString<ElementType>::Atoi(ConvBuffer);
1169 }
1170 return true;
1171 }
1172 return false;
1173}
1174
1176{
1177 UE_STRING_CLASS Result;
1178 Result.Reserve(SrcSize * 2);
1179 // Convert and append each byte in the buffer
1180 for (uint32 Count = 0; Count < SrcSize; Count++)
1181 {
1182 Result += UE_STRING_CLASS::Printf(CHARTEXT(FmtCharType, "%02X"), (uint8)SrcBuffer[Count]);
1183 }
1184 return Result;
1185}
1186
1187bool UE_STRING_CLASS::ToHexBlob(const UE_STRING_CLASS& Source, uint8* DestBuffer, const uint32 DestSize)
1188{
1189 // Make sure the buffer is at least half the size and that the string is an
1190 // even number of characters long
1191 if (DestSize >= (uint32)(Source.Len() / 2) &&
1192 (Source.Len() % 2) == 0)
1193 {
1195 ConvBuffer[2] = CHARTEXT(ElementType, '\0');
1196 int32 WriteIndex = 0;
1197 // Walk the string 2 chars at a time
1198 ElementType* End = nullptr;
1199 for (int32 Index = 0; Index < Source.Len(); Index += 2, WriteIndex++)
1200 {
1201 ConvBuffer[0] = Source[Index];
1202 ConvBuffer[1] = Source[Index + 1];
1203 DestBuffer[WriteIndex] = (uint8)TCString<ElementType>::Strtoi(ConvBuffer, &End, 16);
1204 }
1205 return true;
1206 }
1207 return false;
1208}
1209
1211{
1212 // Avoids negative zero
1214
1215 // First create the string
1217 if (!TempString.IsNumeric())
1218 {
1219 // String did not format as a valid decimal number so avoid messing with it
1220 return TempString;
1221 }
1222
1223 // Trim all trailing zeros (up-to and including the decimal separator) from the fractional part of the number
1226 for (int32 CharIndex = TempString.Len() - 1; CharIndex >= 0; --CharIndex)
1227 {
1229 if (Char == CHARTEXT(ElementType, '.'))
1230 {
1233 break;
1234 }
1235 if (TrimIndex == INDEX_NONE && Char != CHARTEXT(ElementType, '0'))
1236 {
1237 TrimIndex = CharIndex + 1;
1238 }
1239 }
1242
1243 // Pad the number back to the minimum number of fractional digits
1244 if (InMinFractionalDigits > 0)
1245 {
1247 {
1248 // Re-add the decimal separator
1249 TempString.AppendChar(CHARTEXT(ElementType, '.'));
1250 }
1251
1254 if (FractionalDigitsToPad > 0)
1255 {
1257 for (int32 Cx = 0; Cx < FractionalDigitsToPad; ++Cx)
1258 {
1259 TempString.AppendChar(CHARTEXT(ElementType, '0'));
1260 }
1261 }
1262 }
1263
1264 return TempString;
1265}
1266
1268{
1269 ElementType Temp[2]= { Ch, CHARTEXT(ElementType, '\0') };
1270 return UE_STRING_CLASS(Temp);
1271}
1272
1273
1275{
1276 check(NumCharacters >= 0);
1277
1278 UE_STRING_CLASS Temp;
1279 Temp.Data.AddUninitialized(NumCharacters+1);
1280 for (int32 Cx = 0; Cx < NumCharacters; ++Cx)
1281 {
1282 Temp[Cx] = Char;
1283 }
1284 Temp.Data[NumCharacters] = CHARTEXT(ElementType, '\0');
1285 return Temp;
1286}
1287
1289{
1290 int32 Pad = ChCount - Len();
1291
1292 if (Pad > 0)
1293 {
1294 return ChrN(Pad, CHARTEXT(ElementType, ' ')) + *this;
1295 }
1296 else
1297 {
1298 return *this;
1299 }
1300}
1302{
1303 int32 Pad = ChCount - Len();
1304
1305 if (Pad > 0)
1306 {
1307 return *this + ChrN(Pad, CHARTEXT(ElementType, ' '));
1308 }
1309 else
1310 {
1311 return *this;
1312 }
1313}
1314
1316{
1317 if (IsEmpty())
1318 {
1319 return 0;
1320 }
1321
1323}
1324
1326{
1327 check(pchDelim);
1328 OutArray.Reset();
1329 // TODO Legacy behavior: if DelimLength is 0 we return an empty array. Can we change this to return { Text }?
1330 if (pchDelim[0] != '\0')
1331 {
1335 [&OutArray](TStringView<ElementType> Token) { OutArray.Emplace(Token); },
1336 ParseOptions);
1337 }
1338 return OutArray.Num();
1339}
1340
1342{
1343 const ElementType* Target = **this;
1344 int32 TargetLength = Len();
1345
1346 if (SearchCase == ESearchCase::CaseSensitive)
1347 {
1349 Target,
1351 InWildcard,
1354 {
1355 return Lhs == Rhs;
1356 }
1357 );
1358 }
1359 else
1360 {
1362 Target,
1364 InWildcard,
1367 {
1369 }
1370 );
1371 }
1372}
1373
1374
1377{
1378 // default array of White Spaces, the last entry can be replaced with the optional pchExtraDelim string
1379 // (if you want to split on white space and another character)
1380 const ElementType* WhiteSpace[] =
1381 {
1382 CHARTEXT(ElementType, " "),
1383 CHARTEXT(ElementType, "\t"),
1384 CHARTEXT(ElementType, "\r"),
1385 CHARTEXT(ElementType, "\n"),
1386 CHARTEXT(ElementType, ""),
1387 };
1388
1389 // start with just the standard whitespaces
1391 // if we got one passed in, use that in addition
1393 {
1395 }
1396
1398}
1399
1401{
1402 // default array of LineEndings
1403 static const ElementType* LineEndings[] =
1404 {
1405 CHARTEXT(ElementType, "\r\n"),
1406 CHARTEXT(ElementType, "\r"),
1407 CHARTEXT(ElementType, "\n"),
1408 };
1409
1410 // start with just the standard line endings
1413}
1414
1416{
1417 // Make sure the delimit string is not null or empty
1419 OutArray.Reset();
1420 const ElementType* Start = Data.GetData();
1421 const int32 Length = Len();
1423
1424 // Iterate through string.
1425 for(int32 i = 0; i < Length;)
1426 {
1429
1430 // Attempt each delimiter.
1432 {
1434
1435 // If we found a delimiter...
1437 {
1438 // Mark the end of the substring.
1440 break;
1441 }
1442 }
1443
1445 {
1447 // If we're not culling empty strings or if we are but the string isn't empty anyways...
1448 if(!bInCullEmpty || SubstringLength != 0)
1449 {
1450 // ... add new string from substring beginning up to the beginning of this delimiter.
1452 }
1453 // Next substring begins at the end of the discovered delimiter.
1456 }
1457 else
1458 {
1459 ++i;
1460 }
1461 }
1462
1463 // Add any remaining characters after the last delimiter.
1465 // If we're not culling empty strings or if we are but the string isn't empty anyways...
1466 if(!bInCullEmpty || SubstringLength != 0)
1467 {
1468 // ... add new string from substring beginning up to the beginning of this delimiter.
1470 }
1471
1472 return OutArray.Num();
1473}
1474
1476{
1477 // Previous code used to accidentally accept a nullptr replacement string - this is no longer accepted.
1478 check(To);
1479
1480 if (IsEmpty() || !From || !*From)
1481 {
1482 return *this;
1483 }
1484
1485 // get a pointer into the character data
1486 const ElementType* Travel = Data.GetData();
1487
1488 // precalc the lengths of the replacement strings
1491
1492 UE_STRING_CLASS Result;
1493 while (true)
1494 {
1495 // look for From in the remaining string
1497 if (!FromLocation)
1498 {
1499 break;
1500 }
1501
1502 // copy everything up to FromLocation
1504
1505 // copy over the To
1506 Result.AppendChars(To, ToLength);
1507
1509 }
1510
1511 // copy anything left over
1512 Result += Travel;
1513
1514 return Result;
1515}
1516
1518{
1519 ReplaceInline(From, To, SearchCase);
1520 return MoveTemp(*this);
1521}
1522
1524{
1526
1527 if (Len() > 0
1528 && From != nullptr && *From != 0
1529 && To != nullptr && (SearchCase == ESearchCase::IgnoreCase || TCString<ElementType>::Strcmp(From, To) != 0))
1530 {
1533
1535 {
1536 ElementType* Pos = SearchCase == ESearchCase::IgnoreCase ? TCString<ElementType>::Stristr(&(*this)[0], From) : TCString<ElementType>::Strstr(&(*this)[0], From);
1537 while (Pos != nullptr)
1538 {
1540
1541 // TCString<ElementType>::Strcpy now inserts a terminating zero so can't use that
1542 for (int32 i = 0; i < NumCharsToInsert; i++)
1543 {
1544 Pos[i] = To[i];
1545 }
1546
1547 if (Pos + NumCharsToReplace - **this < Len())
1548 {
1550 }
1551 else
1552 {
1553 break;
1554 }
1555 }
1556 }
1557 else if (Contains(From, SearchCase))
1558 {
1560
1561 // get a pointer into the character data
1562 ElementType* WritePosition = (ElementType*)Copy.Data.GetData();
1563 // look for From in the remaining string
1565 while (SearchPosition != nullptr)
1566 {
1568
1569 // replace the first letter of the From with 0 so we can do a strcpy (via operator+=)
1571
1572 // copy everything up to the SearchPosition
1573 (*this) += WritePosition;
1574
1575 // copy over the replacement string
1576 (*this) += To;
1577
1578 // restore the letter, just so we don't have 0's in the string
1579 *SearchPosition = *From;
1580
1583 }
1584
1585 // copy anything left over
1586 (*this) += WritePosition;
1587 }
1588 }
1589
1590 return ReplacementCount;
1591}
1592
1593
1598{
1599 if (Contains(CHARTEXT(ElementType, "\""), ESearchCase::CaseSensitive))
1600 {
1602
1603 const ElementType* pChar = *Copy;
1604
1605 bool bEscaped = false;
1606 while (*pChar != 0)
1607 {
1608 if (bEscaped)
1609 {
1610 bEscaped = false;
1611 }
1612 else if (*pChar == ElementType('\\'))
1613 {
1614 bEscaped = true;
1615 }
1616 else if (*pChar == ElementType('"'))
1617 {
1618 *this += ElementType('\\');
1619 }
1620
1621 *this += *pChar++;
1622 }
1623 }
1624
1625 return MoveTemp(*this);
1626}
1627
1629{
1630 // Always replace \\ first to avoid double-escaping characters
1637};
1638
1640{
1641 if (Len() > 0 && (Chars == nullptr || Chars->Num() > 0))
1642 {
1644
1646 {
1647 if (Chars == nullptr || Chars->Contains(*(CharToEscapeSeqMap[ChIdx][0])))
1648 {
1649 // use ReplaceInline as that won't create a copy of the string if the character isn't found
1651 }
1652 }
1653 }
1654}
1655
1657{
1658 if (Len() > 0 && (Chars == nullptr || Chars->Num() > 0))
1659 {
1661
1662 // Spin CharToEscapeSeqMap backwards to ensure we're doing the inverse of ReplaceCharWithEscapedChar
1664 {
1665 --ChIdx;
1666
1667 if (Chars == nullptr || Chars->Contains(*(CharToEscapeSeqMap[ChIdx][0])))
1668 {
1669 // use ReplaceInline as that won't create a copy of the string if the character isn't found
1671 }
1672 }
1673 }
1674}
1675
1681{
1682 //must call this with at least 1 space so the modulus operation works
1683 check(InSpacesPerTab > 0);
1684
1685 int32 TabIndex = 0;
1687 {
1690
1691 //for a tab size of 4,
1693 if (LineBegin == INDEX_NONE)
1694 {
1695 LineBegin = 0;
1696 }
1697 const int32 CharactersOnLine = (Len()-LineBegin);
1698
1700 for (int32 i = 0; i < NumSpacesForTab; ++i)
1701 {
1703 }
1705 }
1706}
1707
1708// This starting size catches 99.97% of printf calls - there are about 700k printf calls per level
1709#define STARTING_BUFFER_SIZE 512
1710
1711UE_STRING_CLASS UE_STRING_CLASS::PrintfImpl(const ElementType* Fmt, ...)
1712{
1713 int32 BufferSize = STARTING_BUFFER_SIZE;
1715 ElementType* Buffer = StartingBuffer;
1716 int32 Result = -1;
1717
1718 // First try to print to a stack allocated location
1719 GET_TYPED_VARARGS_RESULT(ElementType, Buffer, BufferSize, BufferSize-1, Fmt, Fmt, Result);
1720
1721 // If that fails, start allocating regular memory
1722 if (Result == -1)
1723 {
1724 Buffer = nullptr;
1725 while(Result == -1)
1726 {
1727 BufferSize *= 2;
1728 Buffer = (ElementType*) FMemory::Realloc(Buffer, BufferSize * sizeof(ElementType));
1729 GET_TYPED_VARARGS_RESULT(ElementType, Buffer, BufferSize, BufferSize-1, Fmt, Fmt, Result);
1730 };
1731 }
1732
1733 Buffer[Result] = CHARTEXT(ElementType, '\0');
1734
1735 UE_STRING_CLASS ResultString(Buffer);
1736
1737 if (BufferSize != STARTING_BUFFER_SIZE)
1738 {
1740 }
1741
1742 return ResultString;
1743}
1744
1745void UE_STRING_CLASS::AppendfImpl(UE_STRING_CLASS& AppendToMe, const ElementType* Fmt, ...)
1746{
1747 int32 BufferSize = STARTING_BUFFER_SIZE;
1750 int32 Result = -1;
1751
1752 // First try to print to a stack allocated location
1753 GET_TYPED_VARARGS_RESULT(ElementType, Buffer, BufferSize, BufferSize - 1, Fmt, Fmt, Result);
1754
1755 // If that fails, start allocating regular memory
1756 if (Result == -1)
1757 {
1758 Buffer = nullptr;
1759 while (Result == -1)
1760 {
1761 BufferSize *= 2;
1762 Buffer = (ElementType*)FMemory::Realloc(Buffer, BufferSize * sizeof(ElementType));
1763 GET_TYPED_VARARGS_RESULT(ElementType, Buffer, BufferSize, BufferSize - 1, Fmt, Fmt, Result);
1764 };
1765 }
1766
1767 Buffer[Result] = CHARTEXT(ElementType, '\0');
1768
1769 AppendToMe += Buffer;
1770
1771 if (BufferSize != STARTING_BUFFER_SIZE)
1772 {
1774 }
1775}
1776
1777static_assert(PLATFORM_LITTLE_ENDIAN, PREPROCESSOR_TO_STRING(UE_STRING_CLASS) " serialization needs updating to support big-endian platforms!");
1778
1780{
1782
1783 #if UE_STRING_CHARTYPE_IS_TCHAR
1784 // > 0 for ANSICHAR, < 0 for UTF16CHAR serialization
1785 static_assert(sizeof(UTF16CHAR) == sizeof(UCS2CHAR), "UTF16CHAR and UCS2CHAR are assumed to be the same size!");
1786 #endif
1787
1788 if (Ar.IsLoading())
1789 {
1790 int32 SaveNum = 0;
1791 Ar << SaveNum;
1792
1793 // Validate loaded num to ensure the archive is in a good state
1794 #if UE_STRING_CHARTYPE_IS_TCHAR
1795 bool bLoadUnicodeChar = SaveNum < 0;
1796 if (bLoadUnicodeChar)
1797 {
1798 // If SaveNum cannot be negated due to integer overflow, Ar is corrupted.
1799 if (SaveNum == MIN_int32)
1800 {
1801 Ar.SetCriticalError();
1802 UE_LOG(LogCore, Error, TEXT("Archive is corrupted"));
1803 return Ar;
1804 }
1805
1806 SaveNum = -SaveNum;
1807 }
1808 #else
1809 if (SaveNum < 0)
1810 {
1811 Ar.SetCriticalError();
1812 UE_LOG(LogCore, Error, TEXT("Archive is corrupted"));
1813 return Ar;
1814 }
1815 #endif
1816
1818 // Protect against network packets allocating too much memory
1819 if ((MaxSerializeSize > 0) && (SaveNum > MaxSerializeSize))
1820 {
1821 Ar.SetCriticalError();
1822 UE_LOG(LogCore, Error, TEXT("String is too large (Size: %i, Max: %" INT64_FMT ")"), SaveNum, MaxSerializeSize);
1823 return Ar;
1824 }
1825
1826 #if UE_STRING_CHARTYPE_IS_TCHAR
1827 // Resize the array only if it passes the above tests to prevent rogue packets from crashing
1828 Str.Data.Empty(SaveNum);
1829 Str.Data.AddUninitialized(SaveNum);
1830
1831 if (SaveNum)
1832 {
1833 if (bLoadUnicodeChar)
1834 {
1835 // read in the unicode string
1837 Ar.Serialize(Passthru.Get(), SaveNum * sizeof(UCS2CHAR));
1838 if (Ar.IsByteSwapping())
1839 {
1840 for (int32 CharIndex = 0; CharIndex < SaveNum; ++CharIndex)
1841 {
1842 Passthru.Get()[CharIndex] = ByteSwap(Passthru.Get()[CharIndex]);
1843 }
1844 }
1845 // Ensure the string has a null terminator
1846 Passthru.Get()[SaveNum - 1] = '\0';
1847 Passthru.Apply();
1848
1849 // Inline combine any surrogate pairs in the data when loading into a UTF-32 string
1851
1852 // Since Microsoft's vsnwprintf implementation raises an invalid parameter warning
1853 // with a character of 0xffff, scan for it and terminate the string there.
1854 // 0xffff isn't an actual Unicode character anyway.
1855 int Index = 0;
1856 if (Str.FindChar(0xffff, Index))
1857 {
1858 Str[Index] = CHARTEXT(ElementType, '\0');
1860 }
1861 }
1862 else
1863 {
1865 Ar.Serialize(Passthru.Get(), SaveNum * sizeof(ANSICHAR));
1866 // Ensure the string has a null terminator
1867 Passthru.Get()[SaveNum - 1] = '\0';
1868 Passthru.Apply();
1869 }
1870
1871 // Throw away empty string.
1872 if (SaveNum == 1)
1873 {
1874 Str.Data.Empty();
1875 }
1876 }
1877 #else
1878 if (SaveNum)
1879 {
1880 Str.Data.Empty(SaveNum + 1);
1881 Str.Data.AddUninitialized(SaveNum + 1);
1882
1884 Ar.Serialize(Passthru.Get(), SaveNum * sizeof(ElementType));
1885 // Ensure the string has a null terminator
1886 Passthru.Get()[SaveNum] = UTF8TEXT('\0');
1887 Passthru.Apply();
1888
1889 // We don't need to throw away empty strings here, unlike above, because we never saved a null terminator
1890 }
1891 else
1892 {
1893 Str.Empty();
1894 }
1895 #endif
1896 }
1897 else
1898 {
1899 Str.Data.CountBytes(Ar);
1900
1901 #if UE_STRING_CHARTYPE_IS_TCHAR
1903 if (bSaveUnicodeChar)
1904 {
1905 // This preprocessor block should not be necessary when the StrCast below understands UTF16CHAR.
1906 FTCHARToUTF16 UTF16String(*Str, Str.Len() + 1); // include the null terminator
1907 int32 Num = UTF16String.Length() + 1; // include the null terminator
1908
1909 int32 SaveNum = -Num;
1910 Ar << SaveNum;
1911
1912 if (Num)
1913 {
1914 if (!Ar.IsByteSwapping())
1915 {
1916 Ar.Serialize((void*)UTF16String.Get(), sizeof(UTF16CHAR) * Num);
1917 }
1918 else
1919 {
1921 for (int32 CharIndex = 0; CharIndex < Num; ++CharIndex)
1922 {
1924 }
1925 Ar.Serialize((void*)Swapped.GetData(), sizeof(UTF16CHAR) * Num);
1926 }
1927 }
1928 }
1929 else
1930 {
1931 int32 Num = Str.Data.Num();
1932 Ar << Num;
1933
1934 if (Num)
1935 {
1936 Ar.Serialize((void*)StrCast<ANSICHAR>(Str.Data.GetData(), Num).Get(), sizeof(ANSICHAR) * Num);
1937 }
1938 }
1939 #else
1940 // Unlike the TCHAR case, we don't bother to save the null terminator
1941 int32 SaveNum = Str.Len();
1942 Ar << SaveNum;
1943
1944 if (SaveNum)
1945 {
1946 auto CompactString = StrCast<UTF8CHAR>(Str.Data.GetData(), SaveNum);
1947 Ar.Serialize((void*)CompactString.Get(), sizeof(UTF8CHAR) * CompactString.Length());
1948 }
1949 #endif
1950 }
1951
1952 return Ar;
1953}
1954
1956{
1957 return UE::String::HexToBytes(HexString, OutBytes);
1958}
1959
1961{
1962 using ElementType = UE_STRING_CLASS::ElementType;
1963
1964 check(StartSearch >= 0 && StartSearch <= TargetString.Len());// Check for usage, we do not accept INDEX_NONE like other string functions
1965
1966 const ElementType* const StartPosition = (*TargetString) + StartSearch;
1967 const ElementType* CurrPosition = StartPosition;
1969
1970 // Move to first open parenthesis
1971 while (*CurrPosition != 0 && *CurrPosition != CHARTEXT(ElementType, '('))
1972 {
1973 ++CurrPosition;
1974 }
1975
1976 // Did we find the open parenthesis
1977 if (*CurrPosition == CHARTEXT(ElementType, '('))
1978 {
1980 ++CurrPosition;
1981
1982 while (*CurrPosition != 0 && ParenthesisCount > 0)
1983 {
1984 if (*CurrPosition == CHARTEXT(ElementType, '('))
1985 {
1987 }
1988 else if (*CurrPosition == CHARTEXT(ElementType, ')'))
1989 {
1991 }
1992 ++CurrPosition;
1993 }
1994
1995 // Did we find the matching close parenthesis
1996 if (ParenthesisCount == 0 && *(CurrPosition - 1) == CHARTEXT(ElementType, ')'))
1997 {
1998 return StartSearch + UE_PTRDIFF_TO_INT32((CurrPosition - 1) - StartPosition);
1999 }
2000 }
2001
2002 return INDEX_NONE;
2003}
2004
2005UE_STRING_CLASS SlugStringForValidName(const UE_STRING_CLASS& DisplayString, const UE_STRING_CLASS::ElementType* ReplaceWith /*= CHARTEXT(ElementType, "")*/)
2006{
2007 using ElementType = UE_STRING_CLASS::ElementType;
2008
2009 UE_STRING_CLASS GeneratedName = DisplayString;
2010
2011 // Convert the display label, which may consist of just about any possible character, into a
2012 // suitable name for a UObject (remove whitespace, certain symbols, etc.)
2013 {
2015 {
2016 const ElementType TestChar[2] = { (ElementType)INVALID_OBJECTNAME_CHARACTERS[BadCharacterIndex], CHARTEXT(ElementType, '\0') };
2018 }
2019 }
2020
2021 return GeneratedName;
2022}
2023
2024#undef UE_INCLUDETOOL_IGNORE_INCONSISTENT_STATE
EAllowShrinking
Definition AllowShrinking.h:10
#define INT64_FMT
Definition AndroidPlatformString.h:59
#define PLATFORM_LITTLE_ENDIAN
Definition AndroidPlatform.h:38
#define FORCEINLINE
Definition AndroidPlatform.h:140
#define UE_STRING_CLASS
Definition AnsiString.cpp:6
#define UE_STRING_CHARTYPE
Definition AnsiString.cpp:7
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define check(expr)
Definition AssertionMacros.h:314
#define checkf(expr, format,...)
Definition AssertionMacros.h:315
T ByteSwap(T Value)
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define UE_PTRDIFF_TO_INT32(argument)
Definition CoreMiscDefines.h:442
FPlatformTypes::CHAR16 UCS2CHAR
A 16-bit character containing a UCS2 (Unicode, 16-bit, fixed-width) code unit, used for compatibility...
Definition Platform.h:1139
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::UTF32CHAR UTF32CHAR
A 32-bit character containing a UTF32 (Unicode, 32-bit, fixed-width) code unit.
Definition Platform.h:1143
FPlatformTypes::WIDECHAR WIDECHAR
A wide character. Normally a signed type.
Definition Platform.h:1133
#define CHARTEXT(CharType, x)
Definition Platform.h:1291
FPlatformTypes::int64 int64
A 64-bit signed integer.
Definition Platform.h:1127
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
#define UTF8TEXT(x)
Definition Platform.h:1286
FPlatformTypes::UTF8CHAR UTF8CHAR
An 8-bit character containing a UTF8 (Unicode, 8-bit, variable-width) code unit.
Definition Platform.h:1137
FPlatformTypes::CHAR16 UTF16CHAR
A 16-bit character containing a UTF16 (Unicode, 16-bit, variable-width) code unit.
Definition Platform.h:1141
FPlatformTypes::ANSICHAR ANSICHAR
An ANSI character. Normally a signed type.
Definition Platform.h:1131
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define UE_LOG(CategoryName, Verbosity, Format,...)
Definition LogMacros.h:270
T * New(FMemStackBase &Mem, int32 Count=1, int32 Align=DEFAULT_ALIGNMENT)
Definition MemStack.h:259
@ Num
Definition MetalRHIPrivate.h:234
@ Char
Character type.
#define INVALID_OBJECTNAME_CHARACTERS
Definition NameTypes.h:179
#define MAX_int32
Definition NumericLimits.h:25
#define MIN_int32
Definition NumericLimits.h:16
#define Split(a, ahi, alo)
Definition Predicates.inl:204
#define PREPROCESSOR_TO_STRING(Token)
Definition PreprocessorHelpers.h:103
#define PREPROCESSOR_JOIN(TokenA, TokenB)
Definition PreprocessorHelpers.h:104
FArchive & operator<<(FArchive &Ar, UE_STRING_CLASS &Str)
Definition String.cpp.inl:1779
UE_STRING_CLASS SlugStringForValidName(const UE_STRING_CLASS &DisplayString, const UE_STRING_CLASS::ElementType *ReplaceWith)
Definition String.cpp.inl:2005
int32 FindMatchingClosingParenthesis(const UE_STRING_CLASS &TargetString, const int32 StartSearch)
Definition String.cpp.inl:1960
int32 HexToBytes(const UE_STRING_CLASS &HexString, uint8 *OutBytes)
Definition String.cpp.inl:1955
#define STARTING_BUFFER_SIZE
Definition String.cpp.inl:1709
#define UE_ARRAY_COUNT(array)
Definition UnrealTemplate.h:212
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
#define GET_TYPED_VARARGS_RESULT(CharType, msg, msgsize, len, lastarg, fmt, result)
Definition VarArgs.h:29
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Archive.h:1208
virtual void Serialize(void *V, int64 Length)
Definition Archive.h:1689
bool IsByteSwapping()
Definition Archive.h:169
CORE_API void SetCriticalError()
Definition Archive.cpp:319
UE_FORCEINLINE_HINT bool IsLoading() const
Definition Archive.h:236
UE_FORCEINLINE_HINT bool IsForcingUnicode() const
Definition Archive.h:291
UE_FORCEINLINE_HINT int64 GetMaxSerializeSize() const
Definition Archive.h:508
Definition Array.h:670
UE_FORCEINLINE_HINT SizeType AddUninitialized()
Definition Array.h:1664
UE_REWRITE SizeType Num() const
Definition Array.h:1144
void RemoveAt(SizeType Index, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2083
void Reset(SizeType NewSize=0)
Definition Array.h:2246
UE_NODEBUG UE_FORCEINLINE_HINT ElementType * GetData() UE_LIFETIMEBOUND
Definition Array.h:1027
bool Contains(const ComparisonType &Item) const
Definition Array.h:1518
void SetNum(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2308
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
void Append(const TArray< OtherElementType, OtherAllocatorType > &Source)
Definition Array.h:2412
UE_NODEBUG void CountBytes(FArchive &Ar) const
Definition Array.h:1649
ElementType Pop(EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:1196
void SetNumUninitialized(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2369
UE_FORCEINLINE_HINT void Shrink()
Definition Array.h:1278
SizeType Insert(std::initializer_list< ElementType > InitList, const SizeType InIndex)
Definition Array.h:1875
void Empty(SizeType Slack=0)
Definition Array.h:2273
UE_FORCEINLINE_HINT void Reserve(SizeType Number)
Definition Array.h:3016
Definition StringConv.h:832
Definition StringView.h:107
Definition UnrealString.h.inl:55
CORE_API void PathAppend(const ElementType *Str, int32 StrLength)
Definition String.cpp.inl:824
CORE_API void TrimStartAndEndInline()
Definition String.cpp.inl:898
CORE_API void RemoveSpacesInline()
Definition String.cpp.inl:582
UE_FORCEINLINE_HINT DataType & GetCharArray() UE_LIFETIMEBOUND
Definition UnrealString.h.inl:384
bool EndsWith(CharRangeType &&InSuffix, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase) const
Definition UnrealString.h.inl:1595
static CORE_API UE_STRING_CLASS FormatAsNumber(int32 InNumber)
Definition String.cpp.inl:1062
CORE_API int32 ParseIntoArrayWS(TArray< UE_STRING_CLASS > &OutArray, const ElementType *pchExtraDelim=nullptr, bool bInCullEmpty=true) const
Definition String.cpp.inl:1376
CORE_API UE_STRING_CLASS ToLower() const &
Definition String.cpp.inl:559
static CORE_API UE_STRING_CLASS SanitizeFloat(double InFloat, const int32 InMinFractionalDigits=1)
Definition String.cpp.inl:1210
CORE_API void TrimStartInline()
Definition String.cpp.inl:917
CORE_API void ReplaceCharWithEscapedCharInline(const TArray< ElementType > *Chars=nullptr)
Definition String.cpp.inl:1639
CORE_API void InsertAt(int32 Index, ElementType Character)
Definition String.cpp.inl:637
CORE_API void TrimEndInline()
Definition String.cpp.inl:940
bool MatchesWildcard(CharRangeType &&Wildcard, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase) const
Definition UnrealString.h.inl:1652
CORE_API UE_STRING_CLASS TrimStartAndEnd() const &
Definition String.cpp.inl:904
static UE_STRING_CLASS FromInt(int32 Num)
Definition UnrealString.h.inl:2039
UE_STRING_PRINTF_FMT_CHARTYPE FmtCharType
Definition UnrealString.h.inl:59
CORE_API bool Split(const UE_STRING_CLASS &InStr, UE_STRING_CLASS *LeftS, UE_STRING_CLASS *RightS, ESearchCase::Type SearchCase, ESearchDir::Type SearchDir=ESearchDir::FromStart) const
Definition String.cpp.inl:491
bool Contains(CharRangeType &&SubStr, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase, ESearchDir::Type SearchDir=ESearchDir::FromStart) const
Definition UnrealString.h.inl:1209
void CheckInvariants() const
Definition UnrealString.h.inl:318
CORE_API void ReplaceEscapedCharWithCharInline(const TArray< ElementType > *Chars=nullptr)
Definition String.cpp.inl:1656
CORE_API void ReverseString()
Definition String.cpp.inl:1042
static CORE_API UE_STRING_CLASS ChrN(int32 NumCharacters, ElementType Char)
Definition String.cpp.inl:1274
static CORE_API UE_STRING_CLASS FromHexBlob(const uint8 *SrcBuffer, const uint32 SrcSize)
Definition String.cpp.inl:1175
CORE_API void AppendInt(int32 InNum)
Definition String.cpp.inl:1108
CORE_API UE_STRING_CLASS LeftPad(int32 ChCount) const
Definition String.cpp.inl:1288
static CORE_API bool ToBlob(const UE_STRING_CLASS &Source, uint8 *DestBuffer, const uint32 DestSize)
Definition String.cpp.inl:1152
bool RemoveFromStart(CharRangeType &&InPrefix, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase)
Definition UnrealString.h.inl:520
void MidInline(int32 Start, int32 Count=MAX_int32, EAllowShrinking AllowShrinking=EAllowShrinking::Default)
Definition UnrealString.h.inl:1075
CORE_API UE_STRING_CLASS & AppendChar(ElementType InChar)
Definition String.cpp.inl:368
CORE_API void TrimToNullTerminator()
Definition String.cpp.inl:419
CORE_API void SerializeAsANSICharArray(FArchive &Ar, int32 MinCharacters=0) const
Definition String.cpp.inl:1089
CORE_API UE_STRING_CLASS Mid(int32 Start, int32 Count) const &
Definition String.cpp.inl:863
void LeftInline(int32 Count, EAllowShrinking AllowShrinking=EAllowShrinking::Default)
Definition UnrealString.h.inl:984
CORE_API void Reset(int32 NewReservedSize=0)
Definition String.cpp.inl:326
CORE_API void TrimCharInline(ElementType CharacterToTrim, bool *bCharRemoved)
Definition String.cpp.inl:963
CORE_API void ConvertTabsToSpacesInline(const int32 InSpacesPerTab)
Definition String.cpp.inl:1680
static CORE_API UE_STRING_CLASS Chr(ElementType Ch)
Definition String.cpp.inl:1267
CORE_API int32 ReplaceInline(const ElementType *SearchText, const ElementType *ReplacementText, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase)
Definition String.cpp.inl:1523
CORE_API bool ToBool() const
Definition String.cpp.inl:1135
UE_STRING_CLASS & operator=(UE_STRING_CLASS &&)=default
CORE_API int32 ParseIntoArrayLines(TArray< UE_STRING_CLASS > &OutArray, bool bInCullEmpty=true) const
Definition String.cpp.inl:1400
static CORE_API UE_STRING_CLASS ConstructWithSlack(const ANSICHAR *Str, int32 ExtraSlack)
Definition String.cpp.inl:251
static CORE_API bool ToHexBlob(const UE_STRING_CLASS &Source, uint8 *DestBuffer, const uint32 DestSize)
Definition String.cpp.inl:1187
UE_STRING_CLASS()=default
CORE_API int32 ParseIntoArray(TArray< UE_STRING_CLASS > &OutArray, const ElementType *pchDelim, bool bInCullEmpty=true) const
Definition String.cpp.inl:1325
static CORE_API UE_STRING_CLASS ConstructFromPtrSize(const ANSICHAR *Str, int32 Size)
Definition String.cpp.inl:246
UE_STRING_CLASS ReplaceQuotesWithEscapedQuotes() const &
Definition UnrealString.h.inl:1916
CORE_API void Shrink()
Definition String.cpp.inl:336
CORE_API void RemoveAt(int32 Index, EAllowShrinking AllowShrinking=EAllowShrinking::Default)
Definition String.cpp.inl:667
bool StartsWith(CharRangeType &&InPrefix, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase) const
Definition UnrealString.h.inl:1539
static CORE_API UE_STRING_CLASS ConstructFromPtrSizeWithSlack(const ANSICHAR *Str, int32 Size, int32 ExtraSlack)
Definition String.cpp.inl:256
CORE_API void Reserve(int32 CharacterCount)
Definition String.cpp.inl:307
UE_STRING_CHARTYPE ElementType
Definition UnrealString.h.inl:58
CORE_API UE_STRING_CLASS TrimEnd() const &
Definition String.cpp.inl:950
CORE_API UE_STRING_CLASS RightChop(int32 Count) const &
Definition String.cpp.inl:856
CORE_API UE_STRING_CLASS TrimQuotes(bool *bQuotesRemoved=nullptr) const &
Definition String.cpp.inl:995
CORE_API UE_STRING_CLASS TrimChar(ElementType CharacterToTrim, bool *bCharRemoved=nullptr) const &
Definition String.cpp.inl:1008
CORE_API void ToLowerInline()
Definition String.cpp.inl:572
CORE_API void AppendChars(const ANSICHAR *Str, int32 Count)
Definition String.cpp.inl:389
static UE_STRING_CLASS Printf(UE::Core::TCheckedFormatString< FmtCharType, Types... > Fmt, Types... Args)
Definition UnrealString.h.inl:1423
CORE_API UE_STRING_CLASS Replace(const ElementType *From, const ElementType *To, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase) const &
Definition String.cpp.inl:1475
CORE_API UE_STRING_CLASS Reverse() const &
Definition String.cpp.inl:1029
static CORE_API int32 CullArray(TArray< UE_STRING_CLASS > *InOutArray)
Definition String.cpp.inl:1021
CORE_API void Empty()
Definition String.cpp.inl:321
CORE_API UE_STRING_CLASS RightPad(int32 ChCount) const
Definition String.cpp.inl:1301
CORE_API void TrimQuotesInline(bool *bQuotesRemoved=nullptr)
Definition String.cpp.inl:990
static CORE_API UE_STRING_CLASS FromBlob(const uint8 *SrcBuffer, const uint32 SrcSize)
Definition String.cpp.inl:1140
CORE_API void ToUpperInline()
Definition String.cpp.inl:548
CORE_API UE_STRING_CLASS ToUpper() const &
Definition String.cpp.inl:535
CORE_API UE_STRING_CLASS TrimStart() const &
Definition String.cpp.inl:927
CORE_API bool IsNumeric() const
Definition String.cpp.inl:1315
UE_FORCEINLINE_HINT bool FindChar(ElementType InChar, int32 &OutIndex) const
Definition UnrealString.h.inl:1266
bool RemoveFromEnd(CharRangeType &&InSuffix, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase)
Definition UnrealString.h.inl:576
UE_FORCEINLINE_HINT int32 Len() const
Definition UnrealString.h.inl:954
int32 Find(CharRangeType &&SubStr, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase, ESearchDir::Type SearchDir=ESearchDir::FromStart, int32 StartPosition=INDEX_NONE) const
Definition UnrealString.h.inl:1116
Type
Definition CString.h:21
@ IgnoreCase
Definition CString.h:26
@ CaseSensitive
Definition CString.h:23
Type
Definition CString.h:34
@ FromEnd
Definition CString.h:39
@ FromStart
Definition CString.h:36
CORE_API void InlineCombineSurrogates(FString &Str)
Definition String.cpp:49
implementation
Definition PlayInEditorLoadingScope.h:8
FORCEINLINE void ConstructWithSlack(TArray< UE_STRING_CHARTYPE > &Data, const SrcCharType *Src, int32 ExtraSlack)
Definition String.cpp.inl:208
bool MatchesWildcardRecursive(const UE_STRING_CHARTYPE *Target, int32 TargetLength, const UE_STRING_CHARTYPE *Wildcard, int32 WildcardLength, CompareType Compare)
Definition String.cpp.inl:30
void AppendCharacters(TArray< UE_STRING_CHARTYPE > &Out, const SrcCharType *Str, int32 Count)
Definition String.cpp.inl:112
FORCEINLINE void ConstructFromCString(TArray< UE_STRING_CHARTYPE > &Data, const SrcCharType *Src, int32 ExtraSlack)
Definition String.cpp.inl:163
UE_DISABLE_OPTIMIZATION_SHIP void StripNegativeZero(double &InFloat)
Definition String.cpp:57
FORCEINLINE void ConstructWithLength(TArray< UE_STRING_CHARTYPE > &Data, const SrcCharType *InSrc, int32 InCount, int32 ExtraSlack)
Definition String.cpp.inl:184
Definition String.cpp.inl:714
int32 RhsLen
Definition String.cpp.inl:727
FORCEINLINE UE_STRING_CLASS int32 LhsLen
Definition String.cpp.inl:736
return Forward< RhsType >(Rhs))
FORCEINLINE UE_STRING_CLASS RhsType && Rhs
Definition String.cpp.inl:718
ElementType * ResultData
Definition String.cpp.inl:756
UE_STRING_CLASS Result(Forward< LhsType >(Lhs), RhsLen)
Definition String.cpp.inl:732
CopyAssignItems(ResultData, Lhs, LhsLen)
FORCEINLINE UE_STRING_CLASS PREPROCESSOR_JOIN(ConcatStrings_, UE_STRING_CLASS)(LhsType &&Lhs
EParseTokensOptions
Definition ParseTokens.h:19
void ParseTokens(const FAnsiStringView View, const ANSICHAR Delimiter, TFunctionRef< void(FAnsiStringView)> Visitor, const EParseTokensOptions Options)
Definition ParseTokens.cpp:302
int32 HexToBytes(FWideStringView Hex, uint8 *OutBytes)
Definition HexToBytes.cpp:30
U16 Index
Definition radfft.cpp:71
static constexpr UE_FORCEINLINE_HINT T Clamp(const T X, const T MinValue, const T MaxValue)
Definition UnrealMathUtility.h:592
static UE_FORCEINLINE_HINT void * Memmove(void *Dest, const void *Src, SIZE_T Count)
Definition UnrealMemory.h:109
static FORCENOINLINE CORE_API void Free(void *Original)
Definition UnrealMemory.cpp:685
static UE_FORCEINLINE_HINT void * Memcpy(void *Dest, const void *Src, SIZE_T Count)
Definition UnrealMemory.h:160
Definition CString.h:60
static UE_FORCEINLINE_HINT int32 Strcmp(const CharType *String1, const CharType *String2)
Definition CString.h:1018
static UE_FORCEINLINE_HINT int32 Stricmp(const CharType *String1, const CharType *String2)
Definition CString.h:1030
static int32 Strlen(const CharType *String)
Definition CString.h:1047
static UE_FORCEINLINE_HINT int32 Strncmp(const CharType *String1, const CharType *String2, SIZE_T Count)
Definition CString.h:1024
static const CharType * Strnistr(const CharType *Str, int32 InStrLen, const CharType *Find, int32 FindLen)
Definition CString.h:841
static UE_FORCEINLINE_HINT int32 Strnicmp(const CharType *String1, const CharType *String2, SIZE_T Count)
Definition CString.h:1036
static bool IsPureAnsi(const CharType *Str)
Definition CString.h:67
static bool ToBool(const CharType *String)
Definition CString.h:515
static bool IsNumeric(const CharType *Str)
Definition CString.h:139
static const CharType * Stristr(const CharType *Str, const CharType *Find)
Definition CString.h:799
static const CharType * Strnstr(const CharType *Str, int32 InStrLen, const CharType *Find, int32 FindLen)
Definition CString.h:881
static UE_FORCEINLINE_HINT const CharType * Strstr(const CharType *String, const CharType *Find)
Definition CString.h:1066
Definition Char.h:76
static bool IsUpper(CharType Char)
Definition Char.h:93
static CharType ToLower(CharType Char)
Definition Char.h:88
static CharType ToUpper(CharType Char)
Definition Char.h:80