MCRO
C++23 utilities for Unreal Engine.
Loading...
Searching...
No Matches
Text.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 <string>
15
16#include "CoreMinimal.h"
17#include "Misc/EngineVersionComparison.h"
18
19#include "Mcro/Concepts.h"
20#include "Mcro/FunctionTraits.h"
21#include "Mcro/TypeName.h"
22
23#ifndef MCRO_TEXT_ALLOW_UNSUPPORTED_STRING_CONVERSION
24/**
25 * @brief
26 * If this flag is on, then the default string conversion behavior is returning the result of `TTypeName` and
27 * triggering an ensure. Otherwise, a missing function will result in a compile error.
28 */
29#define MCRO_TEXT_ALLOW_UNSUPPORTED_STRING_CONVERSION 0
30#endif
31
32/** @brief Mixed text utilities and type traits */
33namespace Mcro::Text
34{
35 using namespace Mcro::Concepts;
36 using namespace Mcro::TypeName;
37
38 /** @brief Unreal style alias for STL strings */
39 template <
40 class CharT,
41 class Traits = std::char_traits<CharT>,
42 class Allocator = std::allocator<CharT>
43 >
44 using TStdString = std::basic_string<CharT, Traits, Allocator>;
45
46 /** @brief Unreal style alias for STL string views */
47 template <
48 class CharT,
49 class Traits = std::char_traits<CharT>
50 >
51 using TStdStringView = std::basic_string_view<CharT, Traits>;
52
53 using FUtf16StringView = TStringView<UTF16CHAR>;
54 using FUtf32StringView = TStringView<UTF32CHAR>;
55
56 /** @brief cross-TCHAR alias for `std::[w]string` */
58
59 /** @brief cross-TCHAR alias for `std::[w]string_view` */
61
62 /** @brief Concept constraining given type to a string view of any character type */
63 template<typename T>
64 concept CStringViewInvariant = CSameAsDecayed<T, TStringView<typename T::ElementType>>;
65
66 /** @brief Concept constraining given type to a string of any character type */
67 template<typename T>
68 concept CStringInvariant = CSameAsDecayed<T, FString>
69#if UE_VERSION_NEWER_THAN(5, 5, -1)
70 || CSameAsDecayed<T, FAnsiString>
71 || CSameAsDecayed<T, FUtf8String>
72#endif
73 ;
74
75 /** @brief Concept constraining given type to a string or a a view of TCHAR */
76 template<typename T>
77 concept CStringOrView = CSameAsDecayed<T, FString> || CSameAsDecayed<T, FStringView>;
78
79 /** @brief Concept constraining given type to a string or a a view of any character type */
80 template<typename T>
82
83 /** @brief Concept constraining given type to a string, a view or an FName of TCHAR */
84 template<typename T>
85 concept CStringOrViewOrName = CStringOrView<T> || CSameAsDecayed<T, FName>;
86
87 /** @brief Concept constraining given type to a std::string or a view of TCHAR */
88 template <typename T>
89 concept CStdStringOrView = CConvertibleToDecayed<T, FStdStringView>;
90
91 /** @brief Concept constraining given type to a std::string or a view of given character type */
92 template <typename T, typename CharType>
93 concept CStdStringOrViewTyped = CConvertibleToDecayed<T, TStdStringView<CharType>>;
94
95 /** @brief Concept constraining given type to only a std::string of any character type */
96 template <typename T>
98 CSameAsDecayed<
99 T,
101 typename T::value_type,
102 typename T::traits_type
103 >
104 >
105 ;
106
107 /** @brief Concept constraining given type to only a std::string_view of any character type */
108 template <typename T>
110 CSameAsDecayed<
111 T,
113 typename T::value_type,
114 typename T::traits_type
115 >
116 >
117 ;
118
119 /** @brief Concept constraining given type to a std::string or a view of any character type */
120 template <typename T>
122 CConvertibleToDecayed<
123 T,
125 typename T::value_type,
126 typename T::traits_type
127 >
128 >
129 ;
130
131 namespace Detail
132 {
133 using namespace Mcro::FunctionTraits;
134
135 FORCEINLINE FString MakeStringFromPtrSize(const TCHAR* ptr, int32 size)
136 {
137#if UE_VERSION_OLDER_THAN(5, 5, 0)
138 return FString(size, ptr);
139#else
140 return FString::ConstructFromPtrSize(ptr, size);
141#endif
142 }
143
144 template <
145 typename CharFrom, typename CharOutput,
146 typename StringFrom,
147 CFunctionLike PtrGetter, CFunctionLike LengthGetter, CFunctionLike Constructor,
148 typename StringTo = TFunction_Return<Constructor>
149 >
150 StringTo HighLevelStringCast(const StringFrom& strIn, PtrGetter&& getPtr, LengthGetter&& getLength, Constructor&& construct)
151 {
152 if constexpr (CSameAs<CharFrom, CharOutput>)
153 {
154 return construct(
155 reinterpret_cast<const CharOutput*>(getPtr()),
156 getLength()
157 );
158 }
159 else
160 {
161 auto conversion = StringCast<CharOutput>(
162 reinterpret_cast<const CharFrom*>(getPtr()),
163 getLength()
164 );
165 return construct(
166 reinterpret_cast<const CharOutput*>(conversion.Get()),
167 conversion.Length()
168 );
169 }
170 }
171 }
172
173 /** @brief View an STL string object via an Unreal `TStringView` */
174 template <typename CharType>
175 constexpr auto UnrealView(TStdStringView<CharType> const& stdStr)
176 {
177 return TStringView<CharType>(stdStr.data(), stdStr.size());
178 }
179
180 /** @brief View an Unreal `TStringView` via an STL string view */
181 template <CStringViewInvariant T>
182 constexpr auto StdView(T const& unrealStr)
183 {
184 return TStdStringView<typename T::ElementType>(unrealStr.GetData(), unrealStr.Len());
185 }
186
187 /** @brief View an Unreal string via an STL string view */
188 template <CConvertibleToDecayed<FString> T>
189 auto StdView(T const& unrealStr)
190 {
191 return FStdStringView(*unrealStr, unrealStr.Len());
192 }
193
194 /** @brief Create a copy of an input STL string */
195 MCRO_API FString UnrealCopy(FStdStringView const& stdStr);
196
197 /** @brief Create a copy and convert an input STL string to TCHAR */
198 template <CStdStringOrViewInvariant T>
199 FString UnrealConvert(T const& stdStr)
200 {
202 stdStr,
203 [&] { return stdStr.data(); },
204 [&] { return stdStr.length(); },
205 [](const TCHAR* ptr, int32 len) { return Detail::MakeStringFromPtrSize(ptr, len); }
206 );
207 }
208
209 /** @brief Create a copy of an input STL string as an FName */
210 MCRO_API FName UnrealNameCopy(FStdStringView const& stdStr);
211
212
213 /** @brief Create a copy and convert an input STL string to TCHAR as an FName */
214 template <CStdStringOrViewInvariant T>
215 FName UnrealNameConvert(T const& stdStr)
216 {
218 stdStr,
219 [&] { return stdStr.data(); },
220 [&] { return stdStr.length(); },
221 [](const TCHAR* ptr, int32 len) { return FName(len, ptr); }
222 );
223 }
224
225 /** @brief Create an Stl copy of an input Unreal string view */
226 MCRO_API FStdString StdCopy(FStringView const& unrealStr);
227
228 /** @brief Create an Stl copy of an input Unreal string */
229 MCRO_API FStdString StdCopy(FName const& unrealStr);
230
231 /** @brief Create a copy and convert an input Unreal string to the given character type */
232 template <typename ConvertTo>
233 auto StdConvert(FStringView const& unrealStr) -> TStdString<ConvertTo>
234 {
235 if constexpr (CSameAs<TCHAR, ConvertTo>)
236 return TStdString<ConvertTo>(unrealStr.GetData(), unrealStr.Len());
237 else
238 {
240 unrealStr,
241 [&] { return unrealStr.GetData(); },
242 [&] { return unrealStr.Len(); },
243 [](const ConvertTo* ptr, int32 len) { return TStdString(ptr, len); }
244 );
245 }
246 }
247
248 /** @brief Create a copy and convert an input STL string of TCHAR to the given character type */
249 template <typename ConvertTo>
251 {
252 if constexpr (CSameAs<TCHAR, ConvertTo>)
253 return TStdString<ConvertTo>(stdStr.data(), stdStr.size());
254 else
255 {
257 stdStr,
258 [&] { return stdStr.data(); },
259 [&] { return stdStr.size(); },
260 [](const ConvertTo* ptr, int32 len) { return TStdString(ptr, len); }
261 );
262 }
263 }
264
265 /** @brief Create a copy and convert an input FName to the given character type */
266 template <typename ConvertTo>
267 auto StdConvert(FName const& name) -> TStdString<ConvertTo>
268 {
269 return StdConvert<ConvertTo>(name.ToString());
270 }
271
272 /** @brief Join the given string arguments with a delimiter and skip empty entries */
273 template <CStringOrView... Args>
274 FString Join(const TCHAR* separator, Args... args)
275 {
276 return FString::Join(
277 TArray<FString>{args...}.FilterByPredicate([](FStringView const& str) { return !str.IsEmpty(); }),
278 separator
279 );
280 }
281
282 /** @brief A type which is directly convertible to FStringFormatArg */
283 template <typename T>
284 concept CDirectStringFormatArgument = CConvertibleTo<T, FStringFormatArg>;
285
286 /** @brief A type which which provides a `ToString()` member method */
287 template <typename T>
289 {
290 { t.ToString() } -> CDirectStringFormatArgument;
291 };
292
293 /** @brief A type which which provides a `ToString()` member method */
294 template <typename T>
296 {
297 { t->ToString() } -> CDirectStringFormatArgument;
298 };
299
300 template <typename T>
302 {
303#if MCRO_TEXT_ALLOW_UNSUPPORTED_STRING_CONVERSION
304 template <CConvertibleToDecayed<T> Arg>
305 FStringView operator () (Arg&& left) const
306 {
307 ensureAlwaysMsgf(false,
308 TEXT("Given type %s couldn't be converted to a string. Typename is returned instead"),
310 );
311 return TTypeName<T>;
312 }
313#endif
314 };
315
316 /** @brief A type which can be used with FStringFormatArg via a `TAsFormatArgument` specialization. */
317 template <typename T>
322
323 /** @brief A type which can be converted to FStringFormatArg via any method. */
324 template <typename T>
330 ;
331
332 template <CDirectStringFormatArgument Operand>
333 requires (!CEnum<Operand>)
335 {
336 template <CConvertibleToDecayed<Operand> Arg>
337 Operand operator () (Arg&& left) const { return left; }
338 };
339
340 template <CHasToString Operand>
341 struct TAsFormatArgument<Operand>
342 {
343 template <CConvertibleToDecayed<Operand> Arg>
344 auto operator () (Arg&& left) const { return left.ToString(); }
345 };
346
347 template <CHasPtrToString Operand>
348 struct TAsFormatArgument<Operand>
349 {
350 template <CConvertibleToDecayed<Operand> Arg>
351 auto operator () (Arg&& left) const { return left->ToString(); }
352 };
353
354 template <typename CharType>
356 {
357 const CharType* operator () (TStdString<CharType> const& left) const
358 {
359 return left.c_str();
360 }
361 };
362
363 template <>
365 {
366 FStringView operator () (FStdStringView const& left) const
367 {
368 return UnrealView(left);
369 }
370 };
371
372 template <CStdStringViewInvariant Operand>
373 requires (!CSameAsDecayed<Operand, FStdStringView>)
375 {
376 template <CConvertibleToDecayed<Operand> Arg>
377 auto operator () (Arg&& left) const { return UnrealConvert(left); }
378 };
379
380 template <CStringFormatArgument T>
381 auto AsFormatArgument(T&& input)
382 {
383 return TAsFormatArgument<std::decay_t<T>>()(input);
384 }
385
386 /**
387 * @brief Attempt to convert anything to string which can tell via some method how to do so
388 *
389 * This may be more expensive than directly using an already existing designated string conversion for a given
390 * type, because it uses `FStringFormatArg` and a `TAsFormatArgument` as intermediate steps. However, this can be
391 * still useful for types where such conversion doesn't already exist or when using this in a template.
392 *
393 * It's still much faster than using `FMT_(myVar) "{0}"`
394 */
395 template <CStringFormatArgument T>
396 requires(!CSameAsDecayed<T, FString>)
397 FString AsString(T&& input)
398 {
399 FStringFormatArg format(AsFormatArgument(input));
400 return MoveTemp(format.StringValue);
401 }
402
403 template <CSameAsDecayed<FString> T>
404 decltype(auto) AsString(T&& input)
405 {
406 return FWD(input);
407 }
408
409 /**
410 * @brief Convert anything which is compatible with `AsString` to FText.
411 */
412 template <CStringFormatArgument T>
413 requires(!CSameAsDecayed<T, FText>)
414 FText AsText(T&& input)
415 {
416 return FText::FromString(AsString(input));
417 }
418
419 template <CSameAsDecayed<FText> T>
420 decltype(auto) AsText(T&& input)
421 {
422 return FWD(input);
423 }
424
425 /**
426 * @brief Create an ordered argument list for a string format from input arguments
427 *
428 * While you can it is not recommended to be used directly because the boilerplate it still needs is very verbose.
429 * Check `_FMT` or `FMT_` macros for a comfortable string format syntax.
430 */
431 template <CStringFormatArgument... Args>
432 FStringFormatOrderedArguments OrderedArguments(Args&&... args)
433 {
434 return FStringFormatOrderedArguments { FStringFormatArg(AsFormatArgument(args)) ... };
435 }
436
437 /**
438 * @brief Create a named argument list for a string format from input argument tuples
439 *
440 * While you can it is not recommended to be used directly because the boilerplate it still needs is very verbose.
441 * Check `_FMT` or `FMT_` macros for a comfortable string format syntax.
442 */
443 template <CStringFormatArgument... Args>
444 FStringFormatNamedArguments NamedArguments(TTuple<FString, Args>... args)
445 {
446 return FStringFormatNamedArguments {
447 { args.template Get<0>(), FStringFormatArg(AsFormatArgument(args.template Get<1>())) }
448 ...
449 };
450 }
451}
This header exists because STL headers in Android doesn't define STL concepts (other than same_as whi...
#define FWD(...)
Shorten forwarding expression with this macro so one may not need to specify explicit type.
Definition Macros.h:100
size_t size(TArray< T, A > const &r)
Definition Range.h:101
Convert types to string.
A type which is directly convertible to FStringFormatArg.
Definition Text.h:284
A type which which provides a ToString() member method.
Definition Text.h:295
A type which can be used with FStringFormatArg via a TAsFormatArgument specialization.
Definition Text.h:318
A type which which provides a ToString() member method.
Definition Text.h:288
Concept constraining given type to only a std::string of any character type.
Definition Text.h:97
Concept constraining given type to a std::string or a view of any character type.
Definition Text.h:121
Concept constraining given type to a std::string or a view of given character type.
Definition Text.h:93
Concept constraining given type to a std::string or a view of TCHAR.
Definition Text.h:89
Concept constraining given type to only a std::string_view of any character type.
Definition Text.h:109
A type which can be converted to FStringFormatArg via any method.
Definition Text.h:325
Concept constraining given type to a string of any character type.
Definition Text.h:68
Concept constraining given type to a string or a a view of any character type.
Definition Text.h:81
Concept constraining given type to a string, a view or an FName of TCHAR.
Definition Text.h:85
Concept constraining given type to a string or a a view of TCHAR.
Definition Text.h:77
Concept constraining given type to a string view of any character type.
Definition Text.h:64
typename TFunctionTraits< std::decay_t< T > >::Return TFunction_Return
Shorthand for getting a function return type.
StringTo HighLevelStringCast(const StringFrom &strIn, PtrGetter &&getPtr, LengthGetter &&getLength, Constructor &&construct)
Definition Text.h:150
FORCEINLINE FString MakeStringFromPtrSize(const TCHAR *ptr, int32 size)
Definition Text.h:135
Mixed text utilities and type traits.
Definition Enums.h:51
FString Join(const TCHAR *separator, Args... args)
Join the given string arguments with a delimiter and skip empty entries.
Definition Text.h:274
FStringFormatNamedArguments NamedArguments(TTuple< FString, Args >... args)
Create a named argument list for a string format from input argument tuples.
Definition Text.h:444
TStdString< TCHAR > FStdString
cross-TCHAR alias for std::[w]string
Definition Text.h:57
TStringView< UTF16CHAR > FUtf16StringView
Definition Text.h:53
constexpr auto UnrealView(TStdStringView< CharType > const &stdStr)
View an STL string object via an Unreal TStringView
Definition Text.h:175
std::basic_string< CharT, Traits, Allocator > TStdString
Unreal style alias for STL strings.
Definition Text.h:44
FName UnrealNameConvert(T const &stdStr)
Create a copy and convert an input STL string to TCHAR as an FName.
Definition Text.h:215
FString UnrealConvert(T const &stdStr)
Create a copy and convert an input STL string to TCHAR.
Definition Text.h:199
MCRO_API FName UnrealNameCopy(FStdStringView const &stdStr)
Create a copy of an input STL string as an FName.
constexpr auto StdView(T const &unrealStr)
View an Unreal TStringView via an STL string view.
Definition Text.h:182
TStringView< UTF32CHAR > FUtf32StringView
Definition Text.h:54
FText AsText(T &&input)
Convert anything which is compatible with AsString to FText.
Definition Text.h:414
MCRO_API FString UnrealCopy(FStdStringView const &stdStr)
Create a copy of an input STL string.
auto AsFormatArgument(T &&input)
Definition Text.h:381
FString AsString(T &&input)
Attempt to convert anything to string which can tell via some method how to do so.
Definition Text.h:397
auto StdConvert(FStringView const &unrealStr) -> TStdString< ConvertTo >
Create a copy and convert an input Unreal string to the given character type.
Definition Text.h:233
TStdStringView< TCHAR > FStdStringView
cross-TCHAR alias for std::[w]string_view
Definition Text.h:60
MCRO_API FStdString StdCopy(FStringView const &unrealStr)
Create an Stl copy of an input Unreal string view.
std::basic_string_view< CharT, Traits > TStdStringView
Unreal style alias for STL string views.
Definition Text.h:51
FStringFormatOrderedArguments OrderedArguments(Args &&... args)
Create an ordered argument list for a string format from input arguments.
Definition Text.h:432
constexpr FStringView TTypeName
Get a friendly string of an input type without using typeid(T).name().
Definition TypeName.h:161
FString TTypeString()
Same as TTypeName converted to FString. This is not cached and a new FString is created every time th...
Definition TypeName.h:189