mirror of
https://github.com/shadps4-emu/ext-fmt.git
synced 2024-11-23 17:59:52 +00:00
Reduce the number of nontrivial formatter instantiations
This commit is contained in:
parent
f5f3ffac59
commit
3fdba04924
@ -632,6 +632,28 @@ enum type {
|
|||||||
custom_type
|
custom_type
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Maps core type T to the corresponding type enum constant.
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct type_constant : std::integral_constant<type, none_type> {};
|
||||||
|
|
||||||
|
#define FMT_TYPE_CONSTANT(Type, constant) \
|
||||||
|
template <typename Char> \
|
||||||
|
struct type_constant<Type, Char> : std::integral_constant<type, constant> {}
|
||||||
|
|
||||||
|
FMT_TYPE_CONSTANT(int, int_type);
|
||||||
|
FMT_TYPE_CONSTANT(unsigned, uint_type);
|
||||||
|
FMT_TYPE_CONSTANT(long long, long_long_type);
|
||||||
|
FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type);
|
||||||
|
FMT_TYPE_CONSTANT(bool, bool_type);
|
||||||
|
FMT_TYPE_CONSTANT(Char, char_type);
|
||||||
|
FMT_TYPE_CONSTANT(double, double_type);
|
||||||
|
FMT_TYPE_CONSTANT(long double, long_double_type);
|
||||||
|
FMT_TYPE_CONSTANT(const Char*, cstring_type);
|
||||||
|
FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type);
|
||||||
|
FMT_TYPE_CONSTANT(const void*, pointer_type);
|
||||||
|
|
||||||
|
#undef FMT_TYPE_CONSTANT
|
||||||
|
|
||||||
FMT_CONSTEXPR bool is_integral(type t) {
|
FMT_CONSTEXPR bool is_integral(type t) {
|
||||||
FMT_ASSERT(t != internal::named_arg_type, "invalid argument type");
|
FMT_ASSERT(t != internal::named_arg_type, "invalid argument type");
|
||||||
return t > internal::none_type && t <= internal::last_integer_type;
|
return t > internal::none_type && t <= internal::last_integer_type;
|
||||||
|
@ -2179,7 +2179,7 @@ FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs(
|
|||||||
ParseContext& ctx) {
|
ParseContext& ctx) {
|
||||||
// GCC 7.2 requires initializer.
|
// GCC 7.2 requires initializer.
|
||||||
typedef typename ParseContext::char_type char_type;
|
typedef typename ParseContext::char_type char_type;
|
||||||
conditional_t<is_formattable<T, format_context>::value,
|
conditional_t<is_formattable<T, buffer_context<char_type>>::value,
|
||||||
formatter<T, char_type>,
|
formatter<T, char_type>,
|
||||||
internal::fallback_formatter<T, char_type>>
|
internal::fallback_formatter<T, char_type>>
|
||||||
f;
|
f;
|
||||||
@ -2255,12 +2255,6 @@ void check_format_string(S format_str) {
|
|||||||
(void)invalid_format;
|
(void)invalid_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specifies whether to format T using the standard formatter.
|
|
||||||
// It is not possible to use get_type in formatter specialization directly
|
|
||||||
// because of a bug in MSVC.
|
|
||||||
template <typename Context, typename T>
|
|
||||||
using format_type = bool_constant<get_type<Context, T>::value != custom_type>;
|
|
||||||
|
|
||||||
template <template <typename> class Handler, typename Spec, typename Context>
|
template <template <typename> class Handler, typename Spec, typename Context>
|
||||||
void handle_dynamic_spec(Spec& value, arg_ref<typename Context::char_type> ref,
|
void handle_dynamic_spec(Spec& value, arg_ref<typename Context::char_type> ref,
|
||||||
Context& ctx,
|
Context& ctx,
|
||||||
@ -3041,24 +3035,24 @@ class format_int {
|
|||||||
std::string str() const { return std::string(str_, size()); }
|
std::string str() const { return std::string(str_, size()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Formatter of objects of type T.
|
// formatter specializations for the core types corresponding to internal::type
|
||||||
|
// constants.
|
||||||
template <typename T, typename Char>
|
template <typename T, typename Char>
|
||||||
struct formatter<
|
struct formatter<T, Char,
|
||||||
T, Char,
|
enable_if_t<internal::type_constant<T, Char>::value !=
|
||||||
enable_if_t<internal::format_type<buffer_context<Char>, T>::value>> {
|
internal::none_type>> {
|
||||||
FMT_CONSTEXPR formatter() : format_str_(nullptr) {}
|
FMT_CONSTEXPR formatter() : format_str_(nullptr) {}
|
||||||
|
|
||||||
// Parses format specifiers stopping either at the end of the range or at the
|
// Parses format specifiers stopping either at the end of the range or at the
|
||||||
// terminating '}'.
|
// terminating '}'.
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext& ctx) {
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
format_str_ = ctx.begin();
|
format_str_ = ctx.begin();
|
||||||
typedef internal::dynamic_specs_handler<ParseContext> handler_type;
|
using handler_type = internal::dynamic_specs_handler<ParseContext>;
|
||||||
auto type = internal::get_type<buffer_context<Char>, T>::value;
|
auto type = internal::type_constant<T, Char>::value;
|
||||||
internal::specs_checker<handler_type> handler(handler_type(specs_, ctx),
|
internal::specs_checker<handler_type> handler(handler_type(specs_, ctx),
|
||||||
type);
|
type);
|
||||||
auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
|
auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
|
||||||
auto type_spec = specs_.type;
|
|
||||||
auto eh = ctx.error_handler();
|
auto eh = ctx.error_handler();
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case internal::none_type:
|
case internal::none_type:
|
||||||
@ -3070,27 +3064,27 @@ struct formatter<
|
|||||||
case internal::long_long_type:
|
case internal::long_long_type:
|
||||||
case internal::ulong_long_type:
|
case internal::ulong_long_type:
|
||||||
case internal::bool_type:
|
case internal::bool_type:
|
||||||
handle_int_type_spec(type_spec,
|
handle_int_type_spec(specs_.type,
|
||||||
internal::int_type_checker<decltype(eh)>(eh));
|
internal::int_type_checker<decltype(eh)>(eh));
|
||||||
break;
|
break;
|
||||||
case internal::char_type:
|
case internal::char_type:
|
||||||
handle_char_specs(
|
handle_char_specs(
|
||||||
&specs_, internal::char_specs_checker<decltype(eh)>(type_spec, eh));
|
&specs_, internal::char_specs_checker<decltype(eh)>(specs_.type, eh));
|
||||||
break;
|
break;
|
||||||
case internal::double_type:
|
case internal::double_type:
|
||||||
case internal::long_double_type:
|
case internal::long_double_type:
|
||||||
handle_float_type_spec(type_spec,
|
handle_float_type_spec(specs_.type,
|
||||||
internal::float_type_checker<decltype(eh)>(eh));
|
internal::float_type_checker<decltype(eh)>(eh));
|
||||||
break;
|
break;
|
||||||
case internal::cstring_type:
|
case internal::cstring_type:
|
||||||
internal::handle_cstring_type_spec(
|
internal::handle_cstring_type_spec(
|
||||||
type_spec, internal::cstring_type_checker<decltype(eh)>(eh));
|
specs_.type, internal::cstring_type_checker<decltype(eh)>(eh));
|
||||||
break;
|
break;
|
||||||
case internal::string_type:
|
case internal::string_type:
|
||||||
internal::check_string_type_spec(type_spec, eh);
|
internal::check_string_type_spec(specs_.type, eh);
|
||||||
break;
|
break;
|
||||||
case internal::pointer_type:
|
case internal::pointer_type:
|
||||||
internal::check_pointer_type_spec(type_spec, eh);
|
internal::check_pointer_type_spec(specs_.type, eh);
|
||||||
break;
|
break;
|
||||||
case internal::custom_type:
|
case internal::custom_type:
|
||||||
// Custom format specifiers should be checked in parse functions of
|
// Custom format specifiers should be checked in parse functions of
|
||||||
@ -3106,9 +3100,8 @@ struct formatter<
|
|||||||
specs_.width_, specs_.width_ref, ctx, format_str_);
|
specs_.width_, specs_.width_ref, ctx, format_str_);
|
||||||
internal::handle_dynamic_spec<internal::precision_checker>(
|
internal::handle_dynamic_spec<internal::precision_checker>(
|
||||||
specs_.precision, specs_.precision_ref, ctx, format_str_);
|
specs_.precision, specs_.precision_ref, ctx, format_str_);
|
||||||
typedef output_range<typename FormatContext::iterator,
|
using range_type = output_range<typename FormatContext::iterator,
|
||||||
typename FormatContext::char_type>
|
typename FormatContext::char_type>;
|
||||||
range_type;
|
|
||||||
return visit_format_arg(arg_formatter<range_type>(ctx, nullptr, &specs_),
|
return visit_format_arg(arg_formatter<range_type>(ctx, nullptr, &specs_),
|
||||||
internal::make_arg<FormatContext>(val));
|
internal::make_arg<FormatContext>(val));
|
||||||
}
|
}
|
||||||
@ -3118,6 +3111,44 @@ struct formatter<
|
|||||||
const Char* format_str_;
|
const Char* format_str_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define FMT_FORMAT_AS(Type, Base) \
|
||||||
|
template <typename Char> \
|
||||||
|
struct formatter<Type, Char> : formatter<Base, Char> { \
|
||||||
|
template <typename FormatContext> \
|
||||||
|
auto format(const Type& val, FormatContext& ctx) -> decltype(ctx.out()) { \
|
||||||
|
return formatter<Base, Char>::format(val, ctx); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_FORMAT_AS(signed char, int);
|
||||||
|
FMT_FORMAT_AS(unsigned char, unsigned);
|
||||||
|
FMT_FORMAT_AS(short, int);
|
||||||
|
FMT_FORMAT_AS(unsigned short, unsigned);
|
||||||
|
FMT_FORMAT_AS(long, long long);
|
||||||
|
FMT_FORMAT_AS(unsigned long, unsigned long long);
|
||||||
|
FMT_FORMAT_AS(float, double);
|
||||||
|
FMT_FORMAT_AS(Char*, const Char*);
|
||||||
|
FMT_FORMAT_AS(std::basic_string<Char>, basic_string_view<Char>);
|
||||||
|
FMT_FORMAT_AS(std::nullptr_t, const void*);
|
||||||
|
|
||||||
|
#undef FMT_FORMAT_AS
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
struct formatter<void*, Char> : formatter<const void*, Char> {
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(void* val, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||||
|
return formatter<const void*, Char>::format(val, ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, size_t N>
|
||||||
|
struct formatter<Char[N], Char> : formatter<basic_string_view<Char>, Char> {
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const Char* val, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||||
|
return formatter<basic_string_view<Char>, Char>::format(val, ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// A formatter for types known only at run time such as variant alternatives.
|
// A formatter for types known only at run time such as variant alternatives.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
|
@ -1876,9 +1876,9 @@ enum TestEnum { A };
|
|||||||
|
|
||||||
TEST(FormatTest, Enum) { EXPECT_EQ("0", fmt::format("{}", A)); }
|
TEST(FormatTest, Enum) { EXPECT_EQ("0", fmt::format("{}", A)); }
|
||||||
|
|
||||||
TEST(FormatTest, EnumFormatterUnambiguous) {
|
TEST(FormatTest, FormatterNotSpecialized) {
|
||||||
fmt::formatter<TestEnum> f;
|
EXPECT_FALSE((fmt::internal::is_formattable<
|
||||||
ASSERT_GE(sizeof(f), 0); // use f to avoid compiler warning
|
fmt::formatter<TestEnum>, fmt::format_context>::value));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_HAS_FEATURE(cxx_strong_enums)
|
#if FMT_HAS_FEATURE(cxx_strong_enums)
|
||||||
|
Loading…
Reference in New Issue
Block a user