diff --git a/include/fmt/core.h b/include/fmt/core.h index 8b4c6319..cab3dfe0 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -1331,7 +1331,7 @@ class format_arg_store { private: static const size_t num_args = sizeof...(Args); - static const bool is_packed = num_args < internal::max_packed_args; + static const bool is_packed = num_args <= internal::max_packed_args; using value_type = conditional_t, basic_format_arg>; @@ -1481,25 +1481,27 @@ template class basic_format_args { using format_arg = basic_format_arg; private: - // To reduce compiled code size per formatting function call, types of first - // max_packed_args arguments are passed in the types_ field. - unsigned long long types_; + // A descriptor that contains information about formatting arguments. + // If the number of arguments is less or equal to max_packed_args then + // argument types are passed in the descriptor. This reduces binary code size + // per formatting function call. + unsigned long long desc_; union { - // If the number of arguments is less than max_packed_args, the argument - // values are stored in values_, otherwise they are stored in args_. - // This is done to reduce compiled code size as storing larger objects + // If is_packed() returns true then argument values are stored in values_; + // otherwise they are stored in args_. This is done to improve cache + // locality and reduce compiled code size since storing larger objects // may require more code (at least on x86-64) even if the same amount of // data is actually copied to stack. It saves ~10% on the bloat test. const internal::value* values_; const format_arg* args_; }; - bool is_packed() const { return (types_ & internal::is_unpacked_bit) == 0; } + bool is_packed() const { return (desc_ & internal::is_unpacked_bit) == 0; } internal::type type(int index) const { int shift = index * internal::packed_arg_bits; unsigned int mask = (1 << internal::packed_arg_bits) - 1; - return static_cast((types_ >> shift) & mask); + return static_cast((desc_ >> shift) & mask); } friend class internal::arg_map; @@ -1523,7 +1525,7 @@ template class basic_format_args { } public: - basic_format_args() : types_(0) {} + basic_format_args() : desc_(0) {} /** \rst @@ -1532,7 +1534,7 @@ template class basic_format_args { */ template basic_format_args(const format_arg_store& store) - : types_(store.types) { + : desc_(store.types) { set_data(store.data_); } @@ -1543,7 +1545,7 @@ template class basic_format_args { \endrst */ basic_format_args(const dynamic_format_arg_store& store) - : types_(store.get_types()) { + : desc_(store.get_types()) { set_data(store.data_.data()); } @@ -1553,7 +1555,7 @@ template class basic_format_args { \endrst */ basic_format_args(const format_arg* args, int count) - : types_(internal::is_unpacked_bit | internal::to_unsigned(count)) { + : desc_(internal::is_unpacked_bit | internal::to_unsigned(count)) { set_data(args); } @@ -1568,7 +1570,7 @@ template class basic_format_args { int max_size() const { unsigned long long max_packed = internal::max_packed_args; return static_cast(is_packed() ? max_packed - : types_ & ~internal::is_unpacked_bit); + : desc_ & ~internal::is_unpacked_bit); } };