Fix MSVC 2013 build
diff --git a/include/fmt/core.h b/include/fmt/core.h
index 2650ae2..5019a29 100644
--- a/include/fmt/core.h
+++ b/include/fmt/core.h
@@ -948,10 +948,10 @@
};
template <typename Context>
-FMT_CONSTEXPR uint64_t get_types() { return 0; }
+FMT_CONSTEXPR unsigned long long get_types() { return 0; }
template <typename Context, typename Arg, typename... Args>
-FMT_CONSTEXPR uint64_t get_types() {
+FMT_CONSTEXPR unsigned long long get_types() {
return get_type<Context, Arg>::value | (get_types<Context, Args...>() << 4);
}
@@ -995,27 +995,32 @@
internal::value<Context>, basic_format_arg<Context>>::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<Context>;
- static FMT_CONSTEXPR int64_t get_types() {
+ static FMT_CONSTEXPR long long get_types() {
return IS_PACKED ?
- static_cast<int64_t>(internal::get_types<Context, Args...>()) :
- -static_cast<int64_t>(NUM_ARGS);
+ static_cast<long long>(internal::get_types<Context, Args...>()) :
+ -static_cast<long long>(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<IS_PACKED, Context>(args)...};
+ value_type init[DATA_SIZE] =
+ {internal::make_arg<IS_PACKED, Context>(args)...};
+ std::memcpy(data_, init, sizeof(init));
}
#else
format_arg_store(const Args &... args)
@@ -1025,7 +1030,7 @@
#if !FMT_USE_CONSTEXPR
template <typename Context, typename ...Args>
-const int64_t format_arg_store<Context, Args...>::TYPES = get_types();
+const long long format_arg_store<Context, Args...>::TYPES = get_types();
#endif
/**
@@ -1057,7 +1062,7 @@
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 @@
typename internal::type type(unsigned index) const {
unsigned shift = index * 4;
- uint64_t mask = 0xf;
+ unsigned long long mask = 0xf;
return static_cast<typename internal::type>(
(types_ & (mask << shift)) >> shift);
}
@@ -1081,9 +1086,9 @@
void set_data(const format_arg *args) { args_ = args; }
format_arg do_get(size_type index) const {
- int64_t signed_types = static_cast<int64_t>(types_);
+ long long signed_types = static_cast<long long>(types_);
if (signed_types < 0) {
- uint64_t num_args = static_cast<uint64_t>(-signed_types);
+ unsigned long long num_args = static_cast<unsigned long long>(-signed_types);
return index < num_args ? args_[index] : format_arg();
}
format_arg arg;
@@ -1119,10 +1124,10 @@
}
unsigned max_size() const {
- int64_t signed_types = static_cast<int64_t>(types_);
+ long long signed_types = static_cast<long long>(types_);
return static_cast<unsigned>(
signed_types < 0 ?
- -signed_types : static_cast<int64_t>(internal::max_packed_args));
+ -signed_types : static_cast<long long>(internal::max_packed_args));
}
};
diff --git a/include/fmt/format.h b/include/fmt/format.h
index b5108a4..0fd2756 100644
--- a/include/fmt/format.h
+++ b/include/fmt/format.h
@@ -1293,28 +1293,6 @@
// Format specifiers.
template <typename Char>
class basic_format_specs : public align_spec {
- private:
- template <typename FillChar>
- typename std::enable_if<std::is_same<FillChar, Char>::value ||
- std::is_same<FillChar, char>::value, void>::type
- set(fill_spec<FillChar> fill) {
- fill_ = fill.value();
- }
-
- void set(width_spec width) {
- width_ = width.value();
- }
-
- void set(type_spec type) {
- type_ = type.value();
- }
-
- template <typename Spec, typename... Specs>
- void set(Spec spec, Specs... tail) {
- set(spec);
- set(tail...);
- }
-
public:
unsigned flags_;
int precision_;
@@ -1324,12 +1302,6 @@
unsigned width = 0, char type = 0, wchar_t fill = ' ')
: align_spec(width, fill), flags_(0), precision_(-1), type_(type) {}
- template <typename... FormatSpecs>
- 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 @@
template <typename T>
typename std::enable_if<std::is_integral<T>::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<T, bool>::value) {
+ if (specs_.type_)
+ return (*this)(value ? 1 : 0);
+ write(value);
+ } else if (std::is_same<T, char_type>::value) {
+ internal::handle_char_specs(
+ specs_, char_spec_handler(*this, static_cast<char_type>(value)));
+ } else {
+ writer_.write_int(value, specs_);
+ }
return out();
}
@@ -1587,13 +1570,6 @@
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 @@
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 5a44a83..ba600ca 100644
--- a/include/fmt/printf.h
+++ b/include/fmt/printf.h
@@ -252,23 +252,33 @@
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 T>
+ typename std::enable_if<std::is_integral<T>::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<T, bool>::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<T, char_type>::value) {
+ format_specs &fmt_spec = this->spec();
+ if (fmt_spec.type_ && fmt_spec.type_ != 'c')
+ return (*this)(static_cast<int>(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<int>(value));
- fmt_spec.flags_ = 0;
- fmt_spec.align_ = ALIGN_RIGHT;
+ template <typename T>
+ typename std::enable_if<std::is_floating_point<T>::value, iterator>::type
+ operator()(T value) {
return base::operator()(value);
}