Compare commits

..

70 Commits
4.0.0 ... 4.x

Author SHA1 Message Date
Janusz Chorko
8f5e07656e Remove an old mingw workaround (#2059) (#3975)
Backports fix from master branch as the code no longer compiles
on mingw64/gcc 14.1.0 without gnu extensions enabled.
2024-05-25 07:49:24 -07:00
escherstair
3e8d2c57f3 Add CE6 support (#1749) 2020-07-07 09:29:16 -07:00
Mark Stapper
8ad1c12fb4 Make FMT_CTOR and FMT_WRAP1 macros work with bcc32 2019-03-31 07:21:28 -07:00
Mark Stapper
d2744bc848 Fix compatibility with bcc32 compiler
Resolve namespace issues
Add workaround for compile error on bool template argument of ArgArray struct
Squelch bcc32 warning on accessing the digits array
Squelch bcc32 warning on unused values
Fix warnings about redefinig macros and conditions always true
Disable "LConv" block for bcc32 compiler
Remove macro test for deprecated macro
Fix appveyor-build for cmake v3.13+
2019-03-27 10:10:18 -07:00
Victor Zverovich
b6d435b9a6 Fix an MSVC warning (#798) 2018-07-04 05:42:59 -07:00
Jean-Michaël Celerier
857b382fc3 Mark the whole class FormatError as FMT_API
Else on windows across DLLs the vtable is not visible which causes linking error
2018-05-09 06:12:31 -07:00
Henry Schreiner
b6ac63faf0 Fix warnings when with master project set to hidden 2018-04-27 06:34:52 -07:00
Gabi Melman
1d6188404c Added optional INILINE_BUFFER_SIZE template param to BasicMemoryWriter (#716) 2018-04-21 17:18:13 -07:00
Victor Zverovich
bdab94baf8 Merge branch '4.x' of github.com:fmtlib/fmt into 4.x 2018-04-12 06:07:55 -07:00
Victor Zverovich
a9c0bb4b16 Fix a warning on msvc/clang (#703) 2018-04-12 06:07:16 -07:00
Henry Schreiner
ea2cf449f7 Stop newer CMake's from warning about OLD policy 2018-04-11 09:48:36 -07:00
Henry Schreiner
5c0d7ee157 Fix return that can't be reached 2018-04-11 09:31:10 -07:00
Victor Zverovich
64440783ba Fix an issue with incorrect [[noreturn]] position in clang-cl (#701) 2018-04-08 11:56:47 -07:00
Victor Zverovich
1ecdc1a3bb Fix compilation on gcc 4.4 (#692) 2018-03-23 08:39:24 -07:00
Victor Zverovich
867b330966 Remove ANDROID macro check per comment in #458 2018-02-07 07:44:15 -08:00
Victor Zverovich
8cf30aa2be Fix segfault on complex pointer formatting (#642) 2018-02-01 21:49:03 -08:00
Giuseppe Corbelli
0555cea5fc Added a fmt.pro to support build using qmake (#641) 2018-01-26 17:12:48 -08:00
peterbell10
f78c3e41be Fix unreachable code warning when signbit returns bool 2018-01-21 06:11:29 -08:00
Victor Zverovich
1760c31b52 Workaround Doxygen mess 2018-01-20 08:53:03 -08:00
Victor Zverovich
c15710032e Add debug postfix for libfmt (#636) 2018-01-20 06:47:12 -08:00
Victor Zverovich
6822466aa3 Handle nested braces in join (#638) 2018-01-20 06:26:22 -08:00
Victor Zverovich
c719d94473 Fix experimental/string_view detection 2018-01-13 07:57:33 -08:00
Tim Blechmann
0f98773164 add transition helper to format.h
the transition from v3 to v4 introduced an API change that format.h does
not provide printf functionality. to easi the transition we introduce a
define `FMT_FORMAT_PROVIDE_PRINTF` that will pull in printf.h from format.h
2017-12-27 21:48:55 -08:00
Victor Zverovich
319346025d Update version 2017-12-20 08:38:07 -08:00
Victor Zverovich
51a16f8c58 Update ChangeLog.rst 2017-12-20 08:33:31 -08:00
Victor Zverovich
a00874603d Merge release branch 2017-12-20 08:30:58 -08:00
Virgilio Alexandre Fornazin
5705bf1c71 Added support for pre-c++17 experimental string_view (#607)
Added support for pre-c++17 experimental string_view
2017-12-16 09:03:11 -08:00
Victor Zverovich
cabce31f45 Update syntax.rst 2017-12-16 08:58:54 -08:00
Mihai Todor
f9c97de46b Add note about errno to the documentation 2017-11-28 07:33:51 -08:00
Mike Crowe
62df6f27cb CMakeLists: Use GNUInstallDirs to set install location
CMake's GNUInstallDirs knows where particular Linux architectures and
distributions want to have their libraries installed. In particular,
Debian-derived "multi-arch" distributions keep their libraries in triplet
sudirectories under /lib. Other "bi-arch" distributions keep 64-bit
libraries in /lib64.

Including GNUInstallDirs and using CMAKE_INSTALL_LIBDIR and
CMAKE_INSTALL_INCLUDEDIR means that fmt's libraries and header files are
installed in the correct locations.

Tested with OpenEmbedded and on Debian GNU/Linux 9 (the special naming only
applies when installing in /usr.)
2017-11-13 22:01:41 -08:00
Victor Zverovich
493586cbca Fix overflow check 2017-11-12 07:09:36 -08:00
JP Cimalando
1d751bc617 fix warning in header: signed/unsigned comparison 2017-11-12 06:23:57 -08:00
Victor Zverovich
11415bce3c Update usage.rst 2017-11-08 18:27:10 -08:00
Alex Alabuzhev
9982dd0130 Fix for warning C5030 in VS2015 2017-11-08 18:18:36 -08:00
virgiliofornazin
42e88c4fcb Silenced MSVC 2017 constant if expression warning 2017-11-05 12:27:48 -08:00
Ludek Vodicka
7a9c1ba190 FMT_VARIADIC_CONST - Support for const variadic methods (#591)
FMT_VARIADIC_CONST - Support for const variadic methods
2017-10-22 08:55:40 -07:00
Michael Winterberg
324415c036 Use allocator_traits if available.
This is to avoid using functionality deprecated in C++17.
2017-10-18 06:11:15 -07:00
Victor Zverovich
5f39721c0a Fix a warning 2017-10-15 14:58:41 -07:00
Victor Zverovich
ca96acbe4f Add examples 2017-10-15 07:38:03 -07:00
yumetodo
708d9509ff fix(Clang CodeGen): remove warnings
./fmt/fmt/format.h(308,10): warning : unknown pragma ignored [-Wunknown-pragmas]
         ^
1 warning generated.
format.cc In file included from fmt\fmt\format.cc:28:
fmt\fmt/format.h(308,10): warning : unknown pragma ignored [-Wunknown-pragmas]
         ^
fmt\fmt\format.cc(165,17): warning : 'strerror' is deprecated: This
function or variable may be unsafe. Consider using strerror_s instead.
To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for
details. [-Wdeprecated-declarations]
      buffer_ = strerror(error_code_);
                ^
C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt\string.h(178,24) :  note: 'strerror' has been explicitly marked deprecated here
_ACRTIMP char* __cdecl strerror(
                       ^
fmt\fmt\format.cc(78,37): warning : unused function 'strerror_s' [-Wunused-function]
static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
                                    ^
3 warnings generated.

refactor: use attribute to remove -Wunused-function warnings instead of dummy function call
2017-10-15 07:04:45 -07:00
Victor Zverovich
9328a074b1 Fix handling of fixed enums in clang (#580) 2017-10-14 08:47:08 -07:00
Victor Zverovich
2c077dd442 Enable stream exceptions (#581) 2017-10-14 07:38:16 -07:00
Michael Winterberg
933a33a794 Added MSVC checking for support for string_view.
Also, driveby adding "override" to classes with inherited virtual destructors.
2017-10-08 19:44:09 -07:00
Victor Zverovich
bef89db6e7 Fix a bogus -Wduplicated-branches gcc warning (#573) 2017-09-27 19:32:53 -07:00
Mário Feroldi
2a619d96dd Make format work with C++17 std::string_view (#571)
Tests for C++17 std::string_view
2017-09-20 06:21:11 -07:00
Victor Zverovich
e051de37f3 Use less version 2.6.1 and sudo to fix npm install issues on travis 2017-09-17 08:41:17 -07:00
Mário Feroldi
5de459bf33 Suppress Clang's warning on zero as a null pointer 2017-09-16 18:44:29 -07:00
Elnar Dakeshov
165895346c Make ArgMap::init not explicitly instantiated (#563)
Make ArgMap::init not explicitly instantiated
2017-09-03 19:26:08 -07:00
Victor Zverovich
3e75d3e001 Fix handling of types convertible to int 2017-09-02 07:08:19 -07:00
Alex Alabuzhev
89654cd127 to_wstring added 2017-08-27 18:52:57 +02:00
Victor Zverovich
37eb419af2 Fix noreturn attribute detection (#555) 2017-08-20 09:39:28 -07:00
Manu343726
14d8534900 Explicitly cast range length to std::size_t to prevent conversion warnings 2017-08-20 06:52:52 -07:00
Manu343726
c2201ce02e Accept wide chars as integers to prevent conversion warning 2017-08-20 06:52:52 -07:00
Henry Schreiner
6efbccb387 Add one more CMake warning fix
This will remove one more warning that can't be stopped from a calling CMakeLists. This possibly should be set to new at some point (CMake 3.3 behavior would be different / better), as well as 0048.
2017-08-19 07:03:56 -07:00
Victor Zverovich
032c83807f Fix a segfault in test on glibc 2.26 #551, take 2 2017-08-10 09:27:06 -07:00
Victor Zverovich
6655e804c4 Fix a segfault in test on glibc 2.26 #551 2017-08-06 20:18:04 -07:00
Mário Feroldi
d16c4d20f8 Suppress warning about missing noreturn attribute (#549)
Suppress warning about missing noreturn attribute

Adding `[[noreturn]]` to `report_unknown_type` suppresses the Clang/GCC `-Wmissing-noreturn` warning:

Clang outputs:

    .../fmt/fmt/format.cc:294:74: warning:
          function 'report_unknown_type' could be declared with
          attribute 'noreturn' [-Wmissing-noreturn]
      ...code, const char *type) {
                                 ^

GCC outputs:

    .../fmt/fmt/format.cc:294:74: warning: function might be candidate for
        attribute 'noreturn' [-Wsuggest-attribute=noreturn]
      ...code, const char *type) {
                                 ^
2017-07-21 20:47:01 -07:00
Bjorn Fahller
9c56a8ce5c Make format_arg() accept class hierarchies
If a base class can be formatted, it is assumed
that the hierarchy can be formatted from the base
class. The idiom is not uncommon with ostreams.
2017-07-18 06:16:46 -07:00
Victor Zverovich
ca0e38304c Update README.rst 2017-07-16 14:12:48 -07:00
Alexander Bock
81790d726f Update format.h to remove C4574 error on MSVC 14.2
Similar to the Pullrequest #539, `_SECURE_SCL` caused the same  `warning C4574: '_SECURE_SCL' is defined to be '0': did you mean to use '#if _SECURE_SCL'`.  `_SECURE_SCL` is defined in the `MSVC/14.10.25017/include/yvals.h` by Microsoft itself
2017-07-14 15:29:57 -04:00
Lee, Byoung-young
3028344380 Fix undefined behavior in UDL macro
`FMT_USE_USER_DEFINED_LITERALS` macro expands to `defined()` which is undefined behavior.
2017-07-13 19:10:11 -04:00
Jonathan Müller
4045d7fea2 Fix warning about missing ' character 2017-07-11 20:45:17 +02:00
Alexander Bock
89c3bc585c Remove warning C4668 in MSVC for FMT_GCC_VERSION and FMT_HAS_GXX_CXX11 2017-07-10 13:59:08 -04:00
Alexander Bock
4af9421ff0 Adding OpenSpace to the list of projects 2017-07-07 20:59:39 -07:00
Evgeniy Gerasimenko
1a398b5404 Fixed CMake CMP0048 warning. 2017-07-05 16:55:46 -07:00
Victor Zverovich
589ccc1675 Bump version 2017-07-01 10:37:45 -07:00
Victor Zverovich
c38170461d Add an error on broken includes 2017-07-01 10:09:25 -07:00
Victor Zverovich
16bdd8424f Update scripts 2017-07-01 07:30:51 -07:00
Victor Zverovich
b492316d5d Update version list 2017-07-01 06:57:32 -07:00
Victor Zverovich
91f4ce02b6 Automatically update version in release script (#431) 2017-07-01 06:41:30 -07:00
27 changed files with 735 additions and 218 deletions

View File

@@ -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)

View File

@@ -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>`_):

View File

@@ -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

View File

@@ -84,6 +84,36 @@ Note in the example above the ``format_arg`` function ignores the contents of
``format_arg`` in :file:`fmt/time.h` for an advanced example of how to use
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:

View File

@@ -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',

View File

@@ -143,6 +143,12 @@ its numeric value being written to the stream (i.e. 1070 instead of letter 'ю'
which is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is
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

View File

@@ -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

View File

@@ -41,6 +41,10 @@ current directory. Now you can build the library by running :command:`make`.
Once the library has been built you can invoke :command:`make test` to run
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.

View File

@@ -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 ()

View File

@@ -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

View File

@@ -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_

View File

@@ -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());

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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_

View File

@@ -2,3 +2,5 @@ This directory contains build support files such as
* CMake modules
* Build scripts
* qmake (static build with dynamic libc only)

View File

@@ -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
View 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

View File

@@ -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__':

View File

@@ -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)

View 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})

View File

@@ -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");
}

View File

@@ -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); }
};

View File

@@ -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()));
}

View File

@@ -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));
}

View File

@@ -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());
}