mirror of
https://github.com/fmtlib/fmt.git
synced 2025-12-24 15:58:16 +01:00
Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f5e07656e | ||
|
|
3e8d2c57f3 | ||
|
|
8ad1c12fb4 | ||
|
|
d2744bc848 | ||
|
|
b6d435b9a6 | ||
|
|
857b382fc3 | ||
|
|
b6ac63faf0 | ||
|
|
1d6188404c | ||
|
|
bdab94baf8 | ||
|
|
a9c0bb4b16 | ||
|
|
ea2cf449f7 | ||
|
|
5c0d7ee157 | ||
|
|
64440783ba | ||
|
|
1ecdc1a3bb | ||
|
|
867b330966 | ||
|
|
8cf30aa2be | ||
|
|
0555cea5fc | ||
|
|
f78c3e41be | ||
|
|
1760c31b52 | ||
|
|
c15710032e | ||
|
|
6822466aa3 | ||
|
|
c719d94473 | ||
|
|
0f98773164 | ||
|
|
319346025d | ||
|
|
51a16f8c58 | ||
|
|
a00874603d | ||
|
|
5705bf1c71 | ||
|
|
cabce31f45 | ||
|
|
f9c97de46b | ||
|
|
62df6f27cb | ||
|
|
493586cbca | ||
|
|
1d751bc617 | ||
|
|
11415bce3c | ||
|
|
9982dd0130 | ||
|
|
42e88c4fcb | ||
|
|
7a9c1ba190 | ||
|
|
324415c036 | ||
|
|
5f39721c0a | ||
|
|
ca96acbe4f | ||
|
|
708d9509ff | ||
|
|
9328a074b1 | ||
|
|
2c077dd442 | ||
|
|
933a33a794 | ||
|
|
bef89db6e7 | ||
|
|
2a619d96dd | ||
|
|
e051de37f3 | ||
|
|
5de459bf33 | ||
|
|
165895346c | ||
|
|
3e75d3e001 | ||
|
|
89654cd127 | ||
|
|
37eb419af2 | ||
|
|
14d8534900 | ||
|
|
c2201ce02e | ||
|
|
6efbccb387 | ||
|
|
032c83807f | ||
|
|
6655e804c4 | ||
|
|
d16c4d20f8 | ||
|
|
9c56a8ce5c | ||
|
|
ca0e38304c | ||
|
|
81790d726f | ||
|
|
3028344380 | ||
|
|
4045d7fea2 | ||
|
|
89c3bc585c | ||
|
|
4af9421ff0 | ||
|
|
1a398b5404 | ||
|
|
589ccc1675 | ||
|
|
c38170461d | ||
|
|
16bdd8424f | ||
|
|
b492316d5d | ||
|
|
91f4ce02b6 |
@@ -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 NEW)
|
||||
endif ()
|
||||
|
||||
if (POLICY CMP0063) # Visibility
|
||||
cmake_policy(SET CMP0063 NEW)
|
||||
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,35 @@
|
||||
4.1.1 - TBD
|
||||
------------
|
||||
|
||||
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
|
||||
|
||||
@@ -35,6 +35,8 @@ If the numerical arg_ids in a format string are 0, 1, 2, ... in sequence,
|
||||
they can all be omitted (not just some) and the numbers 0, 1, 2, ... will be
|
||||
automatically inserted in that order.
|
||||
|
||||
Named arguments can be referred to by their names or indices.
|
||||
|
||||
Some simple format string examples::
|
||||
|
||||
"First, thou shalt count to {0}" // References the first argument
|
||||
@@ -335,6 +337,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
|
||||
@@ -350,7 +362,7 @@ Replacing ``%x`` and ``%o`` and converting the value to different bases::
|
||||
// Result: "int: 42; hex: 2a; oct: 52; bin: 101010"
|
||||
// with 0x or 0 or 0b as prefix:
|
||||
format("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42);
|
||||
// Result: "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"
|
||||
// Result: "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"
|
||||
|
||||
.. ifconfig:: False
|
||||
|
||||
@@ -359,13 +371,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.
|
||||
|
||||
@@ -24,6 +24,7 @@ target_include_directories(fmt PUBLIC
|
||||
|
||||
set_target_properties(fmt PROPERTIES
|
||||
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR})
|
||||
set_target_properties(fmt PROPERTIES DEBUG_POSTFIX d)
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
if (UNIX AND NOT APPLE)
|
||||
@@ -49,8 +50,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 +63,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 +91,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 ()
|
||||
|
||||
150
fmt/format.cc
150
fmt/format.cc
@@ -30,7 +30,9 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#if !defined(UNDER_CE)
|
||||
# include <cerrno>
|
||||
#endif
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
@@ -72,16 +74,21 @@
|
||||
|
||||
// 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<>();
|
||||
}
|
||||
|
||||
namespace fmt {
|
||||
|
||||
FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {}
|
||||
namespace internal {
|
||||
FMT_FUNC RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {}
|
||||
} // namespace internal
|
||||
|
||||
FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT {}
|
||||
FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT {}
|
||||
|
||||
@@ -93,7 +100,11 @@ namespace {
|
||||
inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
# if !defined(UNDER_CE)
|
||||
int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
|
||||
# else
|
||||
int result = _vsnprintf_s(buffer, size, _TRUNCATE, format, args);
|
||||
# endif
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
@@ -103,7 +114,11 @@ inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
|
||||
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
|
||||
# define FMT_SWPRINTF snwprintf
|
||||
#else
|
||||
# define FMT_SWPRINTF swprintf
|
||||
# if defined(UNDER_CE)
|
||||
# define FMT_SWPRINTF swprintf_s
|
||||
# else
|
||||
# define FMT_SWPRINTF swprintf
|
||||
#endif
|
||||
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
|
||||
|
||||
const char RESET_COLOR[] = "\x1b[0m";
|
||||
@@ -121,7 +136,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:
|
||||
@@ -132,11 +147,13 @@ int safe_strerror(
|
||||
// A noop assignment operator to avoid bogus warnings.
|
||||
void operator=(const StrError &) {}
|
||||
|
||||
#if !defined(UNDER_CE)
|
||||
// Handle the result of XSI-compliant version of strerror_r.
|
||||
int handle(int result) {
|
||||
// glibc versions before 2.13 return result in errno.
|
||||
return result == -1 ? errno : result;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Handle the result of GNU-specific version of strerror_r.
|
||||
int handle(char *message) {
|
||||
@@ -159,20 +176,31 @@ int safe_strerror(
|
||||
ERANGE : result;
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
# 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<>) {
|
||||
#if !defined(UNDER_CE)
|
||||
errno = 0;
|
||||
buffer_ = strerror(error_code_);
|
||||
return errno;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
# 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_));
|
||||
}
|
||||
};
|
||||
@@ -222,8 +250,9 @@ FMT_FUNC void SystemError::init(
|
||||
base = std::runtime_error(w.str());
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
template <typename T>
|
||||
int internal::CharTraits<char>::format_float(
|
||||
int CharTraits<char>::format_float(
|
||||
char *buffer, std::size_t size, const char *format,
|
||||
unsigned width, int precision, T value) {
|
||||
if (width == 0) {
|
||||
@@ -237,7 +266,7 @@ int internal::CharTraits<char>::format_float(
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int internal::CharTraits<wchar_t>::format_float(
|
||||
int CharTraits<wchar_t>::format_float(
|
||||
wchar_t *buffer, std::size_t size, const wchar_t *format,
|
||||
unsigned width, int precision, T value) {
|
||||
if (width == 0) {
|
||||
@@ -251,7 +280,7 @@ int internal::CharTraits<wchar_t>::format_float(
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const char internal::BasicData<T>::DIGITS[] =
|
||||
const char BasicData<T>::DIGITS[] =
|
||||
"0001020304050607080910111213141516171819"
|
||||
"2021222324252627282930313233343536373839"
|
||||
"4041424344454647484950515253545556575859"
|
||||
@@ -270,12 +299,12 @@ const char internal::BasicData<T>::DIGITS[] =
|
||||
factor * 1000000000
|
||||
|
||||
template <typename T>
|
||||
const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
|
||||
const uint32_t BasicData<T>::POWERS_OF_10_32[] = {
|
||||
0, FMT_POWERS_OF_10(1)
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
|
||||
const uint64_t BasicData<T>::POWERS_OF_10_64[] = {
|
||||
0,
|
||||
FMT_POWERS_OF_10(1),
|
||||
FMT_POWERS_OF_10(ULongLong(1000000000)),
|
||||
@@ -284,7 +313,7 @@ const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
|
||||
ULongLong(1000000000) * ULongLong(1000000000) * 10
|
||||
};
|
||||
|
||||
FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
|
||||
FMT_FUNC void report_unknown_type(char code, const char *type) {
|
||||
(void)type;
|
||||
if (std::isprint(static_cast<unsigned char>(code))) {
|
||||
FMT_THROW(FormatError(
|
||||
@@ -297,7 +326,7 @@ FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
|
||||
FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) {
|
||||
FMT_FUNC UTF8ToUTF16::UTF8ToUTF16(StringRef s) {
|
||||
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
|
||||
if (s.size() > INT_MAX)
|
||||
FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
|
||||
@@ -314,14 +343,14 @@ FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) {
|
||||
buffer_[length] = 0;
|
||||
}
|
||||
|
||||
FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) {
|
||||
FMT_FUNC UTF16ToUTF8::UTF16ToUTF8(WStringRef s) {
|
||||
if (int error_code = convert(s)) {
|
||||
FMT_THROW(WindowsError(error_code,
|
||||
"cannot convert string from UTF-16 to UTF-8"));
|
||||
}
|
||||
}
|
||||
|
||||
FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) {
|
||||
FMT_FUNC int UTF16ToUTF8::convert(WStringRef s) {
|
||||
if (s.size() > INT_MAX)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
int s_size = static_cast<int>(s.size());
|
||||
@@ -337,6 +366,7 @@ FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) {
|
||||
buffer_[length] = 0;
|
||||
return 0;
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
FMT_FUNC void WindowsError::init(
|
||||
int err_code, CStringRef format_str, ArgList args) {
|
||||
@@ -347,7 +377,8 @@ FMT_FUNC void WindowsError::init(
|
||||
base = std::runtime_error(w.str());
|
||||
}
|
||||
|
||||
FMT_FUNC void internal::format_windows_error(
|
||||
namespace internal {
|
||||
FMT_FUNC void format_windows_error(
|
||||
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
|
||||
@@ -375,7 +406,7 @@ FMT_FUNC void internal::format_windows_error(
|
||||
}
|
||||
|
||||
#endif // FMT_USE_WINDOWS_H
|
||||
|
||||
} // namespace internal
|
||||
FMT_FUNC void format_system_error(
|
||||
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
@@ -395,83 +426,37 @@ FMT_FUNC void format_system_error(
|
||||
} FMT_CATCH(...) {}
|
||||
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
|
||||
}
|
||||
} // namespace fmt
|
||||
|
||||
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) {
|
||||
void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
|
||||
FMT_THROW(std::runtime_error("buffer overflow"));
|
||||
}
|
||||
|
||||
FMT_FUNC internal::Arg internal::FormatterBase::do_get_arg(
|
||||
FMT_FUNC fmt::internal::Arg fmt::internal::FormatterBase::do_get_arg(
|
||||
unsigned arg_index, const char *&error) {
|
||||
internal::Arg arg = args_[arg_index];
|
||||
fmt::internal::Arg arg = args_[arg_index];
|
||||
switch (arg.type) {
|
||||
case internal::Arg::NONE:
|
||||
case fmt::internal::Arg::NONE:
|
||||
error = "argument index out of range";
|
||||
break;
|
||||
case internal::Arg::NAMED_ARG:
|
||||
arg = *static_cast<const internal::Arg*>(arg.pointer);
|
||||
case fmt::internal::Arg::NAMED_ARG:
|
||||
arg = *static_cast<const fmt::internal::Arg*>(arg.pointer);
|
||||
break;
|
||||
default:
|
||||
/*nothing*/;
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
namespace fmt {
|
||||
FMT_FUNC void report_system_error(
|
||||
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
|
||||
// 'fmt::' is for bcc32.
|
||||
int error_code, StringRef message) FMT_NOEXCEPT {
|
||||
report_error(format_system_error, error_code, message);
|
||||
}
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
FMT_FUNC void report_windows_error(
|
||||
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
|
||||
// 'fmt::' is for bcc32.
|
||||
int error_code, StringRef message) FMT_NOEXCEPT {
|
||||
report_error(internal::format_windows_error, error_code, message);
|
||||
}
|
||||
#endif
|
||||
@@ -499,32 +484,29 @@ FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) {
|
||||
template struct internal::BasicData<void>;
|
||||
|
||||
// Explicit instantiations for char.
|
||||
namespace internal {
|
||||
template void 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 CharTraits<char>::format_float(
|
||||
char *buffer, std::size_t size, const char *format,
|
||||
unsigned width, int precision, double value);
|
||||
|
||||
template FMT_API int internal::CharTraits<char>::format_float(
|
||||
template FMT_API int CharTraits<char>::format_float(
|
||||
char *buffer, std::size_t size, const char *format,
|
||||
unsigned width, int precision, long double value);
|
||||
|
||||
// Explicit instantiations for wchar_t.
|
||||
|
||||
template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
|
||||
template void 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 CharTraits<wchar_t>::format_float(
|
||||
wchar_t *buffer, std::size_t size, const wchar_t *format,
|
||||
unsigned width, int precision, double value);
|
||||
|
||||
template FMT_API int internal::CharTraits<wchar_t>::format_float(
|
||||
template FMT_API int CharTraits<wchar_t>::format_float(
|
||||
wchar_t *buffer, std::size_t size, const wchar_t *format,
|
||||
unsigned width, int precision, long double value);
|
||||
} //namespace internal
|
||||
|
||||
#endif // FMT_HEADER_ONLY
|
||||
|
||||
|
||||
410
fmt/format.h
410
fmt/format.h
@@ -25,9 +25,15 @@
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// transition helper
|
||||
#ifdef FMT_FORMAT_PROVIDE_PRINTF
|
||||
#include "printf.h"
|
||||
#endif
|
||||
|
||||
#ifndef FMT_FORMAT_H_
|
||||
#define FMT_FORMAT_H_
|
||||
|
||||
#define FMT_INCLUDE
|
||||
#include <cassert>
|
||||
#include <clocale>
|
||||
#include <cmath>
|
||||
@@ -39,11 +45,33 @@
|
||||
#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 40101
|
||||
|
||||
#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
|
||||
# define FMT_HAS_EXPERIMENTAL_STRING_VIEW 0
|
||||
#else
|
||||
# define FMT_HAS_STRING_VIEW 0
|
||||
# if (FMT_HAS_INCLUDE(<experimental/string_view>) && __cplusplus >= 201402L)
|
||||
# include <experimental/string_view>
|
||||
# define FMT_HAS_EXPERIMENTAL_STRING_VIEW 1
|
||||
# else
|
||||
# define FMT_HAS_EXPERIMENTAL_STRING_VIEW 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined _SECURE_SCL && _SECURE_SCL
|
||||
# define FMT_SECURE_SCL _SECURE_SCL
|
||||
#else
|
||||
# define FMT_SECURE_SCL 0
|
||||
@@ -97,7 +125,14 @@ 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
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#pragma warn -8072 // disable "suspicious pointer arithmetic" warning on access of the digits array
|
||||
#pragma warn -8004 // disable "assigned value that is never used" warning
|
||||
#endif
|
||||
|
||||
#if defined(__INTEL_COMPILER)
|
||||
@@ -135,6 +170,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 +217,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 +329,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
|
||||
@@ -300,12 +370,15 @@ typedef __int64 intmax_t;
|
||||
// otherwise support __builtin_clz and __builtin_clzll, so
|
||||
// only define FMT_BUILTIN_CLZ using the MSVC intrinsics
|
||||
// if the clz and clzll builtins are not available.
|
||||
#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED)
|
||||
#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED) && !defined(UNDER_CE)
|
||||
# include <intrin.h> // _BitScanReverse, _BitScanReverse64
|
||||
|
||||
namespace fmt {
|
||||
namespace internal {
|
||||
# pragma intrinsic(_BitScanReverse)
|
||||
// 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 +392,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
|
||||
|
||||
@@ -387,8 +461,7 @@ class numeric_limits<fmt::internal::DummyInt> :
|
||||
using namespace fmt::internal;
|
||||
// The resolution "priority" is:
|
||||
// isinf macro > std::isinf > ::isinf > fmt::internal::isinf
|
||||
if (const_check(sizeof(isinf(x)) == sizeof(bool) ||
|
||||
sizeof(isinf(x)) == sizeof(int))) {
|
||||
if (const_check(sizeof(isinf(x)) != sizeof(fmt::internal::DummyInt))) {
|
||||
return isinf(x) != 0;
|
||||
}
|
||||
return !_finite(static_cast<double>(x));
|
||||
@@ -398,8 +471,7 @@ class numeric_limits<fmt::internal::DummyInt> :
|
||||
template <typename T>
|
||||
static bool isnotanumber(T x) {
|
||||
using namespace fmt::internal;
|
||||
if (const_check(sizeof(isnan(x)) == sizeof(bool) ||
|
||||
sizeof(isnan(x)) == sizeof(int))) {
|
||||
if (const_check(sizeof(isnan(x)) != sizeof(fmt::internal::DummyInt))) {
|
||||
return isnan(x) != 0;
|
||||
}
|
||||
return _isnan(static_cast<double>(x)) != 0;
|
||||
@@ -408,8 +480,7 @@ class numeric_limits<fmt::internal::DummyInt> :
|
||||
// Portable version of signbit.
|
||||
static bool isnegative(double x) {
|
||||
using namespace fmt::internal;
|
||||
if (const_check(sizeof(signbit(x)) == sizeof(bool) ||
|
||||
sizeof(signbit(x)) == sizeof(int))) {
|
||||
if (const_check(sizeof(signbit(x)) != sizeof(fmt::internal::DummyInt))) {
|
||||
return signbit(x) != 0;
|
||||
}
|
||||
if (x < 0) return true;
|
||||
@@ -505,6 +576,46 @@ 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
|
||||
|
||||
#if FMT_HAS_EXPERIMENTAL_STRING_VIEW
|
||||
/**
|
||||
\rst
|
||||
Constructs a string reference from a ``std::experimental::basic_string_view`` object.
|
||||
\endrst
|
||||
*/
|
||||
BasicStringRef(
|
||||
const std::experimental::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::experimental::basic_string_view<Char>() const FMT_NOEXCEPT {
|
||||
return std::experimental::basic_string_view<Char>(data_, size_);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
\rst
|
||||
Converts a string reference to an ``std::string`` object.
|
||||
@@ -604,12 +715,12 @@ typedef BasicCStringRef<char> CStringRef;
|
||||
typedef BasicCStringRef<wchar_t> WCStringRef;
|
||||
|
||||
/** A formatting error such as invalid format string. */
|
||||
class FormatError : public std::runtime_error {
|
||||
class FMT_API FormatError : public std::runtime_error {
|
||||
public:
|
||||
explicit FormatError(CStringRef message)
|
||||
: std::runtime_error(message.c_str()) {}
|
||||
FormatError(const FormatError &ferr) : std::runtime_error(ferr) {}
|
||||
FMT_API ~FormatError() FMT_DTOR_NOEXCEPT;
|
||||
~FormatError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
@@ -726,7 +837,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 +865,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 +909,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 +1032,7 @@ struct IntTraits {
|
||||
TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType;
|
||||
};
|
||||
|
||||
FMT_API void report_unknown_type(char code, const char *type);
|
||||
FMT_NORETURN FMT_API void report_unknown_type(char code, const char *type);
|
||||
|
||||
// Static data is placed in this class template to allow header-only
|
||||
// configuration.
|
||||
@@ -1155,17 +1271,17 @@ T &get();
|
||||
Yes &convert(fmt::ULongLong);
|
||||
No &convert(...);
|
||||
|
||||
template<typename T, bool ENABLE_CONVERSION>
|
||||
template <typename T, bool ENABLE_CONVERSION>
|
||||
struct ConvertToIntImpl {
|
||||
enum { value = ENABLE_CONVERSION };
|
||||
};
|
||||
|
||||
template<typename T, bool ENABLE_CONVERSION>
|
||||
template <typename T, bool ENABLE_CONVERSION>
|
||||
struct ConvertToIntImpl2 {
|
||||
enum { value = false };
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
struct ConvertToIntImpl2<T, true> {
|
||||
enum {
|
||||
// Don't convert numeric types.
|
||||
@@ -1173,9 +1289,10 @@ struct ConvertToIntImpl2<T, true> {
|
||||
};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
struct ConvertToInt {
|
||||
enum {
|
||||
#pragma warning(suppress: 4244)
|
||||
enable_conversion = sizeof(fmt::internal::convert(get<T>())) == sizeof(Yes)
|
||||
};
|
||||
enum { value = ConvertToIntImpl2<T, enable_conversion>::value };
|
||||
@@ -1190,16 +1307,16 @@ FMT_DISABLE_CONVERSION_TO_INT(float);
|
||||
FMT_DISABLE_CONVERSION_TO_INT(double);
|
||||
FMT_DISABLE_CONVERSION_TO_INT(long double);
|
||||
|
||||
template<bool B, class T = void>
|
||||
template <bool B, class T = void>
|
||||
struct EnableIf {};
|
||||
|
||||
template<class T>
|
||||
template <class T>
|
||||
struct EnableIf<true, T> { typedef T type; };
|
||||
|
||||
template<bool B, class T, class F>
|
||||
template <bool B, class T, class F>
|
||||
struct Conditional { typedef T type; };
|
||||
|
||||
template<class T, class F>
|
||||
template <class T, class F>
|
||||
struct Conditional<false, T, F> { typedef F type; };
|
||||
|
||||
// For bcc32 which doesn't understand ! in template arguments.
|
||||
@@ -1216,6 +1333,7 @@ template <typename T, T> struct LConvCheck {
|
||||
LConvCheck(int) {}
|
||||
};
|
||||
|
||||
#ifndef __BORLANDC__
|
||||
// Returns the thousands separator for the current locale.
|
||||
// We check if ``lconv`` contains ``thousands_sep`` because on Android
|
||||
// ``lconv`` is stubbed as an empty struct.
|
||||
@@ -1224,6 +1342,7 @@ inline StringRef thousands_sep(
|
||||
LConv *lc, LConvCheck<char *LConv::*, &LConv::thousands_sep> = 0) {
|
||||
return lc->thousands_sep;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline fmt::StringRef thousands_sep(...) { return ""; }
|
||||
|
||||
@@ -1248,9 +1367,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 +1402,12 @@ 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
|
||||
#if FMT_HAS_EXPERIMENTAL_STRING_VIEW
|
||||
MakeValue(typename WCharHelper<const std::experimental::wstring_view &, Char>::Unsupported);
|
||||
#endif
|
||||
MakeValue(typename WCharHelper<WStringRef, Char>::Unsupported);
|
||||
|
||||
void set_string(StringRef str) {
|
||||
@@ -1352,6 +1477,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 +1509,12 @@ 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
|
||||
#if FMT_HAS_EXPERIMENTAL_STRING_VIEW
|
||||
FMT_MAKE_STR_VALUE(const std::experimental::string_view &, STRING)
|
||||
#endif
|
||||
FMT_MAKE_STR_VALUE(StringRef, STRING)
|
||||
FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str())
|
||||
|
||||
@@ -1382,6 +1527,12 @@ 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
|
||||
#if FMT_HAS_EXPERIMENTAL_STRING_VIEW
|
||||
FMT_MAKE_WSTR_VALUE(const std::experimental::wstring_view &, WSTRING)
|
||||
#endif
|
||||
FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING)
|
||||
|
||||
FMT_MAKE_VALUE(void *, pointer, POINTER)
|
||||
@@ -1447,7 +1598,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 +2072,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 +2085,50 @@ 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*/;
|
||||
}
|
||||
}
|
||||
}
|
||||
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:
|
||||
@@ -1950,6 +2145,8 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> {
|
||||
|
||||
// workaround MSVC two-phase lookup issue
|
||||
typedef internal::Arg Arg;
|
||||
typedef Char CharType;
|
||||
typedef BasicWriter<Char> WriterType;
|
||||
|
||||
protected:
|
||||
BasicWriter<Char> &writer() { return writer_; }
|
||||
@@ -1994,8 +2191,8 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> {
|
||||
}
|
||||
if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
|
||||
FMT_THROW(FormatError("invalid format specifier for char"));
|
||||
typedef typename BasicWriter<Char>::CharPtr CharPtr;
|
||||
Char fill = internal::CharTraits<Char>::cast(spec_.fill());
|
||||
typedef typename WriterType::CharPtr CharPtr;
|
||||
CharType fill = internal::CharTraits<CharType>::cast(spec_.fill());
|
||||
CharPtr out = CharPtr();
|
||||
const unsigned CHAR_SIZE = 1;
|
||||
if (spec_.width_ > CHAR_SIZE) {
|
||||
@@ -2013,7 +2210,7 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> {
|
||||
} else {
|
||||
out = writer_.grow_buffer(CHAR_SIZE);
|
||||
}
|
||||
*out = internal::CharTraits<Char>::cast(value);
|
||||
*out = internal::CharTraits<CharType>::cast(value);
|
||||
}
|
||||
|
||||
void visit_cstring(const char *value) {
|
||||
@@ -2215,12 +2412,14 @@ inline uint64_t make_type(const T &arg) {
|
||||
return MakeValue< BasicFormatter<char> >::type(arg);
|
||||
}
|
||||
|
||||
#ifndef __BORLANDC__
|
||||
template <std::size_t N, bool/*IsPacked*/= (N < ArgList::MAX_PACKED_ARGS)>
|
||||
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) {
|
||||
@@ -2243,6 +2442,25 @@ struct ArgArray<N, false/*IsPacked*/> {
|
||||
template <typename Formatter, typename T>
|
||||
static Arg make(const T &value) { return MakeArg<Formatter>(value); }
|
||||
};
|
||||
#else
|
||||
template <std::size_t N>
|
||||
struct ArgArray {
|
||||
typedef Value Type[N > 0 ? N : 1];
|
||||
|
||||
template <typename Formatter, typename T>
|
||||
static Value make(const T & value) {
|
||||
#ifdef __clang__
|
||||
Value result = MakeValue<Formatter>(value);
|
||||
// Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang:
|
||||
// https://github.com/fmtlib/fmt/issues/276
|
||||
(void)result.custom.format;
|
||||
return result;
|
||||
#else
|
||||
return MakeValue<Formatter>(value);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if FMT_USE_VARIADIC_TEMPLATES
|
||||
template <typename Arg, typename... Args>
|
||||
@@ -2279,6 +2497,8 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
|
||||
arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter<char> >(v##n)
|
||||
# define FMT_ASSIGN_wchar_t(n) \
|
||||
arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter<wchar_t> >(v##n)
|
||||
# define FMT_ASSIGN_Char(n) \
|
||||
arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter<Char> >(v##n)
|
||||
|
||||
#if FMT_USE_VARIADIC_TEMPLATES
|
||||
// Defines a variadic function returning void.
|
||||
@@ -2312,9 +2532,10 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
|
||||
# define FMT_WRAP1(func, arg_type, n) \
|
||||
template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \
|
||||
inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \
|
||||
const fmt::internal::ArgArray<n>::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \
|
||||
fmt::internal::ArgArray<n>::Type arr; \
|
||||
FMT_GEN(n, FMT_ASSIGN_Char) ; \
|
||||
func(arg1, fmt::ArgList( \
|
||||
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \
|
||||
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \
|
||||
}
|
||||
|
||||
// Emulates a variadic function returning void on a pre-C++11 compiler.
|
||||
@@ -2329,9 +2550,10 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
|
||||
# define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \
|
||||
template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \
|
||||
ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \
|
||||
const fmt::internal::ArgArray<n>::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \
|
||||
fmt::internal::ArgArray<n>::Type arr; \
|
||||
FMT_GEN(n, FMT_ASSIGN_Char) ; \
|
||||
func(arg0, arg1, fmt::ArgList( \
|
||||
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \
|
||||
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \
|
||||
}
|
||||
|
||||
// Emulates a variadic constructor on a pre-C++11 compiler.
|
||||
@@ -2410,7 +2632,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_; }
|
||||
};
|
||||
@@ -2811,13 +3033,13 @@ typename BasicWriter<Char>::CharPtr
|
||||
CharPtr p = grow_buffer(fill_size);
|
||||
std::uninitialized_fill(p, p + fill_size, fill);
|
||||
}
|
||||
CharPtr result = prepare_int_buffer(
|
||||
num_digits, subspec, prefix, prefix_size);
|
||||
std::ptrdiff_t offset = get(prepare_int_buffer(
|
||||
num_digits, subspec, prefix, prefix_size)) - &buffer_[0];
|
||||
if (align == ALIGN_LEFT) {
|
||||
CharPtr p = grow_buffer(fill_size);
|
||||
std::uninitialized_fill(p, p + fill_size, fill);
|
||||
}
|
||||
return result;
|
||||
return internal::make_ptr(&buffer_[0], buffer_.size()) + offset;
|
||||
}
|
||||
unsigned size = prefix_size + num_digits;
|
||||
if (width <= size) {
|
||||
@@ -2927,7 +3149,7 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
|
||||
case 'n': {
|
||||
unsigned num_digits = internal::count_digits(abs_value);
|
||||
fmt::StringRef sep = "";
|
||||
#if !(defined(ANDROID) || defined(__ANDROID__))
|
||||
#if !defined(__ANDROID__) && !defined(UNDER_CE)
|
||||
sep = internal::thousands_sep(std::localeconv());
|
||||
#endif
|
||||
unsigned size = static_cast<unsigned>(
|
||||
@@ -3132,10 +3354,10 @@ void BasicWriter<Char>::write_double(T value, const Spec &spec) {
|
||||
accessed as a C string with ``out.c_str()``.
|
||||
\endrst
|
||||
*/
|
||||
template <typename Char, typename Allocator = std::allocator<Char> >
|
||||
template <typename Char, typename Allocator = std::allocator<Char>, std::size_t INLINE_BUFFER_SIZE = internal::INLINE_BUFFER_SIZE>
|
||||
class BasicMemoryWriter : public BasicWriter<Char> {
|
||||
private:
|
||||
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE, Allocator> buffer_;
|
||||
internal::MemoryBuffer<Char, INLINE_BUFFER_SIZE, Allocator> buffer_;
|
||||
|
||||
public:
|
||||
explicit BasicMemoryWriter(const Allocator& alloc = Allocator())
|
||||
@@ -3483,10 +3705,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 +3718,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 +3777,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 +3829,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 +4013,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 +4052,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 {
|
||||
@@ -3891,7 +4123,8 @@ ArgJoin<wchar_t, It> join(It first, It last, const BasicCStringRef<wchar_t>& sep
|
||||
return ArgJoin<wchar_t, It>(first, last, sep);
|
||||
}
|
||||
|
||||
#if FMT_HAS_GXX_CXX11
|
||||
#if FMT_HAS_GXX_CXX11 && \
|
||||
(!FMT_GCC_VERSION || FMT_GCC_VERSION >= 405 || __clang__)
|
||||
template <typename Range>
|
||||
auto join(const Range& range, const BasicCStringRef<char>& sep)
|
||||
-> ArgJoin<char, decltype(std::begin(range))> {
|
||||
@@ -3909,10 +4142,14 @@ template <typename ArgFormatter, typename Char, typename It>
|
||||
void format_arg(fmt::BasicFormatter<Char, ArgFormatter> &f,
|
||||
const Char *&format_str, const ArgJoin<Char, It>& e) {
|
||||
const Char* end = format_str;
|
||||
if (*end == ':')
|
||||
++end;
|
||||
while (*end && *end != '}')
|
||||
int brace_level = 1;
|
||||
while (*end) {
|
||||
if (*end == '}' && --brace_level == 0)
|
||||
break;
|
||||
if (*end == '{')
|
||||
++brace_level;
|
||||
++end;
|
||||
}
|
||||
if (*end != '}')
|
||||
FMT_THROW(FormatError("missing '}' in format string"));
|
||||
|
||||
@@ -4009,4 +4246,9 @@ operator"" _a(const wchar_t *s, std::size_t) { return {s}; }
|
||||
# define FMT_FUNC
|
||||
#endif
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#pragma warn .8072 // restore "suspicious pointer arithmetic" warning on access of the digits array
|
||||
#pragma warn .8004 // restore "assigned value that is never used" warning
|
||||
#endif
|
||||
|
||||
#endif // FMT_FORMAT_H_
|
||||
|
||||
@@ -52,16 +52,19 @@ 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);
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
struct ConvertToIntImpl<T, true> {
|
||||
// Convert to int only if T doesn't have an overloaded operator<<.
|
||||
enum {
|
||||
#pragma warning(suppress: 4244)
|
||||
value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
|
||||
};
|
||||
};
|
||||
@@ -78,6 +81,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());
|
||||
|
||||
15
fmt/posix.cc
15
fmt/posix.cc
@@ -26,10 +26,13 @@
|
||||
# endif
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
|
||||
# define O_CREAT _O_CREAT
|
||||
# define O_TRUNC _O_TRUNC
|
||||
|
||||
#include <algorithm>
|
||||
# ifndef O_CREAT
|
||||
# define O_CREAT _O_CREAT
|
||||
# endif
|
||||
# ifndef O_TRUNC
|
||||
# define O_TRUNC _O_TRUNC
|
||||
# endif
|
||||
# ifndef S_IRUSR
|
||||
# define S_IRUSR _S_IREAD
|
||||
# endif
|
||||
@@ -56,7 +59,7 @@ typedef int RWResult;
|
||||
// On Windows the count argument to read and write is unsigned, so convert
|
||||
// it from size_t preventing integer overflow.
|
||||
inline unsigned convert_rwcount(std::size_t count) {
|
||||
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
|
||||
return static_cast<unsigned>(std::min<std::size_t>(count, UINT_MAX));
|
||||
}
|
||||
#else
|
||||
// Return type of read and write functions.
|
||||
@@ -99,7 +102,7 @@ int fmt::BufferedFile::fileno() const {
|
||||
|
||||
fmt::File::File(fmt::CStringRef path, int oflag) {
|
||||
int mode = S_IRUSR | S_IWUSR;
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__BORLANDC__)
|
||||
fd_ = -1;
|
||||
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
|
||||
#else
|
||||
|
||||
@@ -10,11 +10,6 @@
|
||||
#ifndef FMT_POSIX_H_
|
||||
#define FMT_POSIX_H_
|
||||
|
||||
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
||||
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
|
||||
# undef __STRICT_ANSI__
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h> // for O_RDONLY
|
||||
#include <locale.h> // for locale_t
|
||||
@@ -46,6 +41,10 @@
|
||||
# ifdef _WIN32
|
||||
// Fix warnings about deprecated symbols.
|
||||
# define FMT_POSIX_CALL(call) ::_##call
|
||||
# if defined(__BORLANDC__) && !defined(_dup2)
|
||||
// for some reason the borland headers do define _dup but not _dup2
|
||||
# define _dup2 dup2
|
||||
# endif
|
||||
# else
|
||||
# define FMT_POSIX_CALL(call) ::call
|
||||
# endif
|
||||
|
||||
@@ -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;
|
||||
@@ -333,7 +333,7 @@ class PrintfFormatter : private internal::FormatterBase {
|
||||
\endrst
|
||||
*/
|
||||
explicit PrintfFormatter(const ArgList &al, BasicWriter<Char> &w)
|
||||
: FormatterBase(al), writer_(w) {}
|
||||
: internal::FormatterBase(al), writer_(w) {}
|
||||
|
||||
/** Formats stored arguments and writes the output to the writer. */
|
||||
void format(BasicCStringRef<Char> format_str);
|
||||
@@ -371,7 +371,7 @@ internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s,
|
||||
(void)s;
|
||||
const char *error = FMT_NULL;
|
||||
internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ?
|
||||
next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
|
||||
next_arg(error) : internal::FormatterBase::get_arg(arg_index - 1, error);
|
||||
if (error)
|
||||
FMT_THROW(FormatError(!*s ? "invalid format string" : error));
|
||||
return arg;
|
||||
|
||||
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_
|
||||
|
||||
@@ -2,3 +2,5 @@ This directory contains build support files such as
|
||||
|
||||
* CMake modules
|
||||
* Build scripts
|
||||
* qmake (static build with dynamic libc only)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ build = os.environ['BUILD']
|
||||
config = os.environ['CONFIGURATION']
|
||||
platform = os.environ.get('PLATFORM')
|
||||
path = os.environ['PATH']
|
||||
cmake_command = ['cmake', '-DFMT_PEDANTIC=ON', '-DCMAKE_BUILD_TYPE=' + config]
|
||||
cmake_command = ['cmake', '-DFMT_PEDANTIC=ON', '-DCMAKE_BUILD_TYPE=' + config, '.']
|
||||
if build == 'mingw':
|
||||
cmake_command.append('-GMinGW Makefiles')
|
||||
build_command = ['mingw32-make', '-j4']
|
||||
|
||||
29
support/fmt.pro
Normal file
29
support/fmt.pro
Normal file
@@ -0,0 +1,29 @@
|
||||
# Staticlib configuration for qmake builds
|
||||
# For some reason qmake 3.1 fails to identify source dependencies and excludes format.cc and printf.cc
|
||||
# from compilation so it _MUST_ be called as qmake -nodepend
|
||||
# A workaround is implemented below: a custom compiler is defined which does not track dependencies
|
||||
|
||||
TEMPLATE = lib
|
||||
|
||||
TARGET = fmt
|
||||
|
||||
QMAKE_EXT_CPP = .cc
|
||||
|
||||
CONFIG = staticlib warn_on c++11
|
||||
|
||||
FMT_SOURCES = \
|
||||
../fmt/format.cc \
|
||||
../fmt/ostream.cc \
|
||||
../fmt/posix.cc \
|
||||
../fmt/printf.cc
|
||||
|
||||
fmt.name = libfmt
|
||||
fmt.input = FMT_SOURCES
|
||||
fmt.output = ${QMAKE_FILE_BASE}$$QMAKE_EXT_OBJ
|
||||
fmt.clean = ${QMAKE_FILE_BASE}$$QMAKE_EXT_OBJ
|
||||
fmt.depends = ${QMAKE_FILE_IN}
|
||||
# QMAKE_RUN_CXX will not be expanded
|
||||
fmt.commands = $$QMAKE_CXX -c $$QMAKE_CXXFLAGS $$QMAKE_CXXFLAGS_WARN_ON $$QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO $$QMAKE_CXXFLAGS_CXX11 ${QMAKE_FILE_IN}
|
||||
fmt.variable_out = OBJECTS
|
||||
fmt.CONFIG = no_dependencies no_link
|
||||
QMAKE_EXTRA_COMPILERS += fmt
|
||||
@@ -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.
|
||||
@@ -140,6 +141,7 @@ def update_site(env):
|
||||
b.data = re.sub(pattern, r'doxygenfunction:: \1(int)', b.data)
|
||||
b.data = b.data.replace('std::FILE*', 'std::FILE *')
|
||||
b.data = b.data.replace('unsigned int', 'unsigned')
|
||||
b.data = b.data.replace('operator""_', 'operator"" _')
|
||||
# Fix a broken link in index.rst.
|
||||
index = os.path.join(target_doc_dir, 'index.rst')
|
||||
with rewrite(index) as b:
|
||||
@@ -165,7 +167,11 @@ def update_site(env):
|
||||
os.symlink(target, link)
|
||||
# Copy docs to the website.
|
||||
version_doc_dir = os.path.join(doc_repo.dir, version)
|
||||
shutil.rmtree(version_doc_dir)
|
||||
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 +210,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)
|
||||
|
||||
@@ -11,6 +11,12 @@ target_compile_options(gmock PUBLIC ${CPP11_FLAG})
|
||||
target_compile_definitions(gmock PUBLIC GTEST_HAS_STD_WSTRING=1)
|
||||
target_include_directories(gmock PUBLIC .)
|
||||
|
||||
# Workaround for Cygwin to make google-tests compile and run because the macro
|
||||
# _POSIX_C_SOURCE must be defined to allow fileno(), strdup(), fdopen() calls.
|
||||
if (CYGWIN)
|
||||
target_compile_definitions(gmock PUBLIC _POSIX_C_SOURCE=200809)
|
||||
endif ()
|
||||
|
||||
find_package(Threads)
|
||||
if (Threads_FOUND)
|
||||
target_link_libraries(gmock ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
@@ -151,16 +151,46 @@ 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
|
||||
|
||||
#if FMT_HAS_EXPERIMENTAL_STRING_VIEW
|
||||
EXPECT_STREQ("hijk", StringRef(std::experimental::string_view("hijk")).data());
|
||||
EXPECT_EQ(4u, StringRef(std::experimental::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
|
||||
|
||||
#if FMT_HAS_EXPERIMENTAL_STRING_VIEW
|
||||
StringRef str_ref("defg");
|
||||
std::experimental::string_view sv = static_cast<std::experimental::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_HAS_EXPERIMENTAL_STRING_VIEW
|
||||
EXPECT_STREQ("hijk", CStringRef(std::experimental::string_view("hijk")).c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FMT_USE_TYPE_TRAITS
|
||||
@@ -1378,6 +1408,18 @@ 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
|
||||
|
||||
#if FMT_HAS_EXPERIMENTAL_STRING_VIEW
|
||||
TEST(FormatterTest, FormatExperimentalStringView) {
|
||||
EXPECT_EQ("test", format("{0}", std::experimental::string_view("test")));
|
||||
}
|
||||
#endif
|
||||
|
||||
void format_arg(fmt::BasicFormatter<char> &f, const char *, const Date &d) {
|
||||
f.writer() << d.year() << '-' << d.month() << '-' << d.day();
|
||||
}
|
||||
@@ -1569,13 +1611,15 @@ TEST(FormatTest, JoinArg) {
|
||||
v2.push_back(1.2f);
|
||||
v2.push_back(3.4f);
|
||||
|
||||
EXPECT_EQ("(1, 2, 3)", format("({})", join(v1 + 0, v1 + 3, ", ")));
|
||||
EXPECT_EQ("(1)", format("({})", join(v1 + 0, v1 + 1, ", ")));
|
||||
EXPECT_EQ("()", format("({})", join(v1 + 0, v1 + 0, ", ")));
|
||||
EXPECT_EQ("(001, 002, 003)", format("({:03})", join(v1 + 0, v1 + 3, ", ")));
|
||||
EXPECT_EQ("(+01.20, +03.40)", format("({:+06.2f})", join(v2.begin(), v2.end(), ", ")));
|
||||
EXPECT_EQ("(1, 2, 3)", format("({})", join(v1, v1 + 3, ", ")));
|
||||
EXPECT_EQ("(1)", format("({})", join(v1, v1 + 1, ", ")));
|
||||
EXPECT_EQ("()", format("({})", join(v1, v1, ", ")));
|
||||
EXPECT_EQ("(001, 002, 003)", format("({:03})", join(v1, v1 + 3, ", ")));
|
||||
EXPECT_EQ("(+01.20, +03.40)",
|
||||
format("({:+06.2f})", join(v2.begin(), v2.end(), ", ")));
|
||||
|
||||
EXPECT_EQ(L"(1, 2, 3)", format(L"({})", join(v1 + 0, v1 + 3, L", ")));
|
||||
EXPECT_EQ(L"(1, 2, 3)", format(L"({})", join(v1, v1 + 3, L", ")));
|
||||
EXPECT_EQ("1, 2, 3", format("{0:{1}}", join(v1, v1 + 3, ", "), 1));
|
||||
|
||||
#if FMT_HAS_GXX_CXX11
|
||||
EXPECT_EQ("(1, 2, 3)", format("({})", join(v1, ", ")));
|
||||
@@ -1609,6 +1653,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 +1722,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:
|
||||
@@ -1691,3 +1761,7 @@ void convert(int);
|
||||
TEST(FormatTest, ConvertCollision) {
|
||||
fmt::format("{}", 42);
|
||||
}
|
||||
|
||||
TEST(FormatTest, Regression) {
|
||||
fmt::format("...........{:<77777.7p}", "foo");
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user