Remove extra level of indirection when building args

This commit is contained in:
Victor Zverovich 2024-01-08 15:50:47 -08:00
parent 9f73e45ca0
commit 545d37a8b0

View File

@ -1099,7 +1099,7 @@ FMT_CONSTEXPR void basic_format_parse_context<Char>::check_dynamic_spec(
FMT_EXPORT template <typename Context> class basic_format_arg;
FMT_EXPORT template <typename Context> class basic_format_args;
FMT_EXPORT template <typename Context, typename... Args> class format_arg_store;
FMT_EXPORT template <typename, size_t, typename...> class format_arg_store_impl;
FMT_EXPORT template <typename Context> class dynamic_format_arg_store;
// A formatter for objects of type T.
@ -1192,33 +1192,6 @@ template <typename Char> struct named_arg_info {
int id;
};
template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS>
struct arg_data {
// args_[0].named_args points to named_args_ to avoid bloating format_args.
// +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)];
named_arg_info<Char> named_args_[NUM_NAMED_ARGS];
template <typename... U>
arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {}
arg_data(const arg_data& other) = delete;
auto args() const -> const T* { return args_ + 1; }
auto named_args() -> named_arg_info<Char>* { return named_args_; }
};
template <typename T, typename Char, size_t NUM_ARGS>
struct arg_data<T, Char, NUM_ARGS, 0> {
// +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
T args_[NUM_ARGS != 0 ? NUM_ARGS : +1];
template <typename... U>
FMT_CONSTEXPR FMT_INLINE arg_data(const U&... init) : args_{init...} {}
FMT_CONSTEXPR FMT_INLINE auto args() const -> const T* { return args_; }
FMT_CONSTEXPR FMT_INLINE auto named_args() -> std::nullptr_t {
return nullptr;
}
};
template <typename Char>
inline void init_named_args(named_arg_info<Char>*, int, int) {}
@ -1638,8 +1611,7 @@ template <typename Context> class basic_format_arg {
using char_type = typename Context::char_type;
template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS>
friend struct detail::arg_data;
template <typename, size_t, typename...> friend class format_arg_store_impl;
basic_format_arg(const detail::named_arg_info<char_type>* args, size_t size)
: value_(args, size) {}
@ -1792,11 +1764,11 @@ template <typename Context> class basic_format_args {
Constructs a `basic_format_args` object from `~fmt::format_arg_store`.
\endrst
*/
template <typename... Args>
template <size_t N, typename... Args>
constexpr FMT_INLINE basic_format_args(
const format_arg_store<Context, Args...>& store)
: basic_format_args(format_arg_store<Context, Args...>::desc,
store.data_.args()) {}
const format_arg_store_impl<Context, N, Args...>& store)
: basic_format_args(format_arg_store_impl<Context, N, Args...>::desc,
store.args()) {}
/**
\rst
@ -1926,8 +1898,52 @@ using is_formattable = bool_constant<!std::is_base_of<
such as `~fmt::vformat`.
\endrst
*/
template <typename Context, typename... Args>
class format_arg_store
template <typename Context, size_t NUM_NAMED_ARGS, typename... Args>
class format_arg_store_impl
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround a GCC template argument substitution bug.
: public basic_format_args<Context>
#endif
{
private:
static const size_t num_args = sizeof...(Args);
static const bool is_packed = num_args <= detail::max_packed_args;
using char_type = typename Context::char_type;
using value_type = conditional_t<is_packed, detail::value<Context>,
basic_format_arg<Context>>;
// args_[0].named_args points to named_args_ to avoid bloating format_args.
// +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
value_type args_[1 + (num_args != 0 ? num_args : +1)];
detail::named_arg_info<char_type> named_args_[NUM_NAMED_ARGS];
public:
template <typename... T>
FMT_CONSTEXPR FMT_INLINE format_arg_store_impl(T&... args)
:
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
basic_format_args<Context>(*this),
#endif
args_{value_type(named_args_, NUM_NAMED_ARGS),
detail::make_arg<is_packed, Context>(args)...} {
detail::init_named_args(named_args_, 0, 0, args...);
}
static constexpr unsigned long long desc =
(is_packed ? detail::encode_types<Context, Args...>()
: detail::is_unpacked_bit | num_args) |
(NUM_NAMED_ARGS != 0
? static_cast<unsigned long long>(detail::has_named_args_bit)
: 0);
FMT_CONSTEXPR FMT_INLINE auto args() const -> const value_type* {
return args_ + 1;
}
};
template <typename Context, typename... Args>
class format_arg_store_impl<Context, 0, Args...>
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround a GCC template argument substitution bug.
: public basic_format_args<Context>
@ -1935,38 +1951,37 @@ class format_arg_store
{
private:
static const size_t num_args = sizeof...(Args);
static constexpr size_t num_named_args = detail::count_named_args<Args...>();
static const bool is_packed = num_args <= detail::max_packed_args;
using value_type = conditional_t<is_packed, detail::value<Context>,
basic_format_arg<Context>>;
detail::arg_data<value_type, typename Context::char_type, num_args,
num_named_args>
data_;
friend class basic_format_args<Context>;
static constexpr unsigned long long desc =
(is_packed ? detail::encode_types<Context, Args...>()
: detail::is_unpacked_bit | num_args) |
(num_named_args != 0
? static_cast<unsigned long long>(detail::has_named_args_bit)
: 0);
// +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
value_type args_[num_args != 0 ? num_args : +1];
public:
template <typename... T>
FMT_CONSTEXPR FMT_INLINE format_arg_store(T&... args)
FMT_CONSTEXPR FMT_INLINE format_arg_store_impl(T&... args)
:
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
basic_format_args<Context>(*this),
#endif
data_{detail::make_arg<is_packed, Context>(args)...} {
if (detail::const_check(num_named_args != 0))
detail::init_named_args(data_.named_args(), 0, 0, args...);
args_{detail::make_arg<is_packed, Context>(args)...} {
}
static constexpr unsigned long long desc =
(is_packed ? detail::encode_types<Context, Args...>()
: detail::is_unpacked_bit | num_args);
FMT_CONSTEXPR FMT_INLINE auto args() const -> const value_type* {
return args_;
}
};
template <typename Context, typename... T>
using format_arg_store =
format_arg_store_impl<Context, detail::count_named_args<T...>(), T...>;
/**
\rst
Constructs a `~fmt::format_arg_store` object that contains references to
@ -1976,9 +1991,10 @@ class format_arg_store
\endrst
*/
// Arguments are taken by lvalue references to avoid some lifetime issues.
template <typename Context = format_context, typename... T>
template <typename Context = format_context, typename... T,
size_t N = detail::count_named_args<T...>()>
constexpr auto make_format_args(T&... args)
-> format_arg_store<Context, remove_const_t<T>...> {
-> format_arg_store_impl<Context, N, remove_const_t<T>...> {
return {args...};
}
@ -2302,9 +2318,10 @@ enum class state { start, align, sign, hash, zero, width, precision, locale };
// Parses standard format specifiers.
template <typename Char>
FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(
const Char* begin, const Char* end, dynamic_format_specs<Char>& specs,
basic_format_parse_context<Char>& ctx, type arg_type) -> const Char* {
FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
dynamic_format_specs<Char>& specs,
basic_format_parse_context<Char>& ctx,
type arg_type) -> const Char* {
auto c = '\0';
if (end - begin > 1) {
auto next = to_ascii(begin[1]);
@ -2742,6 +2759,7 @@ struct formatter<T, Char,
public:
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const Char* {
if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin();
auto type = detail::type_constant<T, Char>::value;
auto end =
detail::parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, type);