diff --git a/include/fmt/base.h b/include/fmt/base.h index 37e41b44..965ada13 100644 --- a/include/fmt/base.h +++ b/include/fmt/base.h @@ -808,13 +808,8 @@ template struct named_arg : view { named_arg(const Char* n, const T& v) : name(n), value(v) {} }; -template struct named_arg_info { - const Char* name; - int id; -}; - template struct is_named_arg : std::false_type {}; -template struct is_statically_named_arg : std::false_type {}; +template struct is_static_named_arg : std::false_type {}; template struct is_named_arg> : std::true_type {}; @@ -838,7 +833,35 @@ template constexpr auto count_named_args() -> size_t { return count::value...>(); } template constexpr auto count_static_named_args() -> size_t { - return count::value...>(); + return count::value...>(); +} + +template struct named_arg_info { + const Char* name; + int id; +}; + +template ::value)> +void init_named_arg(named_arg_info*, int& arg_index, int&, const T&) { + ++arg_index; +} +template ::value)> +void init_named_arg(named_arg_info* named_args, int& arg_index, + int& named_arg_index, const T& arg) { + named_args[named_arg_index++] = {arg.name, arg_index++}; +} + +template ::value)> +FMT_CONSTEXPR void init_static_named_arg(named_arg_info*, int& arg_index, + int&) { + ++arg_index; +} +template ::value)> +FMT_CONSTEXPR void init_static_named_arg(named_arg_info* named_args, + int& arg_index, int& named_arg_index) { + named_args[named_arg_index++] = {T::name, arg_index++}; } // To minimize the number of types we need to deal with, long is translated @@ -1761,6 +1784,83 @@ FMT_CONSTEXPR inline auto check_char_specs(const format_specs& specs) -> bool { return true; } +// A base class for compile-time strings. +struct compile_string {}; + +template +FMT_VISIBILITY("hidden") // Suppress an ld warning on macOS (#3769). +FMT_CONSTEXPR auto invoke_parse(parse_context& ctx) -> const Char* { + using mapper = arg_mapper>; + using mapped_type = remove_cvref_t()))>; +#if defined(__cpp_if_constexpr) + if constexpr (std::is_default_constructible>()) + return formatter().parse(ctx); + return ctx.begin(); // Ignore the error - it is reported by make_format_args. +#else + return formatter().parse(ctx); +#endif +} + +template struct arg_pack {}; + +template +class format_string_checker { + private: + type types_[NUM_ARGS > 0 ? NUM_ARGS : 1]; + named_arg_info named_args_[NUM_NAMED_ARGS > 0 ? NUM_NAMED_ARGS : 1]; + compile_parse_context context_; + + using parse_func = auto (*)(parse_context&) -> const Char*; + parse_func parse_funcs_[NUM_ARGS > 0 ? NUM_ARGS : 1]; + + public: + template + explicit FMT_CONSTEXPR format_string_checker(basic_string_view fmt, + arg_pack) + : types_{mapped_type_constant>::value...}, + named_args_{}, + context_(fmt, NUM_ARGS, types_), + parse_funcs_{&invoke_parse...} { + using ignore = int[]; + int arg_index = 0, named_arg_index = 0; + (void)ignore{ + 0, (init_static_named_arg(named_args_, arg_index, named_arg_index), + 0)...}; + ignore_unused(arg_index, named_arg_index); + } + + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + + FMT_CONSTEXPR auto on_arg_id() -> int { return context_.next_arg_id(); } + FMT_CONSTEXPR auto on_arg_id(int id) -> int { + context_.check_arg_id(id); + return id; + } + FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { + for (int i = 0; i < NUM_NAMED_ARGS; ++i) { + if (named_args_[i].name == id) return named_args_[i].id; + } + if (!DYNAMIC_NAMES) on_error("argument not found"); + return -1; + } + + FMT_CONSTEXPR void on_replacement_field(int id, const Char* begin) { + on_format_specs(id, begin, begin); // Call parse() on empty specs. + } + + FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char* end) + -> const Char* { + context_.advance_to(begin); + if (id >= 0 && id < NUM_ARGS) return parse_funcs_[id](context_); + while (begin != end && *begin != '}') ++begin; + return begin; + } + + FMT_NORETURN FMT_CONSTEXPR void on_error(const char* message) { + report_error(message); + } +}; + /// A contiguous memory buffer with an optional growing ability. It is an /// internal class and shouldn't be used directly, only via `memory_buffer`. template class buffer { @@ -2369,30 +2469,6 @@ template using arg_t = conditional_t, basic_format_arg>; -template ::value)> -void init_named_arg(named_arg_info*, int& arg_index, int&, const T&) { - ++arg_index; -} -template ::value)> -void init_named_arg(named_arg_info* named_args, int& arg_index, - int& named_arg_index, const T& arg) { - named_args[named_arg_index++] = {arg.name, arg_index++}; -} - -template ::value)> -FMT_CONSTEXPR void init_statically_named_arg(named_arg_info*, - int& arg_index, int&) { - ++arg_index; -} -template ::value)> -FMT_CONSTEXPR void init_statically_named_arg(named_arg_info* named_args, - int& arg_index, - int& named_arg_index) { - named_args[named_arg_index++] = {T::name, arg_index++}; -} - // An array of references to arguments. It can be implicitly converted to // `fmt::basic_format_args` for passing into type-erased formatting functions // such as `fmt::vformat`. @@ -2702,83 +2778,6 @@ FMT_END_EXPORT namespace detail { -// A base class for compile-time strings. -struct compile_string {}; - -template -FMT_VISIBILITY("hidden") // Suppress an ld warning on macOS (#3769). -FMT_CONSTEXPR auto invoke_parse(parse_context& ctx) -> const Char* { - using mapper = arg_mapper>; - using mapped_type = remove_cvref_t()))>; -#if defined(__cpp_if_constexpr) - if constexpr (std::is_default_constructible>()) - return formatter().parse(ctx); - return ctx.begin(); // Ignore the error - it is reported by make_format_args. -#else - return formatter().parse(ctx); -#endif -} - -template struct arg_pack {}; - -template -class format_string_checker { - private: - type types_[NUM_ARGS > 0 ? NUM_ARGS : 1]; - named_arg_info named_args_[NUM_NAMED_ARGS > 0 ? NUM_NAMED_ARGS : 1]; - compile_parse_context context_; - - using parse_func = auto (*)(parse_context&) -> const Char*; - parse_func parse_funcs_[NUM_ARGS > 0 ? NUM_ARGS : 1]; - - public: - template - explicit FMT_CONSTEXPR format_string_checker(basic_string_view fmt, - arg_pack) - : types_{mapped_type_constant>::value...}, - named_args_{}, - context_(fmt, NUM_ARGS, types_), - parse_funcs_{&invoke_parse...} { - using ignore = int[]; - int arg_index = 0, named_arg_index = 0; - (void)ignore{0, (init_statically_named_arg(named_args_, arg_index, - named_arg_index), - 0)...}; - ignore_unused(arg_index, named_arg_index); - } - - FMT_CONSTEXPR void on_text(const Char*, const Char*) {} - - FMT_CONSTEXPR auto on_arg_id() -> int { return context_.next_arg_id(); } - FMT_CONSTEXPR auto on_arg_id(int id) -> int { - context_.check_arg_id(id); - return id; - } - FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { - for (int i = 0; i < NUM_NAMED_ARGS; ++i) { - if (named_args_[i].name == id) return named_args_[i].id; - } - if (!DYNAMIC_NAMES) on_error("argument not found"); - return -1; - } - - FMT_CONSTEXPR void on_replacement_field(int id, const Char* begin) { - on_format_specs(id, begin, begin); // Call parse() on empty specs. - } - - FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char* end) - -> const Char* { - context_.advance_to(begin); - if (id >= 0 && id < NUM_ARGS) return parse_funcs_[id](context_); - while (begin != end && *begin != '}') ++begin; - return begin; - } - - FMT_NORETURN FMT_CONSTEXPR void on_error(const char* message) { - report_error(message); - } -}; - // TYPE can be different from type_constant, e.g. for __float128. template struct native_formatter { private: diff --git a/include/fmt/compile.h b/include/fmt/compile.h index 235b0922..c33427ab 100644 --- a/include/fmt/compile.h +++ b/include/fmt/compile.h @@ -74,7 +74,7 @@ constexpr const auto& get([[maybe_unused]] const T& first, # if FMT_USE_NONTYPE_TEMPLATE_ARGS template constexpr auto get_arg_index_by_name(basic_string_view name) -> int { - if constexpr (is_statically_named_arg()) { + if constexpr (is_static_named_arg()) { if (name == T::name) return N; } if constexpr (sizeof...(Args) > 0) diff --git a/include/fmt/format.h b/include/fmt/format.h index ec94d55b..154e5871 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3769,27 +3769,27 @@ FMT_CONSTEXPR void handle_dynamic_spec( # if FMT_USE_NONTYPE_TEMPLATE_ARGS template Str> -struct statically_named_arg : view { +struct static_named_arg : view { static constexpr auto name = Str.data; const T& value; - statically_named_arg(const T& v) : value(v) {} + static_named_arg(const T& v) : value(v) {} }; template Str> -struct is_named_arg> : std::true_type {}; +struct is_named_arg> : std::true_type {}; template Str> -struct is_statically_named_arg> - : std::true_type {}; +struct is_static_named_arg> : std::true_type { +}; template Str> struct udl_arg { template auto operator=(T&& value) const { - return statically_named_arg(std::forward(value)); + return static_named_arg(std::forward(value)); } }; # else