21
21
#endif
22
22
23
23
// The fmt library version in the form major * 10000 + minor * 100 + patch.
24
- #define FMT_VERSION 110102
24
+ #define FMT_VERSION 110200
25
25
26
26
// Detect compiler versions.
27
27
#if defined(__clang__) && !defined(__ibmxl__)
96
96
// Detect C++14 relaxed constexpr.
97
97
#ifdef FMT_USE_CONSTEXPR
98
98
// Use the provided definition.
99
- #elif FMT_GCC_VERSION >= 600 && FMT_CPLUSPLUS >= 201402L
100
- // GCC only allows throw in constexpr since version 6 :
101
- // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67371 .
99
+ #elif FMT_GCC_VERSION >= 702 && FMT_CPLUSPLUS >= 201402L
100
+ // GCC only allows constexpr member functions in non-literal types since 7.2 :
101
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66297 .
102
102
# define FMT_USE_CONSTEXPR 1
103
103
#elif FMT_ICC_VERSION
104
104
# define FMT_USE_CONSTEXPR 0 // https://github.com/fmtlib/fmt/issues/1628
209
209
# define FMT_DEPRECATED /* deprecated */
210
210
#endif
211
211
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
-
226
212
#if FMT_GCC_VERSION || FMT_CLANG_VERSION
227
213
# define FMT_VISIBILITY (value ) __attribute__((visibility(value)))
228
214
#else
249
235
# define FMT_MSC_WARNING (...)
250
236
#endif
251
237
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
+
252
260
#ifndef FMT_BEGIN_NAMESPACE
253
261
# define FMT_BEGIN_NAMESPACE \
254
262
namespace fmt { \
294
302
#endif
295
303
296
304
#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__)
303
- FMT_PRAGMA_GCC (optimize(" Og" ))
304
- #endif
305
- FMT_PRAGMA_CLANG (diagnostic push)
305
+ using unused = int []; \
306
+ (void )unused { 0 , (expr, 0 )... }
306
307
307
308
FMT_BEGIN_NAMESPACE
308
309
@@ -325,8 +326,8 @@ using underlying_t = typename std::underlying_type<T>::type;
325
326
template <typename T> using decay_t = typename std::decay<T>::type;
326
327
using nullptr_t = decltype (nullptr );
327
328
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.
330
331
template <typename ...> struct void_t_impl {
331
332
using type = void ;
332
333
};
@@ -526,20 +527,20 @@ template <typename Char> class basic_string_view {
526
527
527
528
constexpr basic_string_view () noexcept : data_(nullptr ), size_(0 ) {}
528
529
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.
530
531
constexpr basic_string_view (const Char* s, size_t count) noexcept
531
532
: data_(s), size_(count) {}
532
533
533
534
constexpr basic_string_view (nullptr_t ) = delete;
534
535
535
- // / Constructs a string reference object from a C string.
536
+ // / Constructs a string view object from a C string.
536
537
#if FMT_GCC_VERSION
537
538
FMT_ALWAYS_INLINE
538
539
#endif
539
540
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.
543
544
return ;
544
545
}
545
546
#endif
@@ -548,7 +549,7 @@ template <typename Char> class basic_string_view {
548
549
size_ = len;
549
550
}
550
551
551
- // / Constructs a string reference from a `std::basic_string` or a
552
+ // / Constructs a string view from a `std::basic_string` or a
552
553
// / `std::basic_string_view` object.
553
554
template <typename S,
554
555
FMT_ENABLE_IF (detail::is_std_string_like<S>::value&& std::is_same<
@@ -585,7 +586,6 @@ template <typename Char> class basic_string_view {
585
586
return starts_with (basic_string_view<Char>(s));
586
587
}
587
588
588
- // Lexicographically compare this string reference to other.
589
589
FMT_CONSTEXPR auto compare (basic_string_view other) const -> int {
590
590
int result =
591
591
detail::compare (data_, other.data_ , min_of (size_, other.size_ ));
@@ -616,7 +616,7 @@ template <typename Char> class basic_string_view {
616
616
617
617
using string_view = basic_string_view<char >;
618
618
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 .
620
620
template <typename T> struct is_xchar : std::false_type {};
621
621
template <> struct is_xchar <wchar_t > : std::true_type {};
622
622
template <> struct is_xchar <char16_t > : std::true_type {};
@@ -625,7 +625,7 @@ template <> struct is_xchar<char32_t> : std::true_type {};
625
625
template <> struct is_xchar <char8_t > : std::true_type {};
626
626
#endif
627
627
628
- // DEPRECATED! Will be replaced with an alias to prevent specializations .
628
+ // Specifies if `T` is a character (code unit) type .
629
629
template <typename T> struct is_char : is_xchar<T> {};
630
630
template <> struct is_char <char > : std::true_type {};
631
631
@@ -739,13 +739,15 @@ class basic_specs {
739
739
max_fill_size = 4
740
740
};
741
741
742
- size_t data_ = 1 << fill_size_shift;
742
+ unsigned data_ = 1 << fill_size_shift;
743
+ static_assert (sizeof (basic_specs::data_) * CHAR_BIT >= 18 , " " );
743
744
744
745
// Character (code unit) type is erased to prevent template bloat.
745
746
char fill_data_[max_fill_size] = {' ' };
746
747
747
748
FMT_CONSTEXPR void set_fill_size (size_t size) {
748
- data_ = (data_ & ~fill_size_mask) | (size << fill_size_shift);
749
+ data_ = (data_ & ~fill_size_mask) |
750
+ (static_cast <unsigned >(size) << fill_size_shift);
749
751
}
750
752
751
753
public:
@@ -1030,6 +1032,11 @@ enum {
1030
1032
1031
1033
struct view {};
1032
1034
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
+
1033
1040
template <typename Char, typename T> struct named_arg ;
1034
1041
template <typename T> struct is_named_arg : std::false_type {};
1035
1042
template <typename T> struct is_static_named_arg : std::false_type {};
@@ -1062,13 +1069,24 @@ template <typename Char> struct named_arg_info {
1062
1069
int id;
1063
1070
};
1064
1071
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
+
1065
1082
template <typename Char, typename T, FMT_ENABLE_IF(!is_named_arg<T>::value)>
1066
1083
void init_named_arg (named_arg_info<Char>*, int & arg_index, int &, const T&) {
1067
1084
++arg_index;
1068
1085
}
1069
1086
template <typename Char, typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
1070
1087
void init_named_arg (named_arg_info<Char>* named_args, int & arg_index,
1071
1088
int & named_arg_index, const T& arg) {
1089
+ check_for_duplicate<Char>(named_args, named_arg_index, arg.name );
1072
1090
named_args[named_arg_index++] = {arg.name , arg_index++};
1073
1091
}
1074
1092
@@ -1082,12 +1100,13 @@ template <typename T, typename Char,
1082
1100
FMT_ENABLE_IF (is_static_named_arg<T>::value)>
1083
1101
FMT_CONSTEXPR void init_static_named_arg (named_arg_info<Char>* named_args,
1084
1102
int & arg_index, int & named_arg_index) {
1103
+ check_for_duplicate<Char>(named_args, named_arg_index, T::name);
1085
1104
named_args[named_arg_index++] = {T::name, arg_index++};
1086
1105
}
1087
1106
1088
1107
// To minimize the number of types we need to deal with, long is translated
1089
1108
// either to int or to long long depending on its size.
1090
- enum { long_short = sizeof (long ) == sizeof (int ) };
1109
+ enum { long_short = sizeof (long ) == sizeof (int ) && FMT_BUILTIN_TYPES };
1091
1110
using long_type = conditional_t <long_short, int , long long >;
1092
1111
using ulong_type = conditional_t <long_short, unsigned , unsigned long long >;
1093
1112
@@ -1119,7 +1138,7 @@ using use_formatter =
1119
1138
bool_constant<(std::is_class<T>::value || std::is_enum<T>::value ||
1120
1139
std::is_union<T>::value || std::is_array<T>::value) &&
1121
1140
!has_to_string_view<T>::value && !is_named_arg<T>::value &&
1122
- !use_format_as<T>::value && !use_format_as_member<T >::value>;
1141
+ !use_format_as<T>::value && !use_format_as_member<U >::value>;
1123
1142
1124
1143
template <typename Char, typename T, typename U = remove_const_t <T>>
1125
1144
auto has_formatter_impl (T* p, buffered_context<Char>* ctx = nullptr )
@@ -1704,7 +1723,17 @@ class format_string_checker {
1704
1723
-> const Char* {
1705
1724
context_.advance_to (begin);
1706
1725
if (id >= 0 && id < NUM_ARGS) return parse_funcs_[id](context_);
1707
- 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
+ }
1708
1737
return begin;
1709
1738
}
1710
1739
@@ -2261,15 +2290,15 @@ template <> struct is_output_iterator<appender, char> : std::true_type {};
2261
2290
template <typename It, typename T>
2262
2291
struct is_output_iterator <
2263
2292
It, T,
2264
- void_t < decltype (*std::declval<decay_t <It>&>()++ = std::declval<T>())>>
2265
- : std::true_type {};
2293
+ enable_if_t <std::is_assignable< decltype (*std::declval<decay_t <It>&>()++),
2294
+ T>::value>> : std::true_type {};
2266
2295
2267
2296
#ifndef FMT_USE_LOCALE
2268
2297
# define FMT_USE_LOCALE (FMT_OPTIMIZE_SIZE <= 1 )
2269
2298
#endif
2270
2299
2271
2300
// A type-erased reference to an std::locale to avoid a heavy <locale> include.
2272
- struct locale_ref {
2301
+ class locale_ref {
2273
2302
#if FMT_USE_LOCALE
2274
2303
private:
2275
2304
const void * locale_; // A type-erased pointer to std::locale.
@@ -2281,6 +2310,7 @@ struct locale_ref {
2281
2310
inline explicit operator bool () const noexcept { return locale_ != nullptr ; }
2282
2311
#endif // FMT_USE_LOCALE
2283
2312
2313
+ public:
2284
2314
template <typename Locale> auto get () const -> Locale;
2285
2315
};
2286
2316
@@ -2654,6 +2684,7 @@ class context {
2654
2684
FMT_CONSTEXPR auto arg_id (string_view name) const -> int {
2655
2685
return args_.get_id (name);
2656
2686
}
2687
+ auto args () const -> const format_args& { return args_; }
2657
2688
2658
2689
// Returns an iterator to the beginning of the output range.
2659
2690
FMT_CONSTEXPR auto out () const -> iterator { return out_; }
@@ -2699,7 +2730,7 @@ template <typename... T> struct fstring {
2699
2730
template <size_t N>
2700
2731
FMT_CONSTEVAL FMT_ALWAYS_INLINE fstring (const char (&s)[N]) : str(s, N - 1 ) {
2701
2732
using namespace detail ;
2702
- static_assert (count<(std::is_base_of<view, remove_reference_t <T>>::value &&
2733
+ static_assert (count<(is_view< remove_cvref_t <T>>::value &&
2703
2734
std::is_reference<T>::value)...>() == 0 ,
2704
2735
" passing views as lvalues is disallowed" );
2705
2736
if (FMT_USE_CONSTEVAL) parse_format_string<char >(s, checker (s, arg_pack ()));
@@ -2726,9 +2757,9 @@ template <typename... T> struct fstring {
2726
2757
std::is_same<typename S::char_type, char >::value)>
2727
2758
FMT_ALWAYS_INLINE fstring(const S&) : str(S()) {
2728
2759
FMT_CONSTEXPR auto sv = string_view (S ());
2729
- FMT_CONSTEXPR int ignore =
2760
+ FMT_CONSTEXPR int unused =
2730
2761
(parse_format_string (sv, checker (sv, arg_pack ())), 0 );
2731
- detail::ignore_unused (ignore );
2762
+ detail::ignore_unused (unused );
2732
2763
}
2733
2764
fstring (runtime_format_string<> fmt) : str(fmt.str) {}
2734
2765
0 commit comments