diff --git a/include/fmt/core.h b/include/fmt/core.h index 2650ae23..5019a295 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -948,10 +948,10 @@ struct get_type { }; template -FMT_CONSTEXPR uint64_t get_types() { return 0; } +FMT_CONSTEXPR unsigned long long get_types() { return 0; } template -FMT_CONSTEXPR uint64_t get_types() { +FMT_CONSTEXPR unsigned long long get_types() { return get_type::value | (get_types() << 4); } @@ -995,27 +995,32 @@ class format_arg_store { internal::value, basic_format_arg>::type value_type; // If the arguments are not packed, add one more element to mark the end. - value_type data_[NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1)]; + static const size_t DATA_SIZE = + NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1); + value_type data_[DATA_SIZE]; friend class basic_format_args; - static FMT_CONSTEXPR int64_t get_types() { + static FMT_CONSTEXPR long long get_types() { return IS_PACKED ? - static_cast(internal::get_types()) : - -static_cast(NUM_ARGS); + static_cast(internal::get_types()) : + -static_cast(NUM_ARGS); } public: #if FMT_USE_CONSTEXPR - static constexpr int64_t TYPES = get_types(); + static constexpr long long TYPES = get_types(); #else - static const int64_t TYPES; + static const long long TYPES; #endif -#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 405 - // Workaround an array initialization bug in gcc 4.5 and earlier. +#if (FMT_GCC_VERSION && FMT_GCC_VERSION <= 405) || \ + (FMT_MSC_VER && FMT_MSC_VER <= 1800) + // Workaround array initialization issues in gcc <= 4.5 and MSVC <= 2013. format_arg_store(const Args &... args) { - data_ = {internal::make_arg(args)...}; + value_type init[DATA_SIZE] = + {internal::make_arg(args)...}; + std::memcpy(data_, init, sizeof(init)); } #else format_arg_store(const Args &... args) @@ -1025,7 +1030,7 @@ class format_arg_store { #if !FMT_USE_CONSTEXPR template -const int64_t format_arg_store::TYPES = get_types(); +const long long format_arg_store::TYPES = get_types(); #endif /** @@ -1057,7 +1062,7 @@ class basic_format_args { private: // To reduce compiled code size per formatting function call, types of first // max_packed_args arguments are passed in the types_ field. - uint64_t types_; + unsigned long long types_; 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_. @@ -1070,7 +1075,7 @@ class basic_format_args { typename internal::type type(unsigned index) const { unsigned shift = index * 4; - uint64_t mask = 0xf; + unsigned long long mask = 0xf; return static_cast( (types_ & (mask << shift)) >> shift); } @@ -1081,9 +1086,9 @@ class basic_format_args { void set_data(const format_arg *args) { args_ = args; } format_arg do_get(size_type index) const { - int64_t signed_types = static_cast(types_); + long long signed_types = static_cast(types_); if (signed_types < 0) { - uint64_t num_args = static_cast(-signed_types); + unsigned long long num_args = static_cast(-signed_types); return index < num_args ? args_[index] : format_arg(); } format_arg arg; @@ -1119,10 +1124,10 @@ class basic_format_args { } unsigned max_size() const { - int64_t signed_types = static_cast(types_); + long long signed_types = static_cast(types_); return static_cast( signed_types < 0 ? - -signed_types : static_cast(internal::max_packed_args)); + -signed_types : static_cast(internal::max_packed_args)); } }; diff --git a/include/fmt/format.h b/include/fmt/format.h index b5108a4a..0fd2756d 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1293,28 +1293,6 @@ struct align_spec : empty_spec { // Format specifiers. template class basic_format_specs : public align_spec { - private: - template - typename std::enable_if::value || - std::is_same::value, void>::type - set(fill_spec fill) { - fill_ = fill.value(); - } - - void set(width_spec width) { - width_ = width.value(); - } - - void set(type_spec type) { - type_ = type.value(); - } - - template - void set(Spec spec, Specs... tail) { - set(spec); - set(tail...); - } - public: unsigned flags_; int precision_; @@ -1324,12 +1302,6 @@ class basic_format_specs : public align_spec { unsigned width = 0, char type = 0, wchar_t fill = ' ') : align_spec(width, fill), flags_(0), precision_(-1), type_(type) {} - template - explicit basic_format_specs(FormatSpecs... specs) - : align_spec(0, ' '), flags_(0), precision_(-1), type_(0) { - set(specs...); - } - FMT_CONSTEXPR bool flag(unsigned f) const { return (flags_ & f) != 0; } FMT_CONSTEXPR int precision() const { return precision_; } FMT_CONSTEXPR Char type() const { return type_; } @@ -1576,7 +1548,18 @@ class arg_formatter_base { template typename std::enable_if::value, iterator>::type operator()(T value) { - writer_.write_int(value, specs_); + // MSVC2013 fails to compile separate overloads for bool and char_type so + // use std::is_same instead. + if (std::is_same::value) { + if (specs_.type_) + return (*this)(value ? 1 : 0); + write(value); + } else if (std::is_same::value) { + internal::handle_char_specs( + specs_, char_spec_handler(*this, static_cast(value))); + } else { + writer_.write_int(value, specs_); + } return out(); } @@ -1587,13 +1570,6 @@ class arg_formatter_base { return out(); } - iterator operator()(bool value) { - if (specs_.type_) - return (*this)(value ? 1 : 0); - write(value); - return out(); - } - struct char_spec_handler : internal::error_handler { arg_formatter_base &formatter; char_type value; @@ -1605,11 +1581,6 @@ class arg_formatter_base { void on_char() { formatter.write_char(value); } }; - iterator operator()(char_type value) { - internal::handle_char_specs(specs_, char_spec_handler(*this, value)); - return out(); - } - struct cstring_spec_handler : internal::error_handler { arg_formatter_base &formatter; const char_type *value; diff --git a/include/fmt/printf.h b/include/fmt/printf.h index 5a44a834..ba600ca4 100644 --- a/include/fmt/printf.h +++ b/include/fmt/printf.h @@ -252,23 +252,33 @@ class printf_arg_formatter: using base::operator(); - /** Formats an argument of type ``bool``. */ - iterator operator()(bool value) { - format_specs &fmt_spec = this->spec(); - if (fmt_spec.type_ != 's') - return (*this)(value ? 1 : 0); - fmt_spec.type_ = 0; - this->write(value); + template + typename std::enable_if::value, iterator>::type + operator()(T value) { + // MSVC2013 fails to compile separate overloads for bool and char_type so + // use std::is_same instead. + if (std::is_same::value) { + format_specs &fmt_spec = this->spec(); + if (fmt_spec.type_ != 's') + return base::operator()(value ? 1 : 0); + fmt_spec.type_ = 0; + this->write(value); + } else if (std::is_same::value) { + format_specs &fmt_spec = this->spec(); + if (fmt_spec.type_ && fmt_spec.type_ != 'c') + return (*this)(static_cast(value)); + fmt_spec.flags_ = 0; + fmt_spec.align_ = ALIGN_RIGHT; + return base::operator()(value); + } else { + return base::operator()(value); + } return this->out(); } - /** Formats a character. */ - iterator operator()(char_type value) { - format_specs &fmt_spec = this->spec(); - if (fmt_spec.type_ && fmt_spec.type_ != 'c') - return (*this)(static_cast(value)); - fmt_spec.flags_ = 0; - fmt_spec.align_ = ALIGN_RIGHT; + template + typename std::enable_if::value, iterator>::type + operator()(T value) { return base::operator()(value); }