11
11
#define _LIBCPP___FORMAT_FORMAT_FUNCTIONS
12
12
13
13
#include < __algorithm/clamp.h>
14
+ #include < __algorithm/ranges_find_first_of.h>
15
+ #include < __chrono/statically_widen.h>
14
16
#include < __concepts/convertible_to.h>
15
17
#include < __concepts/same_as.h>
16
18
#include < __config>
36
38
#include < __iterator/iterator_traits.h> // iter_value_t
37
39
#include < __variant/monostate.h>
38
40
#include < array>
41
+ #include < optional>
39
42
#include < string>
40
43
#include < string_view>
41
44
@@ -447,10 +450,47 @@ format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) {
447
450
}
448
451
# endif
449
452
453
+ // Try constant folding the format string instead of going through the whole formatting machinery. If there is no
454
+ // constant folding no extra code should be emitted (with optimizations enabled) and the function returns nullopt. When
455
+ // constant folding is successful, the formatting is performed and the resulting string is returned.
456
+ namespace __format {
457
+ template <class _CharT >
458
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<basic_string<_CharT>> __try_constant_folding (
459
+ basic_string_view<_CharT> __fmt,
460
+ basic_format_args<basic_format_context<back_insert_iterator<__format::__output_buffer<_CharT>>, _CharT>> __args) {
461
+ // Fold strings not containing '{' or '}' to just return the string
462
+ if (bool __is_identity = [&] [[__gnu__::__pure__]] // Make sure the compiler knows this call can be eliminated
463
+ { return std::ranges::find_first_of (__fmt, array{' {' , ' }' }) == __fmt.end (); }();
464
+ __builtin_constant_p (__is_identity) && __is_identity)
465
+ return basic_string<_CharT>{__fmt};
466
+
467
+ // Fold '{}' to the appropriate conversion function
468
+ if (auto __only_first_arg = __fmt == _LIBCPP_STATICALLY_WIDEN (_CharT, " {}" );
469
+ __builtin_constant_p (__only_first_arg) && __only_first_arg) {
470
+ if (auto __arg = __args.get (0 ); __builtin_constant_p (__arg.__type_ )) {
471
+ return std::__visit_format_arg (
472
+ []<class _Tp >(_Tp&& __argument) -> optional<basic_string<_CharT>> {
473
+ if constexpr (is_same_v<remove_cvref_t <_Tp>, basic_string_view<_CharT>>) {
474
+ return basic_string<_CharT>{__argument};
475
+ } else {
476
+ return nullopt;
477
+ }
478
+ },
479
+ __arg);
480
+ }
481
+ }
482
+
483
+ return nullopt;
484
+ }
485
+ } // namespace __format
486
+
450
487
// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
451
488
// fires too eagerly, see http://llvm.org/PR61563.
452
489
template <class = void >
453
490
[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string vformat (string_view __fmt, format_args __args) {
491
+ auto __result = __format::__try_constant_folding (__fmt, __args);
492
+ if (__result.has_value ())
493
+ return *std::move (__result);
454
494
__format::__allocating_buffer<char > __buffer;
455
495
std::vformat_to (__buffer.__make_output_iterator (), __fmt, __args);
456
496
return string{__buffer.__view ()};
@@ -462,6 +502,9 @@ template <class = void>
462
502
template <class = void >
463
503
[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
464
504
vformat (wstring_view __fmt, wformat_args __args) {
505
+ auto __result = __format::__try_constant_folding (__fmt, __args);
506
+ if (__result.has_value ())
507
+ return *std::move (__result);
465
508
__format::__allocating_buffer<wchar_t > __buffer;
466
509
std::vformat_to (__buffer.__make_output_iterator (), __fmt, __args);
467
510
return wstring{__buffer.__view ()};
0 commit comments