MCRO
C++23 utilities for Unreal Engine.
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages Concepts
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 "Text.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 || CSameAsDecayed<T, FAnsiString>
70 || CSameAsDecayed<T, FUtf8String>
71 ;
72
73 /** @brief Concept constraining given type to a string or a a view of TCHAR */
74 template<typename T>
75 concept CStringOrView = CSameAsDecayed<T, FString> || CSameAsDecayed<T, FStringView>;
76
77 /** @brief Concept constraining given type to a string or a a view of any character type */
78 template<typename T>
80
81 /** @brief Concept constraining given type to a string, a view or an FName of TCHAR */
82 template<typename T>
83 concept CStringOrViewOrName = CStringOrView<T> || CSameAsDecayed<T, FName>;
84
85 /** @brief Concept constraining given type to a std::string or a view of TCHAR */
86 template <typename T>
87 concept CStdStringOrView = CConvertibleToDecayed<T, FStdStringView>;
88
89 /** @brief Concept constraining given type to a std::string or a view of given character type */
90 template <typename T, typename CharType>
91 concept CStdStringOrViewTyped = CConvertibleToDecayed<T, TStdStringView<CharType>>;
92
93 /** @brief Concept constraining given type to only a std::string of any character type */
94 template <typename T>
96 CSameAsDecayed<
97 T,
99 typename T::value_type,
100 typename T::traits_type
101 >
102 >
103 ;
104
105 /** @brief Concept constraining given type to only a std::string_view of any character type */
106 template <typename T>
108 CSameAsDecayed<
109 T,
111 typename T::value_type,
112 typename T::traits_type
113 >
114 >
115 ;
116
117 /** @brief Concept constraining given type to a std::string or a view of any character type */
118 template <typename T>
120 CConvertibleToDecayed<
121 T,
123 typename T::value_type,
124 typename T::traits_type
125 >
126 >
127 ;
128
129 namespace Detail
130 {
131 using namespace Mcro::FunctionTraits;
132
133 template <
134 typename CharFrom, typename CharOutput,
135 typename StringFrom,
136 CFunctionLike PtrGetter, CFunctionLike LengthGetter, CFunctionLike Constructor,
137 typename StringTo = TFunction_Return<Constructor>
138 >
139 StringTo HighLevelStringCast(const StringFrom& strIn, PtrGetter&& getPtr, LengthGetter&& getLength, Constructor&& construct)
140 {
141 if constexpr (CSameAs<CharFrom, CharOutput>)
142 {
143 return construct(
144 reinterpret_cast<const CharOutput*>(getPtr()),
145 getLength()
146 );
147 }
148 else
149 {
150 auto conversion = StringCast<CharOutput>(
151 reinterpret_cast<const CharFrom*>(getPtr()),
152 getLength()
153 );
154 return construct(
155 reinterpret_cast<const CharOutput*>(conversion.Get()),
156 conversion.Length()
157 );
158 }
159 }
160 }
161
162 /** @brief View an STL string object via an Unreal `TStringView` */
163 template <typename CharType>
164 constexpr auto UnrealView(TStdStringView<CharType> const& stdStr)
165 {
166 return TStringView<CharType>(stdStr.data(), stdStr.size());
167 }
168
169 /** @brief View an Unreal `TStringView` via an STL string view */
170 template <CStringViewInvariant T>
171 constexpr auto StdView(T const& unrealStr)
172 {
173 return TStdStringView<typename T::ElementType>(unrealStr.GetData(), unrealStr.Len());
174 }
175
176 /** @brief View an Unreal string via an STL string view */
177 template <CConvertibleToDecayed<FString> T>
178 auto StdView(T const& unrealStr)
179 {
180 return FStdStringView(*unrealStr, unrealStr.Len());
181 }
182
183 /** @brief Create a copy of an input STL string */
184 MCRO_API FString UnrealCopy(FStdStringView const& stdStr);
185
186 /** @brief Create a copy and convert an input STL string to TCHAR */
187 template <CStdStringOrViewInvariant T>
188 FString UnrealConvert(T const& stdStr)
189 {
191 stdStr,
192 [&] { return stdStr.data(); },
193 [&] { return stdStr.length(); },
194 [](const TCHAR* ptr, int32 len) { return FString::ConstructFromPtrSize(ptr, len); }
195 );
196 }
197
198 /** @brief Create a copy of an input STL string as an FName */
199 MCRO_API FName UnrealNameCopy(FStdStringView const& stdStr);
200
201
202 /** @brief Create a copy and convert an input STL string to TCHAR as an FName */
203 template <CStdStringOrViewInvariant T>
204 FName UnrealNameConvert(T const& stdStr)
205 {
207 stdStr,
208 [&] { return stdStr.data(); },
209 [&] { return stdStr.length(); },
210 [](const TCHAR* ptr, int32 len) { return FName(len, ptr); }
211 );
212 }
213
214 /** @brief Create an Stl copy of an input Unreal string view */
215 MCRO_API FStdString StdCopy(FStringView const& unrealStr);
216
217 /** @brief Create an Stl copy of an input Unreal string */
218 MCRO_API FStdString StdCopy(FName const& unrealStr);
219
220 /** @brief Create a copy and convert an input Unreal string to the given character type */
221 template <typename ConvertTo>
222 auto StdConvert(FStringView const& unrealStr) -> TStdString<ConvertTo>
223 {
224 if constexpr (CSameAs<TCHAR, ConvertTo>)
225 return TStdString<ConvertTo>(unrealStr.GetData(), unrealStr.Len());
226 else
227 {
229 unrealStr,
230 [&] { return unrealStr.GetData(); },
231 [&] { return unrealStr.Len(); },
232 [](const ConvertTo* ptr, int32 len) { return TStdString(ptr, len); }
233 );
234 }
235 }
236
237 /** @brief Create a copy and convert an input STL string of TCHAR to the given character type */
238 template <typename ConvertTo>
240 {
241 if constexpr (CSameAs<TCHAR, ConvertTo>)
242 return TStdString<ConvertTo>(stdStr.data(), stdStr.size());
243 else
244 {
246 stdStr,
247 [&] { return stdStr.data(); },
248 [&] { return stdStr.size(); },
249 [](const ConvertTo* ptr, int32 len) { return TStdString(ptr, len); }
250 );
251 }
252 }
253
254 /** @brief Create a copy and convert an input FName to the given character type */
255 template <typename ConvertTo>
256 auto StdConvert(FName const& name) -> TStdString<ConvertTo>
257 {
258 return StdConvert<ConvertTo>(name.ToString());
259 }
260
261 /** @brief Join the given string arguments with a delimiter and skip empty entries */
262 template <CStringOrView... Args>
263 FString Join(const TCHAR* separator, Args... args)
264 {
265 return FString::Join(
266 TArray<FString>{args...}.FilterByPredicate([](FStringView const& str) { return !str.IsEmpty(); }),
267 separator
268 );
269 }
270
271 /** @brief Copy of FString::PrintfImpl but not private so it can work with strings which were not literals */
272 MCRO_API FString DynamicPrintf(const TCHAR* fmt, ...);
273
274 /** @brief A type which is directly convertible to FStringFormatArg */
275 template <typename T>
276 concept CDirectStringFormatArgument = CConvertibleTo<T, FStringFormatArg>;
277
278 /** @brief A type which which provides a `ToString()` member method */
279 template <typename T>
281 {
282 { t.ToString() } -> CDirectStringFormatArgument;
283 };
284
285 /** @brief A type which which provides a `ToString()` member method */
286 template <typename T>
288 {
289 { t->ToString() } -> CDirectStringFormatArgument;
290 };
291
292 template <typename T>
294 {
295#if MCRO_TEXT_ALLOW_UNSUPPORTED_STRING_CONVERSION
296 template <CConvertibleToDecayed<T> Arg>
297 FStringView operator () (Arg&& left) const
298 {
299 ensureAlwaysMsgf(false,
300 TEXT("Given type %s couldn't be converted to a string. Typename is returned instead"),
302 );
303 return TTypeName<T>;
304 }
305#endif
306 };
307
308 /** @brief A type which can be used with FStringFormatArg via a `TAsFormatArgument` specialization. */
309 template <typename T>
314
315 /** @brief A type which can be converted to FStringFormatArg via any method. */
316 template <typename T>
322 ;
323
324 template <CDirectStringFormatArgument Operand>
325 requires (!CEnum<Operand>)
327 {
328 template <CConvertibleToDecayed<Operand> Arg>
329 Operand operator () (Arg&& left) const { return left; }
330 };
331
332 template <CHasToString Operand>
333 struct TAsFormatArgument<Operand>
334 {
335 template <CConvertibleToDecayed<Operand> Arg>
336 auto operator () (Arg&& left) const { return left.ToString(); }
337 };
338
339 template <CHasPtrToString Operand>
340 struct TAsFormatArgument<Operand>
341 {
342 template <CConvertibleToDecayed<Operand> Arg>
343 auto operator () (Arg&& left) const { return left->ToString(); }
344 };
345
346 template <typename CharType>
348 {
349 const CharType* operator () (TStdString<CharType> const& left) const
350 {
351 return left.c_str();
352 }
353 };
354
355 template <>
357 {
358 FStringView operator () (FStdStringView const& left) const
359 {
360 return UnrealView(left);
361 }
362 };
363
364 template <CStdStringViewInvariant Operand>
365 requires (!CSameAsDecayed<Operand, FStdStringView>)
367 {
368 template <CConvertibleToDecayed<Operand> Arg>
369 auto operator () (Arg&& left) const { return UnrealConvert(left); }
370 };
371
372 template <CStringFormatArgument T>
373 auto AsFormatArgument(T&& input)
374 {
375 return TAsFormatArgument<std::decay_t<T>>()(input);
376 }
377
378 /**
379 * @brief Attempt to convert anything to string which can tell via some method how to do so
380 *
381 * This may be more expensive than directly using an already existing designated string conversion for a given
382 * type, because it uses `FStringFormatArg` and a `TAsFormatArgument` as intermediate steps. However, this can be
383 * still useful for types where such conversion doesn't already exist or when using this in a template.
384 *
385 * It's still much faster than using `FMT_(myVar) "{0}"`
386 */
387 template <CStringFormatArgument T>
388 FString AsString(T&& input)
389 {
390 FStringFormatArg format(AsFormatArgument(input));
391 return MoveTemp(format.StringValue);
392 }
393
394 /**
395 * @brief Create an ordered argument list for a string format from input arguments
396 *
397 * While you can it is not recommended to be used directly because the boilerplate it still needs is very verbose.
398 * Check `_FMT` or `FMT_` macros for a comfortable string format syntax.
399 */
400 template <CStringFormatArgument... Args>
401 FStringFormatOrderedArguments OrderedArguments(Args&&... args)
402 {
403 return FStringFormatOrderedArguments { FStringFormatArg(AsFormatArgument(args)) ... };
404 }
405
406 /**
407 * @brief Create a named argument list for a string format from input argument tuples
408 *
409 * While you can it is not recommended to be used directly because the boilerplate it still needs is very verbose.
410 * Check `_FMT` or `FMT_` macros for a comfortable string format syntax.
411 */
412 template <CStringFormatArgument... Args>
413 FStringFormatNamedArguments NamedArguments(TTuple<FString, Args>... args)
414 {
415 return FStringFormatNamedArguments {
416 { args.template Get<0>(), FStringFormatArg(AsFormatArgument(args.template Get<1>())) }
417 ...
418 };
419 }
420}
This header exists because STL headers in Android doesn't define STL concepts (other than same_as whi...
Convert types to string.
A type which is directly convertible to FStringFormatArg.
Definition Text.h:276
A type which which provides a ToString() member method.
Definition Text.h:287
A type which can be used with FStringFormatArg via a TAsFormatArgument specialization.
Definition Text.h:310
A type which which provides a ToString() member method.
Definition Text.h:280
Concept constraining given type to only a std::string of any character type.
Definition Text.h:95
Concept constraining given type to a std::string or a view of any character type.
Definition Text.h:119
Concept constraining given type to a std::string or a view of given character type.
Definition Text.h:91
Concept constraining given type to a std::string or a view of TCHAR.
Definition Text.h:87
Concept constraining given type to only a std::string_view of any character type.
Definition Text.h:107
A type which can be converted to FStringFormatArg via any method.
Definition Text.h:317
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:79
Concept constraining given type to a string, a view or an FName of TCHAR.
Definition Text.h:83
Concept constraining given type to a string or a a view of TCHAR.
Definition Text.h:75
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:139
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:263
FStringFormatNamedArguments NamedArguments(TTuple< FString, Args >... args)
Create a named argument list for a string format from input argument tuples.
Definition Text.h:413
MCRO_API FString DynamicPrintf(const TCHAR *fmt,...)
Copy of FString::PrintfImpl but not private so it can work with strings which were not literals.
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:164
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:204
FString UnrealConvert(T const &stdStr)
Create a copy and convert an input STL string to TCHAR.
Definition Text.h:188
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:171
TStringView< UTF32CHAR > FUtf32StringView
Definition Text.h:54
MCRO_API FString UnrealCopy(FStdStringView const &stdStr)
Create a copy of an input STL string.
auto AsFormatArgument(T &&input)
Definition Text.h:373
FString AsString(T &&input)
Attempt to convert anything to string which can tell via some method how to do so.
Definition Text.h:388
auto StdConvert(FStringView const &unrealStr) -> TStdString< ConvertTo >
Create a copy and convert an input Unreal string to the given character type.
Definition Text.h:222
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:401
constexpr FStringView TTypeName
Get a friendly string of an input type without using typeid(T).name().
Definition TypeName.h:195
FString TTypeString()
Same as TTypeName converted to FString. This is not cached and a new FString is created every time th...
Definition TypeName.h:223