diff --git a/include/fmt/core.h b/include/fmt/core.h index 49f13881e7df..4389ee1693a3 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -197,6 +197,8 @@ template using conditional_t = typename std::conditional::type; template using bool_constant = std::integral_constant; +struct monostate {}; + // An enable_if helper to be used in template parameters which results in much // shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed // to workaround a bug in MSVC 2019 (see #1140 and #1186). @@ -213,17 +215,6 @@ using std_string_view = std::experimental::basic_string_view; template struct std_string_view {}; #endif -#if (__cplusplus >= 201703L || \ - (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)) && \ - __cpp_lib_is_invocable >= 201703L -template -using invoke_result_t = std::invoke_result_t; -#else -// An implementation of invoke_result for pre-C++17. -template -using invoke_result_t = typename std::result_of::type; -#endif - // Casts nonnegative integer to unsigned. template FMT_CONSTEXPR typename std::make_unsigned::type to_unsigned(Int value) { @@ -670,7 +661,7 @@ FMT_CONSTEXPR bool is_arithmetic(type t) { } template struct string_value { - const Char* value; + const Char* data; std::size_t size; }; @@ -690,6 +681,8 @@ template class value { unsigned uint_value; long long long_long_value; unsigned long long ulong_long_value; + bool bool_value; + char_type char_value; double double_value; long double long_double_value; const void* pointer; @@ -704,11 +697,11 @@ template class value { value(unsigned long long val) : ulong_long_value(val) {} value(double val) : double_value(val) {} value(long double val) : long_double_value(val) {} - value(bool val) : int_value(val) {} - value(char_type val) : int_value(val) {} - value(const char_type* val) { string.value = val; } + value(bool val) : bool_value(val) {} + value(char_type val) : char_value(val) {} + value(const char_type* val) { string.data = val; } value(basic_string_view val) { - string.value = val.data(); + string.data = val.data(); string.size = val.size(); } value(const void* val) : pointer(val) {} @@ -764,7 +757,7 @@ template struct arg_mapper { FMT_CONSTEXPR bool map(bool val) { return val; } template ::value)> - FMT_CONSTEXPR char_type map(const T& val) { + FMT_CONSTEXPR char_type map(T val) { static_assert( std::is_same::value || std::is_same::value, "mixing character types is disallowed"); @@ -834,6 +827,12 @@ template struct arg_mapper { } }; +// A type constant after applying arg_mapper. +template +using mapped_type_constant = + type_constant().map(std::declval())), + typename Context::char_type>; + // Maximum number of arguments with packed types. enum { max_packed_args = 15 }; enum : unsigned long long { is_unpacked_bit = 1ull << 63 }; @@ -853,8 +852,9 @@ template class basic_format_arg { const T& value); template - friend FMT_CONSTEXPR internal::invoke_result_t visit_format_arg( - Visitor&& vis, const basic_format_arg& arg); + friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis, + const basic_format_arg& arg) + -> decltype(vis(0)); friend class basic_format_args; friend class internal::arg_map; @@ -886,8 +886,6 @@ template class basic_format_arg { bool is_arithmetic() const { return internal::is_arithmetic(type_); } }; -struct monostate {}; - /** \rst Visits an argument dispatching to the appropriate visit method based on @@ -896,8 +894,9 @@ struct monostate {}; \endrst */ template -FMT_CONSTEXPR internal::invoke_result_t visit_format_arg( - Visitor&& vis, const basic_format_arg& arg) { +FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis, + const basic_format_arg& arg) + -> decltype(vis(0)) { using char_type = typename Context::char_type; switch (arg.type_) { case internal::none_type: @@ -914,17 +913,17 @@ FMT_CONSTEXPR internal::invoke_result_t visit_format_arg( case internal::ulong_long_type: return vis(arg.value_.ulong_long_value); case internal::bool_type: - return vis(arg.value_.int_value != 0); + return vis(arg.value_.bool_value); case internal::char_type: - return vis(static_cast(arg.value_.int_value)); + return vis(arg.value_.char_value); case internal::double_type: return vis(arg.value_.double_value); case internal::long_double_type: return vis(arg.value_.long_double_value); case internal::cstring_type: - return vis(arg.value_.string.value); + return vis(arg.value_.string.data); case internal::string_type: - return vis(basic_string_view(arg.value_.string.value, + return vis(basic_string_view(arg.value_.string.data, arg.value_.string.size)); case internal::pointer_type: return vis(arg.value_.pointer); @@ -935,8 +934,9 @@ FMT_CONSTEXPR internal::invoke_result_t visit_format_arg( } template -FMT_DEPRECATED FMT_CONSTEXPR internal::invoke_result_t visit( - Visitor&& vis, const basic_format_arg& arg) { +FMT_DEPRECATED FMT_CONSTEXPR auto visit(Visitor&& vis, + const basic_format_arg& arg) + -> decltype(vis(0)) { return visit_format_arg(std::forward(vis), arg); } @@ -959,7 +959,7 @@ template class arg_map { void push_back(value val) { const auto& named = *val.named_arg; - map_[size_] = entry{named.name, named.template deserialize()}; + map_[size_] = {named.name, named.template deserialize()}; ++size_; } @@ -989,26 +989,18 @@ class locale_ref { template Locale get() const; }; -template struct get_type { - static const type value = type_constant< - decltype(arg_mapper().map( - std::declval::type>())), - typename Context::char_type>::value; -}; - -template constexpr unsigned long long get_types() { - return 0; -} +template constexpr unsigned long long get_types() { return 0; } template constexpr unsigned long long get_types() { - return get_type::value | (get_types() << 4); + return mapped_type_constant::value | + (get_types() << 4); } template FMT_CONSTEXPR basic_format_arg make_arg(const T& value) { basic_format_arg arg; - arg.type_ = get_type::value; + arg.type_ = mapped_type_constant::value; arg.value_ = arg_mapper().map(value); return arg; } diff --git a/include/fmt/format.h b/include/fmt/format.h index 16b5f98a3db1..55f086c82ec5 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3176,7 +3176,8 @@ template class dynamic_formatter { auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) { handle_specs(ctx); internal::specs_checker checker( - null_handler(), internal::get_type::value); + null_handler(), + internal::mapped_type_constant::value); checker.on_align(specs_.align()); if (specs_.flags == 0) ; // Do nothing. diff --git a/test/core-test.cc b/test/core-test.cc index 84713de852f2..0de26dbe2621 100644 --- a/test/core-test.cc +++ b/test/core-test.cc @@ -567,15 +567,18 @@ TEST(CoreTest, ToStringViewForeignStrings) { EXPECT_EQ(to_string_view(my_string(L"42")), L"42"); EXPECT_EQ(to_string_view(QString(L"42")), L"42"); fmt::internal::type type = - fmt::internal::get_type>::value; + fmt::internal::mapped_type_constant, + fmt::format_context>::value; EXPECT_EQ(type, fmt::internal::string_type); - type = - fmt::internal::get_type>::value; + type = fmt::internal::mapped_type_constant, + fmt::wformat_context>::value; EXPECT_EQ(type, fmt::internal::string_type); - type = fmt::internal::get_type::value; + type = + fmt::internal::mapped_type_constant::value; EXPECT_EQ(type, fmt::internal::string_type); // Does not compile: only wide format contexts are compatible with QString! - // type = fmt::internal::get_type::value; + // type = fmt::internal::mapped_type_constant::value; } TEST(CoreTest, FormatForeignStrings) { diff --git a/test/format b/test/format index 3f9f2f928b6b..53a7b5df5c14 100644 --- a/test/format +++ b/test/format @@ -643,7 +643,7 @@ struct formatter { FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext& ctx) { namespace internal = fmt::internal; typedef internal::dynamic_specs_handler handler_type; - auto type = internal::get_type, T>::value; + auto type = internal::mapped_type_constant>::value; internal::specs_checker handler(handler_type(specs_, ctx), type); auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);