4#ifndef _Stroika_Foundation_Characters_ToString_h_
5#define _Stroika_Foundation_Characters_ToString_h_ 1
7#include "Stroika/Foundation/StroikaPreComp.h"
22#include "Stroika/Foundation/Common/Concepts.h"
23#include "Stroika/Foundation/Common/CountedValue.h"
24#include "Stroika/Foundation/Common/KeyValuePair.h"
27#if __cpp_lib_stacktrace >= 202011 && !qCompiler_clangNotCompatibleWithLibStdCPPStackTrace_Buggy
41#if qStroika_HasComponent_fmtlib && (FMT_VERSION >= 110000)
48namespace Stroika::Foundation::Memory {
113 template <
typename T,
typename... ARGS>
114 String
ToString (T&& t, ARGS... args);
119 template <
typename T>
121 {
ToString (t) } -> convertible_to<Characters::String>;
127 template <
typename T>
136 template <IToString T>
138 qStroika_Foundation_Characters_FMT_PREFIX_::formatter<String, wchar_t> fDelegate2_;
140 template <
class ParseContext>
141 constexpr typename ParseContext::iterator parse (ParseContext& ctx)
143 return fDelegate2_.parse (ctx);
146 template <
class FmtContext>
147 typename FmtContext::iterator format (T s, FmtContext& ctx)
const
152 std::wstringstream out;
154#if __cpp_lib_ranges >= 202207L
155 return std::ranges::copy (std::move (out).str (), ctx.out ()).out;
157 return Common::StdCompat::format_to (ctx.out (), L
"{}",
String{out.str ()});
162 template <IToString T>
163 struct ToStringFormatterASCII {
166 template <
class ParseContext>
167 constexpr typename ParseContext::iterator parse (ParseContext& ctx)
170 auto it = ctx.begin ();
171 while (it != ctx.end ()) {
174 if (it == ctx.end ()) {
175 throw Common::StdCompat::format_error{
"Invalid format args (missing }) for ToStringFormatterASCII."};
185 template <
class FmtContext>
186 typename FmtContext::iterator format (T s, FmtContext& ctx)
const
189 std::wstringstream out;
193#if __cpp_lib_ranges >= 202207L
203namespace Stroika::Foundation::Characters::Private_ {
218 template <
typename T>
224 or
requires { []<
typename TRAITS,
typename ALLOCATOR> (type_identity<std::basic_string<char, TRAITS, ALLOCATOR>>) {}(type_identity<T> ()); }
225 or
requires { []<
typename TRAITS,
typename ALLOCATOR> (type_identity<std::basic_string<wchar_t, TRAITS, ALLOCATOR>>) {}(type_identity<T> ()); }
226 or
requires { []<
typename TRAITS> (type_identity<std::basic_string_view<char, TRAITS>>) {}(type_identity<T> ()); }
227 or
requires { []<
typename TRAITS> (type_identity<std::basic_string_view<wchar_t, TRAITS>>) {}(type_identity<T> ()); }
228 or
requires { []<
size_t N> (type_identity<wchar_t[N]>) {}(type_identity<T> ()); }
229 or std::is_arithmetic_v<T>
230 or Common::IAnyOf<decay_t<T>, nullptr_t,
void*,
const void*>
232 or Common::IDuration<T>
233 or
requires { []<
typename DURATION> (type_identity<std::chrono::sys_time<DURATION>>) {}(type_identity<T> ()); }
234#if !defined(_LIBCPP_VERSION) or _LIBCPP_VERSION > 199999
235 or
requires { []<
typename DURATION> (type_identity<std::chrono::utc_time<DURATION>>) {}(type_identity<T> ()); }
236 or
requires { []<
typename DURATION> (type_identity<std::chrono::tai_time<DURATION>>) {}(type_identity<T> ()); }
237 or
requires { []<
typename DURATION> (type_identity<std::chrono::gps_time<DURATION>>) {}(type_identity<T> ()); }
239 or
requires { []<
typename DURATION> (type_identity<std::chrono::file_time<DURATION>>) {}(type_identity<T> ()); }
240 or
requires { []<
typename DURATION> (type_identity<std::chrono::local_time<DURATION>>) {}(type_identity<T> ()); }
241 or Common::IAnyOf<decay_t<T>, chrono::day, chrono::month, chrono::year,
242 chrono::weekday, chrono::weekday_indexed, chrono::weekday_last,
243 chrono::month_day, chrono::month_day_last, chrono::month_weekday, chrono::month_weekday_last,
244 chrono::year_month, chrono::year_month_day, chrono::year_month_day_last, chrono::year_month_weekday,chrono::year_month_weekday_last
245#if (not defined (_GLIBCXX_RELEASE) or _GLIBCXX_RELEASE > 12) and (!defined(_LIBCPP_VERSION) or _LIBCPP_VERSION > 199999)
246 , chrono::sys_info, chrono::local_info
249 or
requires { []<
typename DURATION> (type_identity<chrono::hh_mm_ss<DURATION>>) {}(type_identity<T> ()); }
250#if (not defined (_GLIBCXX_RELEASE) or _GLIBCXX_RELEASE > 12) and (!defined(_LIBCPP_VERSION) or _LIBCPP_VERSION > 199999)
251 or
requires { []<
typename DURATION,
typename TimeZonePtr> (type_identity<chrono::zoned_time<DURATION, TimeZonePtr>>) {}(type_identity<T> ()); }
261#if __cpp_lib_format_ranges
262 or ranges::range<decay_t<T>>
264#if (__cplusplus > 202101L or _LIBCPP_STD_VER >= 23 or (_MSVC_LANG >= 202004 and _MSC_VER >= _MSC_VER_2k22_17Pt11_)) and not (defined (_GLIBCXX_RELEASE) and _GLIBCXX_RELEASE <= 14)
265 or Common::IPair<remove_cvref_t<T>> or Common::ITuple<remove_cvref_t<T>>
267#if __cplusplus > 202101L or _LIBCPP_STD_VER >= 23 or _MSVC_LANG >= 202004
268 or Common::IAnyOf<remove_cvref_t<T>, thread::id>
270#if __cpp_lib_stacktrace >= 202011 && !qCompiler_clangNotCompatibleWithLibStdCPPStackTrace_Buggy
271 or Common::IAnyOf<remove_cvref_t<T>, stacktrace_entry>
272 or
requires { []<
typename ALLOCATOR> (type_identity<basic_stacktrace<ALLOCATOR>>) {}(type_identity<T> ()); }
274#if __cplusplus > 202101L or _LIBCPP_STD_VER >= 23 or _MSVC_LANG >= 202004
275 or
requires { []<
typename TT> (type_identity<stack<TT>>) {}(type_identity<T> ()); }
276 or
requires { []<
typename TT> (type_identity<queue<TT>>) {}(type_identity<T> ()); }
280#if __cplusplus > 202400L or _LIBCPP_STD_VER >= 26 or _MSVC_LANG >= 202400L
282 or Common::IAnyOf<remove_cvref_t<T>, std::filesystem::path>
289#if qStroika_HasComponent_fmtlib
290 or Common::IAnyOf<decay_t<T>, qStroika_Foundation_Characters_FMT_PREFIX_::string_view, qStroika_Foundation_Characters_FMT_PREFIX_::wstring_view>
291#if (FMT_VERSION >= 110000)
295 or Common::IPair<remove_cvref_t<T>> or Common::ITuple<remove_cvref_t<T>>
303#if _MSVC_LANG == 202004 && (_MSC_VER < _MSC_VER_2k22_17Pt11_)
304 static_assert (not IStdFormatterPredefinedFor_<std::pair<int, char>>);
305 static_assert (not IStdFormatterPredefinedFor_<std::tuple<int>>);
306 static_assert (IStdFormatterPredefinedFor_<std::thread::id>);
307 static_assert (not IStdFormatterPredefinedFor_<std::type_index>);
308 static_assert (not IStdFormatterPredefinedFor_<std::exception_ptr>);
310#if _MSVC_LANG == 202004 && (_MSC_VER == _MSC_VER_2k22_17Pt11_)
311 static_assert (IStdFormatterPredefinedFor_<std::pair<int, char>>);
312 static_assert (IStdFormatterPredefinedFor_<std::tuple<int>>);
313 static_assert (IStdFormatterPredefinedFor_<std::thread::id>);
314 static_assert (not IStdFormatterPredefinedFor_<std::type_index>);
315 static_assert (not IStdFormatterPredefinedFor_<std::exception_ptr>);
317#if __cplusplus == 202002L && _GLIBCXX_RELEASE == 13
318 static_assert (not IStdFormatterPredefinedFor_<std::pair<int, char>>);
319 static_assert (not IStdFormatterPredefinedFor_<std::tuple<int>>);
320 static_assert (not IStdFormatterPredefinedFor_<std::thread::id>);
321 static_assert (not IStdFormatterPredefinedFor_<std::type_index>);
322 static_assert (not IStdFormatterPredefinedFor_<std::exception_ptr>);
324#if __cplusplus == 202002L && _GLIBCXX_RELEASE == 14
325 static_assert (not IStdFormatterPredefinedFor_<std::pair<int, char>>);
326 static_assert (not IStdFormatterPredefinedFor_<std::tuple<int>>);
327 static_assert (not IStdFormatterPredefinedFor_<std::thread::id>);
328 static_assert (not IStdFormatterPredefinedFor_<std::type_index>);
329 static_assert (not IStdFormatterPredefinedFor_<std::exception_ptr>);
331#if __cplusplus == 202302L && _GLIBCXX_RELEASE == 14
332 static_assert (not IStdFormatterPredefinedFor_<std::pair<int, char>>);
333 static_assert (not IStdFormatterPredefinedFor_<std::tuple<int>>);
334 static_assert (IStdFormatterPredefinedFor_<std::thread::id>);
335 static_assert (not IStdFormatterPredefinedFor_<std::type_index>);
336 static_assert (not IStdFormatterPredefinedFor_<std::exception_ptr>);
338#if defined(__APPLE__) && __clang_major__ == 15
339 static_assert (not IStdFormatterPredefinedFor_<std::pair<int, char>>);
340 static_assert (not IStdFormatterPredefinedFor_<std::tuple<int>>);
341 static_assert (not IStdFormatterPredefinedFor_<std::thread::id>);
342 static_assert (not IStdFormatterPredefinedFor_<std::type_index>);
343 static_assert (not IStdFormatterPredefinedFor_<std::exception_ptr>);
355 static_assert (IStdFormatterPredefinedFor_<std::type_index> == Common::StdCompat::formattable<std::type_index, wchar_t>);
356 static_assert (IStdFormatterPredefinedFor_<std::pair<int, char>> == Common::StdCompat::formattable<std::pair<int, char>,
wchar_t>);
357 static_assert (IStdFormatterPredefinedFor_<std::tuple<int>> == Common::StdCompat::formattable<std::tuple<int>,
wchar_t>);
358 static_assert (IStdFormatterPredefinedFor_<std::thread::id> == Common::StdCompat::formattable<std::thread::id, wchar_t>);
359 static_assert (IStdFormatterPredefinedFor_<std::filesystem::path> == Common::StdCompat::formattable<std::filesystem::path, wchar_t>);
360 static_assert (IStdFormatterPredefinedFor_<std::exception_ptr> == Common::StdCompat::formattable<std::exception_ptr, wchar_t>);
369 template <
typename T>
370 concept IUseToStringFormatterForFormatter_ =
375#if !qCompiler_IUseToStringFormatterForFormatter_Buggy
377 and not IStdFormatterPredefinedFor_<T>
379 and (
requires (T t) {
380 { t.ToString () } -> convertible_to<Characters::String>;
381 } or Common::IKeyValuePair<remove_cvref_t<T>> or Common::ICountedValue<remove_cvref_t<T>>
383#if !__cpp_lib_format_ranges
384#if !qStroika_HasComponent_fmtlib or (FMT_VERSION < 110000)
385 or (ranges::range<decay_t<T>> and
386 not Common::IAnyOf<decay_t<T>,
string, wstring, string_view, wstring_view,
const char[],
const wchar_t[],
387 qStroika_Foundation_Characters_FMT_PREFIX_::string_view, qStroika_Foundation_Characters_FMT_PREFIX_::wstring_view>)
390#if _MSC_VER || __cplusplus < 202101L || (__clang__ != 0 && __GLIBCXX__ != 0 && __GLIBCXX__ <= 20240908) || \
391 (!defined(__clang__) && __cplusplus == 202302L && __GLIBCXX__ <= 20240908) and (!defined(_LIBCPP_STD_VER) || _LIBCPP_STD_VER < 23)
392#if !qStroika_HasComponent_fmtlib or (FMT_VERSION < 110000)
394 or Common::IPair<remove_cvref_t<T>> or
395 Common::ITuple<remove_cvref_t<T>>
398#if (!defined(__cpp_lib_formatters) || __cpp_lib_formatters < 202302L) and (!defined(_LIBCPP_STD_VER) || _LIBCPP_STD_VER < 23)
400 or Common::IAnyOf<remove_cvref_t<T>, thread::id>
402#if __cplusplus < 202400L || (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE <= 14)
403 or Common::IAnyOf<remove_cvref_t<T>, std::filesystem::path>
405 or is_enum_v<remove_cvref_t<T>> or Common::IOptional<remove_cvref_t<T>> or Common::IVariant<remove_cvref_t<T>> or
406 same_as<T, std::chrono::time_point<chrono::steady_clock, chrono::duration<double>>> or
407 Common::IAnyOf<remove_cvref_t<T>, exception_ptr, type_index> or derived_from<T, exception> or Common::ISharedPtr<T>);
423template <Stroika::Foundation::Characters::Private_::IUseToStringFormatterForFormatter_ T>
425template <Stroika::Foundation::Characters::Private_::IUseToStringFormatterForFormatter_ T>
426struct qStroika_Foundation_Characters_FMT_PREFIX_::formatter<T, char> : Stroika::Foundation::Characters::ToStringFormatterASCII<T> {};
428#if qCompilerAndStdLib_StdFmtOfPath_Buggy
430struct qStroika_Foundation_Characters_FMT_PREFIX_::formatter<
std::filesystem::path, wchar_t>
433struct qStroika_Foundation_Characters_FMT_PREFIX_::formatter<
std::filesystem::path, char>
434 : Stroika::Foundation::Characters::ToStringFormatterASCII<std::filesystem::path> {};
442static_assert (Stroika::Foundation::Common::StdCompat::formattable<std::exception_ptr, wchar_t>);
443static_assert (Stroika::Foundation::Common::StdCompat::formattable<std::filesystem::path, wchar_t>);
444static_assert (Stroika::Foundation::Common::StdCompat::formattable<std::optional<int>,
wchar_t>);
445static_assert (Stroika::Foundation::Common::StdCompat::formattable<std::shared_ptr<int>,
wchar_t>);
446static_assert (Stroika::Foundation::Common::StdCompat::formattable<std::pair<int, char>,
wchar_t>);
447static_assert (Stroika::Foundation::Common::StdCompat::formattable<std::thread::id, wchar_t>);
448static_assert (Stroika::Foundation::Common::StdCompat::formattable<std::type_index, wchar_t>);
449#if !qCompilerAndStdLib_FormatThreadId_Buggy
450static_assert (Stroika::Foundation::Common::StdCompat::formattable<std::thread::id, wchar_t>);
452#if qCompilerAndStdLib_formattable_of_tuple_Buggy
455static_assert (Stroika::Foundation::Common::StdCompat::formattable<std::tuple<int>,
wchar_t>);
467#include "ToString.inl"
String is like std::u32string, except it is much easier to use, often much more space efficient,...
nonvirtual string AsNarrowSDKString() const
Check if legal to call Characters::ToString(T)...
concept - trivial shorthand for variadic same_as A or same_as B, or ...
Concept ITuple<T> check if T is a tuple.
String UnoverloadedToString(const T &t)
same as ToString()/1 - but without the potentially confusing multi-arg overloads (confused some templ...
String ToString(T &&t, ARGS... args)
Return a debug-friendly, display version of the argument: not guaranteed parsable or usable except fo...