externals: Update fmt subtree to 4.10

Merge commit '097203968f0a9b17628062f4adca63ea5cb97aa2' into HEAD
This commit is contained in:
MerryMage 2020-04-22 20:41:46 +01:00
commit 7639f6ebdc
21 changed files with 481 additions and 141 deletions

View file

@ -2,6 +2,14 @@ message(STATUS "CMake version: ${CMAKE_VERSION}")
cmake_minimum_required(VERSION 2.8.12) cmake_minimum_required(VERSION 2.8.12)
if (POLICY CMP0048) # Version variables
cmake_policy(SET CMP0048 OLD)
endif ()
if (POLICY CMP0063) # Visibility
cmake_policy(SET CMP0063 OLD)
endif (POLICY CMP0063)
# Determine if fmt is built as a subproject (using add_subdirectory) # Determine if fmt is built as a subproject (using add_subdirectory)
# or if it is the master project. # or if it is the master project.
set(MASTER_PROJECT OFF) set(MASTER_PROJECT OFF)

View file

@ -1,7 +1,32 @@
4.1.0 - 2017-12-20
------------------
* Added ``fmt::to_wstring()`` in addition to ``fmt::to_string()`` (`#559 <https://github.com/fmtlib/fmt/pull/559>`_). Thanks `@alabuzhev (Alex Alabuzhev) <https://github.com/alabuzhev>`_.
* Added support for C++17 ``std::string_view`` (`#571 <https://github.com/fmtlib/fmt/pull/571>`_ and `#578 <https://github.com/fmtlib/fmt/pull/578>`_). Thanks `@thelostt (Mário Feroldi) <https://github.com/thelostt>`_ and `@mwinterb <https://github.com/mwinterb>`_.
* Enabled stream exceptions to catch errors (`#581 <https://github.com/fmtlib/fmt/issues/581>`_). Thanks `@crusader-mike <https://github.com/crusader-mike>`_.
* Allowed formatting of class hierarchies with ``fmt::format_arg()`` (`#547 <https://github.com/fmtlib/fmt/pull/547>`_). Thanks `@rollbear (Björn Fahller) <https://github.com/rollbear>`_.
* Removed limitations on character types
(`#563 <https://github.com/fmtlib/fmt/pull/563>`_).
Thanks `@Yelnats321 (Elnar Dakeshov) <https://github.com/Yelnats321>`_.
* Conditionally enabled use of ``std::allocator_traits`` (`#583 <https://github.com/fmtlib/fmt/pull/583>`_). Thanks `@mwinterb <https://github.com/mwinterb>`_.
* Added support for ``const`` variadic member function emulation with ``FMT_VARIADIC_CONST`` (`#591 <https://github.com/fmtlib/fmt/pull/591>`_). Thanks `@ludekvodicka (Ludek Vodicka) <https://github.com/ludekvodicka>`_.
* Various bugfixes: bad overflow check, unsupported implicit type conversion when determining formatting function, test segfaults (`#551 <https://github.com/fmtlib/fmt/issues/551>`_), ill-formed macros (`#542 <https://github.com/fmtlib/fmt/pull/542>`_) and ambiguous overloads (`#580 <https://github.com/fmtlib/fmt/issues/580>`_). Thanks `@xylosper (Byoung-young Lee) <https://github.com/xylosper>`_.
* Prevented warnings on MSVC (`#605 <https://github.com/fmtlib/fmt/pull/605>`_, `#602 <https://github.com/fmtlib/fmt/pull/602>`_, and `#545 <https://github.com/fmtlib/fmt/pull/545>`_), clang (`#582 <https://github.com/fmtlib/fmt/pull/582>`_), GCC (`#573 <https://github.com/fmtlib/fmt/issues/573>`_), various conversion warnings (`#609 <https://github.com/fmtlib/fmt/pull/609>`_, `#567 <https://github.com/fmtlib/fmt/pull/567>`_, `#553 <https://github.com/fmtlib/fmt/pull/553>`_ and `#553 <https://github.com/fmtlib/fmt/pull/553>`_), and added ``override`` and ``[[noreturn]]`` (`#549 <https://github.com/fmtlib/fmt/pull/549>`_ and `#555 <https://github.com/fmtlib/fmt/issues/555>`_). Thanks `@alabuzhev (Alex Alabuzhev) <https://github.com/alabuzhev>`_, `@virgiliofornazin (Virgilio Alexandre Fornazin) <https://gihtub.com/virgiliofornazin>`_, `@alexanderbock (Alexander Bock) <https://github.com/alexanderbock>`_, `@yumetodo <https://github.com/yumetodo>`_, `@VaderY (Császár Mátyás) <https://github.com/VaderY>`_, `@jpcima (JP Cimalando) <https://github.com/jpcima>`_, `@thelostt (Mário Feroldi) <https://github.com/thelostt>`_, and `@Manu343726 (Manu Sánchez) <https://github.com/Manu343726>`_.
* Improved CMake: Used GNUInstallDirs to set installation location (`#610 <https://github.com/fmtlib/fmt/pull/610>`_) and fixed warnings (`#536 <https://github.com/fmtlib/fmt/pull/536>`_ and `#556 <https://github.com/fmtlib/fmt/pull/556>`_). Thanks `@mikecrowe (Mike Crowe) <https://github.com/mikecrowe>`_, `@evgen231 <https://github.com/evgen231>`_ and `@henryiii (Henry Schreiner) <https://github.com/henryiii>`_.
4.0.0 - 2017-06-27 4.0.0 - 2017-06-27
------------------ ------------------
* Removed old compatibility headers ``cppformat/*.h`` and CMake options (`#527 <https://github.com/pull/527>`_). Thanks `@maddinat0r (Alex Martin) <https://github.com/maddinat0r>`_. * Removed old compatibility headers ``cppformat/*.h`` and CMake options (`#527 <https://github.com/fmtlib/fmt/pull/527>`_). Thanks `@maddinat0r (Alex Martin) <https://github.com/maddinat0r>`_.
* Added ``string.h`` containing ``fmt::to_string()`` as alternative to ``std::to_string()`` as well as other string writer functionality (`#326 <https://github.com/fmtlib/fmt/issues/326>`_ and `#441 <https://github.com/fmtlib/fmt/pull/441>`_): * Added ``string.h`` containing ``fmt::to_string()`` as alternative to ``std::to_string()`` as well as other string writer functionality (`#326 <https://github.com/fmtlib/fmt/issues/326>`_ and `#441 <https://github.com/fmtlib/fmt/pull/441>`_):

View file

@ -142,6 +142,8 @@ Projects using this library
* `Envoy <https://lyft.github.io/envoy/>`_: C++ L7 proxy and communication bus (Lyft) * `Envoy <https://lyft.github.io/envoy/>`_: C++ L7 proxy and communication bus (Lyft)
* `FiveM <https://fivem.net/>`_: a modification framework for GTA V
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_: * `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
Player vs Player Gaming Network with tweaks Player vs Player Gaming Network with tweaks
@ -155,6 +157,8 @@ Projects using this library
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to generate randomized datasets * `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to generate randomized datasets
* `OpenSpace <http://openspaceproject.com/>`_: An open-source astrovisualization framework
* `PenUltima Online (POL) <http://www.polserver.com/>`_: * `PenUltima Online (POL) <http://www.polserver.com/>`_:
An MMO server, compatible with most Ultima Online clients An MMO server, compatible with most Ultima Online clients

View file

@ -84,6 +84,36 @@ Note in the example above the ``format_arg`` function ignores the contents of
``format_arg`` in :file:`fmt/time.h` for an advanced example of how to use ``format_arg`` in :file:`fmt/time.h` for an advanced example of how to use
the ``format_str`` argument to customize the formatted output. the ``format_str`` argument to customize the formatted output.
This technique can also be used for formatting class hierarchies::
namespace local {
struct Parent {
Parent(int p) : p(p) {}
virtual void write(fmt::Writer &w) const {
w.write("Parent : p={}", p);
}
int p;
};
struct Child : Parent {
Child(int c, int p) : Parent(p), c(c) {}
virtual void write(fmt::Writer &w) const {
w.write("Child c={} : ", c);
Parent::write(w);
}
int c;
};
void format_arg(fmt::BasicFormatter<char> &f,
const char *&format_str, const Parent &p) {
p.write(f.writer());
}
}
Local::Child c(1,2);
Local::Parent &p = c;
fmt::print("via ref to base: {}\n", p);
fmt::print("direct to child: {}\n", c);
This section shows how to define a custom format function for a user-defined This section shows how to define a custom format function for a user-defined
type. The next section describes how to get ``fmt`` to use a conventional stream type. The next section describes how to get ``fmt`` to use a conventional stream
output ``operator<<`` when one is defined for a user-defined type. output ``operator<<`` when one is defined for a user-defined type.
@ -232,6 +262,8 @@ Utilities
.. doxygenfunction:: fmt::to_string(const T&) .. doxygenfunction:: fmt::to_string(const T&)
.. doxygenfunction:: fmt::to_wstring(const T&)
.. doxygenclass:: fmt::BasicStringRef .. doxygenclass:: fmt::BasicStringRef
:members: :members:

View file

@ -6,6 +6,8 @@ import errno, os, shutil, sys, tempfile
from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE
from distutils.version import LooseVersion from distutils.version import LooseVersion
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0']
def pip_install(package, commit=None, **kwargs): def pip_install(package, commit=None, **kwargs):
"Install package using pip." "Install package using pip."
min_version = kwargs.get('min_version') min_version = kwargs.get('min_version')
@ -93,11 +95,11 @@ def build_docs(version='dev', **kwargs):
if p.returncode != 0: if p.returncode != 0:
raise CalledProcessError(p.returncode, cmd) raise CalledProcessError(p.returncode, cmd)
html_dir = os.path.join(work_dir, 'html') html_dir = os.path.join(work_dir, 'html')
versions = ['3.0.0', '2.0.0', '1.1.0'] main_versions = reversed(versions[-3:])
check_call(['sphinx-build', check_call(['sphinx-build',
'-Dbreathe_projects.format=' + os.path.abspath(doxyxml_dir), '-Dbreathe_projects.format=' + os.path.abspath(doxyxml_dir),
'-Dversion=' + version, '-Drelease=' + version, '-Dversion=' + version, '-Drelease=' + version,
'-Aversion=' + version, '-Aversions=' + ','.join(versions), '-Aversion=' + version, '-Aversions=' + ','.join(main_versions),
'-b', 'html', doc_dir, html_dir]) '-b', 'html', doc_dir, html_dir])
try: try:
check_call(['lessc', '--clean-css', check_call(['lessc', '--clean-css',

View file

@ -143,6 +143,12 @@ its numeric value being written to the stream (i.e. 1070 instead of letter 'ю'
which is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is which is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is
needed. needed.
Note that fmt does not use the value of the ``errno`` global to communicate
errors to the user, but it may call system functions which set ``errno``. Since
fmt does not attempt to preserve the value of ``errno``, users should not make
any assumptions about it and always set it to ``0`` before making any system
calls that convey error information via ``errno``.
.. _portability: .. _portability:
Portability Portability

View file

@ -335,6 +335,16 @@ Aligning the text and specifying a width::
format("{:*^30}", "centered"); // use '*' as a fill char format("{:*^30}", "centered"); // use '*' as a fill char
// Result: "***********centered***********" // Result: "***********centered***********"
Dynamic width::
format("{:<{}}", "left aligned", 30);
// Result: "left aligned "
Dynamic precision::
format("{:.{}f}", 3.14, 1);
// Result: "3.1"
Replacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign:: Replacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign::
format("{:+f}; {:+f}", 3.14, -3.14); // show it always format("{:+f}; {:+f}", 3.14, -3.14); // show it always
@ -359,13 +369,6 @@ Replacing ``%x`` and ``%o`` and converting the value to different bases::
format("{:,}", 1234567890); format("{:,}", 1234567890);
'1,234,567,890' '1,234,567,890'
Expressing a percentage::
>>> points = 19
>>> total = 22
Format("Correct answers: {:.2%}") << points/total)
'Correct answers: 86.36%'
Using type-specific formatting:: Using type-specific formatting::
>>> import datetime >>> import datetime

View file

@ -41,6 +41,10 @@ current directory. Now you can build the library by running :command:`make`.
Once the library has been built you can invoke :command:`make test` to run Once the library has been built you can invoke :command:`make test` to run
the tests. the tests.
You can control generation of the make ``test`` target with the ``FMT_TEST``
CMake option. This can be useful if you include fmt as a subdirectory in
your project but don't want to add fmt's tests to your ``test`` target.
If you use Windows and have Visual Studio installed, a :file:`FORMAT.sln` If you use Windows and have Visual Studio installed, a :file:`FORMAT.sln`
file and several :file:`.vcproj` files will be created. You can then build them file and several :file:`.vcproj` files will be created. You can then build them
using Visual Studio or msbuild. using Visual Studio or msbuild.

View file

@ -49,8 +49,9 @@ endif ()
# Install targets. # Install targets.
if (FMT_INSTALL) if (FMT_INSTALL)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
set(FMT_CMAKE_DIR lib/cmake/fmt CACHE STRING set(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING
"Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.") "Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.")
set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake) set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake)
set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake) set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake)
@ -61,9 +62,12 @@ if (FMT_INSTALL)
set(INSTALL_TARGETS ${INSTALL_TARGETS} fmt-header-only) set(INSTALL_TARGETS ${INSTALL_TARGETS} fmt-header-only)
endif () endif ()
set(FMT_LIB_DIR lib CACHE STRING set(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING
"Installation directory for libraries, relative to ${CMAKE_INSTALL_PREFIX}.") "Installation directory for libraries, relative to ${CMAKE_INSTALL_PREFIX}.")
set(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR}/fmt CACHE STRING
"Installation directory for include files, relative to ${CMAKE_INSTALL_PREFIX}.")
# Generate the version, config and target files into the build directory. # Generate the version, config and target files into the build directory.
write_basic_package_version_file( write_basic_package_version_file(
${version_config} ${version_config}
@ -86,5 +90,5 @@ if (FMT_INSTALL)
# Install the library and headers. # Install the library and headers.
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name} install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
DESTINATION ${FMT_LIB_DIR}) DESTINATION ${FMT_LIB_DIR})
install(FILES ${FMT_HEADERS} DESTINATION include/fmt) install(FILES ${FMT_HEADERS} DESTINATION ${FMT_INC_DIR})
endif () endif ()

View file

@ -72,9 +72,11 @@
// Dummy implementations of strerror_r and strerror_s called if corresponding // Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available. // system functions are not available.
FMT_MAYBE_UNUSED
static inline fmt::internal::Null<> strerror_r(int, char *, ...) { static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
return fmt::internal::Null<>(); return fmt::internal::Null<>();
} }
FMT_MAYBE_UNUSED
static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
return fmt::internal::Null<>(); return fmt::internal::Null<>();
} }
@ -121,7 +123,7 @@ typedef void (*FormatFunc)(Writer &, int, StringRef);
// Buffer should be at least of size 1. // Buffer should be at least of size 1.
int safe_strerror( int safe_strerror(
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer"); FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
class StrError { class StrError {
private: private:
@ -159,6 +161,11 @@ int safe_strerror(
ERANGE : result; ERANGE : result;
} }
#ifdef __c2__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
// Fallback to strerror if strerror_r and strerror_s are not available. // Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(internal::Null<>) { int fallback(internal::Null<>) {
errno = 0; errno = 0;
@ -166,13 +173,15 @@ int safe_strerror(
return errno; return errno;
} }
#ifdef __c2__
# pragma clang diagnostic pop
#endif
public: public:
StrError(int err_code, char *&buf, std::size_t buf_size) StrError(int err_code, char *&buf, std::size_t buf_size)
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
int run() { int run() {
// Suppress a warning about unused strerror_r.
strerror_r(0, FMT_NULL, "");
return handle(strerror_r(error_code_, buffer_, buffer_size_)); return handle(strerror_r(error_code_, buffer_, buffer_size_));
} }
}; };
@ -396,51 +405,6 @@ FMT_FUNC void format_system_error(
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
} }
template <typename Char>
void internal::ArgMap<Char>::init(const ArgList &args) {
if (!map_.empty())
return;
typedef internal::NamedArg<Char> NamedArg;
const NamedArg *named_arg = FMT_NULL;
bool use_values =
args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
if (use_values) {
for (unsigned i = 0;/*nothing*/; ++i) {
internal::Arg::Type arg_type = args.type(i);
switch (arg_type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
return;
}
for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
internal::Arg::Type arg_type = args.type(i);
if (arg_type == internal::Arg::NAMED_ARG) {
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
}
}
for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
switch (args.args_[i].type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
}
template <typename Char> template <typename Char>
void internal::FixedBuffer<Char>::grow(std::size_t) { void internal::FixedBuffer<Char>::grow(std::size_t) {
FMT_THROW(std::runtime_error("buffer overflow")); FMT_THROW(std::runtime_error("buffer overflow"));
@ -502,8 +466,6 @@ template struct internal::BasicData<void>;
template void internal::FixedBuffer<char>::grow(std::size_t); template void internal::FixedBuffer<char>::grow(std::size_t);
template void internal::ArgMap<char>::init(const ArgList &args);
template FMT_API int internal::CharTraits<char>::format_float( template FMT_API int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format, char *buffer, std::size_t size, const char *format,
unsigned width, int precision, double value); unsigned width, int precision, double value);
@ -516,8 +478,6 @@ template FMT_API int internal::CharTraits<char>::format_float(
template void internal::FixedBuffer<wchar_t>::grow(std::size_t); template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
template void internal::ArgMap<wchar_t>::init(const ArgList &args);
template FMT_API int internal::CharTraits<wchar_t>::format_float( template FMT_API int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format, wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, double value); unsigned width, int precision, double value);

View file

@ -28,6 +28,7 @@
#ifndef FMT_FORMAT_H_ #ifndef FMT_FORMAT_H_
#define FMT_FORMAT_H_ #define FMT_FORMAT_H_
#define FMT_INCLUDE
#include <cassert> #include <cassert>
#include <clocale> #include <clocale>
#include <cmath> #include <cmath>
@ -39,11 +40,26 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <utility> // for std::pair #include <utility> // for std::pair
#undef FMT_INCLUDE
// The fmt library version in the form major * 10000 + minor * 100 + patch. // The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 40000 #define FMT_VERSION 40100
#ifdef _SECURE_SCL #if defined(__has_include)
# define FMT_HAS_INCLUDE(x) __has_include(x)
#else
# define FMT_HAS_INCLUDE(x) 0
#endif
#if (FMT_HAS_INCLUDE(<string_view>) && __cplusplus > 201402L) || \
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
# include <string_view>
# define FMT_HAS_STRING_VIEW 1
#else
# define FMT_HAS_STRING_VIEW 0
#endif
#if defined _SECURE_SCL && _SECURE_SCL
# define FMT_SECURE_SCL _SECURE_SCL # define FMT_SECURE_SCL _SECURE_SCL
#else #else
# define FMT_SECURE_SCL 0 # define FMT_SECURE_SCL 0
@ -97,7 +113,9 @@ typedef __int64 intmax_t;
# define FMT_HAS_GXX_CXX11 1 # define FMT_HAS_GXX_CXX11 1
# endif # endif
#else #else
# define FMT_GCC_VERSION 0
# define FMT_GCC_EXTENSION # define FMT_GCC_EXTENSION
# define FMT_HAS_GXX_CXX11 0
#endif #endif
#if defined(__INTEL_COMPILER) #if defined(__INTEL_COMPILER)
@ -135,6 +153,32 @@ typedef __int64 intmax_t;
# define FMT_HAS_CPP_ATTRIBUTE(x) 0 # define FMT_HAS_CPP_ATTRIBUTE(x) 0
#endif #endif
#if FMT_HAS_CPP_ATTRIBUTE(maybe_unused)
# define FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED
// VC++ 1910 support /std: option and that will set _MSVC_LANG macro
// Clang with Microsoft CodeGen doesn't define _MSVC_LANG macro
#elif defined(_MSVC_LANG) && _MSVC_LANG > 201402 && _MSC_VER >= 1910
# define FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED
#endif
#ifdef FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED
# define FMT_MAYBE_UNUSED [[maybe_unused]]
// g++/clang++ also support [[gnu::unused]]. However, we don't use it.
#elif defined(__GNUC__)
# define FMT_MAYBE_UNUSED __attribute__((unused))
#else
# define FMT_MAYBE_UNUSED
#endif
// Use the compiler's attribute noreturn
#if defined(__MINGW32__) || defined(__MINGW64__)
# define FMT_NORETURN __attribute__((noreturn))
#elif FMT_HAS_CPP_ATTRIBUTE(noreturn) && __cplusplus >= 201103L
# define FMT_NORETURN [[noreturn]]
#else
# define FMT_NORETURN
#endif
#ifndef FMT_USE_VARIADIC_TEMPLATES #ifndef FMT_USE_VARIADIC_TEMPLATES
// Variadic templates are available in GCC since version 4.4 // Variadic templates are available in GCC since version 4.4
// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ // (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++
@ -156,6 +200,12 @@ typedef __int64 intmax_t;
# endif # endif
#endif #endif
#if __cplusplus >= 201103L || FMT_MSC_VER >= 1700
# define FMT_USE_ALLOCATOR_TRAITS 1
#else
# define FMT_USE_ALLOCATOR_TRAITS 0
#endif
// Check if exceptions are disabled. // Check if exceptions are disabled.
#if defined(__GNUC__) && !defined(__EXCEPTIONS) #if defined(__GNUC__) && !defined(__EXCEPTIONS)
# define FMT_EXCEPTIONS 0 # define FMT_EXCEPTIONS 0
@ -262,11 +312,14 @@ typedef __int64 intmax_t;
// makes the fmt::literals implementation easier. However, an explicit check // makes the fmt::literals implementation easier. However, an explicit check
// for variadic templates is added here just in case. // for variadic templates is added here just in case.
// For Intel's compiler both it and the system gcc/msc must support UDLs. // For Intel's compiler both it and the system gcc/msc must support UDLs.
# define FMT_USE_USER_DEFINED_LITERALS \ # if FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \
FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \
(FMT_HAS_FEATURE(cxx_user_literals) || \ (FMT_HAS_FEATURE(cxx_user_literals) || \
(FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900) && \ (FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900) && \
(!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500) (!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500)
# define FMT_USE_USER_DEFINED_LITERALS 1
# else
# define FMT_USE_USER_DEFINED_LITERALS 0
# endif
#endif #endif
#ifndef FMT_USE_EXTERN_TEMPLATES #ifndef FMT_USE_EXTERN_TEMPLATES
@ -305,7 +358,10 @@ typedef __int64 intmax_t;
namespace fmt { namespace fmt {
namespace internal { namespace internal {
// avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning
# ifndef __clang__
# pragma intrinsic(_BitScanReverse) # pragma intrinsic(_BitScanReverse)
# endif
inline uint32_t clz(uint32_t x) { inline uint32_t clz(uint32_t x) {
unsigned long r = 0; unsigned long r = 0;
_BitScanReverse(&r, x); _BitScanReverse(&r, x);
@ -319,7 +375,8 @@ inline uint32_t clz(uint32_t x) {
} }
# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) # define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n)
# ifdef _WIN64 // avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning
# if defined(_WIN64) && !defined(__clang__)
# pragma intrinsic(_BitScanReverse64) # pragma intrinsic(_BitScanReverse64)
# endif # endif
@ -505,6 +562,26 @@ class BasicStringRef {
const std::basic_string<Char, std::char_traits<Char>, Allocator> &s) const std::basic_string<Char, std::char_traits<Char>, Allocator> &s)
: data_(s.c_str()), size_(s.size()) {} : data_(s.c_str()), size_(s.size()) {}
#if FMT_HAS_STRING_VIEW
/**
\rst
Constructs a string reference from a ``std::basic_string_view`` object.
\endrst
*/
BasicStringRef(
const std::basic_string_view<Char, std::char_traits<Char>> &s)
: data_(s.data()), size_(s.size()) {}
/**
\rst
Converts a string reference to an ``std::string_view`` object.
\endrst
*/
explicit operator std::basic_string_view<Char>() const FMT_NOEXCEPT {
return std::basic_string_view<Char>(data_, size_);
}
#endif
/** /**
\rst \rst
Converts a string reference to an ``std::string`` object. Converts a string reference to an ``std::string`` object.
@ -609,7 +686,7 @@ class FormatError : public std::runtime_error {
explicit FormatError(CStringRef message) explicit FormatError(CStringRef message)
: std::runtime_error(message.c_str()) {} : std::runtime_error(message.c_str()) {}
FormatError(const FormatError &ferr) : std::runtime_error(ferr) {} FormatError(const FormatError &ferr) : std::runtime_error(ferr) {}
FMT_API ~FormatError() FMT_DTOR_NOEXCEPT; FMT_API ~FormatError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE;
}; };
namespace internal { namespace internal {
@ -726,7 +803,7 @@ template <typename T>
template <typename U> template <typename U>
void Buffer<T>::append(const U *begin, const U *end) { void Buffer<T>::append(const U *begin, const U *end) {
FMT_ASSERT(end >= begin, "negative value"); FMT_ASSERT(end >= begin, "negative value");
std::size_t new_size = size_ + (end - begin); std::size_t new_size = size_ + static_cast<std::size_t>(end - begin);
if (new_size > capacity_) if (new_size > capacity_)
grow(new_size); grow(new_size);
std::uninitialized_copy(begin, end, std::uninitialized_copy(begin, end,
@ -754,7 +831,7 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
public: public:
explicit MemoryBuffer(const Allocator &alloc = Allocator()) explicit MemoryBuffer(const Allocator &alloc = Allocator())
: Allocator(alloc), Buffer<T>(data_, SIZE) {} : Allocator(alloc), Buffer<T>(data_, SIZE) {}
~MemoryBuffer() { deallocate(); } ~MemoryBuffer() FMT_OVERRIDE { deallocate(); }
#if FMT_USE_RVALUE_REFERENCES #if FMT_USE_RVALUE_REFERENCES
private: private:
@ -798,7 +875,12 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) {
std::size_t new_capacity = this->capacity_ + this->capacity_ / 2; std::size_t new_capacity = this->capacity_ + this->capacity_ / 2;
if (size > new_capacity) if (size > new_capacity)
new_capacity = size; new_capacity = size;
#if FMT_USE_ALLOCATOR_TRAITS
T *new_ptr =
std::allocator_traits<Allocator>::allocate(*this, new_capacity, FMT_NULL);
#else
T *new_ptr = this->allocate(new_capacity, FMT_NULL); T *new_ptr = this->allocate(new_capacity, FMT_NULL);
#endif
// The following code doesn't throw, so the raw pointer above doesn't leak. // The following code doesn't throw, so the raw pointer above doesn't leak.
std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_, std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_,
make_ptr(new_ptr, new_capacity)); make_ptr(new_ptr, new_capacity));
@ -916,7 +998,7 @@ struct IntTraits {
TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType; TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType;
}; };
FMT_API void report_unknown_type(char code, const char *type); FMT_API FMT_NORETURN void report_unknown_type(char code, const char *type);
// Static data is placed in this class template to allow header-only // Static data is placed in this class template to allow header-only
// configuration. // configuration.
@ -1248,9 +1330,9 @@ inline fmt::StringRef thousands_sep(...) { return ""; }
typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED
#endif #endif
template <typename Formatter, typename Char, typename T> template <typename Formatter>
void format_arg(Formatter &, const Char *, const T &) { void format_arg(Formatter&, ...) {
FMT_STATIC_ASSERT(FalseType<T>::value, FMT_STATIC_ASSERT(FalseType<Formatter>::value,
"Cannot format argument. To enable the use of ostream " "Cannot format argument. To enable the use of ostream "
"operator<< include fmt/ostream.h. Otherwise provide " "operator<< include fmt/ostream.h. Otherwise provide "
"an overload of format_arg."); "an overload of format_arg.");
@ -1283,6 +1365,9 @@ class MakeValue : public Arg {
MakeValue(typename WCharHelper<wchar_t *, Char>::Unsupported); MakeValue(typename WCharHelper<wchar_t *, Char>::Unsupported);
MakeValue(typename WCharHelper<const wchar_t *, Char>::Unsupported); MakeValue(typename WCharHelper<const wchar_t *, Char>::Unsupported);
MakeValue(typename WCharHelper<const std::wstring &, Char>::Unsupported); MakeValue(typename WCharHelper<const std::wstring &, Char>::Unsupported);
#if FMT_HAS_STRING_VIEW
MakeValue(typename WCharHelper<const std::wstring_view &, Char>::Unsupported);
#endif
MakeValue(typename WCharHelper<WStringRef, Char>::Unsupported); MakeValue(typename WCharHelper<WStringRef, Char>::Unsupported);
void set_string(StringRef str) { void set_string(StringRef str) {
@ -1352,6 +1437,20 @@ class MakeValue : public Arg {
FMT_MAKE_VALUE(unsigned char, uint_value, UINT) FMT_MAKE_VALUE(unsigned char, uint_value, UINT)
FMT_MAKE_VALUE(char, int_value, CHAR) FMT_MAKE_VALUE(char, int_value, CHAR)
#if __cplusplus >= 201103L
template <
typename T,
typename = typename std::enable_if<
std::is_enum<T>::value && ConvertToInt<T>::value>::type>
MakeValue(T value) { int_value = value; }
template <
typename T,
typename = typename std::enable_if<
std::is_enum<T>::value && ConvertToInt<T>::value>::type>
static uint64_t type(T) { return Arg::INT; }
#endif
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
MakeValue(typename WCharHelper<wchar_t, Char>::Supported value) { MakeValue(typename WCharHelper<wchar_t, Char>::Supported value) {
int_value = value; int_value = value;
@ -1370,6 +1469,9 @@ class MakeValue : public Arg {
FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING) FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING)
FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING)
FMT_MAKE_STR_VALUE(const std::string &, STRING) FMT_MAKE_STR_VALUE(const std::string &, STRING)
#if FMT_HAS_STRING_VIEW
FMT_MAKE_STR_VALUE(const std::string_view &, STRING)
#endif
FMT_MAKE_STR_VALUE(StringRef, STRING) FMT_MAKE_STR_VALUE(StringRef, STRING)
FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str())
@ -1382,6 +1484,9 @@ class MakeValue : public Arg {
FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING) FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING)
FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING) FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING)
FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING) FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING)
#if FMT_HAS_STRING_VIEW
FMT_MAKE_WSTR_VALUE(const std::wstring_view &, WSTRING)
#endif
FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING) FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING)
FMT_MAKE_VALUE(void *, pointer, POINTER) FMT_MAKE_VALUE(void *, pointer, POINTER)
@ -1447,7 +1552,7 @@ class RuntimeError : public std::runtime_error {
protected: protected:
RuntimeError() : std::runtime_error("") {} RuntimeError() : std::runtime_error("") {}
RuntimeError(const RuntimeError &rerr) : std::runtime_error(rerr) {} RuntimeError(const RuntimeError &rerr) : std::runtime_error(rerr) {}
FMT_API ~RuntimeError() FMT_DTOR_NOEXCEPT; FMT_API ~RuntimeError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE;
}; };
template <typename Char> template <typename Char>
@ -1921,7 +2026,7 @@ class ArgMap {
MapType map_; MapType map_;
public: public:
FMT_API void init(const ArgList &args); void init(const ArgList &args);
const internal::Arg *find(const fmt::BasicStringRef<Char> &name) const { const internal::Arg *find(const fmt::BasicStringRef<Char> &name) const {
// The list is unsorted, so just return the first matching name. // The list is unsorted, so just return the first matching name.
@ -1934,6 +2039,51 @@ class ArgMap {
} }
}; };
template <typename Char>
void ArgMap<Char>::init(const ArgList &args) {
if (!map_.empty())
return;
typedef internal::NamedArg<Char> NamedArg;
const NamedArg *named_arg = FMT_NULL;
bool use_values =
args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
if (use_values) {
for (unsigned i = 0;/*nothing*/; ++i) {
internal::Arg::Type arg_type = args.type(i);
switch (arg_type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
return;
}
for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
internal::Arg::Type arg_type = args.type(i);
if (arg_type == internal::Arg::NAMED_ARG) {
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
}
}
for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
switch (args.args_[i].type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
}
template <typename Impl, typename Char, typename Spec = fmt::FormatSpec> template <typename Impl, typename Char, typename Spec = fmt::FormatSpec>
class ArgFormatterBase : public ArgVisitor<Impl, void> { class ArgFormatterBase : public ArgVisitor<Impl, void> {
private: private:
@ -2220,7 +2370,8 @@ struct ArgArray;
template <std::size_t N> template <std::size_t N>
struct ArgArray<N, true/*IsPacked*/> { struct ArgArray<N, true/*IsPacked*/> {
typedef Value Type[N > 0 ? N : 1]; // '+' is used to silence GCC -Wduplicated-branches warning.
typedef Value Type[N > 0 ? N : +1];
template <typename Formatter, typename T> template <typename Formatter, typename T>
static Value make(const T &value) { static Value make(const T &value) {
@ -2410,7 +2561,7 @@ class SystemError : public internal::RuntimeError {
FMT_DEFAULTED_COPY_CTOR(SystemError) FMT_DEFAULTED_COPY_CTOR(SystemError)
FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef) FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef)
FMT_API ~SystemError() FMT_DTOR_NOEXCEPT; FMT_API ~SystemError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE;
int error_code() const { return error_code_; } int error_code() const { return error_code_; }
}; };
@ -3483,10 +3634,10 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED;
#define FMT_GET_ARG_NAME(type, index) arg##index #define FMT_GET_ARG_NAME(type, index) arg##index
#if FMT_USE_VARIADIC_TEMPLATES #if FMT_USE_VARIADIC_TEMPLATES
# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ # define FMT_VARIADIC_(Const, Char, ReturnType, func, call, ...) \
template <typename... Args> \ template <typename... Args> \
ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \
const Args & ... args) { \ const Args & ... args) Const { \
typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \ typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \
typename ArgArray::Type array{ \ typename ArgArray::Type array{ \
ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \ ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \
@ -3496,35 +3647,35 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED;
#else #else
// Defines a wrapper for a function taking __VA_ARGS__ arguments // Defines a wrapper for a function taking __VA_ARGS__ arguments
// and n additional arguments of arbitrary types. // and n additional arguments of arbitrary types.
# define FMT_WRAP(Char, ReturnType, func, call, n, ...) \ # define FMT_WRAP(Const, Char, ReturnType, func, call, n, ...) \
template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \ template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \
inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \
FMT_GEN(n, FMT_MAKE_ARG)) { \ FMT_GEN(n, FMT_MAKE_ARG)) Const { \
fmt::internal::ArgArray<n>::Type arr; \ fmt::internal::ArgArray<n>::Type arr; \
FMT_GEN(n, FMT_ASSIGN_##Char); \ FMT_GEN(n, FMT_ASSIGN_##Char); \
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \ fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \
} }
# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ # define FMT_VARIADIC_(Const, Char, ReturnType, func, call, ...) \
inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \ inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) Const { \
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \
} \ } \
FMT_WRAP(Char, ReturnType, func, call, 1, __VA_ARGS__) \ FMT_WRAP(Const, Char, ReturnType, func, call, 1, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 2, __VA_ARGS__) \ FMT_WRAP(Const, Char, ReturnType, func, call, 2, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 3, __VA_ARGS__) \ FMT_WRAP(Const, Char, ReturnType, func, call, 3, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 4, __VA_ARGS__) \ FMT_WRAP(Const, Char, ReturnType, func, call, 4, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 5, __VA_ARGS__) \ FMT_WRAP(Const, Char, ReturnType, func, call, 5, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 6, __VA_ARGS__) \ FMT_WRAP(Const, Char, ReturnType, func, call, 6, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 7, __VA_ARGS__) \ FMT_WRAP(Const, Char, ReturnType, func, call, 7, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 8, __VA_ARGS__) \ FMT_WRAP(Const, Char, ReturnType, func, call, 8, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 9, __VA_ARGS__) \ FMT_WRAP(Const, Char, ReturnType, func, call, 9, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 10, __VA_ARGS__) \ FMT_WRAP(Const, Char, ReturnType, func, call, 10, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 11, __VA_ARGS__) \ FMT_WRAP(Const, Char, ReturnType, func, call, 11, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 12, __VA_ARGS__) \ FMT_WRAP(Const, Char, ReturnType, func, call, 12, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 13, __VA_ARGS__) \ FMT_WRAP(Const, Char, ReturnType, func, call, 13, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 14, __VA_ARGS__) \ FMT_WRAP(Const, Char, ReturnType, func, call, 14, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 15, __VA_ARGS__) FMT_WRAP(Const, Char, ReturnType, func, call, 15, __VA_ARGS__)
#endif // FMT_USE_VARIADIC_TEMPLATES #endif // FMT_USE_VARIADIC_TEMPLATES
/** /**
@ -3555,10 +3706,16 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED;
\endrst \endrst
*/ */
#define FMT_VARIADIC(ReturnType, func, ...) \ #define FMT_VARIADIC(ReturnType, func, ...) \
FMT_VARIADIC_(char, ReturnType, func, return func, __VA_ARGS__) FMT_VARIADIC_(, char, ReturnType, func, return func, __VA_ARGS__)
#define FMT_VARIADIC_CONST(ReturnType, func, ...) \
FMT_VARIADIC_(const, char, ReturnType, func, return func, __VA_ARGS__)
#define FMT_VARIADIC_W(ReturnType, func, ...) \ #define FMT_VARIADIC_W(ReturnType, func, ...) \
FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) FMT_VARIADIC_(, wchar_t, ReturnType, func, return func, __VA_ARGS__)
#define FMT_VARIADIC_CONST_W(ReturnType, func, ...) \
FMT_VARIADIC_(const, wchar_t, ReturnType, func, return func, __VA_ARGS__)
#define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id) #define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id)
@ -3601,17 +3758,19 @@ template <typename Char>
unsigned parse_nonnegative_int(const Char *&s) { unsigned parse_nonnegative_int(const Char *&s) {
assert('0' <= *s && *s <= '9'); assert('0' <= *s && *s <= '9');
unsigned value = 0; unsigned value = 0;
do {
unsigned new_value = value * 10 + (*s++ - '0');
// Check if value wrapped around.
if (new_value < value) {
value = (std::numeric_limits<unsigned>::max)();
break;
}
value = new_value;
} while ('0' <= *s && *s <= '9');
// Convert to unsigned to prevent a warning. // Convert to unsigned to prevent a warning.
unsigned max_int = (std::numeric_limits<int>::max)(); unsigned max_int = (std::numeric_limits<int>::max)();
unsigned big = max_int / 10;
do {
// Check for overflow.
if (value > big) {
value = max_int + 1;
break;
}
value = value * 10 + (*s - '0');
++s;
} while ('0' <= *s && *s <= '9');
// Convert to unsigned to prevent a warning.
if (value > max_int) if (value > max_int)
FMT_THROW(FormatError("number is too big")); FMT_THROW(FormatError("number is too big"));
return value; return value;
@ -3783,7 +3942,8 @@ const Char *BasicFormatter<Char, ArgFormatter>::format(
default: default:
FMT_THROW(FormatError("width is not integer")); FMT_THROW(FormatError("width is not integer"));
} }
if (value > (std::numeric_limits<int>::max)()) unsigned max_int = (std::numeric_limits<int>::max)();
if (value > max_int)
FMT_THROW(FormatError("number is too big")); FMT_THROW(FormatError("number is too big"));
spec.width_ = static_cast<int>(value); spec.width_ = static_cast<int>(value);
} }
@ -3821,7 +3981,8 @@ const Char *BasicFormatter<Char, ArgFormatter>::format(
default: default:
FMT_THROW(FormatError("precision is not integer")); FMT_THROW(FormatError("precision is not integer"));
} }
if (value > (std::numeric_limits<int>::max)()) unsigned max_int = (std::numeric_limits<int>::max)();
if (value > max_int)
FMT_THROW(FormatError("number is too big")); FMT_THROW(FormatError("number is too big"));
spec.precision_ = static_cast<int>(value); spec.precision_ = static_cast<int>(value);
} else { } else {

View file

@ -52,8 +52,10 @@ Yes &convert(std::ostream &);
struct DummyStream : std::ostream { struct DummyStream : std::ostream {
DummyStream(); // Suppress a bogus warning in MSVC. DummyStream(); // Suppress a bogus warning in MSVC.
// Hide all operator<< overloads from std::ostream. // Hide all operator<< overloads from std::ostream.
void operator<<(Null<>); template <typename T>
typename EnableIf<sizeof(T) == 0>::type operator<<(const T &);
}; };
No &operator<<(std::ostream &, int); No &operator<<(std::ostream &, int);
@ -78,6 +80,7 @@ void format_arg(BasicFormatter<Char, ArgFormatter_> &f,
internal::FormatBuf<Char> format_buf(buffer); internal::FormatBuf<Char> format_buf(buffer);
std::basic_ostream<Char> output(&format_buf); std::basic_ostream<Char> output(&format_buf);
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
output << value; output << value;
BasicStringRef<Char> str(&buffer[0], buffer.size()); BasicStringRef<Char> str(&buffer[0], buffer.size());

View file

@ -110,7 +110,7 @@ class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
visit_any_int(value); visit_any_int(value);
} }
void visit_char(char value) { void visit_char(int value) {
if (type_ != 's') if (type_ != 's')
visit_any_int(value); visit_any_int(value);
} }
@ -125,7 +125,7 @@ class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
using internal::Arg; using internal::Arg;
typedef typename internal::Conditional< typedef typename internal::Conditional<
is_same<T, void>::value, U, T>::type TargetType; is_same<T, void>::value, U, T>::type TargetType;
if (sizeof(TargetType) <= sizeof(int)) { if (const_check(sizeof(TargetType) <= sizeof(int))) {
// Extra casts are used to silence warnings. // Extra casts are used to silence warnings.
if (is_signed) { if (is_signed) {
arg_.type = Arg::INT; arg_.type = Arg::INT;

View file

@ -7,6 +7,10 @@
For the license information refer to format.h. For the license information refer to format.h.
*/ */
#ifdef FMT_INCLUDE
# error "Add the fmt's parent directory and not fmt itself to includes."
#endif
#ifndef FMT_STRING_H_ #ifndef FMT_STRING_H_
#define FMT_STRING_H_ #define FMT_STRING_H_
@ -121,6 +125,24 @@ std::string to_string(const T &value) {
w << value; w << value;
return w.str(); return w.str();
} }
/**
\rst
Converts *value* to ``std::wstring`` using the default format for type *T*.
**Example**::
#include "fmt/string.h"
std::wstring answer = fmt::to_wstring(42);
\endrst
*/
template <typename T>
std::wstring to_wstring(const T &value) {
fmt::WMemoryWriter w;
w << value;
return w.str();
}
} }
#endif // FMT_STRING_H_ #endif // FMT_STRING_H_

View file

@ -8,7 +8,7 @@ Usage:
""" """
from __future__ import print_function from __future__ import print_function
import datetime, docopt, fileinput, json, os import datetime, docopt, errno, fileinput, json, os
import re, requests, shutil, sys, tempfile import re, requests, shutil, sys, tempfile
from contextlib import contextmanager from contextlib import contextmanager
from distutils.version import LooseVersion from distutils.version import LooseVersion
@ -80,6 +80,7 @@ def create_build_env():
import build import build
env.build_dir = 'build' env.build_dir = 'build'
env.versions = build.versions
# Virtualenv and repos are cached to speed up builds. # Virtualenv and repos are cached to speed up builds.
build.create_build_env(os.path.join(env.build_dir, 'virtualenv')) build.create_build_env(os.path.join(env.build_dir, 'virtualenv'))
@ -113,7 +114,7 @@ def update_site(env):
doc_repo = Git(os.path.join(env.build_dir, 'fmtlib.github.io')) doc_repo = Git(os.path.join(env.build_dir, 'fmtlib.github.io'))
doc_repo.update('git@github.com:fmtlib/fmtlib.github.io') doc_repo.update('git@github.com:fmtlib/fmtlib.github.io')
for version in ['1.0.0', '1.1.0', '2.0.0', '3.0.0']: for version in env.versions:
clean_checkout(env.fmt_repo, version) clean_checkout(env.fmt_repo, version)
target_doc_dir = os.path.join(env.fmt_repo.dir, 'doc') target_doc_dir = os.path.join(env.fmt_repo.dir, 'doc')
# Remove the old theme. # Remove the old theme.
@ -165,7 +166,11 @@ def update_site(env):
os.symlink(target, link) os.symlink(target, link)
# Copy docs to the website. # Copy docs to the website.
version_doc_dir = os.path.join(doc_repo.dir, version) version_doc_dir = os.path.join(doc_repo.dir, version)
try:
shutil.rmtree(version_doc_dir) shutil.rmtree(version_doc_dir)
except OSError as e:
if e.errno != errno.ENOENT:
raise
shutil.move(html_dir, version_doc_dir) shutil.move(html_dir, version_doc_dir)
@ -204,27 +209,45 @@ def release(args):
line = '-' * title_len + '\n' line = '-' * title_len + '\n'
title_len = 0 title_len = 0
sys.stdout.write(line) sys.stdout.write(line)
# TODO: add new version to manage.py
# Add the version to the build script.
script = os.path.join('doc', 'build.py')
script_path = os.path.join(fmt_repo.dir, script)
for line in fileinput.input(script_path, inplace=True):
m = re.match(r'( *versions = )\[(.+)\]', line)
if m:
line = '{}[{}, \'{}\']\n'.format(m.group(1), m.group(2), version)
sys.stdout.write(line)
fmt_repo.checkout('-B', 'release') fmt_repo.checkout('-B', 'release')
fmt_repo.add(changelog, cmakelists) fmt_repo.add(changelog, cmakelists, script)
fmt_repo.commit('-m', 'Update version') fmt_repo.commit('-m', 'Update version')
# Build the docs and package. # Build the docs and package.
run = Runner(fmt_repo.dir) run = Runner(fmt_repo.dir)
run('cmake', '.') run('cmake', '.')
run('make', 'doc', 'package_source') run('make', 'doc', 'package_source')
update_site(env) update_site(env)
# Create a release on GitHub. # Create a release on GitHub.
fmt_repo.push('origin', 'release') fmt_repo.push('origin', 'release')
params = {'access_token': os.getenv('FMT_TOKEN')}
r = requests.post('https://api.github.com/repos/fmtlib/fmt/releases', r = requests.post('https://api.github.com/repos/fmtlib/fmt/releases',
params={'access_token': os.getenv('FMT_TOKEN')}, params=params,
data=json.dumps({'tag_name': version, data=json.dumps({'tag_name': version,
'target_commitish': 'release', 'target_commitish': 'release',
'body': changes, 'draft': True})) 'body': changes, 'draft': True}))
if r.status_code != 201: if r.status_code != 201:
raise Exception('Failed to create a release ' + str(r)) raise Exception('Failed to create a release ' + str(r))
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))
if __name__ == '__main__': if __name__ == '__main__':

View file

@ -30,7 +30,7 @@ def install_dependencies():
'| sudo tee /etc/apt/sources.list.d/nodesource.list', shell=True) '| sudo tee /etc/apt/sources.list.d/nodesource.list', shell=True)
check_call(['sudo', 'apt-get', 'update']) check_call(['sudo', 'apt-get', 'update'])
check_call(['sudo', 'apt-get', 'install', 'python-virtualenv', 'nodejs']) check_call(['sudo', 'apt-get', 'install', 'python-virtualenv', 'nodejs'])
check_call(['npm', 'install', '-g', 'less', 'less-plugin-clean-css']) check_call(['sudo', 'npm', 'install', '-g', 'less@2.6.1', 'less-plugin-clean-css'])
deb_file = 'doxygen_1.8.6-2_amd64.deb' deb_file = 'doxygen_1.8.6-2_amd64.deb'
urllib.urlretrieve('http://mirrors.kernel.org/ubuntu/pool/main/d/doxygen/' + urllib.urlretrieve('http://mirrors.kernel.org/ubuntu/pool/main/d/doxygen/' +
deb_file, deb_file) deb_file, deb_file)

View file

@ -151,16 +151,31 @@ TEST(StringRefTest, Ctor) {
EXPECT_STREQ("defg", StringRef(std::string("defg")).data()); EXPECT_STREQ("defg", StringRef(std::string("defg")).data());
EXPECT_EQ(4u, StringRef(std::string("defg")).size()); EXPECT_EQ(4u, StringRef(std::string("defg")).size());
#if FMT_HAS_STRING_VIEW
EXPECT_STREQ("hijk", StringRef(std::string_view("hijk")).data());
EXPECT_EQ(4u, StringRef(std::string_view("hijk")).size());
#endif
} }
TEST(StringRefTest, ConvertToString) { TEST(StringRefTest, ConvertToString) {
std::string s = StringRef("abc").to_string(); std::string s = StringRef("abc").to_string();
EXPECT_EQ("abc", s); EXPECT_EQ("abc", s);
#if FMT_HAS_STRING_VIEW
StringRef str_ref("defg");
std::string_view sv = static_cast<std::string_view>(str_ref);
EXPECT_EQ("defg", sv);
#endif
} }
TEST(CStringRefTest, Ctor) { TEST(CStringRefTest, Ctor) {
EXPECT_STREQ("abc", CStringRef("abc").c_str()); EXPECT_STREQ("abc", CStringRef("abc").c_str());
EXPECT_STREQ("defg", CStringRef(std::string("defg")).c_str()); EXPECT_STREQ("defg", CStringRef(std::string("defg")).c_str());
#if FMT_HAS_STRING_VIEW
EXPECT_STREQ("hijk", CStringRef(std::string_view("hijk")).c_str());
#endif
} }
#if FMT_USE_TYPE_TRAITS #if FMT_USE_TYPE_TRAITS
@ -1378,6 +1393,12 @@ TEST(FormatterTest, FormatCStringRef) {
EXPECT_EQ("test", format("{0}", CStringRef("test"))); EXPECT_EQ("test", format("{0}", CStringRef("test")));
} }
#if FMT_HAS_STRING_VIEW
TEST(FormatterTest, FormatStringView) {
EXPECT_EQ("test", format("{0}", std::string_view("test")));
}
#endif
void format_arg(fmt::BasicFormatter<char> &f, const char *, const Date &d) { void format_arg(fmt::BasicFormatter<char> &f, const char *, const Date &d) {
f.writer() << d.year() << '-' << d.month() << '-' << d.day(); f.writer() << d.year() << '-' << d.month() << '-' << d.day();
} }
@ -1609,6 +1630,24 @@ TEST(FormatTest, FormatMessageExample) {
format_message(42, "{} happened", "something")); format_message(42, "{} happened", "something"));
} }
class test_class
{
public:
std::string format_message(int id, const char *format,const fmt::ArgList &args) const {
MemoryWriter w;
w.write("[{}] ", id);
w.write(format, args);
return w.str();
}
FMT_VARIADIC_CONST(std::string, format_message, int, const char *)
};
TEST(FormatTest, ConstFormatMessage) {
test_class c;
EXPECT_EQ("[42] something happened",
c.format_message(42, "{} happened", "something"));
}
#if FMT_USE_VARIADIC_TEMPLATES #if FMT_USE_VARIADIC_TEMPLATES
template<typename... Args> template<typename... Args>
void print_error(const char *file, int line, const char *format, void print_error(const char *file, int line, const char *format,
@ -1660,6 +1699,14 @@ TEST(FormatTest, Enum) {
EXPECT_EQ("0", fmt::format("{}", A)); EXPECT_EQ("0", fmt::format("{}", A));
} }
#if __cplusplus >= 201103L
enum TestFixedEnum : short { B };
TEST(FormatTest, FixedEnum) {
EXPECT_EQ("0", fmt::format("{}", B));
}
#endif
class MockArgFormatter : class MockArgFormatter :
public fmt::internal::ArgFormatterBase<MockArgFormatter, char> { public fmt::internal::ArgFormatterBase<MockArgFormatter, char> {
public: public:

View file

@ -36,7 +36,7 @@ class MockAllocator {
MockAllocator() {} MockAllocator() {}
MockAllocator(const MockAllocator &) {} MockAllocator(const MockAllocator &) {}
typedef T value_type; typedef T value_type;
MOCK_METHOD2_T(allocate, T *(std::size_t n, const T *h)); MOCK_METHOD2_T(allocate, T *(std::size_t n, const void *h));
MOCK_METHOD2_T(deallocate, void (T *p, std::size_t n)); MOCK_METHOD2_T(deallocate, void (T *p, std::size_t n));
}; };
@ -78,8 +78,12 @@ class AllocatorRef {
Allocator *get() const { return alloc_; } Allocator *get() const { return alloc_; }
value_type *allocate(std::size_t n, const value_type *h) { value_type *allocate(std::size_t n, const void *h) {
#if FMT_USE_ALLOCATOR_TRAITS
return std::allocator_traits<Allocator>::allocate(*alloc_, n, h);
#else
return alloc_->allocate(n, h); return alloc_->allocate(n, h);
#endif
} }
void deallocate(value_type *p, std::size_t n) { alloc_->deallocate(p, n); } void deallocate(value_type *p, std::size_t n) { alloc_->deallocate(p, n); }
}; };

View file

@ -172,3 +172,18 @@ TEST(OStreamTest, WriteToOStreamMaxSize) {
} while (size != 0); } while (size != 0);
fmt::internal::write(os, w); fmt::internal::write(os, w);
} }
struct ConvertibleToInt {
template <typename ValueType>
operator ValueType() const {
return 0;
}
friend std::ostream &operator<<(std::ostream &o, ConvertibleToInt) {
return o << "foo";
}
};
TEST(FormatTest, FormatConvertibleToInt) {
EXPECT_EQ("foo", fmt::format("{}", ConvertibleToInt()));
}

View file

@ -78,3 +78,7 @@ TEST(StringWriterTest, WString) {
TEST(StringTest, ToString) { TEST(StringTest, ToString) {
EXPECT_EQ("42", fmt::to_string(42)); EXPECT_EQ("42", fmt::to_string(42));
} }
TEST(StringTest, ToWString) {
EXPECT_EQ(L"42", fmt::to_wstring(42));
}

View file

@ -837,8 +837,21 @@ TEST(UtilTest, FormatSystemError) {
fmt::format_system_error(message, EDOM, "test"); fmt::format_system_error(message, EDOM, "test");
EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), message.str()); EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), message.str());
message.clear(); message.clear();
fmt::format_system_error(
message, EDOM, fmt::StringRef(0, std::numeric_limits<size_t>::max())); // Check if std::allocator throws on allocating max size_t / 2 chars.
size_t max_size = std::numeric_limits<size_t>::max() / 2;
bool throws_on_alloc = false;
try {
std::allocator<char> alloc;
alloc.deallocate(alloc.allocate(max_size), max_size);
} catch (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::StringRef(0, max_size));
EXPECT_EQ(fmt::format("error {}", EDOM), message.str()); EXPECT_EQ(fmt::format("error {}", EDOM), message.str());
} }