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

View File

@ -1,6 +1,6 @@
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)
# or if it is the master project.
@ -28,12 +28,12 @@ if (NOT CMAKE_BUILD_TYPE)
endif ()
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.
option(FMT_DOC "Generate the doc target." ${MASTER_PROJECT})
option(FMT_INSTALL "Generate the install 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)
@ -58,9 +58,62 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_SOURCE_DIR}/support/cmake")
include(cxx14)
include(CheckCXXCompilerFlag)
if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wshadow -pedantic)
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
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 ()
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 ALIAS fmt)
# Starting with CMake 3.1 the CXX_STANDARD property can be used instead.
# Don't export -std since it may break projects that use other standards.
target_compile_options(fmt PRIVATE ${CPP14_FLAG})
if (FMT_WERROR)
target_compile_options(fmt PRIVATE ${WERROR_FLAG})
endif ()
if (FMT_PEDANTIC)
target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
@ -130,17 +183,14 @@ if (BUILD_SHARED_LIBS)
target_compile_definitions(fmt PRIVATE FMT_EXPORT INTERFACE FMT_SHARED)
endif ()
# Additionally define a header-only library when CMake is new enough.
if (CMAKE_VERSION VERSION_GREATER 3.1.0 OR CMAKE_VERSION VERSION_EQUAL 3.1.0)
add_library(fmt-header-only INTERFACE)
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
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
endif ()
target_include_directories(fmt-header-only INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
# Install targets.
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
templates and type traits, and dropped ``FMT_VARIADIC_*`` emulation macros.
@ -24,7 +24,7 @@
std::string s = format(fmt("{:d}"), "foo");
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
@ -41,11 +41,11 @@
.. code:: c++
struct S {};
struct Answer {};
namespace fmt {
template <>
struct formatter<S> {
struct formatter<Answer> {
constexpr auto parse(parse_context& ctx) {
auto it = ctx.begin();
spec = *it;
@ -55,7 +55,7 @@
}
template <typename FormatContext>
auto format(S, FormatContext& ctx) {
auto format(Answer, FormatContext& ctx) {
return spec == 's' ?
format_to(ctx.begin(), "{}", "fourty-two") :
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
<https://godbolt.org/g/ywhrPp>`_)::
<https://godbolt.org/g/2jQ1Dv>`__)::
...
<source>:12:45: error: expression '<throw-expression>' is not a constant expression
@ -192,7 +192,7 @@
fmt::print("{}", std::experimental::string_view("foo"));
Thanks `@virgiliofornazin (Virgilio Alexandre Fornazin)
<https://github.com/virgiliofornazin>`_.
<https://github.com/virgiliofornazin>`__.
* Allowed mixing named and automatic arguments:
@ -221,7 +221,7 @@
* 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>`_).
* Removed unnecessary ``fmt/`` prefix in includes
@ -262,7 +262,7 @@
`#656 <https://github.com/fmtlib/fmt/pull/656>`_,
`#679 <https://github.com/fmtlib/fmt/pull/679>`_,
`#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>`_,
`#717 <https://github.com/fmtlib/fmt/pull/717>`_,
`#720 <https://github.com/fmtlib/fmt/pull/720>`_,
@ -513,7 +513,6 @@
(`#494 <https://github.com/fmtlib/fmt/pull/494>`_,
`#499 <https://github.com/fmtlib/fmt/pull/499>`_,
`#483 <https://github.com/fmtlib/fmt/pull/483>`_,
`#519 <https://github.com/fmtlib/fmt/pull/519>`_,
`#485 <https://github.com/fmtlib/fmt/pull/485>`_,
`#482 <https://github.com/fmtlib/fmt/pull/482>`_,
`#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 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):
"Install package using pip."
@ -56,7 +56,7 @@ def create_build_env(dirname='virtualenv'):
pip_install('sphinx-doc/sphinx', '12b83372ac9316e8cbe86e7fed889296a4cc29ee',
min_version='1.4.1.dev20160531')
pip_install('michaeljones/breathe',
'6b1c5bb7a1866f15fc328b8716258354b10c1daa',
'129222318f7c8f865d2631e7da7b033567e7f56a',
min_version='4.2.0')
def build_docs(version='dev', **kwargs):

View File

@ -16,7 +16,7 @@
#include <type_traits>
// The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 50000
#define FMT_VERSION 50100
#ifdef __has_feature
# define FMT_HAS_FEATURE(x) __has_feature(x)
@ -30,6 +30,12 @@
# define FMT_HAS_INCLUDE(x) 0
#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__)
# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
#else
@ -95,6 +101,12 @@
# define FMT_USE_NULLPTR 0
#endif
#if FMT_HAS_CPP_ATTRIBUTE(noreturn)
# define FMT_NORETURN [[noreturn]]
#else
# define FMT_NORETURN /*noreturn*/
#endif
// Check if exceptions are disabled.
#if defined(__GNUC__) && !defined(__EXCEPTIONS)
# define FMT_EXCEPTIONS 0
@ -218,7 +230,7 @@ class basic_string_view {
#else
struct type {
const char *data() const { return FMT_NULL; }
size_t size() const { return 0; };
size_t size() const { return 0; }
};
#endif
@ -428,7 +440,7 @@ template <typename T, typename Char>
struct is_named_arg<named_arg<T, Char>> : std::true_type {};
enum type {
none_type, name_arg_type,
none_type, named_arg_type,
// Integer types should go first,
int_type, uint_type, long_long_type, ulong_long_type, bool_type, char_type,
last_integer_type = char_type,
@ -438,12 +450,12 @@ enum type {
};
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;
}
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;
}
@ -550,11 +562,17 @@ FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value);
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(int_type, short, int)
FMT_MAKE_VALUE(uint_type, unsigned short, unsigned)
FMT_MAKE_VALUE(int_type, int, int)
FMT_MAKE_VALUE(uint_type, unsigned, unsigned)
FMT_MAKE_VALUE_SAME(int_type, int)
FMT_MAKE_VALUE_SAME(uint_type, unsigned)
// 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.
@ -568,8 +586,8 @@ FMT_MAKE_VALUE(
(sizeof(unsigned long) == sizeof(unsigned) ? uint_type : ulong_long_type),
unsigned long, ulong_type)
FMT_MAKE_VALUE(long_long_type, long long, long long)
FMT_MAKE_VALUE(ulong_long_type, unsigned long long, unsigned long long)
FMT_MAKE_VALUE_SAME(long_long_type, long long)
FMT_MAKE_VALUE_SAME(ulong_long_type, unsigned long long)
FMT_MAKE_VALUE(int_type, signed char, int)
FMT_MAKE_VALUE(uint_type, unsigned char, unsigned)
FMT_MAKE_VALUE(char_type, char, int)
@ -583,8 +601,8 @@ inline typed_value<C, char_type> make_value(wchar_t val) {
#endif
FMT_MAKE_VALUE(double_type, float, double)
FMT_MAKE_VALUE(double_type, double, double)
FMT_MAKE_VALUE(long_double_type, long double, long double)
FMT_MAKE_VALUE_SAME(double_type, double)
FMT_MAKE_VALUE_SAME(long_double_type, long double)
// Formatting of wide strings into a narrow buffer and multibyte strings
// 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*)
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, const unsigned char*, const unsigned char*)
FMT_MAKE_VALUE(string_type, basic_string_view<typename C::char_type>,
basic_string_view<typename C::char_type>)
FMT_MAKE_VALUE_SAME(cstring_type, const unsigned char*)
FMT_MAKE_VALUE_SAME(string_type, basic_string_view<typename C::char_type>)
FMT_MAKE_VALUE(string_type,
typename basic_string_view<typename C::char_type>::type,
basic_string_view<typename C::char_type>)
FMT_MAKE_VALUE(string_type, const std::basic_string<typename C::char_type>&,
basic_string_view<typename C::char_type>)
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
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; }
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) {
basic_format_arg<C> arg = make_arg<C>(val.value);
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 {
// 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)
return it->arg;
}
@ -973,16 +990,17 @@ class format_arg_store {
friend class basic_format_args<Context>;
static FMT_CONSTEXPR uint64_t get_types() {
return IS_PACKED ? internal::get_types<Context, Args...>()
: -static_cast<int64_t>(NUM_ARGS);
static FMT_CONSTEXPR int64_t get_types() {
return IS_PACKED ?
static_cast<int64_t>(internal::get_types<Context, Args...>()) :
-static_cast<int64_t>(NUM_ARGS);
}
public:
#if FMT_USE_CONSTEXPR
static constexpr uint64_t TYPES = get_types();
static constexpr int64_t TYPES = get_types();
#else
static const uint64_t TYPES;
static const int64_t TYPES;
#endif
#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 405
@ -998,7 +1016,7 @@ class format_arg_store {
#if !FMT_USE_CONSTEXPR
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
/**
@ -1087,7 +1105,7 @@ class basic_format_args {
/** Returns the argument at specified index. */
format_arg get(size_type index) const {
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;
}

View File

@ -45,12 +45,6 @@
# define FMT_CATCH(x) if (false)
#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
# pragma warning(push)
# 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_FUNC format_error::~format_error() throw() {}
FMT_FUNC system_error::~system_error() FMT_DTOR_NOEXCEPT {}
namespace {
#ifndef _MSC_VER
@ -232,30 +223,19 @@ FMT_FUNC void system_error::init(
namespace internal {
template <typename T>
int char_traits<char>::format_float(
char *buffer, std::size_t size, const char *format,
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);
}
char *buffer, std::size_t size, const char *format, int precision, T value) {
return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, width, value) :
FMT_SNPRINTF(buffer, size, format, width, precision, value);
FMT_SNPRINTF(buffer, size, format, value) :
FMT_SNPRINTF(buffer, size, format, precision, value);
}
template <typename T>
int char_traits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, T value) {
if (width == 0) {
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, value) :
FMT_SWPRINTF(buffer, size, format, precision, value);
}
wchar_t *buffer, std::size_t size, const wchar_t *format, int precision,
T value) {
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, width, value) :
FMT_SWPRINTF(buffer, size, format, width, precision, value);
FMT_SWPRINTF(buffer, size, format, value) :
FMT_SWPRINTF(buffer, size, format, precision, value);
}
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.
template <typename T>
const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {
0xfa8fd5a0081c0288ull, 0xbaaee17fa23ebf76ull, 0x8b16fb203055ac76ull,
0xcf42894a5dce35eaull, 0x9a6bb0aa55653b2dull, 0xe61acf033d1a45dfull,
0xab70fe17c79ac6caull, 0xff77b1fcbebcdc4full, 0xbe5691ef416bd60cull,
0x8dd01fad907ffc3cull, 0xd3515c2831559a83ull, 0x9d71ac8fada6c9b5ull,
0xea9c227723ee8bcbull, 0xaecc49914078536dull, 0x823c12795db6ce57ull,
0xc21094364dfb5637ull, 0x9096ea6f3848984full, 0xd77485cb25823ac7ull,
0xa086cfcd97bf97f4ull, 0xef340a98172aace5ull, 0xb23867fb2a35b28eull,
0x84c8d4dfd2c63f3bull, 0xc5dd44271ad3cdbaull, 0x936b9fcebb25c996ull,
0xdbac6c247d62a584ull, 0xa3ab66580d5fdaf6ull, 0xf3e2f893dec3f126ull,
0xb5b5ada8aaff80b8ull, 0x87625f056c7c4a8bull, 0xc9bcff6034c13053ull,
0x964e858c91ba2655ull, 0xdff9772470297ebdull, 0xa6dfbd9fb8e5b88full,
0xf8a95fcf88747d94ull, 0xb94470938fa89bcfull, 0x8a08f0f8bf0f156bull,
0xcdb02555653131b6ull, 0x993fe2c6d07b7facull, 0xe45c10c42a2b3b06ull,
0xaa242499697392d3ull, 0xfd87b5f28300ca0eull, 0xbce5086492111aebull,
0x8cbccc096f5088ccull, 0xd1b71758e219652cull, 0x9c40000000000000ull,
0xe8d4a51000000000ull, 0xad78ebc5ac620000ull, 0x813f3978f8940984ull,
0xc097ce7bc90715b3ull, 0x8f7e32ce7bea5c70ull, 0xd5d238a4abe98068ull,
0x9f4f2726179a2245ull, 0xed63a231d4c4fb27ull, 0xb0de65388cc8ada8ull,
0x83c7088e1aab65dbull, 0xc45d1df942711d9aull, 0x924d692ca61be758ull,
0xda01ee641a708deaull, 0xa26da3999aef774aull, 0xf209787bb47d6b85ull,
0xb454e4a179dd1877ull, 0x865b86925b9bc5c2ull, 0xc83553c5c8965d3dull,
0x952ab45cfa97a0b3ull, 0xde469fbd99a05fe3ull, 0xa59bc234db398c25ull,
0xf6c69a72a3989f5cull, 0xb7dcbf5354e9beceull, 0x88fcf317f22241e2ull,
0xcc20ce9bd35c78a5ull, 0x98165af37b2153dfull, 0xe2a0b5dc971f303aull,
0xa8d9d1535ce3b396ull, 0xfb9b7cd9a4a7443cull, 0xbb764c4ca7a44410ull,
0x8bab8eefb6409c1aull, 0xd01fef10a657842cull, 0x9b10a4e5e9913129ull,
0xe7109bfba19c0c9dull, 0xac2820d9623bf429ull, 0x80444b5e7aa7cf85ull,
0xbf21e44003acdd2dull, 0x8e679c2f5e44ff8full, 0xd433179d9c8cb841ull,
0x9e19db92b4e31ba9ull, 0xeb96bf6ebadf77d9ull, 0xaf87023b9bf0ee6bull
0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, 0xcf42894a5dce35ea,
0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f,
0xbe5691ef416bd60c, 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, 0xc21094364dfb5637,
0x9096ea6f3848984f, 0xd77485cb25823ac7, 0xa086cfcd97bf97f4, 0xef340a98172aace5,
0xb23867fb2a35b28e, 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, 0xb5b5ada8aaff80b8,
0x87625f056c7c4a8b, 0xc9bcff6034c13053, 0x964e858c91ba2655, 0xdff9772470297ebd,
0xa6dfbd9fb8e5b88f, 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, 0xaa242499697392d3,
0xfd87b5f28300ca0e, 0xbce5086492111aeb, 0x8cbccc096f5088cc, 0xd1b71758e219652c,
0x9c40000000000000, 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,
0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, 0x9f4f2726179a2245,
0xed63a231d4c4fb27, 0xb0de65388cc8ada8, 0x83c7088e1aab65db, 0xc45d1df942711d9a,
0x924d692ca61be758, 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,
0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, 0x952ab45cfa97a0b3,
0xde469fbd99a05fe3, 0xa59bc234db398c25, 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece,
0x88fcf317f22241e2, 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,
0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, 0x8bab8eefb6409c1a,
0xd01fef10a657842c, 0x9b10a4e5e9913129, 0xe7109bfba19c0c9d, 0xac2820d9623bf429,
0x80444b5e7aa7cf85, 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b
};
// 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);
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
#if FMT_USE_WINDOWS_H

View File

@ -37,6 +37,33 @@
#include <stdexcept>
#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"
#ifdef _SECURE_SCL
@ -55,52 +82,31 @@
# define FMT_HAS_BUILTIN(x) 0
#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__
# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__)
#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
# 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
# define FMT_THROW(x) assert(false)
# define FMT_THROW(x) do { static_cast<void>(sizeof(x)); assert(false); } while(false);
# endif
#endif
@ -108,14 +114,14 @@
// For Intel's compiler both it and the system gcc/msc must support UDLs.
# if (FMT_HAS_FEATURE(cxx_user_literals) || \
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
# else
# define FMT_USE_USER_DEFINED_LITERALS 0
# endif
#endif
#if FMT_USE_USER_DEFINED_LITERALS && \
#if FMT_USE_USER_DEFINED_LITERALS && !defined(FMT_ICC_VERSION) && \
((FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L) || \
(defined(FMT_CLANG_VERSION) && FMT_CLANG_VERSION >= 304))
# define FMT_UDL_TEMPLATE 1
@ -126,14 +132,28 @@
#ifndef FMT_USE_EXTERN_TEMPLATES
# ifndef FMT_HEADER_ONLY
# 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
# define FMT_USE_EXTERN_TEMPLATES 0
# 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
#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
// __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(); }
// A handmade floating-point number f * pow(2, e).
struct fp {
uint64_t f;
class fp {
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;
static FMT_CONSTEXPR_DECL const int significand_size = sizeof(significand_type) * char_size;
fp(uint64_t f, int e): f(f), e(e) {}
// Constructs fp from an IEEE754 double. It is a template to prevent compile
@ -270,24 +304,35 @@ struct fp {
explicit fp(Double d) {
// Assume double is in the format [sign][exponent][significand].
typedef std::numeric_limits<Double> limits;
const int double_size =
sizeof(Double) * std::numeric_limits<unsigned char>::digits;
// Subtract 1 to account for an implicit most significant bit in the
// 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 int double_size = sizeof(Double) * char_size;
const int exponent_size =
double_size - double_significand_size - 1; // -1 for sign
const uint64_t significand_mask = implicit_bit - 1;
const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask;
const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
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;
if (biased_e != 0)
f += implicit_bit;
else
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);
}
// Computes an fp number r with r.f = x.f * y.f / pow(2, 32) rounded to nearest
// with half-up tie breaking, r.e = x.e + y.e + 32. Result may not be normalized.
// 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 + 64. Result may not be normalized.
fp operator*(fp x, fp y);
// Compute k such that its cached power c_k = c_k.f * pow(2, c_k.e) satisfies
// min_exponent <= c_k.e + e <= min_exponent + 3.
inline int compute_cached_power_index(int e, int min_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));
}
// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its
// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3.
fp get_cached_power(int min_exponent, int &pow10_exponent);
template <typename Allocator>
typename Allocator::value_type *allocate(Allocator& alloc, std::size_t n) {
@ -372,6 +414,38 @@ FMT_BEGIN_NAMESPACE
template <typename Range>
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. */
class format_error : public std::runtime_error {
public:
@ -380,8 +454,6 @@ class format_error : public std::runtime_error {
explicit format_error(const std::string &message)
: std::runtime_error(message) {}
FMT_API ~format_error() throw();
};
namespace internal {
@ -601,30 +673,30 @@ struct char_traits<char> {
// Formats a floating-point number.
template <typename T>
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 <>
struct char_traits<wchar_t> {
template <typename T>
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
extern template int char_traits<char>::format_float<double>(
char *buffer, std::size_t size, const char* format, unsigned width,
int precision, double value);
char *buffer, std::size_t size, const char* format, int precision,
double value);
extern template int char_traits<char>::format_float<long double>(
char *buffer, std::size_t size, const char* format, unsigned width,
int precision, long double value);
char *buffer, std::size_t size, const char* format, int precision,
long double value);
extern template int char_traits<wchar_t>::format_float<double>(
wchar_t *buffer, std::size_t size, const wchar_t* format, unsigned width,
int precision, double value);
wchar_t *buffer, std::size_t size, const wchar_t* format, int precision,
double value);
extern template int char_traits<wchar_t>::format_float<long double>(
wchar_t *buffer, std::size_t size, const wchar_t* format, unsigned width,
int precision, long double value);
wchar_t *buffer, std::size_t size, const wchar_t* format, int precision,
long double value);
#endif
template <typename Container>
@ -1124,7 +1196,7 @@ FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
switch (arg.type_) {
case internal::none_type:
break;
case internal::name_arg_type:
case internal::named_arg_type:
FMT_ASSERT(false, "invalid argument type");
break;
case internal::int_type:
@ -1418,7 +1490,7 @@ void arg_map<Context>::init(const basic_format_args<Context> &args) {
switch (arg_type) {
case internal::none_type:
return;
case internal::name_arg_type:
case internal::named_arg_type:
push_back(args.values_[i]);
break;
default:
@ -1427,15 +1499,11 @@ void arg_map<Context>::init(const basic_format_args<Context> &args) {
}
return;
}
for (unsigned i = 0; i != max_packed_args; ++i) {
if (args.type(i) == internal::name_arg_type)
push_back(args.args_[i].value_);
}
for (unsigned i = max_packed_args; ; ++i) {
for (unsigned i = 0; ; ++i) {
switch (args.args_[i].type_) {
case internal::none_type:
return;
case internal::name_arg_type:
case internal::named_arg_type:
push_back(args.args_[i].value_);
break;
default:
@ -1602,6 +1670,13 @@ FMT_CONSTEXPR unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) {
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>
class custom_formatter: public function<bool> {
private:
@ -1619,6 +1694,10 @@ class custom_formatter: public function<bool> {
bool operator()(T) const { return false; }
};
#if FMT_MSC_VER
# pragma warning(pop)
#endif
template <typename T>
struct is_integer {
enum {
@ -1975,41 +2054,42 @@ struct precision_adapter {
template <typename Iterator, typename SpecHandler>
FMT_CONSTEXPR Iterator parse_format_specs(Iterator it, SpecHandler &&handler) {
typedef typename std::iterator_traits<Iterator>::value_type char_type;
char_type c = *it;
if (c == '}' || !c)
return it;
// Parse fill and alignment.
if (char_type c = *it) {
alignment align = ALIGN_DEFAULT;
int i = 1;
do {
auto p = it + i;
switch (*p) {
case '<':
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;
alignment align = ALIGN_DEFAULT;
int i = 1;
do {
auto p = it + i;
switch (*p) {
case '<':
align = ALIGN_LEFT;
break;
}
} while (--i >= 0);
}
case '>':
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.
switch (*it) {
@ -2308,8 +2388,6 @@ class system_error : public std::runtime_error {
init(error_code, message, make_format_args(args...));
}
FMT_API ~system_error() FMT_DTOR_NOEXCEPT;
int error_code() const { return error_code_; }
};
@ -2578,7 +2656,7 @@ class basic_writer {
};
struct double_writer {
unsigned n;
size_t n;
char sign;
basic_memory_buffer<char_type> &buffer;
@ -2595,6 +2673,9 @@ class basic_writer {
// Formats a floating-point number (double or long double).
template <typename T>
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>
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");
basic_memory_buffer<char_type> buffer;
unsigned width = spec.width();
if (sign) {
buffer.reserve(width > 1u ? width : 1u);
if (width > 0)
--width;
}
// Build format string.
enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
char_type format[MAX_FORMAT_SIZE];
char_type *format_ptr = format;
*format_ptr++ = '%';
unsigned width_for_sprintf = width;
if (spec.flag(HASH_FLAG))
*format_ptr++ = '#';
width_for_sprintf = 0;
if (spec.precision() >= 0) {
*format_ptr++ = '.';
*format_ptr++ = '*';
}
append_float_length(format_ptr, value);
*format_ptr++ = handler.type;
*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);
if (FMT_USE_GRISU && sizeof(T) <= sizeof(double) &&
std::numeric_limits<double>::is_iec559) {
internal::fp fp_value(static_cast<double>(value));
fp_value.normalize();
// Find a cached power of 10 close to 1 / fp_value.
int dec_exp = 0;
const int min_exp = -60;
auto dec_pow = internal::get_cached_power(
min_exp - (fp_value.e + internal::fp::significand_size), dec_exp);
internal::fp product = fp_value * dec_pow;
// Generate output.
internal::fp one(1ull << -product.e, product.e);
uint64_t hi = product.f >> -one.e;
uint64_t f = product.f & (one.f - 1);
typedef back_insert_range<internal::basic_buffer<char_type>> range;
basic_writer<range> w{range(buffer)};
w.write(hi);
size_t digits = buffer.size();
w.write('.');
const unsigned max_digits = 18;
while (digits++ < max_digits) {
f *= 10;
w.write(static_cast<char>('0' + (f >> -one.e)));
f &= one.f - 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;
if (spec.align() == ALIGN_NUMERIC) {
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});
}
template <typename OutputIt, typename T = typename OutputIt::value_type>
class output_range {
private:
OutputIt it_;
template <typename Range>
template <typename T>
void basic_writer<Range>::write_double_sprintf(
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.
typedef void sentinel;
sentinel end() const;
// Build format string.
enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
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:
typedef OutputIt iterator;
typedef T value_type;
append_float_length(format_ptr, value);
*format_ptr++ = spec.type();
*format_ptr = '\0';
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;
// Format using snprintf.
char_type *start = FMT_NULL;
for (;;) {
std::size_t buffer_size = buffer.capacity();
start = &buffer[0];
int result = internal::char_traits<char_type>::format_float(
start, buffer_size, format, spec.precision(), value);
if (result >= 0) {
unsigned n = internal::to_unsigned(result);
if (n < buffer.capacity()) {
buffer.resize(n);
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);
}
}
}
// Reports a system error without throwing an exception.
// Can be used to report errors from destructors.
@ -3100,7 +3174,7 @@ struct formatter<
auto eh = ctx.error_handler();
switch (type) {
case internal::none_type:
case internal::name_arg_type:
case internal::named_arg_type:
FMT_ASSERT(false, "invalid argument type");
break;
case internal::int_type:
@ -3147,8 +3221,8 @@ struct formatter<
internal::handle_dynamic_spec<internal::precision_checker>(
specs_.precision_, specs_.precision_ref, ctx);
typedef output_range<typename FormatContext::iterator,
typename FormatContext::char_type> range;
visit(arg_formatter<range>(ctx, specs_),
typename FormatContext::char_type> range_type;
visit(arg_formatter<range_type>(ctx, specs_),
internal::make_arg<FormatContext>(val));
return ctx.out();
}
@ -3634,7 +3708,7 @@ FMT_END_NAMESPACE
#define FMT_STRING(s) [] { \
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); } \
}; \
return S{}; \
@ -3663,12 +3737,8 @@ FMT_END_NAMESPACE
#endif
// Restore warnings.
#if FMT_GCC_VERSION >= 406
#if FMT_GCC_VERSION >= 406 || FMT_CLANG_VERSION
# pragma GCC diagnostic pop
#endif
#if defined(__clang__) && !defined(FMT_ICC_VERSION)
# pragma clang diagnostic pop
#endif
#endif // FMT_FORMAT_H_

View File

@ -53,10 +53,10 @@ struct test_stream : std::basic_ostream<Char> {
void operator<<(null);
};
// Disable conversion to int if T has an overloaded operator<< which is a free
// function (not a member of std::ostream).
// Checks 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> {
class is_streamable {
private:
template <typename U>
static decltype(
@ -69,7 +69,16 @@ class convert_to_int<T, Char, true> {
typedef decltype(test<T>(0)) result;
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.
@ -106,8 +115,7 @@ struct format_enum<T,
// Formats an object of type T that has an overloaded ostream operator<<.
template <typename T, typename Char>
struct formatter<T, Char,
typename std::enable_if<!internal::format_type<
typename buffer_context<Char>::type, T>::value>::type>
typename std::enable_if<internal::is_streamable<T, Char>::value>::type>
: formatter<basic_string_view<Char>, Char> {
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
operator()(T) {
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
operator()(T) {
FMT_THROW(format_error("width is not integer"));
return 0;
return 0; // Silence Visual Studio
}
};
} // namespace internal
@ -635,8 +635,13 @@ inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args)
template <typename... Args>
inline int fprintf(std::FILE *f, wstring_view format_str,
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,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
#endif
}
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 =
is_tuple_like_<T>::value && !is_range_<T>::value;
};
} // namespace internal
#if FMT_HAS_FEATURE(__cpp_lib_integer_sequence)
# define FMT_USE_INTEGER_SEQUENCE 1
// Check for integer_sequence
#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
# 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
#if FMT_USE_INTEGER_SEQUENCE
namespace internal {
template <size_t... Is, class Tuple, class F>
void for_each(std::index_sequence<Is...>, Tuple &&tup, F &&f) noexcept {
template <class Tuple, class F, size_t... Is>
void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) noexcept {
using std::get;
// using free function get<I>(T) now.
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>
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 {}; }
template <class Tuple, class F>
@ -157,21 +178,13 @@ void for_each(Tuple &&tup, F &&f) {
template <typename TupleT, typename Char>
struct formatter<TupleT, Char,
typename std::enable_if<fmt::internal::is_tuple_like<TupleT>::value>::type> {
fmt::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, [&](const auto &v) {
typename std::enable_if<internal::is_tuple_like<TupleT>::value>::type> {
private:
// C++11 generic lambda for format()
template <typename FormatContext>
struct format_each {
template <typename T>
void operator()(const T& v) {
if (i > 0) {
if (formatting.add_prepostfix_space) {
*out++ = ' ';
@ -184,7 +197,28 @@ struct formatter<TupleT, Char,
format_to(out, "{}", v);
}
++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) {
*out++ = ' ';
}
@ -193,13 +227,12 @@ struct formatter<TupleT, Char,
return ctx.out();
}
};
#endif // FMT_USE_INTEGER_SEQUENCE
template <typename RangeT, typename Char>
struct formatter< RangeT, Char,
typename std::enable_if<fmt::internal::is_range<RangeT>::value>::type> {
struct formatter<RangeT, Char,
typename std::enable_if<internal::is_range<RangeT>::value>::type> {
fmt::formatting_range<Char> formatting;
formatting_range<Char> formatting;
template <typename ParseContext>
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_;
// Too big time values may be unsupported.
FMT_THROW(format_error("time_t value out of range"));
return std::tm();
}
// Thread-safe replacement for std::gmtime
@ -90,7 +89,6 @@ inline std::tm gmtime(std::time_t time) {
return gt.tm_;
// Too big time values may be unsupported.
FMT_THROW(format_error("time_t value out of range"));
return std::tm();
}
namespace internal {

View File

@ -21,12 +21,12 @@ template void internal::arg_map<format_context>::init(
const basic_format_args<format_context> &args);
template FMT_API int internal::char_traits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, double value);
char *buffer, std::size_t size, const char *format, int precision,
double value);
template FMT_API int internal::char_traits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, long double value);
char *buffer, std::size_t size, const char *format, int precision,
long double value);
// 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(
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(
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

View File

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

View File

@ -4,7 +4,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := fmt_static
LOCAL_MODULE_FILENAME := libfmt
LOCAL_SRC_FILES := fmt/format.cc
LOCAL_SRC_FILES := ../src/format.cc
LOCAL_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']
config = os.environ['CONFIGURATION']
platform = os.environ.get('PLATFORM')
platform = os.environ['PLATFORM']
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':
cmake_command.append('-GMinGW Makefiles')
build_command = ['mingw32-make', '-j4']
@ -21,7 +23,12 @@ else:
# Add MSBuild 14.0 to PATH as described in
# 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
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':
generator += ' Win64'
cmake_command.append('-G' + generator)

View File

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

View File

@ -1,67 +1,52 @@
# C++14 feature support detection
if (NOT FMT_USE_CPP14)
return()
endif ()
include(CheckCXXSourceCompiles)
include(CheckCXXCompilerFlag)
if (FMT_USE_CPP14)
check_cxx_compiler_flag(-std=c++14 HAVE_STD_CPP14_FLAG)
if (HAVE_STD_CPP14_FLAG)
# Check if including cmath works with -std=c++14 and -O3.
# It may not in MinGW due to bug http://ehc.ac/p/mingw/bugs/2250/.
set(CMAKE_REQUIRED_FLAGS "-std=c++14 -O3")
check_cxx_source_compiles("
#include <cmath>
int main() {}" FMT_CPP14_CMATH)
# Check if including <unistd.h> works with -std=c++14.
# It may not in MinGW due to bug http://sourceforge.net/p/mingw/bugs/2024/.
check_cxx_source_compiles("
#include <unistd.h>
int main() {}" FMT_CPP14_UNISTD_H)
# Check if snprintf works with -std=c++14. It may not in MinGW.
check_cxx_source_compiles("
#include <stdio.h>
int main() {
char buffer[10];
snprintf(buffer, 10, \"foo\");
}" FMT_CPP14_SNPRINTF)
if (FMT_CPP14_CMATH AND FMT_CPP14_UNISTD_H AND FMT_CPP14_SNPRINTF)
set(CPP14_FLAG -std=c++14)
else ()
check_cxx_compiler_flag(-std=gnu++14 HAVE_STD_GNUPP14_FLAG)
if (HAVE_STD_CPP14_FLAG)
set(CPP14_FLAG -std=gnu++14)
endif ()
endif ()
set(CMAKE_REQUIRED_FLAGS )
else ()
check_cxx_compiler_flag(-std=c++1y HAVE_STD_CPP1Y_FLAG)
if (HAVE_STD_CPP1Y_FLAG)
set(CPP14_FLAG -std=c++1y)
else ()
# Fallback on c++11 if c++14 is not available.
check_cxx_compiler_flag(-std=c++11 HAVE_STD_CPP11_FLAG)
if (HAVE_STD_CPP11_FLAG)
set(CPP14_FLAG -std=c++11)
else ()
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 ()
if (NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
endif()
message(STATUS "CXX_STANDARD: ${CMAKE_CXX_STANDARD}")
if (CMAKE_CXX_STANDARD EQUAL 20)
check_cxx_compiler_flag(-std=c++20 has_std_20_flag)
check_cxx_compiler_flag(-std=c++2a has_std_2a_flag)
if (has_std_20_flag)
set(CXX_STANDARD_FLAG -std=c++20)
elseif (has_std_2a_flag)
set(CXX_STANDARD_FLAG -std=c++2a)
endif ()
elseif (CMAKE_CXX_STANDARD EQUAL 17)
check_cxx_compiler_flag(-std=c++17 has_std_17_flag)
check_cxx_compiler_flag(-std=c++1z has_std_1z_flag)
if (has_std_17_flag)
set(CXX_STANDARD_FLAG -std=c++17)
elseif (has_std_1z_flag)
set(CXX_STANDARD_FLAG -std=c++1z)
endif ()
elseif (CMAKE_CXX_STANDARD EQUAL 14)
check_cxx_compiler_flag(-std=c++14 has_std_14_flag)
check_cxx_compiler_flag(-std=c++1y has_std_1y_flag)
if (has_std_14_flag)
set(CXX_STANDARD_FLAG -std=c++14)
elseif (has_std_1y_flag)
set(CXX_STANDARD_FLAG -std=c++1y)
endif ()
elseif (CMAKE_CXX_STANDARD EQUAL 11)
check_cxx_compiler_flag(-std=c++11 has_std_11_flag)
check_cxx_compiler_flag(-std=c++0x has_std_0x_flag)
if (has_std_11_flag)
set(CXX_STANDARD_FLAG -std=c++11)
elseif (has_std_0x_flag)
set(CXX_STANDARD_FLAG -std=c++0x)
endif ()
endif ()
if (CMAKE_CXX_STANDARD)
# 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})
set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG})
# Check if variadic templates are working and not affected by GCC bug 39653:
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39653
@ -69,17 +54,26 @@ check_cxx_source_compiles("
template <class T, class ...Types>
struct S { typedef typename S<Types...>::type type; };
int main() {}" SUPPORTS_VARIADIC_TEMPLATES)
if (NOT SUPPORTS_VARIADIC_TEMPLATES)
set (SUPPORTS_VARIADIC_TEMPLATES OFF)
endif ()
# Check if initializer lists are supported.
check_cxx_source_compiles("
#include <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_cxx_source_compiles("
enum C : char {A};
int main() {}"
SUPPORTS_ENUM_BASE)
if (NOT SUPPORTS_ENUM_BASE)
set (SUPPORTS_ENUM_BASE OFF)
endif ()
# Check if type traits are available
check_cxx_source_compiles("
@ -87,11 +81,17 @@ check_cxx_source_compiles("
class C { void operator=(const C&); };
int main() { static_assert(!std::is_copy_assignable<C>::value, \"\"); }"
SUPPORTS_TYPE_TRAITS)
if (NOT SUPPORTS_TYPE_TRAITS)
set (SUPPORTS_TYPE_TRAITS OFF)
endif ()
# Check if user-defined literals are available
check_cxx_source_compiles("
void operator\"\" _udl(long double);
int main() {}"
SUPPORTS_USER_DEFINED_LITERALS)
if (NOT SUPPORTS_USER_DEFINED_LITERALS)
set (SUPPORTS_USER_DEFINED_LITERALS OFF)
endif ()
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='')
for i, fp in enumerate(powers):
if i % 3 == 0:
if i % 4 == 0:
print(end='\n ')
print(' {:0<#16x}ull'.format(fp.f, ), end=',')
print(' {:0<#16x}'.format(fp.f, ), end=',')
print('\n\nExponents:', end='')
for i, fp in enumerate(powers):
if i % 11 == 0:
print(end='\n ')
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):
shutil.rmtree(html_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')
import build
build.build_docs(version, doc_dir=target_doc_dir,
@ -243,12 +245,11 @@ def release(args):
id = r.json()['id']
uploads_url = 'https://uploads.github.com/repos/fmtlib/fmt/releases'
package = 'fmt-{}.zip'.format(version)
with open('build/fmt/' + package, 'rb') as f:
r = requests.post(
'{}/{}/assets?name={}'.format(uploads_url, id, package),
params=params, files={package: f})
if r.status_code != 201:
raise Exception('Failed to upload an asset ' + str(r))
r = requests.post(
'{}/{}/assets?name={}'.format(uploads_url, id, package),
params=params, files={package: open('build/fmt/' + package, 'rb')})
if r.status_code != 201:
raise Exception('Failed to upload an asset ' + str(r))
if __name__ == '__main__':

View File

@ -2,8 +2,8 @@
# Build the project on Travis CI.
from __future__ import print_function
import errno, os, re, shutil, subprocess, sys, tempfile, urllib
from subprocess import call, check_call, check_output, Popen, PIPE, STDOUT
import errno, os, shutil, subprocess, sys, urllib
from subprocess import call, check_call, Popen, PIPE, STDOUT
def rmtree_if_exists(dir):
try:
@ -85,14 +85,12 @@ test_build_dir = os.path.join(fmt_dir, "_build_test")
# Configure library.
makedirs_if_not_exist(build_dir)
common_cmake_flags = [
'-DCMAKE_INSTALL_PREFIX=' + install_dir, '-DCMAKE_BUILD_TYPE=' + build
cmake_flags = [
'-DCMAKE_INSTALL_PREFIX=' + install_dir, '-DCMAKE_BUILD_TYPE=' + build,
'-DCMAKE_CXX_STANDARD=' + standard
]
extra_cmake_flags = []
if standard != '14':
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)
check_call(['cmake', '-DFMT_DOC=OFF', '-DFMT_PEDANTIC=ON', '-DFMT_WERROR=ON', fmt_dir] +
cmake_flags, cwd=build_dir)
# Build library.
check_call(['make', '-j4'], cwd=build_dir)
@ -101,7 +99,7 @@ check_call(['make', '-j4'], cwd=build_dir)
env = os.environ.copy()
env['CTEST_OUTPUT_ON_FAILURE'] = '1'
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())
sys.exit(-1)
@ -110,7 +108,6 @@ check_call(['make', 'install'], cwd=build_dir)
# Test installation.
makedirs_if_not_exist(test_build_dir)
check_call(['cmake', '-DCMAKE_CXX_FLAGS=-std=c++' + standard,
os.path.join(fmt_dir, "test", "find-package-test")] +
common_cmake_flags, cwd=test_build_dir)
check_call(['cmake', os.path.join(fmt_dir, "test", "find-package-test")] +
cmake_flags, 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.
add_library(gmock STATIC
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_include_directories(gmock PUBLIC .)
target_include_directories(gmock SYSTEM PUBLIC . gmock gtest)
find_package(Threads)
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})
target_compile_definitions(test-main PUBLIC
FMT_USE_FILE_DESCRIPTORS=$<BOOL:${HAVE_OPEN}>)
target_include_directories(test-main SYSTEM PUBLIC gtest gmock)
target_link_libraries(test-main gmock fmt)
include(CheckCXXCompilerFlag)
@ -57,7 +57,7 @@ endif ()
# Use less strict pedantic flags for the tests because GMock doesn't compile
# cleanly with -pedantic and -std=c++98.
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 ()
function(add_fmt_executable name)
@ -80,6 +80,7 @@ function(add_fmt_test name)
if (FMT_PEDANTIC)
target_compile_options(${name} PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
target_include_directories(${name} SYSTEM PUBLIC gtest gmock)
add_test(NAME ${name} COMMAND ${name})
endfunction()
@ -94,12 +95,6 @@ add_fmt_test(util-test mock-allocator.h)
add_fmt_test(custom-formatter-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)
add_fmt_executable(posix-mock-test
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)
target_compile_definitions(posix-mock-test PRIVATE FMT_USE_FILE_DESCRIPTORS=1)
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_fmt_test(posix-test)
endif ()
@ -114,6 +113,7 @@ endif ()
add_fmt_executable(header-only-test
header-only-test.cc header-only-test2.cc test-main.cc)
target_link_libraries(header-only-test gmock)
target_include_directories(header-only-test SYSTEM PUBLIC gtest gmock)
if (TARGET fmt-header-only)
target_link_libraries(header-only-test fmt-header-only)
else ()
@ -126,20 +126,28 @@ endif ()
check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG)
if (HAVE_FNO_EXCEPTIONS_FLAG)
add_library(noexception-test ../src/format.cc)
target_compile_options(noexception-test PUBLIC ${CPP14_FLAG})
target_include_directories(
noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
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 ()
message(STATUS "FMT_PEDANTIC: ${FMT_PEDANTIC}")
if (FMT_PEDANTIC)
# Test that the library compiles without windows.h.
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_library(no-windows-h-test ../src/format.cc)
target_compile_options(no-windows-h-test PUBLIC ${CPP14_FLAG})
target_include_directories(
no-windows-h-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
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 ()
add_test(compile-test ${CMAKE_CTEST_COMMAND}
@ -148,9 +156,11 @@ if (FMT_PEDANTIC)
"${CMAKE_CURRENT_BINARY_DIR}/compile-test"
--build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
--build-options
"-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}")
# test if the targets are findable from the build directory
@ -163,8 +173,9 @@ if (FMT_PEDANTIC)
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCPP14_FLAG=${CPP14_FLAG}"
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DFMT_DIR=${PROJECT_BINARY_DIR}"
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
# test if the targets are findable when add_subdirectory is used
@ -177,6 +188,7 @@ if (FMT_PEDANTIC)
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-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}")
endif ()

View File

@ -1,15 +1,17 @@
cmake_minimum_required(VERSION 2.8.12)
cmake_minimum_required(VERSION 3.1.0)
project(fmt-test)
add_subdirectory(../.. fmt)
add_executable(library-test "main.cc")
target_compile_options(library-test PUBLIC ${CPP14_FLAG})
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)
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_compile_options(header-only-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
target_include_directories(header-only-test PUBLIC SYSTEM .)
endif ()

View File

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

View File

@ -1,10 +1,12 @@
# Test if compile errors are produced where necessary.
cmake_minimum_required(VERSION 2.8)
cmake_minimum_required(VERSION 3.1.0)
include(CheckCXXSourceCompiles)
include(CheckCXXCompilerFlag)
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)
set(${result} "

View File

@ -22,13 +22,21 @@ class custom_arg_formatter :
using base::operator();
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;
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;
// Pass custom argument formatter as a template arg to vwrite.
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)
find_package(FMT REQUIRED)
add_executable(library-test main.cc)
target_compile_options(library-test PUBLIC ${CPP14_FLAG})
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)
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_compile_options(header-only-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
target_include_directories(header-only-test PUBLIC SYSTEM .)
endif ()

View File

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

View File

@ -14,7 +14,7 @@
#include <memory>
#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.
#define None 0
@ -321,6 +321,11 @@ TEST(FormatterTest, NamedArg) {
EXPECT_EQ(" -42", format("{0:{width}}", -42, fmt::arg("width", 4)));
EXPECT_EQ("st", format("{0:.{precision}}", "str", fmt::arg("precision", 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) {
@ -435,6 +440,7 @@ TEST(FormatterTest, Fill) {
EXPECT_EQ("c****", format("{0:*<5}", 'c'));
EXPECT_EQ("abc**", format("{0:*<5}", "abc"));
EXPECT_EQ("**0xface", format("{0:*>8}", reinterpret_cast<void*>(0xface)));
EXPECT_EQ("foo=", format("{:}=", "foo"));
}
TEST(FormatterTest, PlusSign) {
@ -1024,7 +1030,7 @@ TEST(FormatterTest, FormatCString) {
EXPECT_EQ("test", format("{0:s}", "test"));
char nonconst[] = "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");
}
@ -1046,7 +1052,7 @@ TEST(FormatterTest, FormatUCharString) {
TEST(FormatterTest, FormatPointer) {
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:p}", reinterpret_cast<void*>(0x1234)));
EXPECT_EQ("0x" + std::string(sizeof(void*) * CHAR_BIT / 4, 'f'),
@ -1148,7 +1154,7 @@ TEST(FormatterTest, FormatExamples) {
FILE *ftest = safe_fopen(filename, "r");
if (ftest) fclose(ftest);
int error_code = errno;
EXPECT_TRUE(ftest == 0);
EXPECT_TRUE(ftest == nullptr);
EXPECT_SYSTEM_ERROR({
FILE *f = safe_fopen(filename, "r");
if (!f)
@ -1309,7 +1315,7 @@ TEST(StrTest, Convert) {
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;
format_to(buffer, "[{}] ", id);
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::vformat_to<mock_arg_formatter>(buffer, format_str, args);
}
@ -1516,6 +1522,9 @@ TEST(FormatTest, FormatToN) {
EXPECT_EQ(6u, result.size);
EXPECT_EQ(buffer + 3, result.out);
EXPECT_EQ("foox", fmt::string_view(buffer, 4));
// Workaround for potentially unused macro
static_cast<void>(None);
}
#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);
}
#define EXPECT_ERROR_NOARGS(fmt, error) \
static_assert(test_error(fmt, error), "")
#define EXPECT_ERROR(fmt, error, ...) \
static_assert(test_error<__VA_ARGS__>(fmt, error), "")
TEST(FormatTest, FormatStringErrors) {
EXPECT_ERROR("foo", nullptr);
EXPECT_ERROR("}", "unmatched '}' in format string");
EXPECT_ERROR_NOARGS("foo", nullptr);
EXPECT_ERROR_NOARGS("}", "unmatched '}' in format string");
EXPECT_ERROR("{0:s", "unknown format specifier", Date);
#ifndef _MSC_VER
// This causes an internal compiler error in MSVC2017.
@ -1807,7 +1818,7 @@ TEST(FormatTest, FormatStringErrors) {
EXPECT_ERROR("{:{<}", "invalid fill character '{'", 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",
const char *);
EXPECT_ERROR("{:+}", "format specifier requires numeric argument",
@ -1834,15 +1845,15 @@ TEST(FormatTest, FormatStringErrors) {
EXPECT_ERROR("{:s}", "invalid type specifier", void *);
#endif
EXPECT_ERROR("{foo", "missing '}' in format string", int);
EXPECT_ERROR("{10000000000}", "number is too big");
EXPECT_ERROR("{0x}", "invalid format string");
EXPECT_ERROR("{-}", "invalid format string");
EXPECT_ERROR_NOARGS("{10000000000}", "number is too big");
EXPECT_ERROR_NOARGS("{0x}", "invalid format string");
EXPECT_ERROR_NOARGS("{-}", "invalid format string");
EXPECT_ERROR("{:{0x}}", "invalid format string", int);
EXPECT_ERROR("{:{-}}", "invalid format string", int);
EXPECT_ERROR("{:.{0x}}", "invalid format string", int);
EXPECT_ERROR("{:.{-}}", "invalid format string", 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}{}",
"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
// when it's fused.
#include "gtest/gtest.h"
#include "gtest.h"
// The following lines pull in the real gtest *.cc files.
// Copyright 2005, Google Inc.

View File

@ -235,7 +235,7 @@
// Most of the types needed for porting Google Mock are also required
// 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
// 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.
EXPECT_EQ('x', fputc('x', f.get()));
FMT_POSIX(close(write_fd));
scoped_ptr<OutputRedirect> redir;
scoped_ptr<OutputRedirect> redir{nullptr};
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
EBADF, "cannot flush stream");
redir.reset();
redir.reset(nullptr);
write_copy.dup2(write_fd); // "undo" close or dtor will fail
}
@ -352,7 +352,7 @@ TEST(OutputRedirectTest, DupErrorInCtor) {
int fd = (f.fileno)();
file copy = file::dup(fd);
FMT_POSIX(close(fd));
scoped_ptr<OutputRedirect> redir;
scoped_ptr<OutputRedirect> redir{nullptr};
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
EBADF, fmt::format("cannot duplicate file descriptor {}", fd));
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
// redirection.
FMT_POSIX(close(write_fd));
SUPPRESS_ASSERT(redir.reset());
SUPPRESS_ASSERT(redir.reset(nullptr));
}, format_system_error(EBADF, "cannot flush stream"));
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 {
n = f.read(&buffer[offset], count - offset);
// 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);
buffer.resize(offset);
return buffer;

View File

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

View File

@ -8,7 +8,7 @@
#ifndef FMT_MOCK_ALLOCATOR_H_
#define FMT_MOCK_ALLOCATOR_H_
#include "gmock/gmock.h"
#include "gmock.h"
template <typename T>
class MockAllocator {
@ -28,7 +28,7 @@ class AllocatorRef {
public:
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_) {}
@ -41,7 +41,7 @@ class AllocatorRef {
private:
void move(AllocatorRef &other) {
alloc_ = other.alloc_;
other.alloc_ = 0;
other.alloc_ = nullptr;
}
public:

View File

@ -8,29 +8,29 @@
#include "fmt/ostream.h"
#include <sstream>
#include "gmock/gmock.h"
#include "gmock.h"
#include "gtest-extra.h"
#include "util.h"
using fmt::format;
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();
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();
return os;
}
enum TestEnum {};
std::ostream &operator<<(std::ostream &os, TestEnum) {
static std::ostream &operator<<(std::ostream &os, TestEnum) {
return os << "TestEnum";
}
std::wostream &operator<<(std::wostream &os, TestEnum) {
static std::wostream &operator<<(std::wostream &os, TestEnum) {
return os << L"TestEnum";
}
@ -95,7 +95,7 @@ TEST(OStreamTest, FormatSpecs) {
}
struct EmptyTest {};
std::ostream &operator<<(std::ostream &os, EmptyTest) {
static std::ostream &operator<<(std::ostream &os, EmptyTest) {
return os << "";
}
@ -145,7 +145,7 @@ TEST(OStreamTest, WriteToOStreamMaxSize) {
} os(streambuf);
testing::InSequence sequence;
const char *data = 0;
const char *data = nullptr;
std::size_t size = max_size;
do {
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)))
.WillOnce(testing::Return(max_streamsize));
data += n;
size -= static_cast<std::size_t>(n);
size -= n;
} while (size != 0);
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.
// Disable bogus MSVC warnings.
#define _CRT_SECURE_NO_WARNINGS
#ifdef _MSC_VER
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "posix-mock.h"
#include "../src/posix.cc"
@ -21,7 +23,7 @@
# undef ERROR
#endif
#include "gmock/gmock.h"
#include "gmock.h"
#include "gtest-extra.h"
#include "util.h"
@ -131,7 +133,7 @@ int test::dup2(int fildes, int fildes2) {
}
FILE *test::fdopen(int fildes, const char *mode) {
EMULATE_EINTR(fdopen, 0);
EMULATE_EINTR(fdopen, nullptr);
return ::FMT_POSIX(fdopen(fildes, mode));
}
@ -160,7 +162,7 @@ int test::pipe(int *pfds, unsigned psize, int textmode) {
#endif
FILE *test::fopen(const char *filename, const char *mode) {
EMULATE_EINTR(fopen, 0);
EMULATE_EINTR(fopen, nullptr);
return ::fopen(filename, mode);
}
@ -193,7 +195,7 @@ int (test::fileno)(FILE *stream) {
# define EXPECT_EQ_POSIX(expected, actual)
#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");
f.print("{}", content);
}
@ -214,7 +216,7 @@ TEST(UtilTest, GetPageSize) {
TEST(FileTest, OpenRetry) {
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)),
open, "cannot open file test");
#ifndef _WIN32
@ -230,7 +232,7 @@ TEST(FileTest, CloseNoRetryInDtor) {
int saved_close_count = 0;
EXPECT_WRITE(stderr, {
close_count = 1;
f.reset();
f.reset(nullptr);
saved_close_count = close_count;
close_count = 0;
}, format_system_error(EINTR, "cannot close file") + "\n");
@ -383,7 +385,7 @@ TEST(FileTest, FdopenNoRetry) {
TEST(BufferedFileTest, OpenRetry) {
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")),
fopen, "cannot open file test");
#ifndef _WIN32
@ -400,7 +402,7 @@ TEST(BufferedFileTest, CloseNoRetryInDtor) {
int saved_fclose_count = 0;
EXPECT_WRITE(stderr, {
fclose_count = 1;
f.reset();
f.reset(nullptr);
saved_fclose_count = fclose_count;
fclose_count = 0;
}, format_system_error(EINTR, "cannot close file") + "\n");
@ -436,8 +438,9 @@ TEST(ScopedMock, Scope) {
ScopedMock<TestMock> mock;
EXPECT_EQ(&mock, TestMock::instance);
TestMock &copy = mock;
static_cast<void>(copy);
}
EXPECT_EQ(0, TestMock::instance);
EXPECT_EQ(nullptr, TestMock::instance);
}
#ifdef FMT_LOCALE
@ -472,7 +475,13 @@ double _strtod_l(const char *nptr, char **endptr, _locale_t locale) {
# pragma warning(pop)
#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);
}
@ -482,15 +491,17 @@ typedef int FreeLocaleResult;
typedef void FreeLocaleResult;
#endif
FreeLocaleResult freelocale(LocaleType locale) {
FreeLocaleResult freelocale(LocaleType locale) FMT_LOCALE_THROW {
LocaleMock::instance->freelocale(locale);
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);
}
#undef FMT_LOCALE_THROW
TEST(LocaleTest, LocaleMock) {
ScopedMock<LocaleMock> mock;
LocaleType locale = reinterpret_cast<LocaleType>(11);
@ -504,7 +515,7 @@ TEST(LocaleTest, Locale) {
#endif
ScopedMock<LocaleMock> mock;
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));
EXPECT_CALL(mock, freelocale(impl));
fmt::Locale locale;

View File

@ -23,12 +23,12 @@ using fmt::file;
using testing::internal::scoped_ptr;
// Checks if the file is open by reading one character from it.
bool isopen(int fd) {
static bool isopen(int fd) {
char buffer;
return FMT_POSIX(read(fd, &buffer, 1)) == 1;
}
bool isclosed(int fd) {
static bool isclosed(int fd) {
char buffer;
std::streamsize result = 0;
SUPPRESS_ASSERT(result = FMT_POSIX(read(fd, &buffer, 1)));
@ -36,7 +36,7 @@ bool isclosed(int fd) {
}
// Opens a file for reading.
file open_file() {
static file open_file() {
file read_end, write_end;
file::pipe(read_end, write_end);
write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT));
@ -45,7 +45,7 @@ file open_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();
const char *ptr = s.data();
do {
@ -53,32 +53,32 @@ void write(file &f, fmt::string_view s) {
ptr += count;
// We can't write more than size_t bytes since num_chars_left
// has type size_t.
num_chars_left -= static_cast<std::size_t>(count);
num_chars_left -= count;
} while (num_chars_left != 0);
}
TEST(BufferedFileTest, DefaultCtor) {
buffered_file f;
EXPECT_TRUE(f.get() == 0);
EXPECT_TRUE(f.get() == nullptr);
}
TEST(BufferedFileTest, MoveCtor) {
buffered_file bf = open_buffered_file();
FILE *fp = bf.get();
EXPECT_TRUE(fp != 0);
EXPECT_TRUE(fp != nullptr);
buffered_file bf2(std::move(bf));
EXPECT_EQ(fp, bf2.get());
EXPECT_TRUE(bf.get() == 0);
EXPECT_TRUE(bf.get() == nullptr);
}
TEST(BufferedFileTest, MoveAssignment) {
buffered_file bf = open_buffered_file();
FILE *fp = bf.get();
EXPECT_TRUE(fp != 0);
EXPECT_TRUE(fp != nullptr);
buffered_file bf2;
bf2 = std::move(bf);
EXPECT_EQ(fp, bf2.get());
EXPECT_TRUE(bf.get() == 0);
EXPECT_TRUE(bf.get() == nullptr);
}
TEST(BufferedFileTest, MoveAssignmentClosesFile) {
@ -90,13 +90,13 @@ TEST(BufferedFileTest, MoveAssignmentClosesFile) {
}
TEST(BufferedFileTest, MoveFromTemporaryInCtor) {
FILE *fp = 0;
FILE *fp = nullptr;
buffered_file f(open_buffered_file(&fp));
EXPECT_EQ(fp, f.get());
}
TEST(BufferedFileTest, MoveFromTemporaryInAssignment) {
FILE *fp = 0;
FILE *fp = nullptr;
buffered_file f;
f = open_buffered_file(&fp);
EXPECT_EQ(fp, f.get());
@ -126,7 +126,7 @@ TEST(BufferedFileTest, CloseErrorInDtor) {
// output in EXPECT_STDERR and the second close will break output
// redirection.
FMT_POSIX(close(f->fileno()));
SUPPRESS_ASSERT(f.reset());
SUPPRESS_ASSERT(f.reset(nullptr));
}, format_system_error(EBADF, "cannot close file") + "\n");
}
@ -134,7 +134,7 @@ TEST(BufferedFileTest, Close) {
buffered_file f = open_buffered_file();
int fd = f.fileno();
f.close();
EXPECT_TRUE(f.get() == 0);
EXPECT_TRUE(f.get() == nullptr);
EXPECT_TRUE(isclosed(fd));
}
@ -142,7 +142,7 @@ TEST(BufferedFileTest, CloseError) {
buffered_file f = open_buffered_file();
FMT_POSIX(close(f.fileno()));
EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
EXPECT_TRUE(f.get() == 0);
EXPECT_TRUE(f.get() == nullptr);
}
TEST(BufferedFileTest, Fileno) {
@ -153,7 +153,7 @@ TEST(BufferedFileTest, Fileno) {
EXPECT_DEATH_IF_SUPPORTED({
try {
f.fileno();
} catch (fmt::system_error) {
} catch (const fmt::system_error&) {
std::exit(1);
}
}, "");
@ -209,7 +209,7 @@ TEST(FileTest, MoveAssignmentClosesFile) {
EXPECT_TRUE(isclosed(old_fd));
}
file OpenBufferedFile(int &fd) {
static file OpenBufferedFile(int &fd) {
file f = open_file();
fd = f.descriptor();
return f;
@ -253,7 +253,7 @@ TEST(FileTest, CloseErrorInDtor) {
// output in EXPECT_STDERR and the second close will break output
// redirection.
FMT_POSIX(close(f->descriptor()));
SUPPRESS_ASSERT(f.reset());
SUPPRESS_ASSERT(f.reset(nullptr));
}, 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;
// 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());
s.replace(s.find('%'), 1, "%1$");
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());
s.replace(s.find(L'%'), 1, L"%1$");
return s;
@ -410,7 +410,7 @@ TEST(PrintfTest, Inf) {
double inf = std::numeric_limits<double>::infinity();
for (const char* type = "fega"; *type; ++type) {
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);
}
}
@ -426,11 +426,11 @@ TEST(PrintfTest, Char) {
TEST(PrintfTest, String) {
EXPECT_PRINTF("abc", "%s", "abc");
const char *null_str = 0;
const char *null_str = nullptr;
EXPECT_PRINTF("(null)", "%s", null_str);
EXPECT_PRINTF(" (null)", "%10s", null_str);
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"%10s", null_wstr);
}
@ -439,22 +439,22 @@ TEST(PrintfTest, Pointer) {
int n;
void *p = &n;
EXPECT_PRINTF(fmt::format("{}", p), "%p", p);
p = 0;
p = nullptr;
EXPECT_PRINTF("(nil)", "%p", p);
EXPECT_PRINTF(" (nil)", "%10p", p);
const char *s = "test";
EXPECT_PRINTF(fmt::format("{:p}", s), "%p", s);
const char *null_str = 0;
const char *null_str = nullptr;
EXPECT_PRINTF("(nil)", "%p", null_str);
p = &n;
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"%10p", p);
const wchar_t *w = L"test";
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);
}

View File

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

View File

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

View File

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

View File

@ -17,7 +17,7 @@
# include <type_traits>
#endif
#include "gmock/gmock.h"
#include "gmock.h"
#include "gtest-extra.h"
#include "mock-allocator.h"
#include "util.h"
@ -71,8 +71,8 @@ struct formatter<Test, Char> {
};
FMT_END_NAMESPACE
void CheckForwarding(
MockAllocator<int> &alloc, AllocatorRef< MockAllocator<int> > &ref) {
static void CheckForwarding(
MockAllocator<int> &alloc, AllocatorRef<MockAllocator<int>> &ref) {
int mem;
// Check if value_type is properly defined.
AllocatorRef< MockAllocator<int> >::value_type *ptr = &mem;
@ -92,7 +92,7 @@ TEST(AllocatorTest, AllocatorRef) {
TestAllocatorRef ref2(ref);
CheckForwarding(alloc, ref2);
TestAllocatorRef ref3;
EXPECT_EQ(0, ref3.get());
EXPECT_EQ(nullptr, ref3.get());
ref3 = ref;
CheckForwarding(alloc, ref3);
}
@ -112,7 +112,7 @@ TEST(BufferTest, Nonmoveable) {
// A test buffer with a dummy grow method.
template <typename 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>
@ -132,23 +132,23 @@ struct MockBuffer : basic_buffer<T> {
TEST(BufferTest, Ctor) {
{
MockBuffer<int> buffer;
EXPECT_EQ(0, &buffer[0]);
EXPECT_EQ(0u, buffer.size());
EXPECT_EQ(0u, buffer.capacity());
EXPECT_EQ(nullptr, &buffer[0]);
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
EXPECT_EQ(static_cast<size_t>(0), buffer.capacity());
}
{
int dummy;
MockBuffer<int> buffer(&dummy);
EXPECT_EQ(&dummy, &buffer[0]);
EXPECT_EQ(0u, buffer.size());
EXPECT_EQ(0u, buffer.capacity());
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
EXPECT_EQ(static_cast<size_t>(0), buffer.capacity());
}
{
int dummy;
std::size_t capacity = std::numeric_limits<std::size_t>::max();
MockBuffer<int> buffer(&dummy, capacity);
EXPECT_EQ(&dummy, &buffer[0]);
EXPECT_EQ(0u, buffer.size());
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
EXPECT_EQ(capacity, buffer.capacity());
}
}
@ -201,7 +201,7 @@ TEST(BufferTest, Clear) {
TestBuffer<char> buffer;
buffer.resize(20);
buffer.resize(0);
EXPECT_EQ(0u, buffer.size());
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
EXPECT_EQ(20u, buffer.capacity());
}
@ -231,7 +231,7 @@ TEST(BufferTest, AppendAllocatesEnoughStorage) {
TEST(MemoryBufferTest, Ctor) {
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());
}
@ -239,7 +239,7 @@ TEST(MemoryBufferTest, Ctor) {
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) {
std::allocator<char> *alloc = buffer.get_allocator().get();
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(5u, buffer2.capacity());
// 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());
}
@ -273,7 +273,7 @@ TEST(MemoryBufferTest, MoveCtor) {
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) {
basic_memory_buffer<char, 5> buffer2;
buffer2 = std::move(buffer);
@ -335,7 +335,7 @@ TEST(MemoryBufferTest, Grow) {
TEST(MemoryBufferTest, Allocator) {
typedef AllocatorRef< MockAllocator<char> > TestAllocator;
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;
char mem;
{
@ -376,7 +376,7 @@ TEST(MemoryBufferTest, ExceptionInDeallocate) {
TEST(FixedBufferTest, Ctor) {
char array[10] = "garbage";
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(array, buffer.data());
}
@ -384,7 +384,7 @@ TEST(FixedBufferTest, Ctor) {
TEST(FixedBufferTest, CompileTimeSizeCtor) {
char array[10] = "garbage";
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(array, buffer.data());
}
@ -402,7 +402,7 @@ struct uint32_pair {
TEST(UtilTest, BitCast) {
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));
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) {
ctx.called = true;
return 0;
return nullptr;
}
};
};
@ -583,8 +583,8 @@ TEST(UtilTest, WStringArg) {
}
TEST(UtilTest, PointerArg) {
void *p = 0;
const void *cp = 0;
void *p = nullptr;
const void *cp = nullptr;
CHECK_ARG_(char, cp, p);
CHECK_ARG_(wchar_t, cp, p);
CHECK_ARG(cp, );
@ -765,14 +765,14 @@ TEST(UtilTest, FormatSystemError) {
try {
std::allocator<char> alloc;
alloc.deallocate(alloc.allocate(max_size), max_size);
} catch (std::bad_alloc) {
} catch (const std::bad_alloc&) {
throws_on_alloc = true;
}
if (!throws_on_alloc) {
fmt::print("warning: std::allocator allocates {} chars", max_size);
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));
}
@ -822,7 +822,8 @@ TEST(UtilTest, FormatLongWindowsError) {
const int provisioning_not_allowed = 0x80284013L /*TBS_E_PROVISIONING_NOT_ALLOWED*/;
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
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) {
return;
}
@ -867,7 +868,7 @@ TEST(UtilTest, IsEnumConvertibleToInt) {
#endif
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");
return;
}
@ -881,17 +882,52 @@ TEST(UtilTest, ParseNonnegativeInt) {
fmt::format_error, "number is too big");
}
TEST(UtilTest, FPSubtract) {
auto r = fp(123, 1) - fp(102, 1);
EXPECT_EQ(r.f, 21u);
EXPECT_EQ(r.e, 1);
template <bool is_iec559>
void test_construct_from_double() {
fmt::print("warning: double is not IEC559, skipping FP tests\n");
}
TEST(UtilTest, FPMultiply) {
auto r = fp(123ULL << 32, 4) * fp(56ULL << 32, 7);
EXPECT_EQ(r.f, 123u * 56u);
EXPECT_EQ(r.e, 4 + 7 + 64);
r = fp(123ULL << 32, 4) * fp(567ULL << 31, 8);
EXPECT_EQ(r.f, (123 * 567 + 1u) / 2);
EXPECT_EQ(r.e, 4 + 8 + 64);
template <>
void test_construct_from_double<true>() {
auto v = fp(1.23);
EXPECT_EQ(v.f, 0x13ae147ae147aeu);
EXPECT_EQ(v.e, -52);
}
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;
// 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) {
#if defined(_WIN32) && !defined(__MINGW32__)