Skip to content

Commit

Permalink
Remove extra level of indirection when building args
Browse files Browse the repository at this point in the history
  • Loading branch information
vitaut committed Jan 8, 2024
1 parent a5ae9ae commit b9c90f8
Showing 1 changed file with 69 additions and 51 deletions.
120 changes: 69 additions & 51 deletions include/fmt/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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) {}

Expand Down Expand Up @@ -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) {}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1926,47 +1898,90 @@ 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 constexpr size_t num_named_args = detail::count_named_args<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>>;

detail::arg_data<value_type, typename Context::char_type, num_args,
num_named_args>
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.
value_type args_[1 + (num_args != 0 ? num_args : +1)];
detail::named_arg_info<char_type> named_args_[NUM_NAMED_ARGS];

friend class basic_format_args<Context>;
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
(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>
#endif
{
private:
static const size_t num_args = sizeof...(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>>;

// +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
Expand All @@ -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...};
}

Expand Down Expand Up @@ -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]);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit b9c90f8

Please sign in to comment.