2121#endif
2222
2323// The fmt library version in the form major * 10000 + minor * 100 + patch.
24- #define FMT_VERSION 110103
24+ #define FMT_VERSION 110200
2525
2626// Detect compiler versions.
2727#if defined(__clang__) && !defined(__ibmxl__)
209209# define FMT_DEPRECATED /* deprecated */
210210#endif
211211
212- #ifdef FMT_ALWAYS_INLINE
213- // Use the provided definition.
214- #elif FMT_GCC_VERSION || FMT_CLANG_VERSION
215- # define FMT_ALWAYS_INLINE inline __attribute__ ((always_inline))
216- #else
217- # define FMT_ALWAYS_INLINE inline
218- #endif
219- // A version of FMT_ALWAYS_INLINE to prevent code bloat in debug mode.
220- #ifdef NDEBUG
221- # define FMT_INLINE FMT_ALWAYS_INLINE
222- #else
223- # define FMT_INLINE inline
224- #endif
225-
226212#if FMT_GCC_VERSION || FMT_CLANG_VERSION
227213# define FMT_VISIBILITY (value ) __attribute__((visibility(value)))
228214#else
249235# define FMT_MSC_WARNING (...)
250236#endif
251237
238+ // Enable minimal optimizations for more compact code in debug mode.
239+ FMT_PRAGMA_GCC (push_options)
240+ #if !defined(__OPTIMIZE__) && !defined(__CUDACC__) && !defined(FMT_MODULE)
241+ FMT_PRAGMA_GCC (optimize(" Og" ))
242+ # define FMT_GCC_OPTIMIZED
243+ #endif
244+ FMT_PRAGMA_CLANG (diagnostic push)
245+
246+ #ifdef FMT_ALWAYS_INLINE
247+ // Use the provided definition.
248+ #elif FMT_GCC_VERSION || FMT_CLANG_VERSION
249+ # define FMT_ALWAYS_INLINE inline __attribute__ ((always_inline))
250+ #else
251+ # define FMT_ALWAYS_INLINE inline
252+ #endif
253+ // A version of FMT_ALWAYS_INLINE to prevent code bloat in debug mode.
254+ #if defined(NDEBUG) || defined(FMT_GCC_OPTIMIZED)
255+ # define FMT_INLINE FMT_ALWAYS_INLINE
256+ #else
257+ # define FMT_INLINE inline
258+ #endif
259+
252260#ifndef FMT_BEGIN_NAMESPACE
253261# define FMT_BEGIN_NAMESPACE \
254262 namespace fmt { \
294302#endif
295303
296304#define FMT_APPLY_VARIADIC (expr ) \
297- using ignore = int []; \
298- (void )ignore { 0 , (expr, 0 )... }
299-
300- // Enable minimal optimizations for more compact code in debug mode.
301- FMT_PRAGMA_GCC (push_options)
302- #if !defined(__OPTIMIZE__) && !defined(__CUDACC__) && !defined(FMT_MODULE)
303- FMT_PRAGMA_GCC (optimize(" Og" ))
304- #endif
305- FMT_PRAGMA_CLANG (diagnostic push)
305+ using unused = int []; \
306+ (void )unused { 0 , (expr, 0 )... }
306307
307308FMT_BEGIN_NAMESPACE
308309
@@ -325,8 +326,8 @@ using underlying_t = typename std::underlying_type<T>::type;
325326template <typename T> using decay_t = typename std::decay<T>::type;
326327using nullptr_t = decltype (nullptr );
327328
328- #if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
329- // A workaround for gcc 4.9 to make void_t work in a SFINAE context.
329+ #if ( FMT_GCC_VERSION && FMT_GCC_VERSION < 500) || FMT_MSC_VERSION
330+ // A workaround for gcc 4.9 & MSVC v141 to make void_t work in a SFINAE context.
330331template <typename ...> struct void_t_impl {
331332 using type = void ;
332333};
@@ -526,20 +527,20 @@ template <typename Char> class basic_string_view {
526527
527528 constexpr basic_string_view () noexcept : data_(nullptr ), size_(0 ) {}
528529
529- // / Constructs a string reference object from a C string and a size.
530+ // / Constructs a string view object from a C string and a size.
530531 constexpr basic_string_view (const Char* s, size_t count) noexcept
531532 : data_(s), size_(count) {}
532533
533534 constexpr basic_string_view (nullptr_t ) = delete;
534535
535- // / Constructs a string reference object from a C string.
536+ // / Constructs a string view object from a C string.
536537#if FMT_GCC_VERSION
537538 FMT_ALWAYS_INLINE
538539#endif
539540 FMT_CONSTEXPR20 basic_string_view (const Char* s) : data_(s) {
540- #if FMT_HAS_BUILTIN(__buitin_strlen ) || FMT_GCC_VERSION || FMT_CLANG_VERSION
541- if (std::is_same<Char, char >::value) {
542- size_ = __builtin_strlen (detail::narrow (s));
541+ #if FMT_HAS_BUILTIN(__builtin_strlen ) || FMT_GCC_VERSION || FMT_CLANG_VERSION
542+ if (std::is_same<Char, char >::value && ! detail::is_constant_evaluated () ) {
543+ size_ = __builtin_strlen (detail::narrow (s)); // strlen is not costexpr.
543544 return ;
544545 }
545546#endif
@@ -548,7 +549,7 @@ template <typename Char> class basic_string_view {
548549 size_ = len;
549550 }
550551
551- // / Constructs a string reference from a `std::basic_string` or a
552+ // / Constructs a string view from a `std::basic_string` or a
552553 // / `std::basic_string_view` object.
553554 template <typename S,
554555 FMT_ENABLE_IF (detail::is_std_string_like<S>::value&& std::is_same<
@@ -585,7 +586,6 @@ template <typename Char> class basic_string_view {
585586 return starts_with (basic_string_view<Char>(s));
586587 }
587588
588- // Lexicographically compare this string reference to other.
589589 FMT_CONSTEXPR auto compare (basic_string_view other) const -> int {
590590 int result =
591591 detail::compare (data_, other.data_ , min_of (size_, other.size_ ));
@@ -616,7 +616,7 @@ template <typename Char> class basic_string_view {
616616
617617using string_view = basic_string_view<char >;
618618
619- // / Specifies if `T` is an extended character type. Can be specialized by users .
619+ // DEPRECATED! Will be merged with is_char and moved to detail .
620620template <typename T> struct is_xchar : std::false_type {};
621621template <> struct is_xchar <wchar_t > : std::true_type {};
622622template <> struct is_xchar <char16_t > : std::true_type {};
@@ -625,7 +625,7 @@ template <> struct is_xchar<char32_t> : std::true_type {};
625625template <> struct is_xchar <char8_t > : std::true_type {};
626626#endif
627627
628- // DEPRECATED! Will be replaced with an alias to prevent specializations .
628+ // Specifies if `T` is a character (code unit) type .
629629template <typename T> struct is_char : is_xchar<T> {};
630630template <> struct is_char <char > : std::true_type {};
631631
@@ -740,7 +740,7 @@ class basic_specs {
740740 };
741741
742742 unsigned data_ = 1 << fill_size_shift;
743- static_assert (sizeof (data_) * CHAR_BIT >= 18 , " " );
743+ static_assert (sizeof (basic_specs:: data_) * CHAR_BIT >= 18 , " " );
744744
745745 // Character (code unit) type is erased to prevent template bloat.
746746 char fill_data_[max_fill_size] = {' ' };
@@ -1032,6 +1032,11 @@ enum {
10321032
10331033struct view {};
10341034
1035+ template <typename T, typename Enable = std::true_type>
1036+ struct is_view : std::false_type {};
1037+ template <typename T>
1038+ struct is_view <T, bool_constant<sizeof (T) != 0 >> : std::is_base_of<view, T> {};
1039+
10351040template <typename Char, typename T> struct named_arg ;
10361041template <typename T> struct is_named_arg : std::false_type {};
10371042template <typename T> struct is_static_named_arg : std::false_type {};
@@ -1064,13 +1069,24 @@ template <typename Char> struct named_arg_info {
10641069 int id;
10651070};
10661071
1072+ // named_args is non-const to suppress a bogus -Wmaybe-uninitalized in gcc 13.
1073+ template <typename Char>
1074+ FMT_CONSTEXPR void check_for_duplicate (named_arg_info<Char>* named_args,
1075+ int named_arg_index,
1076+ basic_string_view<Char> arg_name) {
1077+ for (int i = 0 ; i < named_arg_index; ++i) {
1078+ if (named_args[i].name == arg_name) report_error (" duplicate named arg" );
1079+ }
1080+ }
1081+
10671082template <typename Char, typename T, FMT_ENABLE_IF(!is_named_arg<T>::value)>
10681083void init_named_arg (named_arg_info<Char>*, int & arg_index, int &, const T&) {
10691084 ++arg_index;
10701085}
10711086template <typename Char, typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
10721087void init_named_arg (named_arg_info<Char>* named_args, int & arg_index,
10731088 int & named_arg_index, const T& arg) {
1089+ check_for_duplicate<Char>(named_args, named_arg_index, arg.name );
10741090 named_args[named_arg_index++] = {arg.name , arg_index++};
10751091}
10761092
@@ -1084,12 +1100,13 @@ template <typename T, typename Char,
10841100 FMT_ENABLE_IF (is_static_named_arg<T>::value)>
10851101FMT_CONSTEXPR void init_static_named_arg (named_arg_info<Char>* named_args,
10861102 int & arg_index, int & named_arg_index) {
1103+ check_for_duplicate<Char>(named_args, named_arg_index, T::name);
10871104 named_args[named_arg_index++] = {T::name, arg_index++};
10881105}
10891106
10901107// To minimize the number of types we need to deal with, long is translated
10911108// either to int or to long long depending on its size.
1092- enum { long_short = sizeof (long ) == sizeof (int ) };
1109+ enum { long_short = sizeof (long ) == sizeof (int ) && FMT_BUILTIN_TYPES };
10931110using long_type = conditional_t <long_short, int , long long >;
10941111using ulong_type = conditional_t <long_short, unsigned , unsigned long long >;
10951112
@@ -1706,7 +1723,17 @@ class format_string_checker {
17061723 -> const Char* {
17071724 context_.advance_to (begin);
17081725 if (id >= 0 && id < NUM_ARGS) return parse_funcs_[id](context_);
1709- while (begin != end && *begin != ' }' ) ++begin;
1726+
1727+ // If id is out of range, it means we do not know the type and cannot parse
1728+ // the format at compile time. Instead, skip over content until we finish
1729+ // the format spec, accounting for any nested replacements.
1730+ for (int bracket_count = 0 ;
1731+ begin != end && (bracket_count > 0 || *begin != ' }' ); ++begin) {
1732+ if (*begin == ' {' )
1733+ ++bracket_count;
1734+ else if (*begin == ' }' )
1735+ --bracket_count;
1736+ }
17101737 return begin;
17111738 }
17121739
@@ -2263,15 +2290,15 @@ template <> struct is_output_iterator<appender, char> : std::true_type {};
22632290template <typename It, typename T>
22642291struct is_output_iterator <
22652292 It, T,
2266- void_t < decltype (*std::declval<decay_t <It>&>()++ = std::declval<T>())>>
2267- : std::true_type {};
2293+ enable_if_t <std::is_assignable< decltype (*std::declval<decay_t <It>&>()++),
2294+ T>::value>> : std::true_type {};
22682295
22692296#ifndef FMT_USE_LOCALE
22702297# define FMT_USE_LOCALE (FMT_OPTIMIZE_SIZE <= 1 )
22712298#endif
22722299
22732300// A type-erased reference to an std::locale to avoid a heavy <locale> include.
2274- struct locale_ref {
2301+ class locale_ref {
22752302#if FMT_USE_LOCALE
22762303 private:
22772304 const void * locale_; // A type-erased pointer to std::locale.
@@ -2283,6 +2310,7 @@ struct locale_ref {
22832310 inline explicit operator bool () const noexcept { return locale_ != nullptr ; }
22842311#endif // FMT_USE_LOCALE
22852312
2313+ public:
22862314 template <typename Locale> auto get () const -> Locale;
22872315};
22882316
@@ -2702,7 +2730,7 @@ template <typename... T> struct fstring {
27022730 template <size_t N>
27032731 FMT_CONSTEVAL FMT_ALWAYS_INLINE fstring (const char (&s)[N]) : str(s, N - 1 ) {
27042732 using namespace detail ;
2705- static_assert (count<(std::is_base_of<view, remove_reference_t <T>>::value &&
2733+ static_assert (count<(is_view< remove_cvref_t <T>>::value &&
27062734 std::is_reference<T>::value)...>() == 0 ,
27072735 " passing views as lvalues is disallowed" );
27082736 if (FMT_USE_CONSTEVAL) parse_format_string<char >(s, checker (s, arg_pack ()));
@@ -2729,9 +2757,9 @@ template <typename... T> struct fstring {
27292757 std::is_same<typename S::char_type, char >::value)>
27302758 FMT_ALWAYS_INLINE fstring(const S&) : str(S()) {
27312759 FMT_CONSTEXPR auto sv = string_view (S ());
2732- FMT_CONSTEXPR int ignore =
2760+ FMT_CONSTEXPR int unused =
27332761 (parse_format_string (sv, checker (sv, arg_pack ())), 0 );
2734- detail::ignore_unused (ignore );
2762+ detail::ignore_unused (unused );
27352763 }
27362764 fstring (runtime_format_string<> fmt) : str(fmt.str) {}
27372765
0 commit comments