This commit is contained in:
Remotion 2018-06-06 16:24:31 +02:00
commit 25c783f8a2
43 changed files with 963 additions and 629 deletions

View File

@ -1,10 +1,12 @@
language: cpp language: cpp
dist: trusty dist: trusty
sudo: required # the doc target uses sudo to install dependencies sudo: false
os: linux
git:
depth: 1
os:
- linux
- osx
env: env:
global: global:
@ -12,18 +14,81 @@ env:
a1eovNn4uol9won7ghr67eD3/59oeESN+G9bWE+ecI1V6yRseG9whniGhIpC/YfMW/Qz5I a1eovNn4uol9won7ghr67eD3/59oeESN+G9bWE+ecI1V6yRseG9whniGhIpC/YfMW/Qz5I
5sxSmFjaw9bxCISNwUIrL1O5x2AmRYTnFcXk4dFsUvlZg+WeF/aKyBYCNRM8C2ndbBmtAO 5sxSmFjaw9bxCISNwUIrL1O5x2AmRYTnFcXk4dFsUvlZg+WeF/aKyBYCNRM8C2ndbBmtAO
o1F2EwFbiso0EmtzhAPs19ujiVxkLn4= o1F2EwFbiso0EmtzhAPs19ujiVxkLn4=
matrix:
- BUILD=Doc
- BUILD=Debug STANDARD=14
- BUILD=Release STANDARD=14
matrix: matrix:
exclude:
- os: osx
env: BUILD=Doc
include: include:
# Documentation
- env: BUILD=Doc
sudo: required
# g++ 6 on Linux with C++14
- env: COMPILER=g++-6 BUILD=Debug STANDARD=14
compiler: gcc
addons:
apt:
update: true
sources:
- ubuntu-toolchain-r-test
packages:
- g++-6
- env: COMPILER=g++-6 BUILD=Release STANDARD=14
compiler: gcc
addons:
apt:
update: true
sources:
- ubuntu-toolchain-r-test
packages:
- g++-6
# Apple clang on OS X with C++14
- env: BUILD=Debug STANDARD=14
compiler: clang
os: osx
- env: BUILD=Release STANDARD=14
compiler: clang
os: osx
# clang 6.0 on Linux with C++14
- env: COMPILER=clang++-6.0 BUILD=Debug STANDARD=14
compiler: clang
addons:
apt:
update: true
packages:
- clang-6.0
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty
- llvm-toolchain-trusty-6.0
# clang 4.0 on Linux with C++14
- env: COMPILER=clang++-4.0 BUILD=Debug STANDARD=11
compiler: clang
addons:
apt:
update: true
packages:
- clang-4.0
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty
- llvm-toolchain-trusty-4.0
# g++ 4.8 on Linux with C++11
- env: COMPILER=g++-4.8 BUILD=Debug STANDARD=11
compiler: gcc
# g++ 4.4 on Linux with C++11
- env: COMPILER=g++-4.4 BUILD=Debug STANDARD=11
compiler: gcc
addons:
apt:
update: true
packages:
- g++-4.4
sources:
- ubuntu-toolchain-r-test
# Android
- language: android - language: android
android: android:
addons:
apt:
update: true
components: components:
- tools - tools
- platform-tools - platform-tools
@ -51,17 +116,14 @@ matrix:
after_success: after_success:
- cd ${TRAVIS_BUILD_DIR} - cd ${TRAVIS_BUILD_DIR}
- tree ./libs - tree ./libs
allow_failures:
# Errors
- env: COMPILER=g++-4.4 BUILD=Debug STANDARD=11
compiler: gcc
# Install gcc-6 for extended constexpr support. before_script:
addons: - if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then export CXX=${COMPILER}; fi
apt: - if [[ "${BUILD}" != "Doc" ]]; then ${CXX} --version; fi
sources:
- ubuntu-toolchain-r-test
packages:
- g++-6
before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export CXX=g++-6; fi
script: script:
- support/travis-build.py - support/travis-build.py

View File

@ -1,6 +1,6 @@
message(STATUS "CMake version: ${CMAKE_VERSION}") message(STATUS "CMake version: ${CMAKE_VERSION}")
cmake_minimum_required(VERSION 2.8.12) cmake_minimum_required(VERSION 3.1.0)
# Determine if fmt is built as a subproject (using add_subdirectory) # Determine if fmt is built as a subproject (using add_subdirectory)
# or if it is the master project. # or if it is the master project.
@ -28,12 +28,12 @@ if (NOT CMAKE_BUILD_TYPE)
endif () endif ()
option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF) option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF)
option(FMT_WERROR "Halt the compilation with an error on compiler warnings." OFF)
# Options that control generation of various targets. # Options that control generation of various targets.
option(FMT_DOC "Generate the doc target." ${MASTER_PROJECT}) 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_USE_CPP14 "Enable the addition of C++14 compiler flags." ON)
project(FMT) project(FMT)
@ -58,9 +58,62 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_SOURCE_DIR}/support/cmake") "${CMAKE_CURRENT_SOURCE_DIR}/support/cmake")
include(cxx14) include(cxx14)
include(CheckCXXCompilerFlag)
if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wshadow -pedantic) set(PEDANTIC_COMPILE_FLAGS -pedantic-errors -Wall -Wextra -pedantic
-Wold-style-cast -Wfloat-equal -Wlogical-op -Wundef
-Wredundant-decls -Wshadow -Wwrite-strings -Wpointer-arith
-Wcast-qual -Wformat=2 -Wmissing-include-dirs
-Wcast-align -Wnon-virtual-dtor
-Wctor-dtor-privacy -Wdisabled-optimization
-Winvalid-pch -Wmissing-declarations -Woverloaded-virtual
-Wno-sign-conversion -Wno-shadow -Wno-format-nonliteral
-Wno-dangling-else -Wno-ctor-dtor-privacy)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnoexcept)
endif ()
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wdouble-promotion
-Wtrampolines -Wzero-as-null-pointer-constant -Wuseless-cast
-Wvector-operation-performance -Wsized-deallocation)
endif ()
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wshift-overflow=2
-Wnull-dereference -Wduplicated-cond)
endif ()
set(WERROR_FLAG -Werror)
endif ()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(PEDANTIC_COMPILE_FLAGS -Weverything -Wpedantic
-Wno-weak-vtables -Wno-padded -Wno-gnu-statement-expression
-Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-reserved-id-macro
-Wno-global-constructors -Wno-disabled-macro-expansion
-Wno-switch-enum -Wno-documentation-unknown-command
-Wno-gnu-string-literal-operator-template -Wno-unused-member-function
-Wno-format-nonliteral -Wno-missing-noreturn -Wno-undefined-func-template
-Wno-shadow -Wno-sign-conversion -Wno-used-but-marked-unused
-Wno-covered-switch-default -Wno-missing-variable-declarations
-Wno-double-promotion)
set(WERROR_FLAG -Werror)
check_cxx_compiler_flag(-Wno-zero-as-null-pointer-constant HAS_NULLPTR_WARNING)
if (HAS_NULLPTR_WARNING)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wno-zero-as-null-pointer-constant)
endif ()
check_cxx_compiler_flag(-Wno-gnu-string-literal-operator-template HAS_GNU_UDL_WARNING)
if (HAS_GNU_UDL_WARNING)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wno-gnu-string-literal-operator-template)
endif ()
endif ()
if (MSVC)
set(PEDANTIC_COMPILE_FLAGS /W4)
set(WERROR_FLAG /WX)
endif () endif ()
if (MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio") if (MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
@ -106,9 +159,9 @@ endif ()
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst) add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
add_library(fmt::fmt ALIAS fmt) add_library(fmt::fmt ALIAS fmt)
# Starting with CMake 3.1 the CXX_STANDARD property can be used instead. if (FMT_WERROR)
# Don't export -std since it may break projects that use other standards. target_compile_options(fmt PRIVATE ${WERROR_FLAG})
target_compile_options(fmt PRIVATE ${CPP14_FLAG}) endif ()
if (FMT_PEDANTIC) if (FMT_PEDANTIC)
target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS}) target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif () endif ()
@ -130,17 +183,14 @@ if (BUILD_SHARED_LIBS)
target_compile_definitions(fmt PRIVATE FMT_EXPORT INTERFACE FMT_SHARED) target_compile_definitions(fmt PRIVATE FMT_EXPORT INTERFACE FMT_SHARED)
endif () endif ()
# Additionally define a header-only library when CMake is new enough. add_library(fmt-header-only INTERFACE)
if (CMAKE_VERSION VERSION_GREATER 3.1.0 OR CMAKE_VERSION VERSION_EQUAL 3.1.0) add_library(fmt::fmt-header-only ALIAS fmt-header-only)
add_library(fmt-header-only INTERFACE)
add_library(fmt::fmt-header-only ALIAS fmt-header-only)
target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1) target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
target_include_directories(fmt-header-only INTERFACE target_include_directories(fmt-header-only INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include> $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>) $<INSTALL_INTERFACE:include>)
endif ()
# Install targets. # Install targets.
if (FMT_INSTALL) if (FMT_INSTALL)

View File

@ -1,5 +1,5 @@
5.0.0 - TBD 5.0.0 - 2018-05-21
----------- ------------------
* Added a requirement for partial C++11 support, most importantly variadic * Added a requirement for partial C++11 support, most importantly variadic
templates and type traits, and dropped ``FMT_VARIADIC_*`` emulation macros. templates and type traits, and dropped ``FMT_VARIADIC_*`` emulation macros.
@ -24,7 +24,7 @@
std::string s = format(fmt("{:d}"), "foo"); std::string s = format(fmt("{:d}"), "foo");
gives a compile-time error because ``d`` is an invalid specifier for strings gives a compile-time error because ``d`` is an invalid specifier for strings
(`godbolt <https://godbolt.org/g/rnCy9Q>`_):: (`godbolt <https://godbolt.org/g/rnCy9Q>`__)::
... ...
<source>:4:19: note: in instantiation of function template specialization 'fmt::v5::format<S, char [4]>' requested here <source>:4:19: note: in instantiation of function template specialization 'fmt::v5::format<S, char [4]>' requested here
@ -41,11 +41,11 @@
.. code:: c++ .. code:: c++
struct S {}; struct Answer {};
namespace fmt { namespace fmt {
template <> template <>
struct formatter<S> { struct formatter<Answer> {
constexpr auto parse(parse_context& ctx) { constexpr auto parse(parse_context& ctx) {
auto it = ctx.begin(); auto it = ctx.begin();
spec = *it; spec = *it;
@ -55,7 +55,7 @@
} }
template <typename FormatContext> template <typename FormatContext>
auto format(S, FormatContext& ctx) { auto format(Answer, FormatContext& ctx) {
return spec == 's' ? return spec == 's' ?
format_to(ctx.begin(), "{}", "fourty-two") : format_to(ctx.begin(), "{}", "fourty-two") :
format_to(ctx.begin(), "{}", 42); format_to(ctx.begin(), "{}", 42);
@ -65,10 +65,10 @@
}; };
} }
std::string s = format(fmt("{:x}"), S()); std::string s = format(fmt("{:x}"), Answer());
gives a compile-time error due to invalid format specifier (`godbolt gives a compile-time error due to invalid format specifier (`godbolt
<https://godbolt.org/g/ywhrPp>`_):: <https://godbolt.org/g/2jQ1Dv>`__)::
... ...
<source>:12:45: error: expression '<throw-expression>' is not a constant expression <source>:12:45: error: expression '<throw-expression>' is not a constant expression
@ -192,7 +192,7 @@
fmt::print("{}", std::experimental::string_view("foo")); fmt::print("{}", std::experimental::string_view("foo"));
Thanks `@virgiliofornazin (Virgilio Alexandre Fornazin) Thanks `@virgiliofornazin (Virgilio Alexandre Fornazin)
<https://github.com/virgiliofornazin>`_. <https://github.com/virgiliofornazin>`__.
* Allowed mixing named and automatic arguments: * Allowed mixing named and automatic arguments:
@ -221,7 +221,7 @@
* Introduced an inline namespace for symbol versioning. * Introduced an inline namespace for symbol versioning.
* Added debug postfix ``d`` to the `fmt`` library name * Added debug postfix ``d`` to the ``fmt`` library name
(`#636 <https://github.com/fmtlib/fmt/issues/636>`_). (`#636 <https://github.com/fmtlib/fmt/issues/636>`_).
* Removed unnecessary ``fmt/`` prefix in includes * Removed unnecessary ``fmt/`` prefix in includes
@ -262,7 +262,7 @@
`#656 <https://github.com/fmtlib/fmt/pull/656>`_, `#656 <https://github.com/fmtlib/fmt/pull/656>`_,
`#679 <https://github.com/fmtlib/fmt/pull/679>`_, `#679 <https://github.com/fmtlib/fmt/pull/679>`_,
`#681 <https://github.com/fmtlib/fmt/pull/681>`_, `#681 <https://github.com/fmtlib/fmt/pull/681>`_,
`#705 <https://github.com/fmtlib/fmt/pull/705>`_, `#705 <https://github.com/fmtlib/fmt/pull/705>`__,
`#715 <https://github.com/fmtlib/fmt/issues/715>`_, `#715 <https://github.com/fmtlib/fmt/issues/715>`_,
`#717 <https://github.com/fmtlib/fmt/pull/717>`_, `#717 <https://github.com/fmtlib/fmt/pull/717>`_,
`#720 <https://github.com/fmtlib/fmt/pull/720>`_, `#720 <https://github.com/fmtlib/fmt/pull/720>`_,
@ -513,7 +513,6 @@
(`#494 <https://github.com/fmtlib/fmt/pull/494>`_, (`#494 <https://github.com/fmtlib/fmt/pull/494>`_,
`#499 <https://github.com/fmtlib/fmt/pull/499>`_, `#499 <https://github.com/fmtlib/fmt/pull/499>`_,
`#483 <https://github.com/fmtlib/fmt/pull/483>`_, `#483 <https://github.com/fmtlib/fmt/pull/483>`_,
`#519 <https://github.com/fmtlib/fmt/pull/519>`_,
`#485 <https://github.com/fmtlib/fmt/pull/485>`_, `#485 <https://github.com/fmtlib/fmt/pull/485>`_,
`#482 <https://github.com/fmtlib/fmt/pull/482>`_, `#482 <https://github.com/fmtlib/fmt/pull/482>`_,
`#475 <https://github.com/fmtlib/fmt/pull/475>`_, `#475 <https://github.com/fmtlib/fmt/pull/475>`_,

View File

@ -6,7 +6,7 @@ import errno, os, shutil, sys, tempfile
from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE
from distutils.version import LooseVersion from distutils.version import LooseVersion
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0'] versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0']
def pip_install(package, commit=None, **kwargs): def pip_install(package, commit=None, **kwargs):
"Install package using pip." "Install package using pip."
@ -56,7 +56,7 @@ def create_build_env(dirname='virtualenv'):
pip_install('sphinx-doc/sphinx', '12b83372ac9316e8cbe86e7fed889296a4cc29ee', pip_install('sphinx-doc/sphinx', '12b83372ac9316e8cbe86e7fed889296a4cc29ee',
min_version='1.4.1.dev20160531') min_version='1.4.1.dev20160531')
pip_install('michaeljones/breathe', pip_install('michaeljones/breathe',
'6b1c5bb7a1866f15fc328b8716258354b10c1daa', '129222318f7c8f865d2631e7da7b033567e7f56a',
min_version='4.2.0') min_version='4.2.0')
def build_docs(version='dev', **kwargs): def build_docs(version='dev', **kwargs):

View File

@ -16,7 +16,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 50000 #define FMT_VERSION 50100
#ifdef __has_feature #ifdef __has_feature
# define FMT_HAS_FEATURE(x) __has_feature(x) # define FMT_HAS_FEATURE(x) __has_feature(x)
@ -30,6 +30,12 @@
# define FMT_HAS_INCLUDE(x) 0 # define FMT_HAS_INCLUDE(x) 0
#endif #endif
#ifdef __has_cpp_attribute
# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
# define FMT_HAS_CPP_ATTRIBUTE(x) 0
#endif
#if defined(__GNUC__) && !defined(__clang__) #if defined(__GNUC__) && !defined(__clang__)
# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
#else #else
@ -95,6 +101,12 @@
# define FMT_USE_NULLPTR 0 # define FMT_USE_NULLPTR 0
#endif #endif
#if FMT_HAS_CPP_ATTRIBUTE(noreturn)
# define FMT_NORETURN [[noreturn]]
#else
# define FMT_NORETURN /*noreturn*/
#endif
// Check if exceptions are disabled. // Check if exceptions are disabled.
#if defined(__GNUC__) && !defined(__EXCEPTIONS) #if defined(__GNUC__) && !defined(__EXCEPTIONS)
# define FMT_EXCEPTIONS 0 # define FMT_EXCEPTIONS 0
@ -218,7 +230,7 @@ class basic_string_view {
#else #else
struct type { struct type {
const char *data() const { return FMT_NULL; } const char *data() const { return FMT_NULL; }
size_t size() const { return 0; }; size_t size() const { return 0; }
}; };
#endif #endif
@ -428,7 +440,7 @@ template <typename T, typename Char>
struct is_named_arg<named_arg<T, Char>> : std::true_type {}; struct is_named_arg<named_arg<T, Char>> : std::true_type {};
enum type { enum type {
none_type, name_arg_type, none_type, named_arg_type,
// Integer types should go first, // Integer types should go first,
int_type, uint_type, long_long_type, ulong_long_type, bool_type, char_type, int_type, uint_type, long_long_type, ulong_long_type, bool_type, char_type,
last_integer_type = char_type, last_integer_type = char_type,
@ -438,12 +450,12 @@ enum type {
}; };
FMT_CONSTEXPR bool is_integral(type t) { FMT_CONSTEXPR bool is_integral(type t) {
FMT_ASSERT(t != internal::name_arg_type, "invalid argument type"); FMT_ASSERT(t != internal::named_arg_type, "invalid argument type");
return t > internal::none_type && t <= internal::last_integer_type; return t > internal::none_type && t <= internal::last_integer_type;
} }
FMT_CONSTEXPR bool is_arithmetic(type t) { FMT_CONSTEXPR bool is_arithmetic(type t) {
FMT_ASSERT(t != internal::name_arg_type, "invalid argument type"); FMT_ASSERT(t != internal::named_arg_type, "invalid argument type");
return t > internal::none_type && t <= internal::last_numeric_type; return t > internal::none_type && t <= internal::last_numeric_type;
} }
@ -550,11 +562,17 @@ FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value);
return static_cast<ValueType>(val); \ return static_cast<ValueType>(val); \
} }
#define FMT_MAKE_VALUE_SAME(TAG, Type) \
template <typename C> \
FMT_CONSTEXPR typed_value<C, TAG> make_value(Type val) { \
return val; \
}
FMT_MAKE_VALUE(bool_type, bool, int) FMT_MAKE_VALUE(bool_type, bool, int)
FMT_MAKE_VALUE(int_type, short, int) FMT_MAKE_VALUE(int_type, short, int)
FMT_MAKE_VALUE(uint_type, unsigned short, unsigned) FMT_MAKE_VALUE(uint_type, unsigned short, unsigned)
FMT_MAKE_VALUE(int_type, int, int) FMT_MAKE_VALUE_SAME(int_type, int)
FMT_MAKE_VALUE(uint_type, unsigned, unsigned) FMT_MAKE_VALUE_SAME(uint_type, unsigned)
// To minimize the number of types we need to deal with, long is translated // To minimize the number of types we need to deal with, long is translated
// either to int or to long long depending on its size. // either to int or to long long depending on its size.
@ -568,8 +586,8 @@ FMT_MAKE_VALUE(
(sizeof(unsigned long) == sizeof(unsigned) ? uint_type : ulong_long_type), (sizeof(unsigned long) == sizeof(unsigned) ? uint_type : ulong_long_type),
unsigned long, ulong_type) unsigned long, ulong_type)
FMT_MAKE_VALUE(long_long_type, long long, long long) FMT_MAKE_VALUE_SAME(long_long_type, long long)
FMT_MAKE_VALUE(ulong_long_type, unsigned long long, unsigned long long) FMT_MAKE_VALUE_SAME(ulong_long_type, unsigned long long)
FMT_MAKE_VALUE(int_type, signed char, int) FMT_MAKE_VALUE(int_type, signed char, int)
FMT_MAKE_VALUE(uint_type, unsigned char, unsigned) FMT_MAKE_VALUE(uint_type, unsigned char, unsigned)
FMT_MAKE_VALUE(char_type, char, int) FMT_MAKE_VALUE(char_type, char, int)
@ -583,8 +601,8 @@ inline typed_value<C, char_type> make_value(wchar_t val) {
#endif #endif
FMT_MAKE_VALUE(double_type, float, double) FMT_MAKE_VALUE(double_type, float, double)
FMT_MAKE_VALUE(double_type, double, double) FMT_MAKE_VALUE_SAME(double_type, double)
FMT_MAKE_VALUE(long_double_type, long double, long double) FMT_MAKE_VALUE_SAME(long_double_type, long double)
// Formatting of wide strings into a narrow buffer and multibyte strings // Formatting of wide strings into a narrow buffer and multibyte strings
// into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606). // into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606).
@ -594,18 +612,17 @@ FMT_MAKE_VALUE(cstring_type, const typename C::char_type*,
const typename C::char_type*) const typename C::char_type*)
FMT_MAKE_VALUE(cstring_type, signed char*, const signed char*) FMT_MAKE_VALUE(cstring_type, signed char*, const signed char*)
FMT_MAKE_VALUE(cstring_type, const signed char*, const signed char*) FMT_MAKE_VALUE_SAME(cstring_type, const signed char*)
FMT_MAKE_VALUE(cstring_type, unsigned char*, const unsigned char*) FMT_MAKE_VALUE(cstring_type, unsigned char*, const unsigned char*)
FMT_MAKE_VALUE(cstring_type, const unsigned char*, const unsigned char*) FMT_MAKE_VALUE_SAME(cstring_type, const unsigned char*)
FMT_MAKE_VALUE(string_type, basic_string_view<typename C::char_type>, FMT_MAKE_VALUE_SAME(string_type, basic_string_view<typename C::char_type>)
basic_string_view<typename C::char_type>)
FMT_MAKE_VALUE(string_type, FMT_MAKE_VALUE(string_type,
typename basic_string_view<typename C::char_type>::type, typename basic_string_view<typename C::char_type>::type,
basic_string_view<typename C::char_type>) basic_string_view<typename C::char_type>)
FMT_MAKE_VALUE(string_type, const std::basic_string<typename C::char_type>&, FMT_MAKE_VALUE(string_type, const std::basic_string<typename C::char_type>&,
basic_string_view<typename C::char_type>) basic_string_view<typename C::char_type>)
FMT_MAKE_VALUE(pointer_type, void*, const void*) FMT_MAKE_VALUE(pointer_type, void*, const void*)
FMT_MAKE_VALUE(pointer_type, const void*, const void*) FMT_MAKE_VALUE_SAME(pointer_type, const void*)
#if FMT_USE_NULLPTR #if FMT_USE_NULLPTR
FMT_MAKE_VALUE(pointer_type, std::nullptr_t, const void*) FMT_MAKE_VALUE(pointer_type, std::nullptr_t, const void*)
@ -637,7 +654,7 @@ inline typename std::enable_if<
make_value(const T &val) { return val; } make_value(const T &val) { return val; }
template <typename C, typename T> template <typename C, typename T>
typed_value<C, name_arg_type> typed_value<C, named_arg_type>
make_value(const named_arg<T, typename C::char_type> &val) { make_value(const named_arg<T, typename C::char_type> &val) {
basic_format_arg<C> arg = make_arg<C>(val.value); basic_format_arg<C> arg = make_arg<C>(val.value);
std::memcpy(val.data, &arg, sizeof(arg)); std::memcpy(val.data, &arg, sizeof(arg));
@ -788,7 +805,7 @@ class arg_map {
basic_format_arg<Context> find(basic_string_view<char_type> name) const { basic_format_arg<Context> find(basic_string_view<char_type> name) const {
// The list is unsorted, so just return the first matching name. // The list is unsorted, so just return the first matching name.
for (auto it = map_, end = map_ + size_; it != end; ++it) { for (entry *it = map_, *end = map_ + size_; it != end; ++it) {
if (it->name == name) if (it->name == name)
return it->arg; return it->arg;
} }
@ -973,16 +990,17 @@ class format_arg_store {
friend class basic_format_args<Context>; friend class basic_format_args<Context>;
static FMT_CONSTEXPR uint64_t get_types() { static FMT_CONSTEXPR int64_t get_types() {
return IS_PACKED ? internal::get_types<Context, Args...>() return IS_PACKED ?
: -static_cast<int64_t>(NUM_ARGS); static_cast<int64_t>(internal::get_types<Context, Args...>()) :
-static_cast<int64_t>(NUM_ARGS);
} }
public: public:
#if FMT_USE_CONSTEXPR #if FMT_USE_CONSTEXPR
static constexpr uint64_t TYPES = get_types(); static constexpr int64_t TYPES = get_types();
#else #else
static const uint64_t TYPES; static const int64_t TYPES;
#endif #endif
#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 405 #if FMT_GCC_VERSION && FMT_GCC_VERSION <= 405
@ -998,7 +1016,7 @@ class format_arg_store {
#if !FMT_USE_CONSTEXPR #if !FMT_USE_CONSTEXPR
template <typename Context, typename ...Args> template <typename Context, typename ...Args>
const uint64_t format_arg_store<Context, Args...>::TYPES = get_types(); const int64_t format_arg_store<Context, Args...>::TYPES = get_types();
#endif #endif
/** /**
@ -1087,7 +1105,7 @@ class basic_format_args {
/** Returns the argument at specified index. */ /** Returns the argument at specified index. */
format_arg get(size_type index) const { format_arg get(size_type index) const {
format_arg arg = do_get(index); format_arg arg = do_get(index);
return arg.type_ == internal::name_arg_type ? return arg.type_ == internal::named_arg_type ?
arg.value_.as_named_arg().template deserialize<Context>() : arg; arg.value_.as_named_arg().template deserialize<Context>() : arg;
} }

View File

@ -45,12 +45,6 @@
# define FMT_CATCH(x) if (false) # define FMT_CATCH(x) if (false)
#endif #endif
#ifdef __GNUC__
// Disable the warning about declaration shadowing because it affects too
// many valid cases.
# pragma GCC diagnostic ignored "-Wshadow"
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
# pragma warning(push) # pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant # pragma warning(disable: 4127) // conditional expression is constant
@ -71,9 +65,6 @@ inline fmt::internal::null<> strerror_s(char *, std::size_t, ...) {
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
FMT_FUNC format_error::~format_error() throw() {}
FMT_FUNC system_error::~system_error() FMT_DTOR_NOEXCEPT {}
namespace { namespace {
#ifndef _MSC_VER #ifndef _MSC_VER
@ -232,30 +223,19 @@ FMT_FUNC void system_error::init(
namespace internal { namespace internal {
template <typename T> template <typename T>
int char_traits<char>::format_float( int char_traits<char>::format_float(
char *buffer, std::size_t size, const char *format, char *buffer, std::size_t size, const char *format, int precision, T value) {
unsigned width, int precision, T value) {
if (width == 0) {
return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, value) :
FMT_SNPRINTF(buffer, size, format, precision, value);
}
return precision < 0 ? return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, width, value) : FMT_SNPRINTF(buffer, size, format, value) :
FMT_SNPRINTF(buffer, size, format, width, precision, value); FMT_SNPRINTF(buffer, size, format, precision, value);
} }
template <typename T> template <typename T>
int char_traits<wchar_t>::format_float( int char_traits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format, wchar_t *buffer, std::size_t size, const wchar_t *format, int precision,
unsigned width, int precision, T value) { T value) {
if (width == 0) {
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, value) :
FMT_SWPRINTF(buffer, size, format, precision, value);
}
return precision < 0 ? return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, width, value) : FMT_SWPRINTF(buffer, size, format, value) :
FMT_SWPRINTF(buffer, size, format, width, precision, value); FMT_SWPRINTF(buffer, size, format, precision, value);
} }
template <typename T> template <typename T>
@ -294,35 +274,28 @@ const uint64_t basic_data<T>::POWERS_OF_10_64[] = {
// These are generated by support/compute-powers.py. // These are generated by support/compute-powers.py.
template <typename T> template <typename T>
const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = { const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {
0xfa8fd5a0081c0288ull, 0xbaaee17fa23ebf76ull, 0x8b16fb203055ac76ull, 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, 0xcf42894a5dce35ea,
0xcf42894a5dce35eaull, 0x9a6bb0aa55653b2dull, 0xe61acf033d1a45dfull, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f,
0xab70fe17c79ac6caull, 0xff77b1fcbebcdc4full, 0xbe5691ef416bd60cull, 0xbe5691ef416bd60c, 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
0x8dd01fad907ffc3cull, 0xd3515c2831559a83ull, 0x9d71ac8fada6c9b5ull, 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, 0xc21094364dfb5637,
0xea9c227723ee8bcbull, 0xaecc49914078536dull, 0x823c12795db6ce57ull, 0x9096ea6f3848984f, 0xd77485cb25823ac7, 0xa086cfcd97bf97f4, 0xef340a98172aace5,
0xc21094364dfb5637ull, 0x9096ea6f3848984full, 0xd77485cb25823ac7ull, 0xb23867fb2a35b28e, 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
0xa086cfcd97bf97f4ull, 0xef340a98172aace5ull, 0xb23867fb2a35b28eull, 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, 0xb5b5ada8aaff80b8,
0x84c8d4dfd2c63f3bull, 0xc5dd44271ad3cdbaull, 0x936b9fcebb25c996ull, 0x87625f056c7c4a8b, 0xc9bcff6034c13053, 0x964e858c91ba2655, 0xdff9772470297ebd,
0xdbac6c247d62a584ull, 0xa3ab66580d5fdaf6ull, 0xf3e2f893dec3f126ull, 0xa6dfbd9fb8e5b88f, 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
0xb5b5ada8aaff80b8ull, 0x87625f056c7c4a8bull, 0xc9bcff6034c13053ull, 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, 0xaa242499697392d3,
0x964e858c91ba2655ull, 0xdff9772470297ebdull, 0xa6dfbd9fb8e5b88full, 0xfd87b5f28300ca0e, 0xbce5086492111aeb, 0x8cbccc096f5088cc, 0xd1b71758e219652c,
0xf8a95fcf88747d94ull, 0xb94470938fa89bcfull, 0x8a08f0f8bf0f156bull, 0x9c40000000000000, 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,
0xcdb02555653131b6ull, 0x993fe2c6d07b7facull, 0xe45c10c42a2b3b06ull, 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, 0x9f4f2726179a2245,
0xaa242499697392d3ull, 0xfd87b5f28300ca0eull, 0xbce5086492111aebull, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, 0x83c7088e1aab65db, 0xc45d1df942711d9a,
0x8cbccc096f5088ccull, 0xd1b71758e219652cull, 0x9c40000000000000ull, 0x924d692ca61be758, 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,
0xe8d4a51000000000ull, 0xad78ebc5ac620000ull, 0x813f3978f8940984ull, 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, 0x952ab45cfa97a0b3,
0xc097ce7bc90715b3ull, 0x8f7e32ce7bea5c70ull, 0xd5d238a4abe98068ull, 0xde469fbd99a05fe3, 0xa59bc234db398c25, 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece,
0x9f4f2726179a2245ull, 0xed63a231d4c4fb27ull, 0xb0de65388cc8ada8ull, 0x88fcf317f22241e2, 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,
0x83c7088e1aab65dbull, 0xc45d1df942711d9aull, 0x924d692ca61be758ull, 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, 0x8bab8eefb6409c1a,
0xda01ee641a708deaull, 0xa26da3999aef774aull, 0xf209787bb47d6b85ull, 0xd01fef10a657842c, 0x9b10a4e5e9913129, 0xe7109bfba19c0c9d, 0xac2820d9623bf429,
0xb454e4a179dd1877ull, 0x865b86925b9bc5c2ull, 0xc83553c5c8965d3dull, 0x80444b5e7aa7cf85, 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
0x952ab45cfa97a0b3ull, 0xde469fbd99a05fe3ull, 0xa59bc234db398c25ull, 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b
0xf6c69a72a3989f5cull, 0xb7dcbf5354e9beceull, 0x88fcf317f22241e2ull,
0xcc20ce9bd35c78a5ull, 0x98165af37b2153dfull, 0xe2a0b5dc971f303aull,
0xa8d9d1535ce3b396ull, 0xfb9b7cd9a4a7443cull, 0xbb764c4ca7a44410ull,
0x8bab8eefb6409c1aull, 0xd01fef10a657842cull, 0x9b10a4e5e9913129ull,
0xe7109bfba19c0c9dull, 0xac2820d9623bf429ull, 0x80444b5e7aa7cf85ull,
0xbf21e44003acdd2dull, 0x8e679c2f5e44ff8full, 0xd433179d9c8cb841ull,
0x9e19db92b4e31ba9ull, 0xeb96bf6ebadf77d9ull, 0xaf87023b9bf0ee6bull
}; };
// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding // Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding
@ -349,6 +322,19 @@ FMT_FUNC fp operator*(fp x, fp y) {
uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64); return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64);
} }
FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
int index = static_cast<int>(std::ceil(
(min_exponent + fp::significand_size - 1) * one_over_log2_10));
// Decimal exponent of the first (smallest) cached power of 10.
const int first_dec_exp = -348;
// Difference between two consecutive decimal exponents in cached powers of 10.
const int dec_exp_step = 8;
index = (index - first_dec_exp - 1) / dec_exp_step + 1;
pow10_exponent = first_dec_exp + index * dec_exp_step;
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
}
} // namespace internal } // namespace internal
#if FMT_USE_WINDOWS_H #if FMT_USE_WINDOWS_H

View File

@ -37,6 +37,33 @@
#include <stdexcept> #include <stdexcept>
#include <stdint.h> #include <stdint.h>
#ifdef __clang__
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
#else
# define FMT_CLANG_VERSION 0
#endif
#ifdef __INTEL_COMPILER
# define FMT_ICC_VERSION __INTEL_COMPILER
#elif defined(__ICL)
# define FMT_ICC_VERSION __ICL
#else
# define FMT_ICC_VERSION 0
#endif
#if (defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 406) || \
FMT_CLANG_VERSION
# pragma GCC diagnostic push
// Disable the warning about declaration shadowing because it affects too
// many valid cases.
# pragma GCC diagnostic ignored "-Wshadow"
// Disable the warning about implicit conversions that may change the sign of
// an integer; silencing it otherwise would require many explicit casts.
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#include "core.h" #include "core.h"
#ifdef _SECURE_SCL #ifdef _SECURE_SCL
@ -55,52 +82,31 @@
# define FMT_HAS_BUILTIN(x) 0 # define FMT_HAS_BUILTIN(x) 0
#endif #endif
#ifdef __GNUC__
# if FMT_GCC_VERSION >= 406
# pragma GCC diagnostic push
// Disable the warning about declaration shadowing because it affects too
// many valid cases.
# pragma GCC diagnostic ignored "-Wshadow"
// Disable the warning about implicit conversions that may change the sign of
// an integer; silencing it otherwise would require many explicit casts.
# pragma GCC diagnostic ignored "-Wsign-conversion"
# endif
#endif
#ifdef __clang__
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
#endif
#if defined(__INTEL_COMPILER)
# define FMT_ICC_VERSION __INTEL_COMPILER
#elif defined(__ICL)
# define FMT_ICC_VERSION __ICL
#endif
#if defined(__clang__) && !defined(FMT_ICC_VERSION)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
# pragma clang diagnostic ignored "-Wgnu-string-literal-operator-template"
# pragma clang diagnostic ignored "-Wpadded"
#endif
#ifdef __GNUC_LIBSTD__ #ifdef __GNUC_LIBSTD__
# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) # define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__)
#endif #endif
#ifdef __has_cpp_attribute
# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
# define FMT_HAS_CPP_ATTRIBUTE(x) 0
#endif
#ifndef FMT_THROW #ifndef FMT_THROW
# if FMT_EXCEPTIONS # if FMT_EXCEPTIONS
# define FMT_THROW(x) throw x # if FMT_MSC_VER
FMT_BEGIN_NAMESPACE
namespace internal {
template <typename Exception>
inline void do_throw(const Exception &x) {
// Silence unreachable code warnings in MSVC because these are nearly
// impossible to fix in a generic code.
volatile bool b = true;
if (b)
throw x;
}
}
FMT_END_NAMESPACE
# define FMT_THROW(x) fmt::internal::do_throw(x)
# else
# define FMT_THROW(x) throw x
# endif
# else # else
# define FMT_THROW(x) assert(false) # define FMT_THROW(x) do { static_cast<void>(sizeof(x)); assert(false); } while(false);
# endif # endif
#endif #endif
@ -108,14 +114,14 @@
// For Intel's compiler both it and the system gcc/msc must support UDLs. // For Intel's compiler both it and the system gcc/msc must support UDLs.
# if (FMT_HAS_FEATURE(cxx_user_literals) || \ # if (FMT_HAS_FEATURE(cxx_user_literals) || \
FMT_GCC_VERSION >= 407 || FMT_MSC_VER >= 1900) && \ FMT_GCC_VERSION >= 407 || FMT_MSC_VER >= 1900) && \
(!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500) (!FMT_ICC_VERSION || FMT_ICC_VERSION >= 1500)
# define FMT_USE_USER_DEFINED_LITERALS 1 # define FMT_USE_USER_DEFINED_LITERALS 1
# else # else
# define FMT_USE_USER_DEFINED_LITERALS 0 # define FMT_USE_USER_DEFINED_LITERALS 0
# endif # endif
#endif #endif
#if FMT_USE_USER_DEFINED_LITERALS && \ #if FMT_USE_USER_DEFINED_LITERALS && !defined(FMT_ICC_VERSION) && \
((FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L) || \ ((FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L) || \
(defined(FMT_CLANG_VERSION) && FMT_CLANG_VERSION >= 304)) (defined(FMT_CLANG_VERSION) && FMT_CLANG_VERSION >= 304))
# define FMT_UDL_TEMPLATE 1 # define FMT_UDL_TEMPLATE 1
@ -126,14 +132,28 @@
#ifndef FMT_USE_EXTERN_TEMPLATES #ifndef FMT_USE_EXTERN_TEMPLATES
# ifndef FMT_HEADER_ONLY # ifndef FMT_HEADER_ONLY
# define FMT_USE_EXTERN_TEMPLATES \ # define FMT_USE_EXTERN_TEMPLATES \
(FMT_CLANG_VERSION >= 209 || (FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11)) ((FMT_CLANG_VERSION >= 209 && __cplusplus >= 201103L) || \
(FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11))
# else # else
# define FMT_USE_EXTERN_TEMPLATES 0 # define FMT_USE_EXTERN_TEMPLATES 0
# endif # endif
#endif #endif
#if FMT_HAS_GXX_CXX11 || FMT_HAS_FEATURE(cxx_trailing_return) || FMT_MSC_VER >= 1600 #if FMT_HAS_GXX_CXX11 || FMT_HAS_FEATURE(cxx_trailing_return) || \
FMT_MSC_VER >= 1600
# define FMT_USE_TRAILING_RETURN 1 # define FMT_USE_TRAILING_RETURN 1
#else
# define FMT_USE_TRAILING_RETURN 0
#endif
#if FMT_HAS_GXX_CXX11 || FMT_HAS_FEATURE(cxx_rvalue_references) || FMT_MSC_VER >= 1600
# define FMT_USE_RVALUE_REFERENCES 1
#else
# define FMT_USE_RVALUE_REFERENCES 0
#endif
#ifndef FMT_USE_GRISU
# define FMT_USE_GRISU 0
#endif #endif
// __builtin_clz is broken in clang with Microsoft CodeGen: // __builtin_clz is broken in clang with Microsoft CodeGen:
@ -258,10 +278,24 @@ inline dummy_int isnan(...) { return dummy_int(); }
inline dummy_int _isnan(...) { return dummy_int(); } inline dummy_int _isnan(...) { return dummy_int(); }
// A handmade floating-point number f * pow(2, e). // A handmade floating-point number f * pow(2, e).
struct fp { class fp {
uint64_t f; private:
typedef uint64_t significand_type;
// All sizes are in bits.
static FMT_CONSTEXPR_DECL const int char_size = std::numeric_limits<unsigned char>::digits;
// Subtract 1 to account for an implicit most significant bit in the
// normalized form.
static FMT_CONSTEXPR_DECL const int double_significand_size =
std::numeric_limits<double>::digits - 1;
static FMT_CONSTEXPR_DECL const uint64_t implicit_bit = 1ull << double_significand_size;
public:
significand_type f;
int e; int e;
static FMT_CONSTEXPR_DECL const int significand_size = sizeof(significand_type) * char_size;
fp(uint64_t f, int e): f(f), e(e) {} fp(uint64_t f, int e): f(f), e(e) {}
// Constructs fp from an IEEE754 double. It is a template to prevent compile // Constructs fp from an IEEE754 double. It is a template to prevent compile
@ -270,24 +304,35 @@ struct fp {
explicit fp(Double d) { explicit fp(Double d) {
// Assume double is in the format [sign][exponent][significand]. // Assume double is in the format [sign][exponent][significand].
typedef std::numeric_limits<Double> limits; typedef std::numeric_limits<Double> limits;
const int double_size = const int double_size = sizeof(Double) * char_size;
sizeof(Double) * std::numeric_limits<unsigned char>::digits; const int exponent_size =
// Subtract 1 to account for an implicit most significant bit in the double_size - double_significand_size - 1; // -1 for sign
// normalized form.
const int significand_size = limits::digits - 1;
const int exponent_size = double_size - significand_size - 1; // -1 for sign
const uint64_t implicit_bit = 1ull << significand_size;
const uint64_t significand_mask = implicit_bit - 1; const uint64_t significand_mask = implicit_bit - 1;
const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask; const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask;
const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1; const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
auto u = bit_cast<uint64_t>(d); auto u = bit_cast<uint64_t>(d);
auto biased_e = (u & exponent_mask) >> significand_size; auto biased_e = (u & exponent_mask) >> double_significand_size;
f = u & significand_mask; f = u & significand_mask;
if (biased_e != 0) if (biased_e != 0)
f += implicit_bit; f += implicit_bit;
else else
biased_e = 1; // Subnormals use biased exponent 1 (min exponent). biased_e = 1; // Subnormals use biased exponent 1 (min exponent).
e = biased_e - exponent_bias - significand_size; e = static_cast<int>(biased_e - exponent_bias - double_significand_size);
}
// Normalizes the value converted from double and multiplied by (1 << SHIFT).
template <int SHIFT = 0>
void normalize() {
// Handle subnormals.
auto shifted_implicit_bit = implicit_bit << SHIFT;
while ((f & shifted_implicit_bit) == 0) {
f <<= 1;
--e;
}
// Subtract 1 to account for hidden bit.
auto offset = significand_size - double_significand_size - SHIFT - 1;
f <<= offset;
e -= offset;
} }
}; };
@ -297,16 +342,13 @@ inline fp operator-(fp x, fp y) {
return fp(x.f - y.f, x.e); return fp(x.f - y.f, x.e);
} }
// Computes an fp number r with r.f = x.f * y.f / pow(2, 32) rounded to nearest // Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest
// with half-up tie breaking, r.e = x.e + y.e + 32. Result may not be normalized. // with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be normalized.
fp operator*(fp x, fp y); fp operator*(fp x, fp y);
// Compute k such that its cached power c_k = c_k.f * pow(2, c_k.e) satisfies // Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its
// min_exponent <= c_k.e + e <= min_exponent + 3. // (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3.
inline int compute_cached_power_index(int e, int min_exponent) { fp get_cached_power(int min_exponent, int &pow10_exponent);
const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
return static_cast<int>(std::ceil((min_exponent - e + 63) * one_over_log2_10));
}
template <typename Allocator> template <typename Allocator>
typename Allocator::value_type *allocate(Allocator& alloc, std::size_t n) { typename Allocator::value_type *allocate(Allocator& alloc, std::size_t n) {
@ -372,6 +414,38 @@ FMT_BEGIN_NAMESPACE
template <typename Range> template <typename Range>
class basic_writer; class basic_writer;
template <typename OutputIt, typename T = typename OutputIt::value_type>
class output_range {
private:
OutputIt it_;
// Unused yet.
typedef void sentinel;
sentinel end() const;
public:
typedef OutputIt iterator;
typedef T value_type;
explicit output_range(OutputIt it): it_(it) {}
OutputIt begin() const { return it_; }
};
// A range where begin() returns back_insert_iterator.
template <typename Container>
class back_insert_range:
public output_range<std::back_insert_iterator<Container>> {
typedef output_range<std::back_insert_iterator<Container>> base;
public:
typedef typename Container::value_type value_type;
back_insert_range(Container &c): base(std::back_inserter(c)) {}
back_insert_range(typename base::iterator it): base(it) {}
};
typedef basic_writer<back_insert_range<internal::buffer>> writer;
typedef basic_writer<back_insert_range<internal::wbuffer>> wwriter;
/** A formatting error such as invalid format string. */ /** A formatting error such as invalid format string. */
class format_error : public std::runtime_error { class format_error : public std::runtime_error {
public: public:
@ -380,8 +454,6 @@ class format_error : public std::runtime_error {
explicit format_error(const std::string &message) explicit format_error(const std::string &message)
: std::runtime_error(message) {} : std::runtime_error(message) {}
FMT_API ~format_error() throw();
}; };
namespace internal { namespace internal {
@ -601,30 +673,30 @@ struct char_traits<char> {
// Formats a floating-point number. // Formats a floating-point number.
template <typename T> template <typename T>
FMT_API static int format_float(char *buffer, std::size_t size, FMT_API static int format_float(char *buffer, std::size_t size,
const char *format, unsigned width, int precision, T value); const char *format, int precision, T value);
}; };
template <> template <>
struct char_traits<wchar_t> { struct char_traits<wchar_t> {
template <typename T> template <typename T>
FMT_API static int format_float(wchar_t *buffer, std::size_t size, FMT_API static int format_float(wchar_t *buffer, std::size_t size,
const wchar_t *format, unsigned width, int precision, T value); const wchar_t *format, int precision, T value);
}; };
#if FMT_USE_EXTERN_TEMPLATES #if FMT_USE_EXTERN_TEMPLATES
extern template int char_traits<char>::format_float<double>( extern template int char_traits<char>::format_float<double>(
char *buffer, std::size_t size, const char* format, unsigned width, char *buffer, std::size_t size, const char* format, int precision,
int precision, double value); double value);
extern template int char_traits<char>::format_float<long double>( extern template int char_traits<char>::format_float<long double>(
char *buffer, std::size_t size, const char* format, unsigned width, char *buffer, std::size_t size, const char* format, int precision,
int precision, long double value); long double value);
extern template int char_traits<wchar_t>::format_float<double>( extern template int char_traits<wchar_t>::format_float<double>(
wchar_t *buffer, std::size_t size, const wchar_t* format, unsigned width, wchar_t *buffer, std::size_t size, const wchar_t* format, int precision,
int precision, double value); double value);
extern template int char_traits<wchar_t>::format_float<long double>( extern template int char_traits<wchar_t>::format_float<long double>(
wchar_t *buffer, std::size_t size, const wchar_t* format, unsigned width, wchar_t *buffer, std::size_t size, const wchar_t* format, int precision,
int precision, long double value); long double value);
#endif #endif
template <typename Container> template <typename Container>
@ -1124,7 +1196,7 @@ FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
switch (arg.type_) { switch (arg.type_) {
case internal::none_type: case internal::none_type:
break; break;
case internal::name_arg_type: case internal::named_arg_type:
FMT_ASSERT(false, "invalid argument type"); FMT_ASSERT(false, "invalid argument type");
break; break;
case internal::int_type: case internal::int_type:
@ -1418,7 +1490,7 @@ void arg_map<Context>::init(const basic_format_args<Context> &args) {
switch (arg_type) { switch (arg_type) {
case internal::none_type: case internal::none_type:
return; return;
case internal::name_arg_type: case internal::named_arg_type:
push_back(args.values_[i]); push_back(args.values_[i]);
break; break;
default: default:
@ -1427,15 +1499,11 @@ void arg_map<Context>::init(const basic_format_args<Context> &args) {
} }
return; return;
} }
for (unsigned i = 0; i != max_packed_args; ++i) { for (unsigned i = 0; ; ++i) {
if (args.type(i) == internal::name_arg_type)
push_back(args.args_[i].value_);
}
for (unsigned i = max_packed_args; ; ++i) {
switch (args.args_[i].type_) { switch (args.args_[i].type_) {
case internal::none_type: case internal::none_type:
return; return;
case internal::name_arg_type: case internal::named_arg_type:
push_back(args.args_[i].value_); push_back(args.args_[i].value_);
break; break;
default: default:
@ -1602,6 +1670,13 @@ FMT_CONSTEXPR unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) {
return value; return value;
} }
#if FMT_MSC_VER
// Warns that the compiler cannot generate an assignment operator
// The class has a reference member variable, so this is obviously the case
# pragma warning(push)
# pragma warning(disable: 4512)
#endif
template <typename Char, typename Context> template <typename Char, typename Context>
class custom_formatter: public function<bool> { class custom_formatter: public function<bool> {
private: private:
@ -1619,6 +1694,10 @@ class custom_formatter: public function<bool> {
bool operator()(T) const { return false; } bool operator()(T) const { return false; }
}; };
#if FMT_MSC_VER
# pragma warning(pop)
#endif
template <typename T> template <typename T>
struct is_integer { struct is_integer {
enum { enum {
@ -1975,41 +2054,42 @@ struct precision_adapter {
template <typename Iterator, typename SpecHandler> template <typename Iterator, typename SpecHandler>
FMT_CONSTEXPR Iterator parse_format_specs(Iterator it, SpecHandler &&handler) { FMT_CONSTEXPR Iterator parse_format_specs(Iterator it, SpecHandler &&handler) {
typedef typename std::iterator_traits<Iterator>::value_type char_type; typedef typename std::iterator_traits<Iterator>::value_type char_type;
char_type c = *it;
if (c == '}' || !c)
return it;
// Parse fill and alignment. // Parse fill and alignment.
if (char_type c = *it) { alignment align = ALIGN_DEFAULT;
alignment align = ALIGN_DEFAULT; int i = 1;
int i = 1; do {
do { auto p = it + i;
auto p = it + i; switch (*p) {
switch (*p) { case '<':
case '<': align = ALIGN_LEFT;
align = ALIGN_LEFT;
break;
case '>':
align = ALIGN_RIGHT;
break;
case '=':
align = ALIGN_NUMERIC;
break;
case '^':
align = ALIGN_CENTER;
break;
}
if (align != ALIGN_DEFAULT) {
handler.on_align(align);
if (p != it) {
if (c == '}') break;
if (c == '{') {
handler.on_error("invalid fill character '{'");
return it;
}
it += 2;
handler.on_fill(c);
} else ++it;
break; break;
} case '>':
} while (--i >= 0); align = ALIGN_RIGHT;
} break;
case '=':
align = ALIGN_NUMERIC;
break;
case '^':
align = ALIGN_CENTER;
break;
}
if (align != ALIGN_DEFAULT) {
if (p != it) {
if (c == '{') {
handler.on_error("invalid fill character '{'");
return it;
}
it += 2;
handler.on_fill(c);
} else ++it;
handler.on_align(align);
break;
}
} while (--i >= 0);
// Parse sign. // Parse sign.
switch (*it) { switch (*it) {
@ -2308,8 +2388,6 @@ class system_error : public std::runtime_error {
init(error_code, message, make_format_args(args...)); init(error_code, message, make_format_args(args...));
} }
FMT_API ~system_error() FMT_DTOR_NOEXCEPT;
int error_code() const { return error_code_; } int error_code() const { return error_code_; }
}; };
@ -2578,7 +2656,7 @@ class basic_writer {
}; };
struct double_writer { struct double_writer {
unsigned n; size_t n;
char sign; char sign;
basic_memory_buffer<char_type> &buffer; basic_memory_buffer<char_type> &buffer;
@ -2595,6 +2673,9 @@ class basic_writer {
// Formats a floating-point number (double or long double). // Formats a floating-point number (double or long double).
template <typename T> template <typename T>
void write_double(T value, const format_specs &spec); void write_double(T value, const format_specs &spec);
template <typename T>
void write_double_sprintf(T value, const format_specs &spec,
internal::basic_buffer<char_type>& buffer);
template <typename Char> template <typename Char>
struct str_writer { struct str_writer {
@ -2817,60 +2898,39 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
return write_inf_or_nan(handler.upper ? "INF" : "inf"); return write_inf_or_nan(handler.upper ? "INF" : "inf");
basic_memory_buffer<char_type> buffer; basic_memory_buffer<char_type> buffer;
if (FMT_USE_GRISU && sizeof(T) <= sizeof(double) &&
unsigned width = spec.width(); std::numeric_limits<double>::is_iec559) {
if (sign) { internal::fp fp_value(static_cast<double>(value));
buffer.reserve(width > 1u ? width : 1u); fp_value.normalize();
if (width > 0) // Find a cached power of 10 close to 1 / fp_value.
--width; int dec_exp = 0;
} const int min_exp = -60;
auto dec_pow = internal::get_cached_power(
// Build format string. min_exp - (fp_value.e + internal::fp::significand_size), dec_exp);
enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg internal::fp product = fp_value * dec_pow;
char_type format[MAX_FORMAT_SIZE]; // Generate output.
char_type *format_ptr = format; internal::fp one(1ull << -product.e, product.e);
*format_ptr++ = '%'; uint64_t hi = product.f >> -one.e;
unsigned width_for_sprintf = width; uint64_t f = product.f & (one.f - 1);
if (spec.flag(HASH_FLAG)) typedef back_insert_range<internal::basic_buffer<char_type>> range;
*format_ptr++ = '#'; basic_writer<range> w{range(buffer)};
width_for_sprintf = 0; w.write(hi);
if (spec.precision() >= 0) { size_t digits = buffer.size();
*format_ptr++ = '.'; w.write('.');
*format_ptr++ = '*'; const unsigned max_digits = 18;
} while (digits++ < max_digits) {
f *= 10;
append_float_length(format_ptr, value); w.write(static_cast<char>('0' + (f >> -one.e)));
*format_ptr++ = handler.type; f &= one.f - 1;
*format_ptr = '\0';
// Format using snprintf.
unsigned n = 0;
char_type *start = FMT_NULL;
for (;;) {
std::size_t buffer_size = buffer.capacity();
#if FMT_MSC_VER
// MSVC's vsnprintf_s doesn't work with zero size, so reserve
// space for at least one extra character to make the size non-zero.
// Note that the buffer's capacity may increase by more than 1.
if (buffer_size == 0) {
buffer.reserve(1);
buffer_size = buffer.capacity();
}
#endif
start = &buffer[0];
int result = internal::char_traits<char_type>::format_float(
start, buffer_size, format, width_for_sprintf, spec.precision(), value);
if (result >= 0) {
n = internal::to_unsigned(result);
if (n < buffer.capacity())
break; // The buffer is large enough - continue with formatting.
buffer.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.
buffer.reserve(buffer.capacity() + 1);
} }
w.write('e');
w.write(-dec_exp);
} else {
format_specs normalized_spec(spec);
normalized_spec.type_ = handler.type;
write_double_sprintf(value, normalized_spec, buffer);
} }
size_t n = buffer.size();
align_spec as = spec; align_spec as = spec;
if (spec.align() == ALIGN_NUMERIC) { if (spec.align() == ALIGN_NUMERIC) {
if (sign) { if (sign) {
@ -2889,37 +2949,51 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
write_padded(n, as, double_writer{n, sign, buffer}); write_padded(n, as, double_writer{n, sign, buffer});
} }
template <typename OutputIt, typename T = typename OutputIt::value_type> template <typename Range>
class output_range { template <typename T>
private: void basic_writer<Range>::write_double_sprintf(
OutputIt it_; T value, const format_specs &spec,
internal::basic_buffer<char_type>& buffer) {
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
FMT_ASSERT(buffer.capacity() != 0, "empty buffer");
// Unused yet. // Build format string.
typedef void sentinel; enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
sentinel end() const; char_type format[MAX_FORMAT_SIZE];
char_type *format_ptr = format;
*format_ptr++ = '%';
if (spec.flag(HASH_FLAG))
*format_ptr++ = '#';
if (spec.precision() >= 0) {
*format_ptr++ = '.';
*format_ptr++ = '*';
}
public: append_float_length(format_ptr, value);
typedef OutputIt iterator; *format_ptr++ = spec.type();
typedef T value_type; *format_ptr = '\0';
explicit output_range(OutputIt it): it_(it) {} // Format using snprintf.
OutputIt begin() const { return it_; } char_type *start = FMT_NULL;
}; for (;;) {
std::size_t buffer_size = buffer.capacity();
// A range where begin() returns back_insert_iterator. start = &buffer[0];
template <typename Container> int result = internal::char_traits<char_type>::format_float(
class back_insert_range: start, buffer_size, format, spec.precision(), value);
public output_range<std::back_insert_iterator<Container>> { if (result >= 0) {
typedef output_range<std::back_insert_iterator<Container>> base; unsigned n = internal::to_unsigned(result);
public: if (n < buffer.capacity()) {
typedef typename Container::value_type value_type; buffer.resize(n);
break; // The buffer is large enough - continue with formatting.
back_insert_range(Container &c): base(std::back_inserter(c)) {} }
back_insert_range(typename base::iterator it): base(it) {} buffer.reserve(n + 1);
}; } else {
// If result is negative we ask to increase the capacity by at least 1,
typedef basic_writer<back_insert_range<internal::buffer>> writer; // but as std::vector, the buffer grows exponentially.
typedef basic_writer<back_insert_range<internal::wbuffer>> wwriter; buffer.reserve(buffer.capacity() + 1);
}
}
}
// Reports a system error without throwing an exception. // Reports a system error without throwing an exception.
// Can be used to report errors from destructors. // Can be used to report errors from destructors.
@ -3100,7 +3174,7 @@ struct formatter<
auto eh = ctx.error_handler(); auto eh = ctx.error_handler();
switch (type) { switch (type) {
case internal::none_type: case internal::none_type:
case internal::name_arg_type: case internal::named_arg_type:
FMT_ASSERT(false, "invalid argument type"); FMT_ASSERT(false, "invalid argument type");
break; break;
case internal::int_type: case internal::int_type:
@ -3147,8 +3221,8 @@ struct formatter<
internal::handle_dynamic_spec<internal::precision_checker>( internal::handle_dynamic_spec<internal::precision_checker>(
specs_.precision_, specs_.precision_ref, ctx); specs_.precision_, specs_.precision_ref, ctx);
typedef output_range<typename FormatContext::iterator, typedef output_range<typename FormatContext::iterator,
typename FormatContext::char_type> range; typename FormatContext::char_type> range_type;
visit(arg_formatter<range>(ctx, specs_), visit(arg_formatter<range_type>(ctx, specs_),
internal::make_arg<FormatContext>(val)); internal::make_arg<FormatContext>(val));
return ctx.out(); return ctx.out();
} }
@ -3634,7 +3708,7 @@ FMT_END_NAMESPACE
#define FMT_STRING(s) [] { \ #define FMT_STRING(s) [] { \
struct S : fmt::format_string { \ struct S : fmt::format_string { \
static FMT_CONSTEXPR auto data() { return s; } \ static FMT_CONSTEXPR decltype(s) data() { return s; } \
static FMT_CONSTEXPR size_t size() { return sizeof(s); } \ static FMT_CONSTEXPR size_t size() { return sizeof(s); } \
}; \ }; \
return S{}; \ return S{}; \
@ -3663,12 +3737,8 @@ FMT_END_NAMESPACE
#endif #endif
// Restore warnings. // Restore warnings.
#if FMT_GCC_VERSION >= 406 #if FMT_GCC_VERSION >= 406 || FMT_CLANG_VERSION
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
#if defined(__clang__) && !defined(FMT_ICC_VERSION)
# pragma clang diagnostic pop
#endif
#endif // FMT_FORMAT_H_ #endif // FMT_FORMAT_H_

View File

@ -53,10 +53,10 @@ struct test_stream : std::basic_ostream<Char> {
void operator<<(null); void operator<<(null);
}; };
// Disable conversion to int if T has an overloaded operator<< which is a free // Checks if T has an overloaded operator<< which is a free function (not a
// function (not a member of std::ostream). // member of std::ostream).
template <typename T, typename Char> template <typename T, typename Char>
class convert_to_int<T, Char, true> { class is_streamable {
private: private:
template <typename U> template <typename U>
static decltype( static decltype(
@ -69,7 +69,16 @@ class convert_to_int<T, Char, true> {
typedef decltype(test<T>(0)) result; typedef decltype(test<T>(0)) result;
public: public:
static const bool value = !result::value; static const bool value = result::value;
};
// Disable conversion to int if T has an overloaded operator<< which is a free
// function (not a member of std::ostream).
template <typename T, typename Char>
class convert_to_int<T, Char, true> {
public:
static const bool value =
convert_to_int<T, Char, false>::value && !is_streamable<T, Char>::value;
}; };
// Write the content of buf to os. // Write the content of buf to os.
@ -106,8 +115,7 @@ struct format_enum<T,
// Formats an object of type T that has an overloaded ostream operator<<. // Formats an object of type T that has an overloaded ostream operator<<.
template <typename T, typename Char> template <typename T, typename Char>
struct formatter<T, Char, struct formatter<T, Char,
typename std::enable_if<!internal::format_type< typename std::enable_if<internal::is_streamable<T, Char>::value>::type>
typename buffer_context<Char>::type, T>::value>::type>
: formatter<basic_string_view<Char>, Char> { : formatter<basic_string_view<Char>, Char> {
template <typename Context> template <typename Context>

View File

@ -52,7 +52,7 @@ class printf_precision_handler: public function<int> {
typename std::enable_if<!std::is_integral<T>::value, int>::type typename std::enable_if<!std::is_integral<T>::value, int>::type
operator()(T) { operator()(T) {
FMT_THROW(format_error("precision is not integer")); FMT_THROW(format_error("precision is not integer"));
return 0; return 0; // Silence visual studio
} }
}; };
@ -194,7 +194,7 @@ class printf_width_handler: public function<unsigned> {
typename std::enable_if<!std::is_integral<T>::value, unsigned>::type typename std::enable_if<!std::is_integral<T>::value, unsigned>::type
operator()(T) { operator()(T) {
FMT_THROW(format_error("width is not integer")); FMT_THROW(format_error("width is not integer"));
return 0; return 0; // Silence Visual Studio
} }
}; };
} // namespace internal } // namespace internal
@ -635,8 +635,13 @@ inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args)
template <typename... Args> template <typename... Args>
inline int fprintf(std::FILE *f, wstring_view format_str, inline int fprintf(std::FILE *f, wstring_view format_str,
const Args & ... args) { const Args & ... args) {
#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 440
return vfprintf<wchar_t>(f, format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
#else
return vfprintf(f, format_str, return vfprintf(f, format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...)); make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
#endif
} }
inline int vprintf(string_view format, printf_args args) { inline int vprintf(string_view format, printf_args args) {

View File

@ -126,18 +126,39 @@ struct is_tuple_like {
static FMT_CONSTEXPR_DECL const bool value = static FMT_CONSTEXPR_DECL const bool value =
is_tuple_like_<T>::value && !is_range_<T>::value; is_tuple_like_<T>::value && !is_range_<T>::value;
}; };
} // namespace internal
#if FMT_HAS_FEATURE(__cpp_lib_integer_sequence) // Check for integer_sequence
# define FMT_USE_INTEGER_SEQUENCE 1 #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
template <typename T, T... N>
using integer_sequence = std::integer_sequence<T, N...>;
template <std::size_t... N>
using index_sequence = std::index_sequence<N...>;
template <std::size_t N>
using make_index_sequence = std::make_index_sequence<N>;
#else #else
# define FMT_USE_INTEGER_SEQUENCE 0 template <typename T, T... N>
struct integer_sequence {
typedef T value_type;
static FMT_CONSTEXPR std::size_t size() {
return sizeof...(N);
}
};
template <std::size_t... N>
using index_sequence = integer_sequence<std::size_t, N...>;
template <typename T, std::size_t N, T... Ns>
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
template <typename T, T... Ns>
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
template <std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
#endif #endif
#if FMT_USE_INTEGER_SEQUENCE template <class Tuple, class F, size_t... Is>
namespace internal { void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) noexcept {
template <size_t... Is, class Tuple, class F>
void for_each(std::index_sequence<Is...>, Tuple &&tup, F &&f) noexcept {
using std::get; using std::get;
// using free function get<I>(T) now. // using free function get<I>(T) now.
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...}; const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
@ -145,7 +166,7 @@ void for_each(std::index_sequence<Is...>, Tuple &&tup, F &&f) noexcept {
} }
template <class T> template <class T>
FMT_CONSTEXPR std::make_index_sequence<std::tuple_size<T>::value> FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value>
get_indexes(T const &) { return {}; } get_indexes(T const &) { return {}; }
template <class Tuple, class F> template <class Tuple, class F>
@ -157,21 +178,13 @@ void for_each(Tuple &&tup, F &&f) {
template <typename TupleT, typename Char> template <typename TupleT, typename Char>
struct formatter<TupleT, Char, struct formatter<TupleT, Char,
typename std::enable_if<fmt::internal::is_tuple_like<TupleT>::value>::type> { typename std::enable_if<internal::is_tuple_like<TupleT>::value>::type> {
private:
fmt::formatting_tuple<Char> formatting; // C++11 generic lambda for format()
template <typename FormatContext>
template <typename ParseContext> struct format_each {
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { template <typename T>
return formatting.parse(ctx); void operator()(const T& v) {
}
template <typename FormatContext = format_context>
auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) {
auto out = ctx.out();
std::size_t i = 0;
internal::copy(formatting.prefix, out);
internal::for_each(values, [&](const auto &v) {
if (i > 0) { if (i > 0) {
if (formatting.add_prepostfix_space) { if (formatting.add_prepostfix_space) {
*out++ = ' '; *out++ = ' ';
@ -184,7 +197,28 @@ struct formatter<TupleT, Char,
format_to(out, "{}", v); format_to(out, "{}", v);
} }
++i; ++i;
}); }
formatting_tuple<Char>& formatting;
std::size_t& i;
typename std::add_lvalue_reference<decltype(std::declval<FormatContext>().out())>::type out;
};
public:
formatting_tuple<Char> formatting;
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return formatting.parse(ctx);
}
template <typename FormatContext = format_context>
auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) {
auto out = ctx.out();
std::size_t i = 0;
internal::copy(formatting.prefix, out);
internal::for_each(values, format_each<FormatContext>{formatting, i, out});
if (formatting.add_prepostfix_space) { if (formatting.add_prepostfix_space) {
*out++ = ' '; *out++ = ' ';
} }
@ -193,13 +227,12 @@ struct formatter<TupleT, Char,
return ctx.out(); return ctx.out();
} }
}; };
#endif // FMT_USE_INTEGER_SEQUENCE
template <typename RangeT, typename Char> template <typename RangeT, typename Char>
struct formatter< RangeT, Char, struct formatter<RangeT, Char,
typename std::enable_if<fmt::internal::is_range<RangeT>::value>::type> { typename std::enable_if<internal::is_range<RangeT>::value>::type> {
fmt::formatting_range<Char> formatting; formatting_range<Char> formatting;
template <typename ParseContext> template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {

View File

@ -54,7 +54,6 @@ inline std::tm localtime(std::time_t time) {
return lt.tm_; return lt.tm_;
// Too big time values may be unsupported. // Too big time values may be unsupported.
FMT_THROW(format_error("time_t value out of range")); FMT_THROW(format_error("time_t value out of range"));
return std::tm();
} }
// Thread-safe replacement for std::gmtime // Thread-safe replacement for std::gmtime
@ -90,7 +89,6 @@ inline std::tm gmtime(std::time_t time) {
return gt.tm_; return gt.tm_;
// Too big time values may be unsupported. // Too big time values may be unsupported.
FMT_THROW(format_error("time_t value out of range")); FMT_THROW(format_error("time_t value out of range"));
return std::tm();
} }
namespace internal { namespace internal {

View File

@ -21,12 +21,12 @@ template void internal::arg_map<format_context>::init(
const basic_format_args<format_context> &args); const basic_format_args<format_context> &args);
template FMT_API int internal::char_traits<char>::format_float( template FMT_API int internal::char_traits<char>::format_float(
char *buffer, std::size_t size, const char *format, char *buffer, std::size_t size, const char *format, int precision,
unsigned width, int precision, double value); double value);
template FMT_API int internal::char_traits<char>::format_float( template FMT_API int internal::char_traits<char>::format_float(
char *buffer, std::size_t size, const char *format, char *buffer, std::size_t size, const char *format, int precision,
unsigned width, int precision, long double value); long double value);
// Explicit instantiations for wchar_t. // Explicit instantiations for wchar_t.
@ -39,9 +39,9 @@ template void internal::arg_map<wformat_context>::init(
template FMT_API int internal::char_traits<wchar_t>::format_float( template FMT_API int internal::char_traits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format, wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, double value); int precision, double value);
template FMT_API int internal::char_traits<wchar_t>::format_float( template FMT_API int internal::char_traits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format, wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, long double value); int precision, long double value);
FMT_END_NAMESPACE FMT_END_NAMESPACE

View File

@ -6,7 +6,7 @@
// For the license information refer to format.h. // For the license information refer to format.h.
// Disable bogus MSVC warnings. // Disable bogus MSVC warnings.
#ifndef _CRT_SECURE_NO_WARNINGS #if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
# define _CRT_SECURE_NO_WARNINGS # define _CRT_SECURE_NO_WARNINGS
#endif #endif

View File

@ -4,7 +4,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := fmt_static LOCAL_MODULE := fmt_static
LOCAL_MODULE_FILENAME := libfmt LOCAL_MODULE_FILENAME := libfmt
LOCAL_SRC_FILES := fmt/format.cc LOCAL_SRC_FILES := ../src/format.cc
LOCAL_C_INCLUDES := $(LOCAL_PATH) LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)

13
support/appveyor-build.py Executable file → Normal file
View File

@ -6,9 +6,11 @@ from subprocess import check_call
build = os.environ['BUILD'] build = os.environ['BUILD']
config = os.environ['CONFIGURATION'] config = os.environ['CONFIGURATION']
platform = os.environ.get('PLATFORM') platform = os.environ['PLATFORM']
path = os.environ['PATH'] path = os.environ['PATH']
cmake_command = ['cmake', '-DFMT_PEDANTIC=ON', '-DCMAKE_BUILD_TYPE=' + config] image = os.environ['APPVEYOR_BUILD_WORKER_IMAGE']
jobid = os.environ['APPVEYOR_JOB_ID']
cmake_command = ['cmake', '-DFMT_PEDANTIC=ON', '-DCMAKE_BUILD_TYPE=' + config, '..']
if build == 'mingw': if build == 'mingw':
cmake_command.append('-GMinGW Makefiles') cmake_command.append('-GMinGW Makefiles')
build_command = ['mingw32-make', '-j4'] build_command = ['mingw32-make', '-j4']
@ -21,7 +23,12 @@ else:
# Add MSBuild 14.0 to PATH as described in # Add MSBuild 14.0 to PATH as described in
# http://help.appveyor.com/discussions/problems/2229-v140-not-found-on-vs2105rc. # http://help.appveyor.com/discussions/problems/2229-v140-not-found-on-vs2105rc.
os.environ['PATH'] = r'C:\Program Files (x86)\MSBuild\15.0\Bin;' + path os.environ['PATH'] = r'C:\Program Files (x86)\MSBuild\15.0\Bin;' + path
generator = 'Visual Studio 15 2017' if image == 'Visual Studio 2013':
generator = 'Visual Studio 12 2013'
elif image == 'Visual Studio 2015':
generator = 'Visual Studio 14 2015'
elif image == 'Visual Studio 2017':
generator = 'Visual Studio 15 2017'
if platform == 'x64': if platform == 'x64':
generator += ' Win64' generator += ' Win64'
cmake_command.append('-G' + generator) cmake_command.append('-G' + generator)

View File

@ -2,21 +2,32 @@ configuration:
- Debug - Debug
- Release - Release
image: Visual Studio 2017 clone_depth: 1
platform:
- Win32
- x64
image:
- Visual Studio 2013
- Visual Studio 2015
- Visual Studio 2017
environment: environment:
CTEST_OUTPUT_ON_FAILURE: 1 CTEST_OUTPUT_ON_FAILURE: 1
matrix: MSVC_DEFAULT_OPTIONS: ON
- BUILD: msvc BUILD: msvc
- BUILD: msvc
PLATFORM: x64 matrix:
allow_failures:
- image: Visual Studio 2013
before_build: before_build:
# Workaround for CMake not wanting sh.exe on PATH for MinGW. - mkdir build
- set PATH=%PATH:C:\Program Files\Git\usr\bin;=% - cd build
build_script: build_script:
- python support/appveyor-build.py - python ../support/appveyor-build.py
on_failure: on_failure:
- appveyor PushArtifact Testing/Temporary/LastTest.log - appveyor PushArtifact Testing/Temporary/LastTest.log

View File

@ -1,67 +1,52 @@
# C++14 feature support detection # C++14 feature support detection
if (NOT FMT_USE_CPP14) include(CheckCXXSourceCompiles)
return()
endif ()
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
if (FMT_USE_CPP14) if (NOT CMAKE_CXX_STANDARD)
check_cxx_compiler_flag(-std=c++14 HAVE_STD_CPP14_FLAG) set(CMAKE_CXX_STANDARD 11)
if (HAVE_STD_CPP14_FLAG) endif()
# Check if including cmath works with -std=c++14 and -O3. message(STATUS "CXX_STANDARD: ${CMAKE_CXX_STANDARD}")
# It may not in MinGW due to bug http://ehc.ac/p/mingw/bugs/2250/.
set(CMAKE_REQUIRED_FLAGS "-std=c++14 -O3") if (CMAKE_CXX_STANDARD EQUAL 20)
check_cxx_source_compiles(" check_cxx_compiler_flag(-std=c++20 has_std_20_flag)
#include <cmath> check_cxx_compiler_flag(-std=c++2a has_std_2a_flag)
int main() {}" FMT_CPP14_CMATH)
# Check if including <unistd.h> works with -std=c++14. if (has_std_20_flag)
# It may not in MinGW due to bug http://sourceforge.net/p/mingw/bugs/2024/. set(CXX_STANDARD_FLAG -std=c++20)
check_cxx_source_compiles(" elseif (has_std_2a_flag)
#include <unistd.h> set(CXX_STANDARD_FLAG -std=c++2a)
int main() {}" FMT_CPP14_UNISTD_H) endif ()
# Check if snprintf works with -std=c++14. It may not in MinGW. elseif (CMAKE_CXX_STANDARD EQUAL 17)
check_cxx_source_compiles(" check_cxx_compiler_flag(-std=c++17 has_std_17_flag)
#include <stdio.h> check_cxx_compiler_flag(-std=c++1z has_std_1z_flag)
int main() {
char buffer[10]; if (has_std_17_flag)
snprintf(buffer, 10, \"foo\"); set(CXX_STANDARD_FLAG -std=c++17)
}" FMT_CPP14_SNPRINTF) elseif (has_std_1z_flag)
if (FMT_CPP14_CMATH AND FMT_CPP14_UNISTD_H AND FMT_CPP14_SNPRINTF) set(CXX_STANDARD_FLAG -std=c++1z)
set(CPP14_FLAG -std=c++14) endif ()
else () elseif (CMAKE_CXX_STANDARD EQUAL 14)
check_cxx_compiler_flag(-std=gnu++14 HAVE_STD_GNUPP14_FLAG) check_cxx_compiler_flag(-std=c++14 has_std_14_flag)
if (HAVE_STD_CPP14_FLAG) check_cxx_compiler_flag(-std=c++1y has_std_1y_flag)
set(CPP14_FLAG -std=gnu++14)
endif () if (has_std_14_flag)
endif () set(CXX_STANDARD_FLAG -std=c++14)
set(CMAKE_REQUIRED_FLAGS ) elseif (has_std_1y_flag)
else () set(CXX_STANDARD_FLAG -std=c++1y)
check_cxx_compiler_flag(-std=c++1y HAVE_STD_CPP1Y_FLAG) endif ()
if (HAVE_STD_CPP1Y_FLAG) elseif (CMAKE_CXX_STANDARD EQUAL 11)
set(CPP14_FLAG -std=c++1y) check_cxx_compiler_flag(-std=c++11 has_std_11_flag)
else () check_cxx_compiler_flag(-std=c++0x has_std_0x_flag)
# Fallback on c++11 if c++14 is not available.
check_cxx_compiler_flag(-std=c++11 HAVE_STD_CPP11_FLAG) if (has_std_11_flag)
if (HAVE_STD_CPP11_FLAG) set(CXX_STANDARD_FLAG -std=c++11)
set(CPP14_FLAG -std=c++11) elseif (has_std_0x_flag)
else () set(CXX_STANDARD_FLAG -std=c++0x)
check_cxx_compiler_flag(-std=c++0x HAVE_STD_CPP0X_FLAG)
if (HAVE_STD_CPP0X_FLAG)
set(CPP14_FLAG -std=c++0x)
endif ()
endif ()
endif ()
endif () endif ()
endif () endif ()
if (CMAKE_CXX_STANDARD) set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG})
# Don't use -std compiler flag if CMAKE_CXX_STANDARD is specified.
set(CPP14_FLAG )
endif ()
message(STATUS "CPP14_FLAG: ${CPP14_FLAG}")
set(CMAKE_REQUIRED_FLAGS ${CPP14_FLAG})
# Check if variadic templates are working and not affected by GCC bug 39653: # Check if variadic templates are working and not affected by GCC bug 39653:
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39653 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39653
@ -69,17 +54,26 @@ check_cxx_source_compiles("
template <class T, class ...Types> template <class T, class ...Types>
struct S { typedef typename S<Types...>::type type; }; struct S { typedef typename S<Types...>::type type; };
int main() {}" SUPPORTS_VARIADIC_TEMPLATES) int main() {}" SUPPORTS_VARIADIC_TEMPLATES)
if (NOT SUPPORTS_VARIADIC_TEMPLATES)
set (SUPPORTS_VARIADIC_TEMPLATES OFF)
endif ()
# Check if initializer lists are supported. # Check if initializer lists are supported.
check_cxx_source_compiles(" check_cxx_source_compiles("
#include <initializer_list> #include <initializer_list>
int main() {}" SUPPORTS_INITIALIZER_LIST) int main() {}" SUPPORTS_INITIALIZER_LIST)
if (NOT SUPPORTS_INITIALIZER_LIST)
set (SUPPORTS_INITIALIZER_LIST OFF)
endif ()
# Check if enum bases are available # Check if enum bases are available
check_cxx_source_compiles(" check_cxx_source_compiles("
enum C : char {A}; enum C : char {A};
int main() {}" int main() {}"
SUPPORTS_ENUM_BASE) SUPPORTS_ENUM_BASE)
if (NOT SUPPORTS_ENUM_BASE)
set (SUPPORTS_ENUM_BASE OFF)
endif ()
# Check if type traits are available # Check if type traits are available
check_cxx_source_compiles(" check_cxx_source_compiles("
@ -87,11 +81,17 @@ check_cxx_source_compiles("
class C { void operator=(const C&); }; class C { void operator=(const C&); };
int main() { static_assert(!std::is_copy_assignable<C>::value, \"\"); }" int main() { static_assert(!std::is_copy_assignable<C>::value, \"\"); }"
SUPPORTS_TYPE_TRAITS) SUPPORTS_TYPE_TRAITS)
if (NOT SUPPORTS_TYPE_TRAITS)
set (SUPPORTS_TYPE_TRAITS OFF)
endif ()
# Check if user-defined literals are available # Check if user-defined literals are available
check_cxx_source_compiles(" check_cxx_source_compiles("
void operator\"\" _udl(long double); void operator\"\" _udl(long double);
int main() {}" int main() {}"
SUPPORTS_USER_DEFINED_LITERALS) SUPPORTS_USER_DEFINED_LITERALS)
if (NOT SUPPORTS_USER_DEFINED_LITERALS)
set (SUPPORTS_USER_DEFINED_LITERALS OFF)
endif ()
set(CMAKE_REQUIRED_FLAGS ) set(CMAKE_REQUIRED_FLAGS )

View File

@ -39,12 +39,15 @@ for i, exp in enumerate(range(min_exponent, max_exponent + 1, step)):
print('Significands:', end='') print('Significands:', end='')
for i, fp in enumerate(powers): for i, fp in enumerate(powers):
if i % 3 == 0: if i % 4 == 0:
print(end='\n ') print(end='\n ')
print(' {:0<#16x}ull'.format(fp.f, ), end=',') print(' {:0<#16x}'.format(fp.f, ), end=',')
print('\n\nExponents:', end='') print('\n\nExponents:', end='')
for i, fp in enumerate(powers): for i, fp in enumerate(powers):
if i % 11 == 0: if i % 11 == 0:
print(end='\n ') print(end='\n ')
print(' {:5}'.format(fp.e), end=',') print(' {:5}'.format(fp.e), end=',')
print('\n\nMax exponent difference:',
max([x.e - powers[i - 1].e for i, x in enumerate(powers)][1:]))

View File

@ -152,7 +152,9 @@ def update_site(env):
if os.path.exists(html_dir): if os.path.exists(html_dir):
shutil.rmtree(html_dir) shutil.rmtree(html_dir)
include_dir = env.fmt_repo.dir include_dir = env.fmt_repo.dir
if LooseVersion(version) >= LooseVersion('3.0.0'): if LooseVersion(version) >= LooseVersion('5.0.0'):
include_dir = os.path.join(include_dir, 'include', 'fmt')
elif LooseVersion(version) >= LooseVersion('3.0.0'):
include_dir = os.path.join(include_dir, 'fmt') include_dir = os.path.join(include_dir, 'fmt')
import build import build
build.build_docs(version, doc_dir=target_doc_dir, build.build_docs(version, doc_dir=target_doc_dir,
@ -243,12 +245,11 @@ def release(args):
id = r.json()['id'] id = r.json()['id']
uploads_url = 'https://uploads.github.com/repos/fmtlib/fmt/releases' uploads_url = 'https://uploads.github.com/repos/fmtlib/fmt/releases'
package = 'fmt-{}.zip'.format(version) package = 'fmt-{}.zip'.format(version)
with open('build/fmt/' + package, 'rb') as f: r = requests.post(
r = requests.post( '{}/{}/assets?name={}'.format(uploads_url, id, package),
'{}/{}/assets?name={}'.format(uploads_url, id, package), params=params, files={package: open('build/fmt/' + package, 'rb')})
params=params, files={package: f}) if r.status_code != 201:
if r.status_code != 201: raise Exception('Failed to upload an asset ' + str(r))
raise Exception('Failed to upload an asset ' + str(r))
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -2,8 +2,8 @@
# Build the project on Travis CI. # Build the project on Travis CI.
from __future__ import print_function from __future__ import print_function
import errno, os, re, shutil, subprocess, sys, tempfile, urllib import errno, os, shutil, subprocess, sys, urllib
from subprocess import call, check_call, check_output, Popen, PIPE, STDOUT from subprocess import call, check_call, Popen, PIPE, STDOUT
def rmtree_if_exists(dir): def rmtree_if_exists(dir):
try: try:
@ -85,14 +85,12 @@ test_build_dir = os.path.join(fmt_dir, "_build_test")
# Configure library. # Configure library.
makedirs_if_not_exist(build_dir) makedirs_if_not_exist(build_dir)
common_cmake_flags = [ cmake_flags = [
'-DCMAKE_INSTALL_PREFIX=' + install_dir, '-DCMAKE_BUILD_TYPE=' + build '-DCMAKE_INSTALL_PREFIX=' + install_dir, '-DCMAKE_BUILD_TYPE=' + build,
'-DCMAKE_CXX_STANDARD=' + standard
] ]
extra_cmake_flags = [] check_call(['cmake', '-DFMT_DOC=OFF', '-DFMT_PEDANTIC=ON', '-DFMT_WERROR=ON', fmt_dir] +
if standard != '14': cmake_flags, cwd=build_dir)
extra_cmake_flags = ['-DCMAKE_CXX_FLAGS=-std=c++' + standard]
check_call(['cmake', '-DFMT_DOC=OFF', '-DFMT_PEDANTIC=ON', fmt_dir] +
common_cmake_flags + extra_cmake_flags, cwd=build_dir)
# Build library. # Build library.
check_call(['make', '-j4'], cwd=build_dir) check_call(['make', '-j4'], cwd=build_dir)
@ -101,7 +99,7 @@ check_call(['make', '-j4'], cwd=build_dir)
env = os.environ.copy() env = os.environ.copy()
env['CTEST_OUTPUT_ON_FAILURE'] = '1' env['CTEST_OUTPUT_ON_FAILURE'] = '1'
if call(['make', 'test'], env=env, cwd=build_dir): if call(['make', 'test'], env=env, cwd=build_dir):
with open('Testing/Temporary/LastTest.log', 'r') as f: with open(os.path.join(build_dir, 'Testing', 'Temporary', 'LastTest.log'), 'r') as f:
print(f.read()) print(f.read())
sys.exit(-1) sys.exit(-1)
@ -110,7 +108,6 @@ check_call(['make', 'install'], cwd=build_dir)
# Test installation. # Test installation.
makedirs_if_not_exist(test_build_dir) makedirs_if_not_exist(test_build_dir)
check_call(['cmake', '-DCMAKE_CXX_FLAGS=-std=c++' + standard, check_call(['cmake', os.path.join(fmt_dir, "test", "find-package-test")] +
os.path.join(fmt_dir, "test", "find-package-test")] + cmake_flags, cwd=test_build_dir)
common_cmake_flags, cwd=test_build_dir)
check_call(['make', '-j4'], cwd=test_build_dir) check_call(['make', '-j4'], cwd=test_build_dir)

View File

@ -7,9 +7,8 @@
# at http://code.google.com/p/googletest/wiki/FAQ for more details. # at http://code.google.com/p/googletest/wiki/FAQ for more details.
add_library(gmock STATIC add_library(gmock STATIC
gmock-gtest-all.cc gmock/gmock.h gtest/gtest.h gtest/gtest-spi.h) gmock-gtest-all.cc gmock/gmock.h gtest/gtest.h gtest/gtest-spi.h)
target_compile_options(gmock PUBLIC ${CPP14_FLAG})
target_compile_definitions(gmock PUBLIC GTEST_HAS_STD_WSTRING=1) target_compile_definitions(gmock PUBLIC GTEST_HAS_STD_WSTRING=1)
target_include_directories(gmock PUBLIC .) target_include_directories(gmock SYSTEM PUBLIC . gmock gtest)
find_package(Threads) find_package(Threads)
if (Threads_FOUND) if (Threads_FOUND)
@ -43,6 +42,7 @@ set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc)
add_library(test-main STATIC ${TEST_MAIN_SRC}) add_library(test-main STATIC ${TEST_MAIN_SRC})
target_compile_definitions(test-main PUBLIC target_compile_definitions(test-main PUBLIC
FMT_USE_FILE_DESCRIPTORS=$<BOOL:${HAVE_OPEN}>) FMT_USE_FILE_DESCRIPTORS=$<BOOL:${HAVE_OPEN}>)
target_include_directories(test-main SYSTEM PUBLIC gtest gmock)
target_link_libraries(test-main gmock fmt) target_link_libraries(test-main gmock fmt)
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
@ -57,7 +57,7 @@ endif ()
# Use less strict pedantic flags for the tests because GMock doesn't compile # Use less strict pedantic flags for the tests because GMock doesn't compile
# cleanly with -pedantic and -std=c++98. # cleanly with -pedantic and -std=c++98.
if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wno-long-long -Wno-variadic-macros) #set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wno-long-long -Wno-variadic-macros)
endif () endif ()
function(add_fmt_executable name) function(add_fmt_executable name)
@ -80,6 +80,7 @@ function(add_fmt_test name)
if (FMT_PEDANTIC) if (FMT_PEDANTIC)
target_compile_options(${name} PRIVATE ${PEDANTIC_COMPILE_FLAGS}) target_compile_options(${name} PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif () endif ()
target_include_directories(${name} SYSTEM PUBLIC gtest gmock)
add_test(NAME ${name} COMMAND ${name}) add_test(NAME ${name} COMMAND ${name})
endfunction() endfunction()
@ -94,12 +95,6 @@ add_fmt_test(util-test mock-allocator.h)
add_fmt_test(custom-formatter-test) add_fmt_test(custom-formatter-test)
add_fmt_test(ranges-test) add_fmt_test(ranges-test)
# Enable stricter options for one test to make sure that the header is free of
# warnings.
if (FMT_PEDANTIC AND MSVC)
target_compile_options(format-test PRIVATE /W4)
endif ()
if (HAVE_OPEN) if (HAVE_OPEN)
add_fmt_executable(posix-mock-test add_fmt_executable(posix-mock-test
posix-mock-test.cc ../src/format.cc ${TEST_MAIN_SRC}) posix-mock-test.cc ../src/format.cc ${TEST_MAIN_SRC})
@ -107,6 +102,10 @@ if (HAVE_OPEN)
posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR}/include) posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_definitions(posix-mock-test PRIVATE FMT_USE_FILE_DESCRIPTORS=1) target_compile_definitions(posix-mock-test PRIVATE FMT_USE_FILE_DESCRIPTORS=1)
target_link_libraries(posix-mock-test gmock) target_link_libraries(posix-mock-test gmock)
target_include_directories(posix-mock-test SYSTEM PUBLIC gtest gmock)
if (FMT_PEDANTIC)
target_compile_options(posix-mock-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
add_test(NAME posix-mock-test COMMAND posix-mock-test) add_test(NAME posix-mock-test COMMAND posix-mock-test)
add_fmt_test(posix-test) add_fmt_test(posix-test)
endif () endif ()
@ -114,6 +113,7 @@ endif ()
add_fmt_executable(header-only-test add_fmt_executable(header-only-test
header-only-test.cc header-only-test2.cc test-main.cc) header-only-test.cc header-only-test2.cc test-main.cc)
target_link_libraries(header-only-test gmock) target_link_libraries(header-only-test gmock)
target_include_directories(header-only-test SYSTEM PUBLIC gtest gmock)
if (TARGET fmt-header-only) if (TARGET fmt-header-only)
target_link_libraries(header-only-test fmt-header-only) target_link_libraries(header-only-test fmt-header-only)
else () else ()
@ -126,20 +126,28 @@ endif ()
check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG) check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG)
if (HAVE_FNO_EXCEPTIONS_FLAG) if (HAVE_FNO_EXCEPTIONS_FLAG)
add_library(noexception-test ../src/format.cc) add_library(noexception-test ../src/format.cc)
target_compile_options(noexception-test PUBLIC ${CPP14_FLAG})
target_include_directories( target_include_directories(
noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include) noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_options(noexception-test PRIVATE -fno-exceptions) target_compile_options(noexception-test PRIVATE -fno-exceptions)
if (FMT_PEDANTIC)
target_compile_options(noexception-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
target_include_directories(noexception-test SYSTEM PUBLIC gtest gmock)
endif () endif ()
message(STATUS "FMT_PEDANTIC: ${FMT_PEDANTIC}")
if (FMT_PEDANTIC) if (FMT_PEDANTIC)
# Test that the library compiles without windows.h. # Test that the library compiles without windows.h.
if (CMAKE_SYSTEM_NAME STREQUAL "Windows") if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_library(no-windows-h-test ../src/format.cc) add_library(no-windows-h-test ../src/format.cc)
target_compile_options(no-windows-h-test PUBLIC ${CPP14_FLAG})
target_include_directories( target_include_directories(
no-windows-h-test PRIVATE ${PROJECT_SOURCE_DIR}/include) no-windows-h-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_definitions(no-windows-h-test PRIVATE FMT_USE_WINDOWS_H=0) target_compile_definitions(no-windows-h-test PRIVATE FMT_USE_WINDOWS_H=0)
if (FMT_PEDANTIC)
target_compile_options(no-windows-h-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
target_include_directories(no-windows-h-test SYSTEM PUBLIC gtest gmock)
endif () endif ()
add_test(compile-test ${CMAKE_CTEST_COMMAND} add_test(compile-test ${CMAKE_CTEST_COMMAND}
@ -148,9 +156,11 @@ if (FMT_PEDANTIC)
"${CMAKE_CURRENT_BINARY_DIR}/compile-test" "${CMAKE_CURRENT_BINARY_DIR}/compile-test"
--build-generator ${CMAKE_GENERATOR} --build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options --build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCPP14_FLAG=${CPP14_FLAG}" "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DCXX_STANDARD_FLAG=${CXX_STANDARD_FLAG}"
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
"-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}") "-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}")
# test if the targets are findable from the build directory # test if the targets are findable from the build directory
@ -163,8 +173,9 @@ if (FMT_PEDANTIC)
--build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options --build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCPP14_FLAG=${CPP14_FLAG}" "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DFMT_DIR=${PROJECT_BINARY_DIR}" "-DFMT_DIR=${PROJECT_BINARY_DIR}"
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
# test if the targets are findable when add_subdirectory is used # test if the targets are findable when add_subdirectory is used
@ -177,6 +188,7 @@ if (FMT_PEDANTIC)
--build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options --build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCPP14_FLAG=${CPP14_FLAG}" "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
endif () endif ()

View File

@ -1,15 +1,17 @@
cmake_minimum_required(VERSION 2.8.12) cmake_minimum_required(VERSION 3.1.0)
project(fmt-test) project(fmt-test)
add_subdirectory(../.. fmt) add_subdirectory(../.. fmt)
add_executable(library-test "main.cc") add_executable(library-test "main.cc")
target_compile_options(library-test PUBLIC ${CPP14_FLAG})
target_link_libraries(library-test fmt::fmt) target_link_libraries(library-test fmt::fmt)
target_compile_options(library-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
target_include_directories(library-test PUBLIC SYSTEM .)
if (TARGET fmt::fmt-header-only) if (TARGET fmt::fmt-header-only)
add_executable(header-only-test "main.cc") add_executable(header-only-test "main.cc")
target_compile_options(header-only-test PUBLIC ${CPP14_FLAG})
target_link_libraries(header-only-test fmt::fmt-header-only) target_link_libraries(header-only-test fmt::fmt-header-only)
target_compile_options(header-only-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
target_include_directories(header-only-test PUBLIC SYSTEM .)
endif () endif ()

View File

@ -6,7 +6,7 @@
// For the license information refer to format.h. // For the license information refer to format.h.
#include "fmt/core.h" #include "fmt/core.h"
#include "gtest/gtest.h" #include "gtest.h"
#if GTEST_HAS_DEATH_TEST #if GTEST_HAS_DEATH_TEST
# define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \ # define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \

View File

@ -1,10 +1,12 @@
# Test if compile errors are produced where necessary. # Test if compile errors are produced where necessary.
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 3.1.0)
include(CheckCXXSourceCompiles) include(CheckCXXSourceCompiles)
include(CheckCXXCompilerFlag)
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/../../include) set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
set(CMAKE_REQUIRED_FLAGS ${CPP14_FLAG}) set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG} ${PEDANTIC_COMPILE_FLAGS})
function (generate_source result fragment) function (generate_source result fragment)
set(${result} " set(${result} "

View File

@ -22,13 +22,21 @@ class custom_arg_formatter :
using base::operator(); using base::operator();
iterator operator()(double value) { iterator operator()(double value) {
if (round(value * pow(10, spec().precision())) == 0) #if FMT_GCC_VERSION
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
// Comparing a float to 0.0 is safe
if (round(value * pow(10, spec().precision())) == 0.0)
value = 0; value = 0;
return base::operator()(value); return base::operator()(value);
#if FMT_GCC_VERSION
#pragma GCC diagnostic pop
#endif
} }
}; };
std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) { static std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) {
fmt::memory_buffer buffer; fmt::memory_buffer buffer;
// Pass custom argument formatter as a template arg to vwrite. // Pass custom argument formatter as a template arg to vwrite.
fmt::vformat_to<custom_arg_formatter>(buffer, format_str, args); fmt::vformat_to<custom_arg_formatter>(buffer, format_str, args);

View File

@ -1,15 +1,17 @@
cmake_minimum_required(VERSION 2.8.12) cmake_minimum_required(VERSION 3.1.0)
project(fmt-test) project(fmt-test)
find_package(FMT REQUIRED) find_package(FMT REQUIRED)
add_executable(library-test main.cc) add_executable(library-test main.cc)
target_compile_options(library-test PUBLIC ${CPP14_FLAG})
target_link_libraries(library-test fmt::fmt) target_link_libraries(library-test fmt::fmt)
target_compile_options(library-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
target_include_directories(library-test PUBLIC SYSTEM .)
if (TARGET fmt::fmt-header-only) if (TARGET fmt::fmt-header-only)
add_executable(header-only-test main.cc) add_executable(header-only-test main.cc)
target_compile_options(header-only-test PUBLIC ${CPP14_FLAG})
target_link_libraries(header-only-test fmt::fmt-header-only) target_link_libraries(header-only-test fmt::fmt-header-only)
target_compile_options(header-only-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
target_include_directories(header-only-test PUBLIC SYSTEM .)
endif () endif ()

View File

@ -16,7 +16,7 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include "gmock/gmock.h" #include "gmock.h"
#include "gtest-extra.h" #include "gtest-extra.h"
#include "util.h" #include "util.h"
@ -30,9 +30,8 @@ struct ValueExtractor: fmt::internal::function<T> {
} }
template <typename U> template <typename U>
T operator()(U) { FMT_NORETURN T operator()(U) {
throw std::runtime_error(fmt::format("invalid type {}", typeid(U).name())); throw std::runtime_error(fmt::format("invalid type {}", typeid(U).name()));
return T();
} }
}; };
@ -53,9 +52,9 @@ TEST(FormatTest, FormatNegativeNaN) {
} }
TEST(FormatTest, StrError) { TEST(FormatTest, StrError) {
char *message = 0; char *message = nullptr;
char buffer[BUFFER_SIZE]; char buffer[BUFFER_SIZE];
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = 0, 0), "invalid buffer"); EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = nullptr, 0), "invalid buffer");
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = buffer, 0), EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = buffer, 0),
"invalid buffer"); "invalid buffer");
buffer[0] = 'x'; buffer[0] = 'x';

View File

@ -14,7 +14,7 @@
#include <memory> #include <memory>
#include <stdint.h> #include <stdint.h>
#include "gmock/gmock.h" #include "gmock.h"
// Test that the library compiles if None is defined to 0 as done by xlib.h. // Test that the library compiles if None is defined to 0 as done by xlib.h.
#define None 0 #define None 0
@ -321,6 +321,11 @@ TEST(FormatterTest, NamedArg) {
EXPECT_EQ(" -42", format("{0:{width}}", -42, fmt::arg("width", 4))); EXPECT_EQ(" -42", format("{0:{width}}", -42, fmt::arg("width", 4)));
EXPECT_EQ("st", format("{0:.{precision}}", "str", fmt::arg("precision", 2))); EXPECT_EQ("st", format("{0:.{precision}}", "str", fmt::arg("precision", 2)));
EXPECT_EQ("1 2", format("{} {two}", 1, fmt::arg("two", 2))); EXPECT_EQ("1 2", format("{} {two}", 1, fmt::arg("two", 2)));
EXPECT_EQ("42", format("{c}",
fmt::arg("a", 0), fmt::arg("b", 0), fmt::arg("c", 42), fmt::arg("d", 0),
fmt::arg("e", 0), fmt::arg("f", 0), fmt::arg("g", 0), fmt::arg("h", 0),
fmt::arg("i", 0), fmt::arg("j", 0), fmt::arg("k", 0), fmt::arg("l", 0),
fmt::arg("m", 0), fmt::arg("n", 0), fmt::arg("o", 0), fmt::arg("p", 0)));
} }
TEST(FormatterTest, AutoArgIndex) { TEST(FormatterTest, AutoArgIndex) {
@ -435,6 +440,7 @@ TEST(FormatterTest, Fill) {
EXPECT_EQ("c****", format("{0:*<5}", 'c')); EXPECT_EQ("c****", format("{0:*<5}", 'c'));
EXPECT_EQ("abc**", format("{0:*<5}", "abc")); EXPECT_EQ("abc**", format("{0:*<5}", "abc"));
EXPECT_EQ("**0xface", format("{0:*>8}", reinterpret_cast<void*>(0xface))); EXPECT_EQ("**0xface", format("{0:*>8}", reinterpret_cast<void*>(0xface)));
EXPECT_EQ("foo=", format("{:}=", "foo"));
} }
TEST(FormatterTest, PlusSign) { TEST(FormatterTest, PlusSign) {
@ -1024,7 +1030,7 @@ TEST(FormatterTest, FormatCString) {
EXPECT_EQ("test", format("{0:s}", "test")); EXPECT_EQ("test", format("{0:s}", "test"));
char nonconst[] = "nonconst"; char nonconst[] = "nonconst";
EXPECT_EQ("nonconst", format("{0}", nonconst)); EXPECT_EQ("nonconst", format("{0}", nonconst));
EXPECT_THROW_MSG(format("{0}", reinterpret_cast<const char*>(0)), EXPECT_THROW_MSG(format("{0}", static_cast<const char*>(nullptr)),
format_error, "string pointer is null"); format_error, "string pointer is null");
} }
@ -1046,7 +1052,7 @@ TEST(FormatterTest, FormatUCharString) {
TEST(FormatterTest, FormatPointer) { TEST(FormatterTest, FormatPointer) {
check_unknown_types(reinterpret_cast<void*>(0x1234), "p", "pointer"); check_unknown_types(reinterpret_cast<void*>(0x1234), "p", "pointer");
EXPECT_EQ("0x0", format("{0}", reinterpret_cast<void*>(0))); EXPECT_EQ("0x0", format("{0}", static_cast<void*>(nullptr)));
EXPECT_EQ("0x1234", format("{0}", reinterpret_cast<void*>(0x1234))); EXPECT_EQ("0x1234", format("{0}", reinterpret_cast<void*>(0x1234)));
EXPECT_EQ("0x1234", format("{0:p}", reinterpret_cast<void*>(0x1234))); EXPECT_EQ("0x1234", format("{0:p}", reinterpret_cast<void*>(0x1234)));
EXPECT_EQ("0x" + std::string(sizeof(void*) * CHAR_BIT / 4, 'f'), EXPECT_EQ("0x" + std::string(sizeof(void*) * CHAR_BIT / 4, 'f'),
@ -1148,7 +1154,7 @@ TEST(FormatterTest, FormatExamples) {
FILE *ftest = safe_fopen(filename, "r"); FILE *ftest = safe_fopen(filename, "r");
if (ftest) fclose(ftest); if (ftest) fclose(ftest);
int error_code = errno; int error_code = errno;
EXPECT_TRUE(ftest == 0); EXPECT_TRUE(ftest == nullptr);
EXPECT_SYSTEM_ERROR({ EXPECT_SYSTEM_ERROR({
FILE *f = safe_fopen(filename, "r"); FILE *f = safe_fopen(filename, "r");
if (!f) if (!f)
@ -1309,7 +1315,7 @@ TEST(StrTest, Convert) {
EXPECT_EQ("2012-12-9", s); EXPECT_EQ("2012-12-9", s);
} }
std::string vformat_message(int id, const char *format, fmt::format_args args) { static std::string vformat_message(int id, const char *format, fmt::format_args args) {
fmt::memory_buffer buffer; fmt::memory_buffer buffer;
format_to(buffer, "[{}] ", id); format_to(buffer, "[{}] ", id);
vformat_to(buffer, format, args); vformat_to(buffer, format, args);
@ -1421,7 +1427,7 @@ class mock_arg_formatter:
} }
}; };
void custom_vformat(fmt::string_view format_str, fmt::format_args args) { static void custom_vformat(fmt::string_view format_str, fmt::format_args args) {
fmt::memory_buffer buffer; fmt::memory_buffer buffer;
fmt::vformat_to<mock_arg_formatter>(buffer, format_str, args); fmt::vformat_to<mock_arg_formatter>(buffer, format_str, args);
} }
@ -1516,6 +1522,9 @@ TEST(FormatTest, FormatToN) {
EXPECT_EQ(6u, result.size); EXPECT_EQ(6u, result.size);
EXPECT_EQ(buffer + 3, result.out); EXPECT_EQ(buffer + 3, result.out);
EXPECT_EQ("foox", fmt::string_view(buffer, 4)); EXPECT_EQ("foox", fmt::string_view(buffer, 4));
// Workaround for potentially unused macro
static_cast<void>(None);
} }
#if FMT_USE_CONSTEXPR #if FMT_USE_CONSTEXPR
@ -1794,12 +1803,14 @@ FMT_CONSTEXPR bool test_error(const char *fmt, const char *expected_error) {
return equal(actual_error, expected_error); return equal(actual_error, expected_error);
} }
#define EXPECT_ERROR_NOARGS(fmt, error) \
static_assert(test_error(fmt, error), "")
#define EXPECT_ERROR(fmt, error, ...) \ #define EXPECT_ERROR(fmt, error, ...) \
static_assert(test_error<__VA_ARGS__>(fmt, error), "") static_assert(test_error<__VA_ARGS__>(fmt, error), "")
TEST(FormatTest, FormatStringErrors) { TEST(FormatTest, FormatStringErrors) {
EXPECT_ERROR("foo", nullptr); EXPECT_ERROR_NOARGS("foo", nullptr);
EXPECT_ERROR("}", "unmatched '}' in format string"); EXPECT_ERROR_NOARGS("}", "unmatched '}' in format string");
EXPECT_ERROR("{0:s", "unknown format specifier", Date); EXPECT_ERROR("{0:s", "unknown format specifier", Date);
#ifndef _MSC_VER #ifndef _MSC_VER
// This causes an internal compiler error in MSVC2017. // This causes an internal compiler error in MSVC2017.
@ -1807,7 +1818,7 @@ TEST(FormatTest, FormatStringErrors) {
EXPECT_ERROR("{:{<}", "invalid fill character '{'", int); EXPECT_ERROR("{:{<}", "invalid fill character '{'", int);
EXPECT_ERROR("{:10000000000}", "number is too big", int); EXPECT_ERROR("{:10000000000}", "number is too big", int);
EXPECT_ERROR("{:.10000000000}", "number is too big", int); EXPECT_ERROR("{:.10000000000}", "number is too big", int);
EXPECT_ERROR("{:x}", "argument index out of range"); EXPECT_ERROR_NOARGS("{:x}", "argument index out of range");
EXPECT_ERROR("{:=}", "format specifier requires numeric argument", EXPECT_ERROR("{:=}", "format specifier requires numeric argument",
const char *); const char *);
EXPECT_ERROR("{:+}", "format specifier requires numeric argument", EXPECT_ERROR("{:+}", "format specifier requires numeric argument",
@ -1834,15 +1845,15 @@ TEST(FormatTest, FormatStringErrors) {
EXPECT_ERROR("{:s}", "invalid type specifier", void *); EXPECT_ERROR("{:s}", "invalid type specifier", void *);
#endif #endif
EXPECT_ERROR("{foo", "missing '}' in format string", int); EXPECT_ERROR("{foo", "missing '}' in format string", int);
EXPECT_ERROR("{10000000000}", "number is too big"); EXPECT_ERROR_NOARGS("{10000000000}", "number is too big");
EXPECT_ERROR("{0x}", "invalid format string"); EXPECT_ERROR_NOARGS("{0x}", "invalid format string");
EXPECT_ERROR("{-}", "invalid format string"); EXPECT_ERROR_NOARGS("{-}", "invalid format string");
EXPECT_ERROR("{:{0x}}", "invalid format string", int); EXPECT_ERROR("{:{0x}}", "invalid format string", int);
EXPECT_ERROR("{:{-}}", "invalid format string", int); EXPECT_ERROR("{:{-}}", "invalid format string", int);
EXPECT_ERROR("{:.{0x}}", "invalid format string", int); EXPECT_ERROR("{:.{0x}}", "invalid format string", int);
EXPECT_ERROR("{:.{-}}", "invalid format string", int); EXPECT_ERROR("{:.{-}}", "invalid format string", int);
EXPECT_ERROR("{:.x}", "missing precision specifier", int); EXPECT_ERROR("{:.x}", "missing precision specifier", int);
EXPECT_ERROR("{}", "argument index out of range"); EXPECT_ERROR_NOARGS("{}", "argument index out of range");
EXPECT_ERROR("{1}", "argument index out of range", int); EXPECT_ERROR("{1}", "argument index out of range", int);
EXPECT_ERROR("{1}{}", EXPECT_ERROR("{1}{}",
"cannot switch from manual to automatic argument indexing", "cannot switch from manual to automatic argument indexing",

View File

@ -36,7 +36,7 @@
// This line ensures that gtest.h can be compiled on its own, even // This line ensures that gtest.h can be compiled on its own, even
// when it's fused. // when it's fused.
#include "gtest/gtest.h" #include "gtest.h"
// The following lines pull in the real gtest *.cc files. // The following lines pull in the real gtest *.cc files.
// Copyright 2005, Google Inc. // Copyright 2005, Google Inc.

View File

@ -235,7 +235,7 @@
// Most of the types needed for porting Google Mock are also required // Most of the types needed for porting Google Mock are also required
// for Google Test and are defined in gtest-port.h. // for Google Test and are defined in gtest-port.h.
#include "gtest/gtest.h" #include "gtest.h"
// To avoid conditional compilation everywhere, we make it // To avoid conditional compilation everywhere, we make it
// gmock-port.h's responsibility to #include the header implementing // gmock-port.h's responsibility to #include the header implementing

View File

@ -340,10 +340,10 @@ TEST(OutputRedirectTest, FlushErrorInCtor) {
// Put a character in a file buffer. // Put a character in a file buffer.
EXPECT_EQ('x', fputc('x', f.get())); EXPECT_EQ('x', fputc('x', f.get()));
FMT_POSIX(close(write_fd)); FMT_POSIX(close(write_fd));
scoped_ptr<OutputRedirect> redir; scoped_ptr<OutputRedirect> redir{nullptr};
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())), EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
EBADF, "cannot flush stream"); EBADF, "cannot flush stream");
redir.reset(); redir.reset(nullptr);
write_copy.dup2(write_fd); // "undo" close or dtor will fail write_copy.dup2(write_fd); // "undo" close or dtor will fail
} }
@ -352,7 +352,7 @@ TEST(OutputRedirectTest, DupErrorInCtor) {
int fd = (f.fileno)(); int fd = (f.fileno)();
file copy = file::dup(fd); file copy = file::dup(fd);
FMT_POSIX(close(fd)); FMT_POSIX(close(fd));
scoped_ptr<OutputRedirect> redir; scoped_ptr<OutputRedirect> redir{nullptr};
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())), EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
EBADF, fmt::format("cannot duplicate file descriptor {}", fd)); EBADF, fmt::format("cannot duplicate file descriptor {}", fd));
copy.dup2(fd); // "undo" close or dtor will fail copy.dup2(fd); // "undo" close or dtor will fail
@ -403,7 +403,7 @@ TEST(OutputRedirectTest, ErrorInDtor) {
// output in EXPECT_STDERR and the second close will break output // output in EXPECT_STDERR and the second close will break output
// redirection. // redirection.
FMT_POSIX(close(write_fd)); FMT_POSIX(close(write_fd));
SUPPRESS_ASSERT(redir.reset()); SUPPRESS_ASSERT(redir.reset(nullptr));
}, format_system_error(EBADF, "cannot flush stream")); }, format_system_error(EBADF, "cannot flush stream"));
write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail
} }

View File

@ -75,7 +75,7 @@ std::string read(file &f, std::size_t count) {
do { do {
n = f.read(&buffer[offset], count - offset); n = f.read(&buffer[offset], count - offset);
// We can't read more than size_t bytes since count has type size_t. // We can't read more than size_t bytes since count has type size_t.
offset += static_cast<std::size_t>(n); offset += n;
} while (offset < count && n != 0); } while (offset < count && n != 0);
buffer.resize(offset); buffer.resize(offset);
return buffer; return buffer;

View File

@ -9,7 +9,7 @@
#define FMT_GTEST_EXTRA_H_ #define FMT_GTEST_EXTRA_H_
#include <string> #include <string>
#include <gmock/gmock.h> #include "gmock.h"
#include "fmt/core.h" #include "fmt/core.h"
@ -155,7 +155,7 @@ std::string read(fmt::file &f, std::size_t count);
template <typename Mock> template <typename Mock>
struct ScopedMock : testing::StrictMock<Mock> { struct ScopedMock : testing::StrictMock<Mock> {
ScopedMock() { Mock::instance = this; } ScopedMock() { Mock::instance = this; }
~ScopedMock() { Mock::instance = 0; } ~ScopedMock() { Mock::instance = nullptr; }
}; };
#endif // FMT_GTEST_EXTRA_H_ #endif // FMT_GTEST_EXTRA_H_

View File

@ -8,7 +8,7 @@
#ifndef FMT_MOCK_ALLOCATOR_H_ #ifndef FMT_MOCK_ALLOCATOR_H_
#define FMT_MOCK_ALLOCATOR_H_ #define FMT_MOCK_ALLOCATOR_H_
#include "gmock/gmock.h" #include "gmock.h"
template <typename T> template <typename T>
class MockAllocator { class MockAllocator {
@ -28,7 +28,7 @@ class AllocatorRef {
public: public:
typedef typename Allocator::value_type value_type; typedef typename Allocator::value_type value_type;
explicit AllocatorRef(Allocator *alloc = 0) : alloc_(alloc) {} explicit AllocatorRef(Allocator *alloc = nullptr) : alloc_(alloc) {}
AllocatorRef(const AllocatorRef &other) : alloc_(other.alloc_) {} AllocatorRef(const AllocatorRef &other) : alloc_(other.alloc_) {}
@ -41,7 +41,7 @@ class AllocatorRef {
private: private:
void move(AllocatorRef &other) { void move(AllocatorRef &other) {
alloc_ = other.alloc_; alloc_ = other.alloc_;
other.alloc_ = 0; other.alloc_ = nullptr;
} }
public: public:

View File

@ -8,29 +8,29 @@
#include "fmt/ostream.h" #include "fmt/ostream.h"
#include <sstream> #include <sstream>
#include "gmock/gmock.h" #include "gmock.h"
#include "gtest-extra.h" #include "gtest-extra.h"
#include "util.h" #include "util.h"
using fmt::format; using fmt::format;
using fmt::format_error; using fmt::format_error;
std::ostream &operator<<(std::ostream &os, const Date &d) { static std::ostream &operator<<(std::ostream &os, const Date &d) {
os << d.year() << '-' << d.month() << '-' << d.day(); os << d.year() << '-' << d.month() << '-' << d.day();
return os; return os;
} }
std::wostream &operator<<(std::wostream &os, const Date &d) { static std::wostream &operator<<(std::wostream &os, const Date &d) {
os << d.year() << L'-' << d.month() << L'-' << d.day(); os << d.year() << L'-' << d.month() << L'-' << d.day();
return os; return os;
} }
enum TestEnum {}; enum TestEnum {};
std::ostream &operator<<(std::ostream &os, TestEnum) { static std::ostream &operator<<(std::ostream &os, TestEnum) {
return os << "TestEnum"; return os << "TestEnum";
} }
std::wostream &operator<<(std::wostream &os, TestEnum) { static std::wostream &operator<<(std::wostream &os, TestEnum) {
return os << L"TestEnum"; return os << L"TestEnum";
} }
@ -95,7 +95,7 @@ TEST(OStreamTest, FormatSpecs) {
} }
struct EmptyTest {}; struct EmptyTest {};
std::ostream &operator<<(std::ostream &os, EmptyTest) { static std::ostream &operator<<(std::ostream &os, EmptyTest) {
return os << ""; return os << "";
} }
@ -145,7 +145,7 @@ TEST(OStreamTest, WriteToOStreamMaxSize) {
} os(streambuf); } os(streambuf);
testing::InSequence sequence; testing::InSequence sequence;
const char *data = 0; const char *data = nullptr;
std::size_t size = max_size; std::size_t size = max_size;
do { do {
typedef std::make_unsigned<std::streamsize>::type ustreamsize; typedef std::make_unsigned<std::streamsize>::type ustreamsize;
@ -154,7 +154,12 @@ TEST(OStreamTest, WriteToOStreamMaxSize) {
EXPECT_CALL(streambuf, xsputn(data, static_cast<std::streamsize>(n))) EXPECT_CALL(streambuf, xsputn(data, static_cast<std::streamsize>(n)))
.WillOnce(testing::Return(max_streamsize)); .WillOnce(testing::Return(max_streamsize));
data += n; data += n;
size -= static_cast<std::size_t>(n); size -= n;
} while (size != 0); } while (size != 0);
fmt::internal::write(os, buffer); fmt::internal::write(os, buffer);
} }
TEST(OStreamTest, Join) {
int v[3] = {1, 2, 3};
EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join(v, v + 3, ", ")));
}

View File

@ -6,7 +6,9 @@
// For the license information refer to format.h. // For the license information refer to format.h.
// Disable bogus MSVC warnings. // Disable bogus MSVC warnings.
#define _CRT_SECURE_NO_WARNINGS #ifdef _MSC_VER
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "posix-mock.h" #include "posix-mock.h"
#include "../src/posix.cc" #include "../src/posix.cc"
@ -21,7 +23,7 @@
# undef ERROR # undef ERROR
#endif #endif
#include "gmock/gmock.h" #include "gmock.h"
#include "gtest-extra.h" #include "gtest-extra.h"
#include "util.h" #include "util.h"
@ -131,7 +133,7 @@ int test::dup2(int fildes, int fildes2) {
} }
FILE *test::fdopen(int fildes, const char *mode) { FILE *test::fdopen(int fildes, const char *mode) {
EMULATE_EINTR(fdopen, 0); EMULATE_EINTR(fdopen, nullptr);
return ::FMT_POSIX(fdopen(fildes, mode)); return ::FMT_POSIX(fdopen(fildes, mode));
} }
@ -160,7 +162,7 @@ int test::pipe(int *pfds, unsigned psize, int textmode) {
#endif #endif
FILE *test::fopen(const char *filename, const char *mode) { FILE *test::fopen(const char *filename, const char *mode) {
EMULATE_EINTR(fopen, 0); EMULATE_EINTR(fopen, nullptr);
return ::fopen(filename, mode); return ::fopen(filename, mode);
} }
@ -193,7 +195,7 @@ int (test::fileno)(FILE *stream) {
# define EXPECT_EQ_POSIX(expected, actual) # define EXPECT_EQ_POSIX(expected, actual)
#endif #endif
void write_file(fmt::cstring_view filename, fmt::string_view content) { static void write_file(fmt::cstring_view filename, fmt::string_view content) {
fmt::buffered_file f(filename, "w"); fmt::buffered_file f(filename, "w");
f.print("{}", content); f.print("{}", content);
} }
@ -214,7 +216,7 @@ TEST(UtilTest, GetPageSize) {
TEST(FileTest, OpenRetry) { TEST(FileTest, OpenRetry) {
write_file("test", "there must be something here"); write_file("test", "there must be something here");
scoped_ptr<file> f; scoped_ptr<file> f{nullptr};
EXPECT_RETRY(f.reset(new file("test", file::RDONLY)), EXPECT_RETRY(f.reset(new file("test", file::RDONLY)),
open, "cannot open file test"); open, "cannot open file test");
#ifndef _WIN32 #ifndef _WIN32
@ -230,7 +232,7 @@ TEST(FileTest, CloseNoRetryInDtor) {
int saved_close_count = 0; int saved_close_count = 0;
EXPECT_WRITE(stderr, { EXPECT_WRITE(stderr, {
close_count = 1; close_count = 1;
f.reset(); f.reset(nullptr);
saved_close_count = close_count; saved_close_count = close_count;
close_count = 0; close_count = 0;
}, format_system_error(EINTR, "cannot close file") + "\n"); }, format_system_error(EINTR, "cannot close file") + "\n");
@ -383,7 +385,7 @@ TEST(FileTest, FdopenNoRetry) {
TEST(BufferedFileTest, OpenRetry) { TEST(BufferedFileTest, OpenRetry) {
write_file("test", "there must be something here"); write_file("test", "there must be something here");
scoped_ptr<buffered_file> f; scoped_ptr<buffered_file> f{nullptr};
EXPECT_RETRY(f.reset(new buffered_file("test", "r")), EXPECT_RETRY(f.reset(new buffered_file("test", "r")),
fopen, "cannot open file test"); fopen, "cannot open file test");
#ifndef _WIN32 #ifndef _WIN32
@ -400,7 +402,7 @@ TEST(BufferedFileTest, CloseNoRetryInDtor) {
int saved_fclose_count = 0; int saved_fclose_count = 0;
EXPECT_WRITE(stderr, { EXPECT_WRITE(stderr, {
fclose_count = 1; fclose_count = 1;
f.reset(); f.reset(nullptr);
saved_fclose_count = fclose_count; saved_fclose_count = fclose_count;
fclose_count = 0; fclose_count = 0;
}, format_system_error(EINTR, "cannot close file") + "\n"); }, format_system_error(EINTR, "cannot close file") + "\n");
@ -436,8 +438,9 @@ TEST(ScopedMock, Scope) {
ScopedMock<TestMock> mock; ScopedMock<TestMock> mock;
EXPECT_EQ(&mock, TestMock::instance); EXPECT_EQ(&mock, TestMock::instance);
TestMock &copy = mock; TestMock &copy = mock;
static_cast<void>(copy);
} }
EXPECT_EQ(0, TestMock::instance); EXPECT_EQ(nullptr, TestMock::instance);
} }
#ifdef FMT_LOCALE #ifdef FMT_LOCALE
@ -472,7 +475,13 @@ double _strtod_l(const char *nptr, char **endptr, _locale_t locale) {
# pragma warning(pop) # pragma warning(pop)
#endif #endif
LocaleType newlocale(int category_mask, const char *locale, LocaleType base) { #if defined(__THROW) && FMT_GCC_VERSION > 0 && FMT_GCC_VERSION <= 408
#define FMT_LOCALE_THROW __THROW
#else
#define FMT_LOCALE_THROW
#endif
LocaleType newlocale(int category_mask, const char *locale, LocaleType base) FMT_LOCALE_THROW {
return LocaleMock::instance->newlocale(category_mask, locale, base); return LocaleMock::instance->newlocale(category_mask, locale, base);
} }
@ -482,15 +491,17 @@ typedef int FreeLocaleResult;
typedef void FreeLocaleResult; typedef void FreeLocaleResult;
#endif #endif
FreeLocaleResult freelocale(LocaleType locale) { FreeLocaleResult freelocale(LocaleType locale) FMT_LOCALE_THROW {
LocaleMock::instance->freelocale(locale); LocaleMock::instance->freelocale(locale);
return FreeLocaleResult(); return FreeLocaleResult();
} }
double strtod_l(const char *nptr, char **endptr, LocaleType locale) { double strtod_l(const char *nptr, char **endptr, LocaleType locale) FMT_LOCALE_THROW {
return LocaleMock::instance->strtod_l(nptr, endptr, locale); return LocaleMock::instance->strtod_l(nptr, endptr, locale);
} }
#undef FMT_LOCALE_THROW
TEST(LocaleTest, LocaleMock) { TEST(LocaleTest, LocaleMock) {
ScopedMock<LocaleMock> mock; ScopedMock<LocaleMock> mock;
LocaleType locale = reinterpret_cast<LocaleType>(11); LocaleType locale = reinterpret_cast<LocaleType>(11);
@ -504,7 +515,7 @@ TEST(LocaleTest, Locale) {
#endif #endif
ScopedMock<LocaleMock> mock; ScopedMock<LocaleMock> mock;
LocaleType impl = reinterpret_cast<LocaleType>(42); LocaleType impl = reinterpret_cast<LocaleType>(42);
EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), 0)) EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), nullptr))
.WillOnce(Return(impl)); .WillOnce(Return(impl));
EXPECT_CALL(mock, freelocale(impl)); EXPECT_CALL(mock, freelocale(impl));
fmt::Locale locale; fmt::Locale locale;

View File

@ -23,12 +23,12 @@ using fmt::file;
using testing::internal::scoped_ptr; using testing::internal::scoped_ptr;
// Checks if the file is open by reading one character from it. // Checks if the file is open by reading one character from it.
bool isopen(int fd) { static bool isopen(int fd) {
char buffer; char buffer;
return FMT_POSIX(read(fd, &buffer, 1)) == 1; return FMT_POSIX(read(fd, &buffer, 1)) == 1;
} }
bool isclosed(int fd) { static bool isclosed(int fd) {
char buffer; char buffer;
std::streamsize result = 0; std::streamsize result = 0;
SUPPRESS_ASSERT(result = FMT_POSIX(read(fd, &buffer, 1))); SUPPRESS_ASSERT(result = FMT_POSIX(read(fd, &buffer, 1)));
@ -36,7 +36,7 @@ bool isclosed(int fd) {
} }
// Opens a file for reading. // Opens a file for reading.
file open_file() { static file open_file() {
file read_end, write_end; file read_end, write_end;
file::pipe(read_end, write_end); file::pipe(read_end, write_end);
write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT)); write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT));
@ -45,7 +45,7 @@ file open_file() {
} }
// Attempts to write a string to a file. // Attempts to write a string to a file.
void write(file &f, fmt::string_view s) { static void write(file &f, fmt::string_view s) {
std::size_t num_chars_left = s.size(); std::size_t num_chars_left = s.size();
const char *ptr = s.data(); const char *ptr = s.data();
do { do {
@ -53,32 +53,32 @@ void write(file &f, fmt::string_view s) {
ptr += count; ptr += count;
// We can't write more than size_t bytes since num_chars_left // We can't write more than size_t bytes since num_chars_left
// has type size_t. // has type size_t.
num_chars_left -= static_cast<std::size_t>(count); num_chars_left -= count;
} while (num_chars_left != 0); } while (num_chars_left != 0);
} }
TEST(BufferedFileTest, DefaultCtor) { TEST(BufferedFileTest, DefaultCtor) {
buffered_file f; buffered_file f;
EXPECT_TRUE(f.get() == 0); EXPECT_TRUE(f.get() == nullptr);
} }
TEST(BufferedFileTest, MoveCtor) { TEST(BufferedFileTest, MoveCtor) {
buffered_file bf = open_buffered_file(); buffered_file bf = open_buffered_file();
FILE *fp = bf.get(); FILE *fp = bf.get();
EXPECT_TRUE(fp != 0); EXPECT_TRUE(fp != nullptr);
buffered_file bf2(std::move(bf)); buffered_file bf2(std::move(bf));
EXPECT_EQ(fp, bf2.get()); EXPECT_EQ(fp, bf2.get());
EXPECT_TRUE(bf.get() == 0); EXPECT_TRUE(bf.get() == nullptr);
} }
TEST(BufferedFileTest, MoveAssignment) { TEST(BufferedFileTest, MoveAssignment) {
buffered_file bf = open_buffered_file(); buffered_file bf = open_buffered_file();
FILE *fp = bf.get(); FILE *fp = bf.get();
EXPECT_TRUE(fp != 0); EXPECT_TRUE(fp != nullptr);
buffered_file bf2; buffered_file bf2;
bf2 = std::move(bf); bf2 = std::move(bf);
EXPECT_EQ(fp, bf2.get()); EXPECT_EQ(fp, bf2.get());
EXPECT_TRUE(bf.get() == 0); EXPECT_TRUE(bf.get() == nullptr);
} }
TEST(BufferedFileTest, MoveAssignmentClosesFile) { TEST(BufferedFileTest, MoveAssignmentClosesFile) {
@ -90,13 +90,13 @@ TEST(BufferedFileTest, MoveAssignmentClosesFile) {
} }
TEST(BufferedFileTest, MoveFromTemporaryInCtor) { TEST(BufferedFileTest, MoveFromTemporaryInCtor) {
FILE *fp = 0; FILE *fp = nullptr;
buffered_file f(open_buffered_file(&fp)); buffered_file f(open_buffered_file(&fp));
EXPECT_EQ(fp, f.get()); EXPECT_EQ(fp, f.get());
} }
TEST(BufferedFileTest, MoveFromTemporaryInAssignment) { TEST(BufferedFileTest, MoveFromTemporaryInAssignment) {
FILE *fp = 0; FILE *fp = nullptr;
buffered_file f; buffered_file f;
f = open_buffered_file(&fp); f = open_buffered_file(&fp);
EXPECT_EQ(fp, f.get()); EXPECT_EQ(fp, f.get());
@ -126,7 +126,7 @@ TEST(BufferedFileTest, CloseErrorInDtor) {
// output in EXPECT_STDERR and the second close will break output // output in EXPECT_STDERR and the second close will break output
// redirection. // redirection.
FMT_POSIX(close(f->fileno())); FMT_POSIX(close(f->fileno()));
SUPPRESS_ASSERT(f.reset()); SUPPRESS_ASSERT(f.reset(nullptr));
}, format_system_error(EBADF, "cannot close file") + "\n"); }, format_system_error(EBADF, "cannot close file") + "\n");
} }
@ -134,7 +134,7 @@ TEST(BufferedFileTest, Close) {
buffered_file f = open_buffered_file(); buffered_file f = open_buffered_file();
int fd = f.fileno(); int fd = f.fileno();
f.close(); f.close();
EXPECT_TRUE(f.get() == 0); EXPECT_TRUE(f.get() == nullptr);
EXPECT_TRUE(isclosed(fd)); EXPECT_TRUE(isclosed(fd));
} }
@ -142,7 +142,7 @@ TEST(BufferedFileTest, CloseError) {
buffered_file f = open_buffered_file(); buffered_file f = open_buffered_file();
FMT_POSIX(close(f.fileno())); FMT_POSIX(close(f.fileno()));
EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file"); EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
EXPECT_TRUE(f.get() == 0); EXPECT_TRUE(f.get() == nullptr);
} }
TEST(BufferedFileTest, Fileno) { TEST(BufferedFileTest, Fileno) {
@ -153,7 +153,7 @@ TEST(BufferedFileTest, Fileno) {
EXPECT_DEATH_IF_SUPPORTED({ EXPECT_DEATH_IF_SUPPORTED({
try { try {
f.fileno(); f.fileno();
} catch (fmt::system_error) { } catch (const fmt::system_error&) {
std::exit(1); std::exit(1);
} }
}, ""); }, "");
@ -209,7 +209,7 @@ TEST(FileTest, MoveAssignmentClosesFile) {
EXPECT_TRUE(isclosed(old_fd)); EXPECT_TRUE(isclosed(old_fd));
} }
file OpenBufferedFile(int &fd) { static file OpenBufferedFile(int &fd) {
file f = open_file(); file f = open_file();
fd = f.descriptor(); fd = f.descriptor();
return f; return f;
@ -253,7 +253,7 @@ TEST(FileTest, CloseErrorInDtor) {
// output in EXPECT_STDERR and the second close will break output // output in EXPECT_STDERR and the second close will break output
// redirection. // redirection.
FMT_POSIX(close(f->descriptor())); FMT_POSIX(close(f->descriptor()));
SUPPRESS_ASSERT(f.reset()); SUPPRESS_ASSERT(f.reset(nullptr));
}, format_system_error(EBADF, "cannot close file") + "\n"); }, format_system_error(EBADF, "cannot close file") + "\n");
} }

View File

@ -20,13 +20,13 @@ using fmt::format_error;
const unsigned BIG_NUM = INT_MAX + 1u; const unsigned BIG_NUM = INT_MAX + 1u;
// Makes format string argument positional. // Makes format string argument positional.
std::string make_positional(fmt::string_view format) { static std::string make_positional(fmt::string_view format) {
std::string s(format.data(), format.size()); std::string s(format.data(), format.size());
s.replace(s.find('%'), 1, "%1$"); s.replace(s.find('%'), 1, "%1$");
return s; return s;
} }
std::wstring make_positional(fmt::wstring_view format) { static std::wstring make_positional(fmt::wstring_view format) {
std::wstring s(format.data(), format.size()); std::wstring s(format.data(), format.size());
s.replace(s.find(L'%'), 1, L"%1$"); s.replace(s.find(L'%'), 1, L"%1$");
return s; return s;
@ -410,7 +410,7 @@ TEST(PrintfTest, Inf) {
double inf = std::numeric_limits<double>::infinity(); double inf = std::numeric_limits<double>::infinity();
for (const char* type = "fega"; *type; ++type) { for (const char* type = "fega"; *type; ++type) {
EXPECT_PRINTF("inf", fmt::format("%{}", *type), inf); EXPECT_PRINTF("inf", fmt::format("%{}", *type), inf);
char upper = std::toupper(*type); char upper = static_cast<char>(std::toupper(*type));
EXPECT_PRINTF("INF", fmt::format("%{}", upper), inf); EXPECT_PRINTF("INF", fmt::format("%{}", upper), inf);
} }
} }
@ -426,11 +426,11 @@ TEST(PrintfTest, Char) {
TEST(PrintfTest, String) { TEST(PrintfTest, String) {
EXPECT_PRINTF("abc", "%s", "abc"); EXPECT_PRINTF("abc", "%s", "abc");
const char *null_str = 0; const char *null_str = nullptr;
EXPECT_PRINTF("(null)", "%s", null_str); EXPECT_PRINTF("(null)", "%s", null_str);
EXPECT_PRINTF(" (null)", "%10s", null_str); EXPECT_PRINTF(" (null)", "%10s", null_str);
EXPECT_PRINTF(L"abc", L"%s", L"abc"); EXPECT_PRINTF(L"abc", L"%s", L"abc");
const wchar_t *null_wstr = 0; const wchar_t *null_wstr = nullptr;
EXPECT_PRINTF(L"(null)", L"%s", null_wstr); EXPECT_PRINTF(L"(null)", L"%s", null_wstr);
EXPECT_PRINTF(L" (null)", L"%10s", null_wstr); EXPECT_PRINTF(L" (null)", L"%10s", null_wstr);
} }
@ -439,22 +439,22 @@ TEST(PrintfTest, Pointer) {
int n; int n;
void *p = &n; void *p = &n;
EXPECT_PRINTF(fmt::format("{}", p), "%p", p); EXPECT_PRINTF(fmt::format("{}", p), "%p", p);
p = 0; p = nullptr;
EXPECT_PRINTF("(nil)", "%p", p); EXPECT_PRINTF("(nil)", "%p", p);
EXPECT_PRINTF(" (nil)", "%10p", p); EXPECT_PRINTF(" (nil)", "%10p", p);
const char *s = "test"; const char *s = "test";
EXPECT_PRINTF(fmt::format("{:p}", s), "%p", s); EXPECT_PRINTF(fmt::format("{:p}", s), "%p", s);
const char *null_str = 0; const char *null_str = nullptr;
EXPECT_PRINTF("(nil)", "%p", null_str); EXPECT_PRINTF("(nil)", "%p", null_str);
p = &n; p = &n;
EXPECT_PRINTF(fmt::format(L"{}", p), L"%p", p); EXPECT_PRINTF(fmt::format(L"{}", p), L"%p", p);
p = 0; p = nullptr;
EXPECT_PRINTF(L"(nil)", L"%p", p); EXPECT_PRINTF(L"(nil)", L"%p", p);
EXPECT_PRINTF(L" (nil)", L"%10p", p); EXPECT_PRINTF(L" (nil)", L"%10p", p);
const wchar_t *w = L"test"; const wchar_t *w = L"test";
EXPECT_PRINTF(fmt::format(L"{:p}", w), L"%p", w); EXPECT_PRINTF(fmt::format(L"{:p}", w), L"%p", w);
const wchar_t *null_wstr = 0; const wchar_t *null_wstr = nullptr;
EXPECT_PRINTF(L"(nil)", L"%p", null_wstr); EXPECT_PRINTF(L"(nil)", L"%p", null_wstr);
} }

View File

@ -11,7 +11,7 @@
#include "fmt/ranges.h" #include "fmt/ranges.h"
#include "gtest/gtest.h" #include "gtest.h"
#include <vector> #include <vector>
#include <array> #include <array>
@ -30,7 +30,6 @@ TEST(RangesTest, FormatVector2) {
EXPECT_EQ("{{1, 2}, {3, 5}, {7, 11}}", ivf); EXPECT_EQ("{{1, 2}, {3, 5}, {7, 11}}", ivf);
} }
#if FMT_USE_INTEGER_SEQUENCE
TEST(RangesTest, FormatMap) { TEST(RangesTest, FormatMap) {
std::map<std::string, int32_t> simap{{"one", 1}, {"two", 2}}; std::map<std::string, int32_t> simap{{"one", 1}, {"two", 2}};
EXPECT_EQ("{(one, 1), (two, 2)}", fmt::format("{}", simap)); EXPECT_EQ("{(one, 1), (two, 2)}", fmt::format("{}", simap));
@ -87,4 +86,3 @@ TEST(RangesTest, FormatStruct) {
#endif // (__cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG > #endif // (__cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >
// 201402L && _MSC_VER >= 1910) // 201402L && _MSC_VER >= 1910)
#endif // FMT_USE_INTEGER_SEQUENCE

View File

@ -6,7 +6,7 @@
// For the license information refer to format.h. // For the license information refer to format.h.
#include <cstdlib> #include <cstdlib>
#include <gtest/gtest.h> #include "gtest.h"
#ifdef _WIN32 #ifdef _WIN32
# include <windows.h> # include <windows.h>

View File

@ -9,7 +9,7 @@
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#endif #endif
#include "gmock/gmock.h" #include "gmock.h"
#include "fmt/time.h" #include "fmt/time.h"
TEST(TimeTest, Format) { TEST(TimeTest, Format) {
@ -26,7 +26,7 @@ TEST(TimeTest, GrowBuffer) {
for (int i = 0; i < 30; ++i) for (int i = 0; i < 30; ++i)
s += "%c"; s += "%c";
s += "}\n"; s += "}\n";
std::time_t t = std::time(0); std::time_t t = std::time(nullptr);
fmt::format(s, *std::localtime(&t)); fmt::format(s, *std::localtime(&t));
} }
@ -34,7 +34,7 @@ TEST(TimeTest, EmptyResult) {
EXPECT_EQ("", fmt::format("{}", std::tm())); EXPECT_EQ("", fmt::format("{}", std::tm()));
} }
bool EqualTime(const std::tm &lhs, const std::tm &rhs) { static bool EqualTime(const std::tm &lhs, const std::tm &rhs) {
return lhs.tm_sec == rhs.tm_sec && return lhs.tm_sec == rhs.tm_sec &&
lhs.tm_min == rhs.tm_min && lhs.tm_min == rhs.tm_min &&
lhs.tm_hour == rhs.tm_hour && lhs.tm_hour == rhs.tm_hour &&
@ -47,13 +47,13 @@ bool EqualTime(const std::tm &lhs, const std::tm &rhs) {
} }
TEST(TimeTest, LocalTime) { TEST(TimeTest, LocalTime) {
std::time_t t = std::time(0); std::time_t t = std::time(nullptr);
std::tm tm = *std::localtime(&t); std::tm tm = *std::localtime(&t);
EXPECT_TRUE(EqualTime(tm, fmt::localtime(t))); EXPECT_TRUE(EqualTime(tm, fmt::localtime(t)));
} }
TEST(TimeTest, GMTime) { TEST(TimeTest, GMTime) {
std::time_t t = std::time(0); std::time_t t = std::time(nullptr);
std::tm tm = *std::gmtime(&t); std::tm tm = *std::gmtime(&t);
EXPECT_TRUE(EqualTime(tm, fmt::gmtime(t))); EXPECT_TRUE(EqualTime(tm, fmt::gmtime(t)));
} }

View File

@ -17,7 +17,7 @@
# include <type_traits> # include <type_traits>
#endif #endif
#include "gmock/gmock.h" #include "gmock.h"
#include "gtest-extra.h" #include "gtest-extra.h"
#include "mock-allocator.h" #include "mock-allocator.h"
#include "util.h" #include "util.h"
@ -71,8 +71,8 @@ struct formatter<Test, Char> {
}; };
FMT_END_NAMESPACE FMT_END_NAMESPACE
void CheckForwarding( static void CheckForwarding(
MockAllocator<int> &alloc, AllocatorRef< MockAllocator<int> > &ref) { MockAllocator<int> &alloc, AllocatorRef<MockAllocator<int>> &ref) {
int mem; int mem;
// Check if value_type is properly defined. // Check if value_type is properly defined.
AllocatorRef< MockAllocator<int> >::value_type *ptr = &mem; AllocatorRef< MockAllocator<int> >::value_type *ptr = &mem;
@ -92,7 +92,7 @@ TEST(AllocatorTest, AllocatorRef) {
TestAllocatorRef ref2(ref); TestAllocatorRef ref2(ref);
CheckForwarding(alloc, ref2); CheckForwarding(alloc, ref2);
TestAllocatorRef ref3; TestAllocatorRef ref3;
EXPECT_EQ(0, ref3.get()); EXPECT_EQ(nullptr, ref3.get());
ref3 = ref; ref3 = ref;
CheckForwarding(alloc, ref3); CheckForwarding(alloc, ref3);
} }
@ -112,7 +112,7 @@ TEST(BufferTest, Nonmoveable) {
// A test buffer with a dummy grow method. // A test buffer with a dummy grow method.
template <typename T> template <typename T>
struct TestBuffer : basic_buffer<T> { struct TestBuffer : basic_buffer<T> {
void grow(std::size_t capacity) { this->set(0, capacity); } void grow(std::size_t capacity) { this->set(nullptr, capacity); }
}; };
template <typename T> template <typename T>
@ -132,23 +132,23 @@ struct MockBuffer : basic_buffer<T> {
TEST(BufferTest, Ctor) { TEST(BufferTest, Ctor) {
{ {
MockBuffer<int> buffer; MockBuffer<int> buffer;
EXPECT_EQ(0, &buffer[0]); EXPECT_EQ(nullptr, &buffer[0]);
EXPECT_EQ(0u, buffer.size()); EXPECT_EQ(static_cast<size_t>(0), buffer.size());
EXPECT_EQ(0u, buffer.capacity()); EXPECT_EQ(static_cast<size_t>(0), buffer.capacity());
} }
{ {
int dummy; int dummy;
MockBuffer<int> buffer(&dummy); MockBuffer<int> buffer(&dummy);
EXPECT_EQ(&dummy, &buffer[0]); EXPECT_EQ(&dummy, &buffer[0]);
EXPECT_EQ(0u, buffer.size()); EXPECT_EQ(static_cast<size_t>(0), buffer.size());
EXPECT_EQ(0u, buffer.capacity()); EXPECT_EQ(static_cast<size_t>(0), buffer.capacity());
} }
{ {
int dummy; int dummy;
std::size_t capacity = std::numeric_limits<std::size_t>::max(); std::size_t capacity = std::numeric_limits<std::size_t>::max();
MockBuffer<int> buffer(&dummy, capacity); MockBuffer<int> buffer(&dummy, capacity);
EXPECT_EQ(&dummy, &buffer[0]); EXPECT_EQ(&dummy, &buffer[0]);
EXPECT_EQ(0u, buffer.size()); EXPECT_EQ(static_cast<size_t>(0), buffer.size());
EXPECT_EQ(capacity, buffer.capacity()); EXPECT_EQ(capacity, buffer.capacity());
} }
} }
@ -201,7 +201,7 @@ TEST(BufferTest, Clear) {
TestBuffer<char> buffer; TestBuffer<char> buffer;
buffer.resize(20); buffer.resize(20);
buffer.resize(0); buffer.resize(0);
EXPECT_EQ(0u, buffer.size()); EXPECT_EQ(static_cast<size_t>(0), buffer.size());
EXPECT_EQ(20u, buffer.capacity()); EXPECT_EQ(20u, buffer.capacity());
} }
@ -231,7 +231,7 @@ TEST(BufferTest, AppendAllocatesEnoughStorage) {
TEST(MemoryBufferTest, Ctor) { TEST(MemoryBufferTest, Ctor) {
basic_memory_buffer<char, 123> buffer; basic_memory_buffer<char, 123> buffer;
EXPECT_EQ(0u, buffer.size()); EXPECT_EQ(static_cast<size_t>(0), buffer.size());
EXPECT_EQ(123u, buffer.capacity()); EXPECT_EQ(123u, buffer.capacity());
} }
@ -239,7 +239,7 @@ TEST(MemoryBufferTest, Ctor) {
typedef AllocatorRef< std::allocator<char> > TestAllocator; typedef AllocatorRef< std::allocator<char> > TestAllocator;
void check_move_buffer(const char *str, static void check_move_buffer(const char *str,
basic_memory_buffer<char, 5, TestAllocator> &buffer) { basic_memory_buffer<char, 5, TestAllocator> &buffer) {
std::allocator<char> *alloc = buffer.get_allocator().get(); std::allocator<char> *alloc = buffer.get_allocator().get();
basic_memory_buffer<char, 5, TestAllocator> buffer2(std::move(buffer)); basic_memory_buffer<char, 5, TestAllocator> buffer2(std::move(buffer));
@ -248,7 +248,7 @@ void check_move_buffer(const char *str,
EXPECT_EQ(str, std::string(&buffer2[0], buffer2.size())); EXPECT_EQ(str, std::string(&buffer2[0], buffer2.size()));
EXPECT_EQ(5u, buffer2.capacity()); EXPECT_EQ(5u, buffer2.capacity());
// Move should transfer allocator. // Move should transfer allocator.
EXPECT_EQ(0, buffer.get_allocator().get()); EXPECT_EQ(nullptr, buffer.get_allocator().get());
EXPECT_EQ(alloc, buffer2.get_allocator().get()); EXPECT_EQ(alloc, buffer2.get_allocator().get());
} }
@ -273,7 +273,7 @@ TEST(MemoryBufferTest, MoveCtor) {
EXPECT_GT(buffer2.capacity(), 5u); EXPECT_GT(buffer2.capacity(), 5u);
} }
void check_move_assign_buffer( static void check_move_assign_buffer(
const char *str, basic_memory_buffer<char, 5> &buffer) { const char *str, basic_memory_buffer<char, 5> &buffer) {
basic_memory_buffer<char, 5> buffer2; basic_memory_buffer<char, 5> buffer2;
buffer2 = std::move(buffer); buffer2 = std::move(buffer);
@ -335,7 +335,7 @@ TEST(MemoryBufferTest, Grow) {
TEST(MemoryBufferTest, Allocator) { TEST(MemoryBufferTest, Allocator) {
typedef AllocatorRef< MockAllocator<char> > TestAllocator; typedef AllocatorRef< MockAllocator<char> > TestAllocator;
basic_memory_buffer<char, 10, TestAllocator> buffer; basic_memory_buffer<char, 10, TestAllocator> buffer;
EXPECT_EQ(0, buffer.get_allocator().get()); EXPECT_EQ(nullptr, buffer.get_allocator().get());
StrictMock< MockAllocator<char> > alloc; StrictMock< MockAllocator<char> > alloc;
char mem; char mem;
{ {
@ -376,7 +376,7 @@ TEST(MemoryBufferTest, ExceptionInDeallocate) {
TEST(FixedBufferTest, Ctor) { TEST(FixedBufferTest, Ctor) {
char array[10] = "garbage"; char array[10] = "garbage";
fmt::basic_fixed_buffer<char> buffer(array, sizeof(array)); fmt::basic_fixed_buffer<char> buffer(array, sizeof(array));
EXPECT_EQ(0u, buffer.size()); EXPECT_EQ(static_cast<size_t>(0), buffer.size());
EXPECT_EQ(10u, buffer.capacity()); EXPECT_EQ(10u, buffer.capacity());
EXPECT_EQ(array, buffer.data()); EXPECT_EQ(array, buffer.data());
} }
@ -384,7 +384,7 @@ TEST(FixedBufferTest, Ctor) {
TEST(FixedBufferTest, CompileTimeSizeCtor) { TEST(FixedBufferTest, CompileTimeSizeCtor) {
char array[10] = "garbage"; char array[10] = "garbage";
fmt::basic_fixed_buffer<char> buffer(array); fmt::basic_fixed_buffer<char> buffer(array);
EXPECT_EQ(0u, buffer.size()); EXPECT_EQ(static_cast<size_t>(0), buffer.size());
EXPECT_EQ(10u, buffer.capacity()); EXPECT_EQ(10u, buffer.capacity());
EXPECT_EQ(array, buffer.data()); EXPECT_EQ(array, buffer.data());
} }
@ -402,7 +402,7 @@ struct uint32_pair {
TEST(UtilTest, BitCast) { TEST(UtilTest, BitCast) {
auto s = fmt::internal::bit_cast<uint32_pair>(uint64_t{42}); auto s = fmt::internal::bit_cast<uint32_pair>(uint64_t{42});
EXPECT_EQ(fmt::internal::bit_cast<uint64_t>(s), 42u); EXPECT_EQ(fmt::internal::bit_cast<uint64_t>(s), 42ull);
s = fmt::internal::bit_cast<uint32_pair>(uint64_t(~0ull)); s = fmt::internal::bit_cast<uint32_pair>(uint64_t(~0ull));
EXPECT_EQ(fmt::internal::bit_cast<uint64_t>(s), ~0ull); EXPECT_EQ(fmt::internal::bit_cast<uint64_t>(s), ~0ull);
} }
@ -439,7 +439,7 @@ struct custom_context {
const char *format(const T &, custom_context& ctx) { const char *format(const T &, custom_context& ctx) {
ctx.called = true; ctx.called = true;
return 0; return nullptr;
} }
}; };
}; };
@ -583,8 +583,8 @@ TEST(UtilTest, WStringArg) {
} }
TEST(UtilTest, PointerArg) { TEST(UtilTest, PointerArg) {
void *p = 0; void *p = nullptr;
const void *cp = 0; const void *cp = nullptr;
CHECK_ARG_(char, cp, p); CHECK_ARG_(char, cp, p);
CHECK_ARG_(wchar_t, cp, p); CHECK_ARG_(wchar_t, cp, p);
CHECK_ARG(cp, ); CHECK_ARG(cp, );
@ -765,14 +765,14 @@ TEST(UtilTest, FormatSystemError) {
try { try {
std::allocator<char> alloc; std::allocator<char> alloc;
alloc.deallocate(alloc.allocate(max_size), max_size); alloc.deallocate(alloc.allocate(max_size), max_size);
} catch (std::bad_alloc) { } catch (const std::bad_alloc&) {
throws_on_alloc = true; throws_on_alloc = true;
} }
if (!throws_on_alloc) { if (!throws_on_alloc) {
fmt::print("warning: std::allocator allocates {} chars", max_size); fmt::print("warning: std::allocator allocates {} chars", max_size);
return; return;
} }
fmt::format_system_error(message, EDOM, fmt::string_view(0, max_size)); fmt::format_system_error(message, EDOM, fmt::string_view(nullptr, max_size));
EXPECT_EQ(fmt::format("error {}", EDOM), to_string(message)); EXPECT_EQ(fmt::format("error {}", EDOM), to_string(message));
} }
@ -822,7 +822,8 @@ TEST(UtilTest, FormatLongWindowsError) {
const int provisioning_not_allowed = 0x80284013L /*TBS_E_PROVISIONING_NOT_ALLOWED*/; const int provisioning_not_allowed = 0x80284013L /*TBS_E_PROVISIONING_NOT_ALLOWED*/;
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
provisioning_not_allowed, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), static_cast<DWORD>(provisioning_not_allowed),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&message), 0, 0) == 0) { reinterpret_cast<LPWSTR>(&message), 0, 0) == 0) {
return; return;
} }
@ -867,7 +868,7 @@ TEST(UtilTest, IsEnumConvertibleToInt) {
#endif #endif
TEST(UtilTest, ParseNonnegativeInt) { TEST(UtilTest, ParseNonnegativeInt) {
if (std::numeric_limits<int>::max() != (1 << 31)) { if (std::numeric_limits<int>::max() != static_cast<int>(static_cast<unsigned>(1) << 31)) {
fmt::print("Skipping parse_nonnegative_int test\n"); fmt::print("Skipping parse_nonnegative_int test\n");
return; return;
} }
@ -881,17 +882,52 @@ TEST(UtilTest, ParseNonnegativeInt) {
fmt::format_error, "number is too big"); fmt::format_error, "number is too big");
} }
TEST(UtilTest, FPSubtract) { template <bool is_iec559>
auto r = fp(123, 1) - fp(102, 1); void test_construct_from_double() {
EXPECT_EQ(r.f, 21u); fmt::print("warning: double is not IEC559, skipping FP tests\n");
EXPECT_EQ(r.e, 1);
} }
TEST(UtilTest, FPMultiply) { template <>
auto r = fp(123ULL << 32, 4) * fp(56ULL << 32, 7); void test_construct_from_double<true>() {
EXPECT_EQ(r.f, 123u * 56u); auto v = fp(1.23);
EXPECT_EQ(r.e, 4 + 7 + 64); EXPECT_EQ(v.f, 0x13ae147ae147aeu);
r = fp(123ULL << 32, 4) * fp(567ULL << 31, 8); EXPECT_EQ(v.e, -52);
EXPECT_EQ(r.f, (123 * 567 + 1u) / 2); }
EXPECT_EQ(r.e, 4 + 8 + 64);
TEST(FPTest, ConstructFromDouble) {
test_construct_from_double<std::numeric_limits<double>::is_iec559>();
}
TEST(FPTest, Normalize) {
auto v = fp(0xbeef, 42);
v.normalize();
EXPECT_EQ(0xbeef000000000000, v.f);
EXPECT_EQ(-6, v.e);
}
TEST(FPTest, Subtract) {
auto v = fp(123, 1) - fp(102, 1);
EXPECT_EQ(v.f, 21u);
EXPECT_EQ(v.e, 1);
}
TEST(FPTest, Multiply) {
auto v = fp(123ULL << 32, 4) * fp(56ULL << 32, 7);
EXPECT_EQ(v.f, 123u * 56u);
EXPECT_EQ(v.e, 4 + 7 + 64);
v = fp(123ULL << 32, 4) * fp(567ULL << 31, 8);
EXPECT_EQ(v.f, (123 * 567 + 1u) / 2);
EXPECT_EQ(v.e, 4 + 8 + 64);
}
TEST(FPTest, GetCachedPower) {
typedef std::numeric_limits<double> limits;
for (auto exp = limits::min_exponent; exp <= limits::max_exponent; ++exp) {
int dec_exp = 0;
auto fp = fmt::internal::get_cached_power(exp, dec_exp);
EXPECT_LE(exp, fp.e);
int dec_exp_step = 8;
EXPECT_LE(fp.e, exp + dec_exp_step * log2(10));
EXPECT_DOUBLE_EQ(pow(10, dec_exp), ldexp(fp.f, fp.e));
}
} }

View File

@ -35,7 +35,7 @@ std::string get_system_error(int error_code);
extern const char *const FILE_CONTENT; extern const char *const FILE_CONTENT;
// Opens a buffered file for reading. // Opens a buffered file for reading.
fmt::buffered_file open_buffered_file(FILE **fp = 0); fmt::buffered_file open_buffered_file(FILE **fp = nullptr);
inline FILE *safe_fopen(const char *filename, const char *mode) { inline FILE *safe_fopen(const char *filename, const char *mode) {
#if defined(_WIN32) && !defined(__MINGW32__) #if defined(_WIN32) && !defined(__MINGW32__)