Squashed 'externals/fmt/' changes from 39834389..135ab5cf
135ab5cf Update version 93d95f17 Fix markup 4f15c72f Fix markup e9b19414 Automatically add package to release c3d1f604 Fix markup c96062bf Update changelog and version number f9c97de4 Add note about errno to the documentation 62df6f27 CMakeLists: Use GNUInstallDirs to set install location 493586cb Fix overflow check 1d751bc6 fix warning in header: signed/unsigned comparison 11415bce Update usage.rst 9982dd01 Fix for warning C5030 in VS2015 42e88c4f Silenced MSVC 2017 constant if expression warning 7a9c1ba1 FMT_VARIADIC_CONST - Support for const variadic methods (#591) 324415c0 Use allocator_traits if available. 5f39721c Fix a warning ca96acbe Add examples 708d9509 fix(Clang CodeGen): remove warnings 9328a074 Fix handling of fixed enums in clang (#580) 2c077dd4 Enable stream exceptions (#581) 933a33a7 Added MSVC checking for support for string_view. bef89db6 Fix a bogus -Wduplicated-branches gcc warning (#573) 2a619d96 Make format work with C++17 std::string_view (#571) e051de37 Use less version 2.6.1 and sudo to fix npm install issues on travis 5de459bf Suppress Clang's warning on zero as a null pointer 16589534 Make ArgMap::init not explicitly instantiated (#563) 3e75d3e0 Fix handling of types convertible to int 89654cd1 to_wstring added 37eb419a Fix noreturn attribute detection (#555) 14d85349 Explicitly cast range length to std::size_t to prevent conversion warnings c2201ce0 Accept wide chars as integers to prevent conversion warning 6efbccb3 Add one more CMake warning fix 032c8380 Fix a segfault in test on glibc 2.26 #551, take 2 6655e804 Fix a segfault in test on glibc 2.26 #551 d16c4d20 Suppress warning about missing noreturn attribute (#549) 9c56a8ce Make format_arg() accept class hierarchies ca0e3830 Update README.rst 81790d72 Update format.h to remove C4574 error on MSVC 14.2 30283443 Fix undefined behavior in UDL macro 4045d7fe Fix warning about missing ' character 89c3bc58 Remove warning C4668 in MSVC for FMT_GCC_VERSION and FMT_HAS_GXX_CXX11 4af9421f Adding OpenSpace to the list of projects 1a398b54 Fixed CMake CMP0048 warning. 589ccc16 Bump version c3817046 Add an error on broken includes 16bdd842 Update scripts b492316d Update version list 91f4ce02 Automatically update version in release script (#431) git-subtree-dir: externals/fmt git-subtree-split: 135ab5cf71ed731fc9fa0653051e7d4884a3652f
This commit is contained in:
parent
a9f62a15cd
commit
097203968f
21 changed files with 481 additions and 141 deletions
|
@ -2,6 +2,14 @@ message(STATUS "CMake version: ${CMAKE_VERSION}")
|
|||
|
||||
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)
|
||||
# or if it is the master project.
|
||||
set(MASTER_PROJECT OFF)
|
||||
|
|
|
@ -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
|
||||
------------------
|
||||
|
||||
* 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>`_):
|
||||
|
||||
|
|
|
@ -142,6 +142,8 @@ Projects using this library
|
|||
|
||||
* `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>`_:
|
||||
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
|
||||
|
||||
* `OpenSpace <http://openspaceproject.com/>`_: An open-source astrovisualization framework
|
||||
|
||||
* `PenUltima Online (POL) <http://www.polserver.com/>`_:
|
||||
An MMO server, compatible with most Ultima Online clients
|
||||
|
||||
|
|
32
doc/api.rst
32
doc/api.rst
|
@ -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
|
||||
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
|
||||
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.
|
||||
|
@ -232,6 +262,8 @@ Utilities
|
|||
|
||||
.. doxygenfunction:: fmt::to_string(const T&)
|
||||
|
||||
.. doxygenfunction:: fmt::to_wstring(const T&)
|
||||
|
||||
.. doxygenclass:: fmt::BasicStringRef
|
||||
:members:
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ 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']
|
||||
|
||||
def pip_install(package, commit=None, **kwargs):
|
||||
"Install package using pip."
|
||||
min_version = kwargs.get('min_version')
|
||||
|
@ -93,11 +95,11 @@ def build_docs(version='dev', **kwargs):
|
|||
if p.returncode != 0:
|
||||
raise CalledProcessError(p.returncode, cmd)
|
||||
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',
|
||||
'-Dbreathe_projects.format=' + os.path.abspath(doxyxml_dir),
|
||||
'-Dversion=' + version, '-Drelease=' + version,
|
||||
'-Aversion=' + version, '-Aversions=' + ','.join(versions),
|
||||
'-Aversion=' + version, '-Aversions=' + ','.join(main_versions),
|
||||
'-b', 'html', doc_dir, html_dir])
|
||||
try:
|
||||
check_call(['lessc', '--clean-css',
|
||||
|
|
|
@ -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
|
||||
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
|
||||
|
|
|
@ -335,6 +335,16 @@ Aligning the text and specifying a width::
|
|||
format("{:*^30}", "centered"); // use '*' as a fill char
|
||||
// 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::
|
||||
|
||||
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);
|
||||
'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::
|
||||
|
||||
>>> import datetime
|
||||
|
|
|
@ -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
|
||||
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`
|
||||
file and several :file:`.vcproj` files will be created. You can then build them
|
||||
using Visual Studio or msbuild.
|
||||
|
|
|
@ -49,8 +49,9 @@ endif ()
|
|||
|
||||
# Install targets.
|
||||
if (FMT_INSTALL)
|
||||
include(GNUInstallDirs)
|
||||
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}.")
|
||||
set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.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)
|
||||
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}.")
|
||||
|
||||
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.
|
||||
write_basic_package_version_file(
|
||||
${version_config}
|
||||
|
@ -86,5 +90,5 @@ if (FMT_INSTALL)
|
|||
# Install the library and headers.
|
||||
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
|
||||
DESTINATION ${FMT_LIB_DIR})
|
||||
install(FILES ${FMT_HEADERS} DESTINATION include/fmt)
|
||||
install(FILES ${FMT_HEADERS} DESTINATION ${FMT_INC_DIR})
|
||||
endif ()
|
||||
|
|
|
@ -72,9 +72,11 @@
|
|||
|
||||
// Dummy implementations of strerror_r and strerror_s called if corresponding
|
||||
// system functions are not available.
|
||||
FMT_MAYBE_UNUSED
|
||||
static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
|
||||
return fmt::internal::Null<>();
|
||||
}
|
||||
FMT_MAYBE_UNUSED
|
||||
static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
|
||||
return fmt::internal::Null<>();
|
||||
}
|
||||
|
@ -121,7 +123,7 @@ typedef void (*FormatFunc)(Writer &, int, StringRef);
|
|||
// Buffer should be at least of size 1.
|
||||
int safe_strerror(
|
||||
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 {
|
||||
private:
|
||||
|
@ -159,6 +161,11 @@ int safe_strerror(
|
|||
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.
|
||||
int fallback(internal::Null<>) {
|
||||
errno = 0;
|
||||
|
@ -166,13 +173,15 @@ int safe_strerror(
|
|||
return errno;
|
||||
}
|
||||
|
||||
#ifdef __c2__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
public:
|
||||
StrError(int err_code, char *&buf, std::size_t buf_size)
|
||||
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
|
||||
|
||||
int run() {
|
||||
// Suppress a warning about unused strerror_r.
|
||||
strerror_r(0, FMT_NULL, "");
|
||||
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.
|
||||
}
|
||||
|
||||
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>
|
||||
void internal::FixedBuffer<Char>::grow(std::size_t) {
|
||||
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::ArgMap<char>::init(const ArgList &args);
|
||||
|
||||
template FMT_API int internal::CharTraits<char>::format_float(
|
||||
char *buffer, std::size_t size, const char *format,
|
||||
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::ArgMap<wchar_t>::init(const ArgList &args);
|
||||
|
||||
template FMT_API int internal::CharTraits<wchar_t>::format_float(
|
||||
wchar_t *buffer, std::size_t size, const wchar_t *format,
|
||||
unsigned width, int precision, double value);
|
||||
|
|
261
fmt/format.h
261
fmt/format.h
|
@ -28,6 +28,7 @@
|
|||
#ifndef FMT_FORMAT_H_
|
||||
#define FMT_FORMAT_H_
|
||||
|
||||
#define FMT_INCLUDE
|
||||
#include <cassert>
|
||||
#include <clocale>
|
||||
#include <cmath>
|
||||
|
@ -39,11 +40,26 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility> // for std::pair
|
||||
#undef FMT_INCLUDE
|
||||
|
||||
// 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
|
||||
#else
|
||||
# define FMT_SECURE_SCL 0
|
||||
|
@ -97,7 +113,9 @@ typedef __int64 intmax_t;
|
|||
# define FMT_HAS_GXX_CXX11 1
|
||||
# endif
|
||||
#else
|
||||
# define FMT_GCC_VERSION 0
|
||||
# define FMT_GCC_EXTENSION
|
||||
# define FMT_HAS_GXX_CXX11 0
|
||||
#endif
|
||||
|
||||
#if defined(__INTEL_COMPILER)
|
||||
|
@ -135,6 +153,32 @@ typedef __int64 intmax_t;
|
|||
# define FMT_HAS_CPP_ATTRIBUTE(x) 0
|
||||
#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
|
||||
// Variadic templates are available in GCC since version 4.4
|
||||
// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++
|
||||
|
@ -156,6 +200,12 @@ typedef __int64 intmax_t;
|
|||
# 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.
|
||||
#if defined(__GNUC__) && !defined(__EXCEPTIONS)
|
||||
# define FMT_EXCEPTIONS 0
|
||||
|
@ -262,11 +312,14 @@ typedef __int64 intmax_t;
|
|||
// makes the fmt::literals implementation easier. However, an explicit check
|
||||
// for variadic templates is added here just in case.
|
||||
// For Intel's compiler both it and the system gcc/msc must support UDLs.
|
||||
# define FMT_USE_USER_DEFINED_LITERALS \
|
||||
FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \
|
||||
# if FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \
|
||||
(FMT_HAS_FEATURE(cxx_user_literals) || \
|
||||
(FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900) && \
|
||||
(!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
|
||||
|
||||
#ifndef FMT_USE_EXTERN_TEMPLATES
|
||||
|
@ -305,7 +358,10 @@ typedef __int64 intmax_t;
|
|||
|
||||
namespace fmt {
|
||||
namespace internal {
|
||||
// avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning
|
||||
# ifndef __clang__
|
||||
# pragma intrinsic(_BitScanReverse)
|
||||
# endif
|
||||
inline uint32_t clz(uint32_t x) {
|
||||
unsigned long r = 0;
|
||||
_BitScanReverse(&r, x);
|
||||
|
@ -319,7 +375,8 @@ inline uint32_t clz(uint32_t x) {
|
|||
}
|
||||
# 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)
|
||||
# endif
|
||||
|
||||
|
@ -505,6 +562,26 @@ class BasicStringRef {
|
|||
const std::basic_string<Char, std::char_traits<Char>, Allocator> &s)
|
||||
: 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
|
||||
Converts a string reference to an ``std::string`` object.
|
||||
|
@ -609,7 +686,7 @@ class FormatError : public std::runtime_error {
|
|||
explicit FormatError(CStringRef message)
|
||||
: std::runtime_error(message.c_str()) {}
|
||||
FormatError(const FormatError &ferr) : std::runtime_error(ferr) {}
|
||||
FMT_API ~FormatError() FMT_DTOR_NOEXCEPT;
|
||||
FMT_API ~FormatError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
@ -726,7 +803,7 @@ template <typename T>
|
|||
template <typename U>
|
||||
void Buffer<T>::append(const U *begin, const U *end) {
|
||||
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_)
|
||||
grow(new_size);
|
||||
std::uninitialized_copy(begin, end,
|
||||
|
@ -754,7 +831,7 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
|
|||
public:
|
||||
explicit MemoryBuffer(const Allocator &alloc = Allocator())
|
||||
: Allocator(alloc), Buffer<T>(data_, SIZE) {}
|
||||
~MemoryBuffer() { deallocate(); }
|
||||
~MemoryBuffer() FMT_OVERRIDE { deallocate(); }
|
||||
|
||||
#if FMT_USE_RVALUE_REFERENCES
|
||||
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;
|
||||
if (size > new_capacity)
|
||||
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);
|
||||
#endif
|
||||
// The following code doesn't throw, so the raw pointer above doesn't leak.
|
||||
std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_,
|
||||
make_ptr(new_ptr, new_capacity));
|
||||
|
@ -916,7 +998,7 @@ struct IntTraits {
|
|||
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
|
||||
// configuration.
|
||||
|
@ -1248,9 +1330,9 @@ inline fmt::StringRef thousands_sep(...) { return ""; }
|
|||
typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED
|
||||
#endif
|
||||
|
||||
template <typename Formatter, typename Char, typename T>
|
||||
void format_arg(Formatter &, const Char *, const T &) {
|
||||
FMT_STATIC_ASSERT(FalseType<T>::value,
|
||||
template <typename Formatter>
|
||||
void format_arg(Formatter&, ...) {
|
||||
FMT_STATIC_ASSERT(FalseType<Formatter>::value,
|
||||
"Cannot format argument. To enable the use of ostream "
|
||||
"operator<< include fmt/ostream.h. Otherwise provide "
|
||||
"an overload of format_arg.");
|
||||
|
@ -1283,6 +1365,9 @@ class MakeValue : public Arg {
|
|||
MakeValue(typename WCharHelper<wchar_t *, Char>::Unsupported);
|
||||
MakeValue(typename WCharHelper<const wchar_t *, 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);
|
||||
|
||||
void set_string(StringRef str) {
|
||||
|
@ -1352,6 +1437,20 @@ class MakeValue : public Arg {
|
|||
FMT_MAKE_VALUE(unsigned char, uint_value, UINT)
|
||||
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)
|
||||
MakeValue(typename WCharHelper<wchar_t, Char>::Supported value) {
|
||||
int_value = value;
|
||||
|
@ -1370,6 +1469,9 @@ class MakeValue : public Arg {
|
|||
FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING)
|
||||
FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING)
|
||||
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_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(const wchar_t *, 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_VALUE(void *, pointer, POINTER)
|
||||
|
@ -1447,7 +1552,7 @@ class RuntimeError : public std::runtime_error {
|
|||
protected:
|
||||
RuntimeError() : std::runtime_error("") {}
|
||||
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>
|
||||
|
@ -1921,7 +2026,7 @@ class ArgMap {
|
|||
MapType map_;
|
||||
|
||||
public:
|
||||
FMT_API void init(const ArgList &args);
|
||||
void init(const ArgList &args);
|
||||
|
||||
const internal::Arg *find(const fmt::BasicStringRef<Char> &name) const {
|
||||
// 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>
|
||||
class ArgFormatterBase : public ArgVisitor<Impl, void> {
|
||||
private:
|
||||
|
@ -2220,7 +2370,8 @@ struct ArgArray;
|
|||
|
||||
template <std::size_t N>
|
||||
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>
|
||||
static Value make(const T &value) {
|
||||
|
@ -2410,7 +2561,7 @@ class SystemError : public internal::RuntimeError {
|
|||
FMT_DEFAULTED_COPY_CTOR(SystemError)
|
||||
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_; }
|
||||
};
|
||||
|
@ -3483,10 +3634,10 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED;
|
|||
#define FMT_GET_ARG_NAME(type, index) arg##index
|
||||
|
||||
#if FMT_USE_VARIADIC_TEMPLATES
|
||||
# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \
|
||||
# define FMT_VARIADIC_(Const, Char, ReturnType, func, call, ...) \
|
||||
template <typename... 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; \
|
||||
typename ArgArray::Type array{ \
|
||||
ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \
|
||||
|
@ -3496,35 +3647,35 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED;
|
|||
#else
|
||||
// Defines a wrapper for a function taking __VA_ARGS__ arguments
|
||||
// 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)> \
|
||||
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_GEN(n, FMT_ASSIGN_##Char); \
|
||||
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \
|
||||
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \
|
||||
}
|
||||
|
||||
# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \
|
||||
inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \
|
||||
# define FMT_VARIADIC_(Const, Char, ReturnType, func, call, ...) \
|
||||
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()); \
|
||||
} \
|
||||
FMT_WRAP(Char, ReturnType, func, call, 1, __VA_ARGS__) \
|
||||
FMT_WRAP(Char, ReturnType, func, call, 2, __VA_ARGS__) \
|
||||
FMT_WRAP(Char, ReturnType, func, call, 3, __VA_ARGS__) \
|
||||
FMT_WRAP(Char, ReturnType, func, call, 4, __VA_ARGS__) \
|
||||
FMT_WRAP(Char, ReturnType, func, call, 5, __VA_ARGS__) \
|
||||
FMT_WRAP(Char, ReturnType, func, call, 6, __VA_ARGS__) \
|
||||
FMT_WRAP(Char, ReturnType, func, call, 7, __VA_ARGS__) \
|
||||
FMT_WRAP(Char, ReturnType, func, call, 8, __VA_ARGS__) \
|
||||
FMT_WRAP(Char, ReturnType, func, call, 9, __VA_ARGS__) \
|
||||
FMT_WRAP(Char, ReturnType, func, call, 10, __VA_ARGS__) \
|
||||
FMT_WRAP(Char, ReturnType, func, call, 11, __VA_ARGS__) \
|
||||
FMT_WRAP(Char, ReturnType, func, call, 12, __VA_ARGS__) \
|
||||
FMT_WRAP(Char, ReturnType, func, call, 13, __VA_ARGS__) \
|
||||
FMT_WRAP(Char, ReturnType, func, call, 14, __VA_ARGS__) \
|
||||
FMT_WRAP(Char, ReturnType, func, call, 15, __VA_ARGS__)
|
||||
FMT_WRAP(Const, Char, ReturnType, func, call, 1, __VA_ARGS__) \
|
||||
FMT_WRAP(Const, Char, ReturnType, func, call, 2, __VA_ARGS__) \
|
||||
FMT_WRAP(Const, Char, ReturnType, func, call, 3, __VA_ARGS__) \
|
||||
FMT_WRAP(Const, Char, ReturnType, func, call, 4, __VA_ARGS__) \
|
||||
FMT_WRAP(Const, Char, ReturnType, func, call, 5, __VA_ARGS__) \
|
||||
FMT_WRAP(Const, Char, ReturnType, func, call, 6, __VA_ARGS__) \
|
||||
FMT_WRAP(Const, Char, ReturnType, func, call, 7, __VA_ARGS__) \
|
||||
FMT_WRAP(Const, Char, ReturnType, func, call, 8, __VA_ARGS__) \
|
||||
FMT_WRAP(Const, Char, ReturnType, func, call, 9, __VA_ARGS__) \
|
||||
FMT_WRAP(Const, Char, ReturnType, func, call, 10, __VA_ARGS__) \
|
||||
FMT_WRAP(Const, Char, ReturnType, func, call, 11, __VA_ARGS__) \
|
||||
FMT_WRAP(Const, Char, ReturnType, func, call, 12, __VA_ARGS__) \
|
||||
FMT_WRAP(Const, Char, ReturnType, func, call, 13, __VA_ARGS__) \
|
||||
FMT_WRAP(Const, Char, ReturnType, func, call, 14, __VA_ARGS__) \
|
||||
FMT_WRAP(Const, Char, ReturnType, func, call, 15, __VA_ARGS__)
|
||||
#endif // FMT_USE_VARIADIC_TEMPLATES
|
||||
|
||||
/**
|
||||
|
@ -3555,10 +3706,16 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED;
|
|||
\endrst
|
||||
*/
|
||||
#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, ...) \
|
||||
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)
|
||||
|
||||
|
@ -3601,17 +3758,19 @@ template <typename Char>
|
|||
unsigned parse_nonnegative_int(const Char *&s) {
|
||||
assert('0' <= *s && *s <= '9');
|
||||
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.
|
||||
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)
|
||||
FMT_THROW(FormatError("number is too big"));
|
||||
return value;
|
||||
|
@ -3783,7 +3942,8 @@ const Char *BasicFormatter<Char, ArgFormatter>::format(
|
|||
default:
|
||||
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"));
|
||||
spec.width_ = static_cast<int>(value);
|
||||
}
|
||||
|
@ -3821,7 +3981,8 @@ const Char *BasicFormatter<Char, ArgFormatter>::format(
|
|||
default:
|
||||
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"));
|
||||
spec.precision_ = static_cast<int>(value);
|
||||
} else {
|
||||
|
|
|
@ -52,8 +52,10 @@ Yes &convert(std::ostream &);
|
|||
|
||||
struct DummyStream : std::ostream {
|
||||
DummyStream(); // Suppress a bogus warning in MSVC.
|
||||
|
||||
// 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);
|
||||
|
@ -78,6 +80,7 @@ void format_arg(BasicFormatter<Char, ArgFormatter_> &f,
|
|||
|
||||
internal::FormatBuf<Char> format_buf(buffer);
|
||||
std::basic_ostream<Char> output(&format_buf);
|
||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
output << value;
|
||||
|
||||
BasicStringRef<Char> str(&buffer[0], buffer.size());
|
||||
|
|
|
@ -110,7 +110,7 @@ class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
|
|||
visit_any_int(value);
|
||||
}
|
||||
|
||||
void visit_char(char value) {
|
||||
void visit_char(int value) {
|
||||
if (type_ != 's')
|
||||
visit_any_int(value);
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
|
|||
using internal::Arg;
|
||||
typedef typename internal::Conditional<
|
||||
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.
|
||||
if (is_signed) {
|
||||
arg_.type = Arg::INT;
|
||||
|
|
22
fmt/string.h
22
fmt/string.h
|
@ -7,6 +7,10 @@
|
|||
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_
|
||||
#define FMT_STRING_H_
|
||||
|
||||
|
@ -121,6 +125,24 @@ std::string to_string(const T &value) {
|
|||
w << value;
|
||||
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_
|
||||
|
|
|
@ -8,7 +8,7 @@ Usage:
|
|||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import datetime, docopt, fileinput, json, os
|
||||
import datetime, docopt, errno, fileinput, json, os
|
||||
import re, requests, shutil, sys, tempfile
|
||||
from contextlib import contextmanager
|
||||
from distutils.version import LooseVersion
|
||||
|
@ -80,6 +80,7 @@ def create_build_env():
|
|||
import build
|
||||
|
||||
env.build_dir = 'build'
|
||||
env.versions = build.versions
|
||||
|
||||
# Virtualenv and repos are cached to speed up builds.
|
||||
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.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)
|
||||
target_doc_dir = os.path.join(env.fmt_repo.dir, 'doc')
|
||||
# Remove the old theme.
|
||||
|
@ -165,7 +166,11 @@ def update_site(env):
|
|||
os.symlink(target, link)
|
||||
# Copy docs to the website.
|
||||
version_doc_dir = os.path.join(doc_repo.dir, version)
|
||||
try:
|
||||
shutil.rmtree(version_doc_dir)
|
||||
except OSError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
shutil.move(html_dir, version_doc_dir)
|
||||
|
||||
|
||||
|
@ -204,27 +209,45 @@ def release(args):
|
|||
line = '-' * title_len + '\n'
|
||||
title_len = 0
|
||||
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.add(changelog, cmakelists)
|
||||
fmt_repo.add(changelog, cmakelists, script)
|
||||
fmt_repo.commit('-m', 'Update version')
|
||||
|
||||
# Build the docs and package.
|
||||
run = Runner(fmt_repo.dir)
|
||||
run('cmake', '.')
|
||||
run('make', 'doc', 'package_source')
|
||||
|
||||
update_site(env)
|
||||
|
||||
# Create a release on GitHub.
|
||||
fmt_repo.push('origin', 'release')
|
||||
params = {'access_token': os.getenv('FMT_TOKEN')}
|
||||
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,
|
||||
'target_commitish': 'release',
|
||||
'body': changes, 'draft': True}))
|
||||
if r.status_code != 201:
|
||||
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__':
|
||||
|
|
|
@ -30,7 +30,7 @@ def install_dependencies():
|
|||
'| sudo tee /etc/apt/sources.list.d/nodesource.list', shell=True)
|
||||
check_call(['sudo', 'apt-get', 'update'])
|
||||
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'
|
||||
urllib.urlretrieve('http://mirrors.kernel.org/ubuntu/pool/main/d/doxygen/' +
|
||||
deb_file, deb_file)
|
||||
|
|
|
@ -151,16 +151,31 @@ TEST(StringRefTest, Ctor) {
|
|||
|
||||
EXPECT_STREQ("defg", StringRef(std::string("defg")).data());
|
||||
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) {
|
||||
std::string s = StringRef("abc").to_string();
|
||||
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) {
|
||||
EXPECT_STREQ("abc", CStringRef("abc").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
|
||||
|
@ -1378,6 +1393,12 @@ TEST(FormatterTest, FormatCStringRef) {
|
|||
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) {
|
||||
f.writer() << d.year() << '-' << d.month() << '-' << d.day();
|
||||
}
|
||||
|
@ -1609,6 +1630,24 @@ TEST(FormatTest, FormatMessageExample) {
|
|||
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
|
||||
template<typename... Args>
|
||||
void print_error(const char *file, int line, const char *format,
|
||||
|
@ -1660,6 +1699,14 @@ TEST(FormatTest, Enum) {
|
|||
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 :
|
||||
public fmt::internal::ArgFormatterBase<MockArgFormatter, char> {
|
||||
public:
|
||||
|
|
|
@ -36,7 +36,7 @@ class MockAllocator {
|
|||
MockAllocator() {}
|
||||
MockAllocator(const MockAllocator &) {}
|
||||
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));
|
||||
};
|
||||
|
||||
|
@ -78,8 +78,12 @@ class AllocatorRef {
|
|||
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
void deallocate(value_type *p, std::size_t n) { alloc_->deallocate(p, n); }
|
||||
};
|
||||
|
|
|
@ -172,3 +172,18 @@ TEST(OStreamTest, WriteToOStreamMaxSize) {
|
|||
} while (size != 0);
|
||||
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()));
|
||||
}
|
||||
|
|
|
@ -78,3 +78,7 @@ TEST(StringWriterTest, WString) {
|
|||
TEST(StringTest, ToString) {
|
||||
EXPECT_EQ("42", fmt::to_string(42));
|
||||
}
|
||||
|
||||
TEST(StringTest, ToWString) {
|
||||
EXPECT_EQ(L"42", fmt::to_wstring(42));
|
||||
}
|
||||
|
|
|
@ -837,8 +837,21 @@ TEST(UtilTest, FormatSystemError) {
|
|||
fmt::format_system_error(message, EDOM, "test");
|
||||
EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), message.str());
|
||||
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());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue