mirror of
https://github.com/fmtlib/fmt.git
synced 2025-04-25 03:02:38 +00:00
Merge branch 'master' into update-project-layout
This commit is contained in:
commit
a659d8079e
@ -328,8 +328,10 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
|
|||||||
} else {
|
} else {
|
||||||
if (is_signed) {
|
if (is_signed) {
|
||||||
arg_.type = Arg::LONG_LONG;
|
arg_.type = Arg::LONG_LONG;
|
||||||
arg_.long_long_value =
|
// glibc's printf doesn't sign extend arguments of smaller types:
|
||||||
static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
|
// std::printf("%lld", -42); // prints "4294967254"
|
||||||
|
// but we don't have to do the same because it's a UB.
|
||||||
|
arg_.long_long_value = value;
|
||||||
} else {
|
} else {
|
||||||
arg_.type = Arg::ULONG_LONG;
|
arg_.type = Arg::ULONG_LONG;
|
||||||
arg_.ulong_long_value =
|
arg_.ulong_long_value =
|
||||||
|
@ -34,8 +34,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h> // for O_RDONLY
|
#include <fcntl.h> // for O_RDONLY
|
||||||
|
#include <locale.h> // for locale_t
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h> // for strtod_l
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
@ -331,6 +333,54 @@ class File {
|
|||||||
|
|
||||||
// Returns the memory page size.
|
// Returns the memory page size.
|
||||||
long getpagesize();
|
long getpagesize();
|
||||||
|
|
||||||
|
#if defined(LC_NUMERIC_MASK) || defined(_MSC_VER)
|
||||||
|
|
||||||
|
// A "C" numeric locale.
|
||||||
|
class Locale {
|
||||||
|
private:
|
||||||
|
# ifdef _MSC_VER
|
||||||
|
typedef _locale_t locale_t;
|
||||||
|
|
||||||
|
enum { LC_NUMERIC_MASK = LC_NUMERIC };
|
||||||
|
|
||||||
|
static locale_t newlocale(int category_mask, const char *locale, locale_t) {
|
||||||
|
return _create_locale(category_mask, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void freelocale(locale_t locale) {
|
||||||
|
_free_locale(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {
|
||||||
|
return _strtod_l(nptr, endptr, locale);
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
locale_t locale_;
|
||||||
|
|
||||||
|
FMT_DISALLOW_COPY_AND_ASSIGN(Locale);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) {
|
||||||
|
if (!locale_)
|
||||||
|
throw fmt::SystemError(errno, "cannot create locale");
|
||||||
|
}
|
||||||
|
~Locale() { freelocale(locale_); }
|
||||||
|
|
||||||
|
locale_t get() const { return locale_; }
|
||||||
|
|
||||||
|
// Converts string to floating-point number and advances str past the end
|
||||||
|
// of the parsed input.
|
||||||
|
double strtod(const char *&str) const {
|
||||||
|
char *end = 0;
|
||||||
|
double result = strtod_l(str, &end, locale_);
|
||||||
|
str = end;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LC_NUMERIC
|
||||||
} // namespace fmt
|
} // namespace fmt
|
||||||
|
|
||||||
#if !FMT_USE_RVALUE_REFERENCES
|
#if !FMT_USE_RVALUE_REFERENCES
|
||||||
|
@ -262,6 +262,8 @@ The available presentation types for floating-point values are:
|
|||||||
| none | The same as ``'g'``. |
|
| none | The same as ``'g'``. |
|
||||||
+---------+----------------------------------------------------------+
|
+---------+----------------------------------------------------------+
|
||||||
|
|
||||||
|
Floating-point formatting is locale-dependent.
|
||||||
|
|
||||||
.. ifconfig:: False
|
.. ifconfig:: False
|
||||||
|
|
||||||
+---------+----------------------------------------------------------+
|
+---------+----------------------------------------------------------+
|
||||||
|
@ -387,3 +387,12 @@ TEST(FileTest, FdopenError) {
|
|||||||
EXPECT_SYSTEM_ERROR_NOASSERT(
|
EXPECT_SYSTEM_ERROR_NOASSERT(
|
||||||
f.fdopen("r"), EBADF, "cannot associate stream with file descriptor");
|
f.fdopen("r"), EBADF, "cannot associate stream with file descriptor");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LC_NUMERIC_MASK
|
||||||
|
TEST(LocaleTest, Strtod) {
|
||||||
|
fmt::Locale locale;
|
||||||
|
const char *start = "4.2", *ptr = start;
|
||||||
|
EXPECT_EQ(4.2, locale.strtod(ptr));
|
||||||
|
EXPECT_EQ(start + 3, ptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -306,8 +306,8 @@ void TestLength(const char *length_spec, U value) {
|
|||||||
}
|
}
|
||||||
using fmt::internal::MakeUnsigned;
|
using fmt::internal::MakeUnsigned;
|
||||||
if (sizeof(U) <= sizeof(int) && sizeof(int) < sizeof(T)) {
|
if (sizeof(U) <= sizeof(int) && sizeof(int) < sizeof(T)) {
|
||||||
signed_value = unsigned_value =
|
signed_value = value;
|
||||||
static_cast<typename MakeUnsigned<unsigned>::Type>(value);
|
unsigned_value = static_cast<typename MakeUnsigned<unsigned>::Type>(value);
|
||||||
} else {
|
} else {
|
||||||
signed_value = static_cast<typename MakeSigned<T>::Type>(value);
|
signed_value = static_cast<typename MakeSigned<T>::Type>(value);
|
||||||
unsigned_value = static_cast<typename MakeUnsigned<T>::Type>(value);
|
unsigned_value = static_cast<typename MakeUnsigned<T>::Type>(value);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user