diff --git a/include/fmt/core.h b/include/fmt/core.h index 847e85e2..84f878de 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -28,12 +28,10 @@ #ifndef FMT_CORE_H_ #define FMT_CORE_H_ -#include #include #include #include #include -#include #ifdef __has_feature # define FMT_HAS_FEATURE(x) __has_feature(x) @@ -684,6 +682,8 @@ struct named_arg : basic_arg { template class arg_map { private: + FMT_DISALLOW_COPY_AND_ASSIGN(arg_map); + using Char = typename Context::char_type; struct arg { @@ -691,15 +691,23 @@ class arg_map { basic_arg value; }; - std::vector map_; + arg *map_ = nullptr; + unsigned size_ = 0; + + void push_back(arg a) { + map_[size_] = a; + ++size_; + } public: + arg_map() {} void init(const basic_format_args &args); + ~arg_map() { delete [] map_; } const basic_arg *find(const fmt::basic_string_view &name) const { // The list is unsorted, so just return the first matching name. - for (auto it = map_.begin(), end = map_.end(); it != end; ++it) { + for (auto it = map_, end = map_ + size_; it != end; ++it) { if (it->name == name) return &it->value; } @@ -789,21 +797,20 @@ class arg_store { // Packed is a macro on MinGW so use IS_PACKED instead. static const bool IS_PACKED = NUM_ARGS < internal::MAX_PACKED_ARGS; - using value_type = typename std::conditional, basic_arg>::type; + using value_type = typename std::conditional< + IS_PACKED, internal::value, basic_arg>::type; // If the arguments are not packed, add one more element to mark the end. - using Array = std::array; - Array data_; + value_type data_[NUM_ARGS + (IS_PACKED ? 0 : 1)]; public: static const uint64_t TYPES = IS_PACKED ? internal::get_types() : -static_cast(NUM_ARGS); arg_store(const Args &... args) - : data_(Array{{internal::make_arg(args)...}}) {} + : data_{internal::make_arg(args)...} {} - const value_type *data() const { return data_.data(); } + const value_type *data() const { return data_; } }; template @@ -881,6 +888,11 @@ class basic_format_args { return arg.type_ == internal::NAMED_ARG ? *static_cast(arg.value_.pointer) : arg; } + + unsigned max_size() const { + int64_t signed_types = static_cast(types_); + return signed_types < 0 ? -signed_types : internal::MAX_PACKED_ARGS; + } }; using format_args = basic_format_args; diff --git a/include/fmt/format.h b/include/fmt/format.h index 93c0ed1a..05cfaebd 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1167,8 +1167,9 @@ class cstring_type_checker : public ErrorHandler { template void arg_map::init(const basic_format_args &args) { - if (!map_.empty()) + if (map_) return; + map_ = new arg[args.max_size()]; typedef internal::named_arg NamedArg; const NamedArg *named_arg = 0; bool use_values = @@ -1181,7 +1182,7 @@ void arg_map::init(const basic_format_args &args) { return; case internal::NAMED_ARG: named_arg = static_cast(args.values_[i].pointer); - map_.push_back(arg{named_arg->name, *named_arg}); + push_back(arg{named_arg->name, *named_arg}); break; default: break; // Do nothing. @@ -1193,7 +1194,7 @@ void arg_map::init(const basic_format_args &args) { internal::type arg_type = args.type(i); if (arg_type == internal::NAMED_ARG) { named_arg = static_cast(args.args_[i].value_.pointer); - map_.push_back(arg{named_arg->name, *named_arg}); + push_back(arg{named_arg->name, *named_arg}); } } for (unsigned i = MAX_PACKED_ARGS; ; ++i) { @@ -1202,7 +1203,7 @@ void arg_map::init(const basic_format_args &args) { return; case internal::NAMED_ARG: named_arg = static_cast(args.args_[i].value_.pointer); - map_.push_back(arg{named_arg->name, *named_arg}); + push_back(arg{named_arg->name, *named_arg}); break; default: break; // Do nothing.