Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
Characters/Format.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4
6
7 /*
8 ********************************************************************************
9 ********************* Characters::Private_::WithFormatArgs_ ********************
10 ********************************************************************************
11 */
12 namespace Private_ {
13#if qCompilerAndStdLib_formatter_narrowStringIntoWide_Buggy
14 // the narrow strings the standard disables formatting into a wide string
15 template <typename T>
16 concept INarrowString_ = same_as<T, string> or same_as<T, string_view> or (is_bounded_array_v<T> and same_as<remove_extent_t<T>, char>);
17#endif
18 // t itself where std::format can format it, else its Characters::ToString. A char itself too: with fmtlib, StdCompat::formattable
19 // says no to one, though fmtlib formats it as the character - where ToString would print its number
20 template <typename T>
21 inline decltype (auto) AsFormatArg_ (const T& t)
22 {
23#if qCompilerAndStdLib_formatter_narrowStringIntoWide_Buggy
24 if constexpr ((Common::StdCompat::formattable<T, wchar_t> and not INarrowString_<T>) or same_as<T, char>) {
25#else
26 if constexpr (Common::StdCompat::formattable<T, wchar_t> or same_as<T, char>) {
27#endif
28 return (t);
29 }
30 else {
31 return Characters::ToString (t);
32 }
33 }
34 /*
35 * make_wformat_args copies no argument - it keeps references, which f's vformat reads later. So the Strings AsFormatArg_
36 * makes must outlive f: they are this lambda's parameters, alive until it returns, and named (newer libraries'
37 * make_wformat_args takes no temporary). Not make_wformat_args (AsFormatArg_ (args)...) in the caller: those temporaries
38 * die at the end of that statement, before vformat reads them. RESULT is explicit, not deduced, so that Debug/Trace.h -
39 * which cannot include this header - can call this through its declaration.
40 */
41 template <typename RESULT, typename F, typename... ARGS>
42 inline RESULT WithFormatArgs_ (F&& f, const ARGS&... args)
43 {
44 return [&f] (const auto&... a) -> RESULT { return forward<F> (f) (Common::StdCompat::make_wformat_args (a...)); }(AsFormatArg_ (args)...);
45 }
46
47 // the type of what std::format is given for an argument of type T (@see AsFormatArg_)
48 template <typename T>
49 using FormatArg_t = remove_cvref_t<decltype (AsFormatArg_ (declval<const remove_cvref_t<T>&> ()))>;
50 }
51
52 /*
53 ********************************************************************************
54 ********************** Characters::Private_::FixedString_ **********************
55 ********************************************************************************
56 */
57 template <typename CHAR_T, size_t N>
58 consteval Private_::FixedString_<CHAR_T, N>::FixedString_ (const CHAR_T (&s)[N])
59 {
60 for (size_t i = 0; i < N; ++i) {
61 fChars[i] = s[i];
62 }
63 }
64 template <Private_::FixedString_ LITERAL>
65 consteval array<wchar_t, decltype (LITERAL)::kChars + 1> Private_::Widen_ ()
66 {
67 array<wchar_t, decltype (LITERAL)::kChars + 1> result{};
68 for (size_t i = 0; i < result.size (); ++i) {
69 result[i] = static_cast<wchar_t> (LITERAL.fChars[i]); // a narrow one is ASCII - @see IsASCII_
70 }
71 return result;
72 }
73 template <Private_::FixedString_ LITERAL>
74 consteval bool Private_::IsASCII_ ()
75 {
76 if constexpr (same_as<typename decltype (LITERAL)::CharType, char>) {
77 for (char c : LITERAL.fChars) {
78 if (static_cast<unsigned char> (c) >= 0x80) {
79 return false;
80 }
81 }
82 }
83 return true;
84 }
85
86 /*
87 ********************************************************************************
88 ***************************** FormatString<CHAR_T> *****************************
89 ********************************************************************************
90 */
91 template <typename CHAR_T>
92 constexpr FormatString<CHAR_T>::FormatString (const basic_string_view<CHAR_T>& s)
93 : fSV_{s}
94 {
95#if qStroika_Foundation_Debug_AssertionsChecked
96 if (not is_constant_evaluated ()) {
97 Require (Private_::LastsAppLifetime_ (fSV_)); // @see the lifetime note on FormatString
98 }
99#endif
100 }
101 template <typename CHAR_T>
102 constexpr FormatString<CHAR_T>::FormatString (const basic_string_view<CHAR_T>& s, Unchecked_)
103 : fSV_{s}
104 {
105 }
106 template <typename CHAR_T>
107 constexpr wstring_view FormatString<CHAR_T>::get () const
108 {
109 return fSV_;
110 }
111 template <typename CHAR_T>
112 constexpr qStroika_Foundation_Characters_FMT_PREFIX_::wstring_view FormatString<CHAR_T>::getx_ () const
113 {
114 return qStroika_Foundation_Characters_FMT_PREFIX_::wstring_view{fSV_.data (), fSV_.size ()};
115 }
116 template <typename CHAR_T>
117 template <IFormattable... ARGS>
118 [[nodiscard]] inline String FormatString<CHAR_T>::operator() (ARGS&&... args) const
120 return Private_::WithFormatArgs_<String> (
121 [this] (Common::StdCompat::wformat_args a) { return Common::StdCompat::vformat (getx_ (), a); }, args...);
122 }
123 template <typename CHAR_T>
124 template <IFormattable... ARGS>
125 [[nodiscard]] inline String FormatString<CHAR_T>::operator() (const locale& loc, ARGS&&... args) const
127 return Private_::WithFormatArgs_<String> (
128 [&] (Common::StdCompat::wformat_args a) { return Common::StdCompat::vformat (loc, getx_ (), a); }, args...);
129 }
130#if qCompilerAndStdLib_vector_constexpr_warning_Buggy
131 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Winvalid-constexpr\"");
132#endif
133#if qCompilerAndStdLib_vector_constexpr_Buggy
134 inline
135#else
136 constexpr
137#endif
139 : fStringData_{src.fStringData_}
140 , fFmtStr_{basic_string_view<wchar_t>{fStringData_.data (), fStringData_.size ()}, FormatString<wchar_t>::Unchecked_{}}
141 {
142 }
143#if qCompilerAndStdLib_vector_constexpr_Buggy
144 inline
145#else
146 constexpr
147#endif
148 FormatString<char>::FormatString (const basic_string_view<char>& s)
149 : fStringData_{s.begin (), s.end ()}
150 , fFmtStr_{basic_string_view<wchar_t>{fStringData_.data (), fStringData_.size ()}, FormatString<wchar_t>::Unchecked_{}}
151 {
152 Character::CheckASCII (span{s});
153 }
154#if qCompilerAndStdLib_vector_constexpr_Buggy
155 inline
156#else
157 constexpr
158#endif
159 FormatString<char>& FormatString<char>::operator= (const FormatString& rhs)
160 {
161 // not defaulted: that would copy rhs's view - of rhs's copy, not this one's
162 fStringData_ = rhs.fStringData_;
163 fFmtStr_ = FormatString<wchar_t>{basic_string_view<wchar_t>{fStringData_.data (), fStringData_.size ()}, FormatString<wchar_t>::Unchecked_{}};
164 return *this;
165 }
166 constexpr wstring_view FormatString<char>::get () const
167 {
168 return fFmtStr_.get ();
169 }
170 constexpr qStroika_Foundation_Characters_FMT_PREFIX_::wstring_view FormatString<char>::getx_ () const
171 {
172 return fFmtStr_.getx_ ();
173 }
174 template <Stroika_Foundation_Common_formattable_FilterOnStringLitOp_BWA (IFormattable)... ARGS>
175 [[nodiscard]] inline String FormatString<char>::operator() (ARGS&&... args) const
176 {
177 return fFmtStr_ (forward<ARGS> (args)...);
178 }
179 template <Stroika_Foundation_Common_formattable_FilterOnStringLitOp_BWA (IFormattable)... ARGS>
180 [[nodiscard]] inline String FormatString<char>::operator() (const locale& loc, ARGS&&... args) const
181 {
182 return fFmtStr_ (loc, forward<ARGS> (args)...);
183 }
184
185 /*
186 ********************************************************************************
187 ************************ FormatLiteral<LITERAL> ********************************
188 ********************************************************************************
189 */
190 template <Private_::FixedString_ LITERAL>
191 constexpr FormatLiteral<LITERAL>::FormatLiteral ()
192 : FormatString<wchar_t>{wstring_view{kWide_.data (), decltype (LITERAL)::kChars}, Unchecked_{}}
193 {
194 }
195 template <Private_::FixedString_ LITERAL>
196 template <Stroika_Foundation_Common_formattable_FilterOnStringLitOp_BWA (IFormattable)... ARGS>
197 [[nodiscard]] inline String FormatLiteral<LITERAL>::operator() (ARGS&&... args) const
198 {
199 CheckArgs<ARGS...> ();
200 return FormatString<wchar_t>::operator() (forward<ARGS> (args)...);
201 }
202 template <Private_::FixedString_ LITERAL>
203 template <Stroika_Foundation_Common_formattable_FilterOnStringLitOp_BWA (IFormattable)... ARGS>
204 [[nodiscard]] inline String FormatLiteral<LITERAL>::operator() (const locale& loc, ARGS&&... args) const
205 {
206 CheckArgs<ARGS...> ();
207 return FormatString<wchar_t>::operator() (loc, forward<ARGS> (args)...);
208 }
209 template <Private_::FixedString_ LITERAL>
210 template <typename... ARGS>
212 {
213 // as WithFormatArgs_ passes them on
214 using Checked = Common::StdCompat::wformat_string<Private_::FormatArg_t<ARGS>...>;
215#if qCompilerAndStdLib_format_dynamic_spec_Buggy
216 // a replacement field within a replacement field - a dynamic width or precision - is checked only at run time
217 bool inField = false;
218 for (size_t i = 0; i < decltype (LITERAL)::kChars; ++i) {
219 if (kWide_[i] == '{') {
220 if (inField) {
221 return;
222 }
223 if (kWide_[i + 1] == '{') {
224 ++i; // an escaped { (kWide_ ends with a NUL, so [i + 1] is there)
225 }
226 else {
227 inField = true;
228 }
229 }
230 else if (kWide_[i] == '}') {
231 inField = false;
232 }
233 }
234#endif
235#if qCompilerAndStdLib_format_check_StaticArray_Buggy
236 const auto wide = Private_::Widen_<LITERAL> ();
237 [[maybe_unused]] Checked checked{wstring_view{wide.data (), decltype (LITERAL)::kChars}};
238#else
239 [[maybe_unused]] Checked checked{wstring_view{kWide_.data (), decltype (LITERAL)::kChars}};
240#endif
241 }
242 template <Private_::FixedString_ LITERAL>
244 requires (same_as<typename decltype (LITERAL)::CharType, char>)
245 {
246 return FormatString<char>{string_view{LITERAL.fChars, decltype (LITERAL)::kChars}};
247 }
248
249 /*
250 ********************************************************************************
251 ************************* Characters::Literals *********************************
252 ********************************************************************************
253 */
254 inline namespace Literals {
255 template <Private_::FixedString_ LITERAL>
256 consteval FormatLiteral<LITERAL> operator""_f ()
257 {
258 return FormatLiteral<LITERAL>{};
259 }
260 }
261#if qCompilerAndStdLib_vector_constexpr_warning_Buggy
262 DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Winvalid-constexpr\"");
263#endif
264
265 /*
266 ********************************************************************************
267 *********************************** VFormat ************************************
268 ********************************************************************************
269 */
270 template <typename CHAR_T>
271 [[nodiscard]] inline String VFormat (const FormatString<CHAR_T>& f, const Common::StdCompat::wformat_args& args)
272 {
273 return Common::StdCompat::vformat (f.getx_ (), args);
274 }
275 template <typename CHAR_T>
276 [[nodiscard]] inline String VFormat (const locale& loc, const FormatString<CHAR_T>& f, const Common::StdCompat::wformat_args& args)
277 {
278 return Common::StdCompat::vformat (loc, f.getx_ (), args);
279 }
280
281 /*
282 ********************************************************************************
283 ************************************ Format ************************************
284 ********************************************************************************
285 */
286 template <typename CHAR_T, IFormattable... ARGS>
287 inline String Format (const FormatString<CHAR_T>& f, ARGS&&... args)
288 {
289 return f (forward<ARGS> (args)...);
290 }
291 template <typename CHAR_T, IFormattable... ARGS>
292 inline String Format (const locale& loc, const FormatString<CHAR_T>& f, ARGS&&... args)
293 {
294 return f (loc, forward<ARGS> (args)...);
295 }
296 template <Private_::FixedString_ LITERAL, Stroika_Foundation_Common_formattable_FilterOnStringLitOp_BWA (IFormattable)... ARGS>
297 inline String Format (const FormatLiteral<LITERAL>& f, ARGS&&... args)
298 {
299 return f (forward<ARGS> (args)...);
300 }
301 template <Private_::FixedString_ LITERAL, Stroika_Foundation_Common_formattable_FilterOnStringLitOp_BWA (IFormattable)... ARGS>
302 inline String Format (const locale& loc, const FormatLiteral<LITERAL>& f, ARGS&&... args)
303 {
304 return f (loc, forward<ARGS> (args)...);
305 }
306
307}
RESULT WithFormatArgs_(F &&f, const ARGS &... args)
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
what types Stroika's formatting - FormatString (_f), Format, DbgTrace - formats: anything std::format...
String ToString(T &&t, ARGS... args)
Return a debug-friendly, display version of the argument: not guaranteed parsable or usable except fo...
Definition ToString.inl:424
String VFormat(const FormatString< CHAR_T > &f, const Common::StdCompat::wformat_args &args)
same as std::vformat, except that it always uses wformat_args, and produces a Stroika String
what "..."_f is: a format string whose literal is part of its type - so it is widened (if narrow) at ...
Stroika's format string: it always formats WIDE - each argument as std::formatter<T,...
String operator()(ARGS &&... args) const
format args - checked against the format string at run time: a mismatch throws format_error (a Format...
constexpr qStroika_Foundation_Characters_FMT_PREFIX_::wstring_view getx_() const
the format string as the formatting library's own wstring_view (std's, or fmtlib's) - only for callin...