mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-26 20:20:04 +00:00
Fix tests on MSVC, take 2.
This commit is contained in:
parent
3f444fe3e2
commit
d81fafc295
39
format.cc
39
format.cc
@ -207,16 +207,6 @@ class PrecisionHandler :
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
|
|
||||||
template <typename T>
|
|
||||||
struct MakeUnsigned { typedef T Type; };
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct MakeUnsigned<signed char> { typedef unsigned char Type; };
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct MakeUnsigned<short> { typedef unsigned short Type; };
|
|
||||||
|
|
||||||
// Converts an integer argument to type T.
|
// Converts an integer argument to type T.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
|
class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
|
||||||
@ -229,12 +219,26 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
|
|||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
void visit_any_int(U value) {
|
void visit_any_int(U value) {
|
||||||
if (type_ == 'd' || type_ == 'i') {
|
bool is_signed = type_ == 'd' || type_ == 'i';
|
||||||
arg_.type = fmt::internal::Arg::INT;
|
using fmt::internal::Arg;
|
||||||
|
if (sizeof(T) <= sizeof(int)) {
|
||||||
|
if (is_signed) {
|
||||||
|
arg_.type = Arg::INT;
|
||||||
arg_.int_value = static_cast<T>(value);
|
arg_.int_value = static_cast<T>(value);
|
||||||
} else {
|
} else {
|
||||||
arg_.type = fmt::internal::Arg::UINT;
|
arg_.type = Arg::UINT;
|
||||||
arg_.uint_value = static_cast<typename MakeUnsigned<T>::Type>(value);
|
arg_.uint_value =
|
||||||
|
static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (is_signed) {
|
||||||
|
arg_.type = Arg::LONG_LONG;
|
||||||
|
arg_.long_long_value = static_cast<T>(value);
|
||||||
|
} else {
|
||||||
|
arg_.type = Arg::ULONG_LONG;
|
||||||
|
arg_.ulong_long_value =
|
||||||
|
static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -902,6 +906,10 @@ void fmt::internal::PrintfFormatter<Char>::format(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse length and convert the argument to the required type.
|
// Parse length and convert the argument to the required type.
|
||||||
|
// Conversion is done for compatibility with glibc's printf, MSVC's
|
||||||
|
// printf simply ignores width specifiers. For example:
|
||||||
|
// printf("%hhd", -129);
|
||||||
|
// prints 127 when using glibc's printf and -129 when using MSVC's one.
|
||||||
switch (*s) {
|
switch (*s) {
|
||||||
case 'h': {
|
case 'h': {
|
||||||
++s;
|
++s;
|
||||||
@ -912,6 +920,9 @@ void fmt::internal::PrintfFormatter<Char>::format(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'l':
|
case 'l':
|
||||||
|
++s;
|
||||||
|
ArgConverter<long>(arg, *s).visit(arg);
|
||||||
|
break;
|
||||||
case 'j':
|
case 'j':
|
||||||
case 'z':
|
case 'z':
|
||||||
case 't':
|
case 't':
|
||||||
|
12
format.h
12
format.h
@ -420,6 +420,18 @@ struct IntTraits {
|
|||||||
TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType;
|
TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
|
||||||
|
template <typename T>
|
||||||
|
struct MakeUnsigned { typedef T Type; };
|
||||||
|
|
||||||
|
#define SPECIALIZE_MAKE_UNSIGNED(T) \
|
||||||
|
template <> \
|
||||||
|
struct MakeUnsigned<signed T> { typedef unsigned T Type; }
|
||||||
|
|
||||||
|
SPECIALIZE_MAKE_UNSIGNED(char);
|
||||||
|
SPECIALIZE_MAKE_UNSIGNED(short);
|
||||||
|
SPECIALIZE_MAKE_UNSIGNED(long);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct IsLongDouble { enum {VALUE = 0}; };
|
struct IsLongDouble { enum {VALUE = 0}; };
|
||||||
|
|
||||||
|
@ -273,10 +273,27 @@ TEST(PrintfTest, DynamicPrecision) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define EXPECT_STD_PRINTF(format, Type, arg) { \
|
// Cast value to T to workaround an issue with MSVC not implementing
|
||||||
|
// various format specifiers.
|
||||||
|
template <typename T, typename U>
|
||||||
|
T Cast(U value) { return value; }
|
||||||
|
|
||||||
|
bool IsSupported(const std::string &format) {
|
||||||
|
#ifdef _MSVC
|
||||||
|
// MSVC doesn't support hh, j, z and t format specifiers.
|
||||||
|
return format != "hh";
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXPECT_STD_PRINTF(format, T, arg) { \
|
||||||
char buffer[BUFFER_SIZE]; \
|
char buffer[BUFFER_SIZE]; \
|
||||||
Type conv_arg = static_cast<Type>(arg); \
|
if (IsSupported(format)) \
|
||||||
safe_sprintf(buffer, fmt::StringRef(format).c_str(), conv_arg); \
|
safe_sprintf(buffer, fmt::StringRef(format).c_str(), arg); \
|
||||||
|
else \
|
||||||
|
safe_sprintf(buffer, fmt::StringRef(format).c_str(), \
|
||||||
|
Cast<typename fmt::internal::MakeUnsigned<T>::Type>(arg)); \
|
||||||
EXPECT_PRINTF(buffer, format, arg); \
|
EXPECT_PRINTF(buffer, format, arg); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user