Merge branch 'master' into error_message

This commit is contained in:
Aamr El Kazdadi 2019-12-11 15:11:01 +01:00 committed by GitHub
commit b07b009b42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 173 additions and 20 deletions

View File

@ -42,6 +42,7 @@ option(FMT_DOC "Generate the doc target." ${MASTER_PROJECT})
option(FMT_INSTALL "Generate the install target." ${MASTER_PROJECT}) option(FMT_INSTALL "Generate the install target." ${MASTER_PROJECT})
option(FMT_TEST "Generate the test target." ${MASTER_PROJECT}) option(FMT_TEST "Generate the test target." ${MASTER_PROJECT})
option(FMT_FUZZ "Generate the fuzz target." OFF) option(FMT_FUZZ "Generate the fuzz target." OFF)
option(FMT_CUDA_TEST "Generate the cuda-test target." OFF)
project(FMT CXX) project(FMT CXX)

View File

@ -1,3 +1,18 @@
6.1.2 - TBD
-----------
* Fixed ABI compatibility with ``libfmt.so.6.0.0``.
* Fixed handling types convertible to ``std::string_view``
(`#1451 <https://github.com/fmtlib/fmt/pull/1451>`_).
Thanks `@denizevrenci (Deniz Evrenci) <https://github.com/denizevrenci>`_.
* Made CUDA test an opt-in enabled via the ``FMT_CUDA_TEST`` CMake option.
* Fixed sign conversion warnings
(`#1440 <https://github.com/fmtlib/fmt/pull/1440>`_).
Thanks `@0x8000-0000 (Florin Iucha) <https://github.com/0x8000-0000>`_.
6.1.1 - 2019-12-04 6.1.1 - 2019-12-04
------------------ ------------------

View File

@ -15,7 +15,7 @@
#include <type_traits> #include <type_traits>
// The fmt library version in the form major * 10000 + minor * 100 + patch. // The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 60101 #define FMT_VERSION 60102
#ifdef __has_feature #ifdef __has_feature
# define FMT_HAS_FEATURE(x) __has_feature(x) # define FMT_HAS_FEATURE(x) __has_feature(x)
@ -889,7 +889,7 @@ template <typename Context> struct arg_mapper_impl {
FMT_ENABLE_IF( FMT_ENABLE_IF(
std::is_constructible<std_string_view<char_type>, T>::value && std::is_constructible<std_string_view<char_type>, T>::value &&
!std::is_constructible<basic_string_view<char_type>, T>::value && !std::is_constructible<basic_string_view<char_type>, T>::value &&
!is_string<T>::value && !has_any_formatter<T, Context>::value)> !is_string<T>::value && !has_formatter<T, Context>::value)>
FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) { FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
return std_string_view<char_type>(val); return std_string_view<char_type>(val);
} }
@ -920,11 +920,13 @@ template <typename Context> struct arg_mapper_impl {
map(static_cast<typename std::underlying_type<T>::type>(val))) { map(static_cast<typename std::underlying_type<T>::type>(val))) {
return map(static_cast<typename std::underlying_type<T>::type>(val)); return map(static_cast<typename std::underlying_type<T>::type>(val));
} }
template <typename T, template <typename T,
FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value && FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value &&
!std::is_constructible<basic_string_view<char_type>, !std::is_constructible<basic_string_view<char_type>,
T>::value && T>::value &&
has_any_formatter<T, Context>::value)> has_any_formatter<T, Context>::value &&
!std::is_constructible<std_string_view<char_type>, T>::value)>
FMT_CONSTEXPR const T& map(const T& val) { FMT_CONSTEXPR const T& map(const T& val) {
return val; return val;
} }

View File

@ -8,6 +8,119 @@
#include "fmt/format-inl.h" #include "fmt/format-inl.h"
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
namespace internal {
template <typename T>
int format_float(char* buf, std::size_t size, const char* format, int precision,
T value) {
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if (precision > 100000)
throw std::runtime_error(
"fuzz mode - avoid large allocation inside snprintf");
#endif
// Suppress the warning about nonliteral format string.
auto snprintf_ptr = FMT_SNPRINTF;
return precision < 0 ? snprintf_ptr(buf, size, format, value)
: snprintf_ptr(buf, size, format, precision, value);
}
struct sprintf_specs {
int precision;
char type;
bool alt : 1;
template <typename Char>
constexpr sprintf_specs(basic_format_specs<Char> specs)
: precision(specs.precision), type(specs.type), alt(specs.alt) {}
constexpr bool has_precision() const { return precision >= 0; }
};
// This is deprecated and is kept only to preserve ABI compatibility.
template <typename Double>
char* sprintf_format(Double value, internal::buffer<char>& buf,
sprintf_specs specs) {
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
FMT_ASSERT(buf.capacity() != 0, "empty buffer");
// Build format string.
enum { max_format_size = 10 }; // longest format: %#-*.*Lg
char format[max_format_size];
char* format_ptr = format;
*format_ptr++ = '%';
if (specs.alt || !specs.type) *format_ptr++ = '#';
if (specs.precision >= 0) {
*format_ptr++ = '.';
*format_ptr++ = '*';
}
if (std::is_same<Double, long double>::value) *format_ptr++ = 'L';
char type = specs.type;
if (type == '%')
type = 'f';
else if (type == 0 || type == 'n')
type = 'g';
#if FMT_MSC_VER
if (type == 'F') {
// MSVC's printf doesn't support 'F'.
type = 'f';
}
#endif
*format_ptr++ = type;
*format_ptr = '\0';
// Format using snprintf.
char* start = nullptr;
char* decimal_point_pos = nullptr;
for (;;) {
std::size_t buffer_size = buf.capacity();
start = &buf[0];
int result =
format_float(start, buffer_size, format, specs.precision, value);
if (result >= 0) {
unsigned n = internal::to_unsigned(result);
if (n < buf.capacity()) {
// Find the decimal point.
auto p = buf.data(), end = p + n;
if (*p == '+' || *p == '-') ++p;
if (specs.type != 'a' && specs.type != 'A') {
while (p < end && *p >= '0' && *p <= '9') ++p;
if (p < end && *p != 'e' && *p != 'E') {
decimal_point_pos = p;
if (!specs.type) {
// Keep only one trailing zero after the decimal point.
++p;
if (*p == '0') ++p;
while (p != end && *p >= '1' && *p <= '9') ++p;
char* where = p;
while (p != end && *p == '0') ++p;
if (p == end || *p < '0' || *p > '9') {
if (p != end) std::memmove(where, p, to_unsigned(end - p));
n -= static_cast<unsigned>(p - where);
}
}
}
}
buf.resize(n);
break; // The buffer is large enough - continue with formatting.
}
buf.reserve(n + 1);
} else {
// If result is negative we ask to increase the capacity by at least 1,
// but as std::vector, the buffer grows exponentially.
buf.reserve(buf.capacity() + 1);
}
}
return decimal_point_pos;
}
} // namespace internal
template FMT_API char* internal::sprintf_format(double, internal::buffer<char>&,
sprintf_specs);
template FMT_API char* internal::sprintf_format(long double,
internal::buffer<char>&,
sprintf_specs);
template struct FMT_API internal::basic_data<void>; template struct FMT_API internal::basic_data<void>;
// Workaround a bug in MSVC2013 that prevents instantiation of format_float. // Workaround a bug in MSVC2013 that prevents instantiation of format_float.

View File

@ -229,20 +229,22 @@ if (FMT_PEDANTIC AND NOT WIN32)
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
endif () endif ()
# Activate optional CUDA tests if CUDA is found. For version selection, see # Activate optional CUDA tests if CUDA is found. For version selection see
# https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#cpp14-language-features # https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#cpp14-language-features
if (${CMAKE_VERSION} VERSION_LESS 3.15) if (FMT_CUDA_TEST)
if (${CMAKE_VERSION} VERSION_LESS 3.15)
find_package(CUDA 9.0) find_package(CUDA 9.0)
else () else ()
include(CheckLanguage) include(CheckLanguage)
check_language(CUDA) check_language(CUDA)
if (CMAKE_CUDA_COMPILER) if (CMAKE_CUDA_COMPILER)
enable_language(CUDA OPTIONAL) enable_language(CUDA OPTIONAL)
set(CUDA_FOUND TRUE) set(CUDA_FOUND TRUE)
endif () endif ()
endif () endif ()
if (CUDA_FOUND) if (CUDA_FOUND)
add_subdirectory(cuda-test) add_subdirectory(cuda-test)
add_test(NAME cuda-test COMMAND fmt-in-cuda-test) add_test(NAME cuda-test COMMAND fmt-in-cuda-test)
endif ()
endif () endif ()

View File

@ -1691,16 +1691,14 @@ struct explicitly_convertible_to_std_string_view {
}; };
namespace fmt { namespace fmt {
template <> template <>
struct formatter<explicitly_convertible_to_std_string_view> struct formatter<explicitly_convertible_to_std_string_view>
: formatter<std::string_view> { : formatter<std::string_view> {
auto format(const explicitly_convertible_to_std_string_view& v, auto format(const explicitly_convertible_to_std_string_view& v,
format_context& ctx) { format_context& ctx) -> decltype(ctx.out()) {
return format_to(ctx.out(), "'{}'", std::string_view(v)); return format_to(ctx.out(), "'{}'", std::string_view(v));
} }
}; };
} // namespace fmt } // namespace fmt
TEST(FormatterTest, FormatExplicitlyConvertibleToStdStringView) { TEST(FormatterTest, FormatExplicitlyConvertibleToStdStringView) {

View File

@ -276,3 +276,25 @@ std::ostream& operator<<(std::ostream& os,
TEST(FormatterTest, FormatExplicitlyConvertibleToStringLikeIgnoreInserter) { TEST(FormatterTest, FormatExplicitlyConvertibleToStringLikeIgnoreInserter) {
EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_like())); EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_like()));
} }
#ifdef FMT_USE_STRING_VIEW
struct explicitly_convertible_to_std_string_view {
explicit operator fmt::internal::std_string_view<char>() const {
return {"foo", 3u};
}
};
TEST(FormatterTest, FormatExplicitlyConvertibleToStdStringView) {
EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_like()));
}
std::ostream& operator<<(std::ostream& os,
explicitly_convertible_to_std_string_view) {
return os << "bar";
}
TEST(FormatterTest, FormatExplicitlyConvertibleToStdStringViewIgnoreInserter) {
EXPECT_EQ("foo",
fmt::format("{}", explicitly_convertible_to_std_string_view()));
}
#endif // FMT_USE_STRING_VIEW