1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 00:37:15 +01:00

Update the format library to the latest version.

This commit is contained in:
Sandu Liviu Catalin 2016-05-22 23:37:55 +03:00
parent edf4d6cd38
commit 49a9983799
13 changed files with 711 additions and 1106 deletions

View File

@ -392,6 +392,7 @@
<Add directory="../source" /> <Add directory="../source" />
<Add directory="../shared" /> <Add directory="../shared" />
<Add directory="../include" /> <Add directory="../include" />
<Add directory="../include/fmt" />
<Add directory="../config/common" /> <Add directory="../config/common" />
<Add directory="../external/Common" /> <Add directory="../external/Common" />
<Add directory="../external/Hash" /> <Add directory="../external/Hash" />
@ -400,6 +401,7 @@
<Add library="squirrel" /> <Add library="squirrel" />
</Linker> </Linker>
<Unit filename="../external/Common/aes256.cpp" /> <Unit filename="../external/Common/aes256.cpp" />
<Unit filename="../external/Common/posix.cc" />
<Unit filename="../external/CppFormat/format.cc" /> <Unit filename="../external/CppFormat/format.cc" />
<Unit filename="../external/Hash/crc32.cpp" /> <Unit filename="../external/Hash/crc32.cpp" />
<Unit filename="../external/Hash/crc32.h" /> <Unit filename="../external/Hash/crc32.h" />

View File

@ -154,6 +154,7 @@
<Add directory="../sandbox" /> <Add directory="../sandbox" />
<Add directory="../source" /> <Add directory="../source" />
<Add directory="../shared" /> <Add directory="../shared" />
<Add directory="../include/fmt" />
<Add directory="../config/common" /> <Add directory="../config/common" />
<Add directory="../external/Common" /> <Add directory="../external/Common" />
<Add directory="../external/Hash" /> <Add directory="../external/Hash" />

View File

@ -1,7 +1,7 @@
/* /*
A C++ interface to POSIX functions. A C++ interface to POSIX functions.
Copyright (c) 2014 - 2015, Victor Zverovich Copyright (c) 2014 - 2016, Victor Zverovich
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@ -1,335 +0,0 @@
1.1.0 - 2015-03-06
------------------
* Added ``BasicArrayWriter``, a class template that provides operations for
formatting and writing data into a fixed-size array
(`#105 <https://github.com/cppformat/cppformat/issues/105>`_ and
`#122 <https://github.com/cppformat/cppformat/issues/122>`_):
.. code:: c++
char buffer[100];
fmt::ArrayWriter w(buffer);
w.write("The answer is {}", 42);
* Added `0 A.D. <http://play0ad.com/>`_ and `PenUltima Online (POL)
<http://www.polserver.com/>`_ to the list of notable projects using C++ Format.
* C++ Format now uses MSVC intrinsics for better formatting performance
(`#115 <https://github.com/cppformat/cppformat/pull/115>`_,
`#116 <https://github.com/cppformat/cppformat/pull/116>`_,
`#118 <https://github.com/cppformat/cppformat/pull/118>`_ and
`#121 <https://github.com/cppformat/cppformat/pull/121>`_).
Previously these optimizations where only used on GCC and Clang.
Thanks to `@CarterLi <https://github.com/CarterLi>`_ and
`@objectx <https://github.com/objectx>`_.
* CMake install target (`#119 <https://github.com/cppformat/cppformat/pull/119>`_).
Thanks to `@TrentHouliston <https://github.com/TrentHouliston>`_.
You can now install C++ Format with ``make install`` command.
* Improved `Biicode <http://www.biicode.com/>`_ support
(`#98 <https://github.com/cppformat/cppformat/pull/98>`_ and
`#104 <https://github.com/cppformat/cppformat/pull/104>`_). Thanks to
`@MariadeAnton <https://github.com/MariadeAnton>`_ and
`@franramirez688 <https://github.com/franramirez688>`_.
* Improved support for bulding with `Android NDK
<https://developer.android.com/tools/sdk/ndk/index.html>`_
(`#107 <https://github.com/cppformat/cppformat/pull/107>`_).
Thanks to `@newnon <https://github.com/newnon>`_.
The `android-ndk-example <https://github.com/cppformat/android-ndk-example>`_
repository provides and example of using C++ Format with Android NDK:
.. image:: https://raw.githubusercontent.com/cppformat/android-ndk-example/
master/screenshot.png
* Improved documentation of ``SystemError`` and ``WindowsError``
(`#54 <https://github.com/cppformat/cppformat/issues/54>`_).
* Various code improvements
(`#110 <https://github.com/cppformat/cppformat/pull/110>`_,
`#111 <https://github.com/cppformat/cppformat/pull/111>`_
`#112 <https://github.com/cppformat/cppformat/pull/112>`_).
Thanks to `@CarterLi <https://github.com/CarterLi>`_.
* Improved compile-time errors when formatting wide into narrow strings
(`#117 <https://github.com/cppformat/cppformat/issues/117>`_).
* Fixed ``BasicWriter::write`` without formatting arguments when C++11 support
is disabled (`#109 <https://github.com/cppformat/cppformat/issues/109>`_).
* Fixed header-only build on OS X with GCC 4.9
(`#124 <https://github.com/cppformat/cppformat/issues/124>`_).
* Fixed packaging issues (`#94 <https://github.com/cppformat/cppformat/issues/94>`_).
* Fixed warnings in GCC, MSVC and Xcode/Clang
(`#95 <https://github.com/cppformat/cppformat/issues/95>`_,
`#96 <https://github.com/cppformat/cppformat/issues/96>`_ and
`#114 <https://github.com/cppformat/cppformat/pull/114>`_).
* Added `changelog <https://github.com/cppformat/cppformat/blob/master/ChangeLog.rst>`_
(`#103 <https://github.com/cppformat/cppformat/issues/103>`_).
1.0.0 - 2015-02-05
------------------
* Add support for a header-only configuration when ``FMT_HEADER_ONLY`` is
defined before including ``format.h``:
.. code:: c++
#define FMT_HEADER_ONLY
#include "format.h"
* Compute string length in the constructor of ``BasicStringRef``
instead of the ``size`` method
(`#79 <https://github.com/cppformat/cppformat/issues/79>`_).
This eliminates size computation for string literals on reasonable optimizing
compilers.
* Fix formatting of types with overloaded ``operator <<`` for ``std::wostream``
(`#86 <https://github.com/cppformat/cppformat/issues/86>`_):
.. code:: c++
fmt::format(L"The date is {0}", Date(2012, 12, 9));
* Fix linkage of tests on Arch Linux
(`#89 <https://github.com/cppformat/cppformat/issues/89>`_).
* Allow precision specifier for non-float arguments
(`#90 <https://github.com/cppformat/cppformat/issues/90>`_):
.. code:: c++
fmt::print("{:.3}\n", "Carpet"); // prints "Car"
* Fix build on Android NDK
(`#93 <https://github.com/cppformat/cppformat/issues/93>`_)
* Improvements to documentation build procedure.
* Remove ``FMT_SHARED`` CMake variable in favor of standard `BUILD_SHARED_LIBS
<http://www.cmake.org/cmake/help/v3.0/variable/BUILD_SHARED_LIBS.html>`_.
* Fix error handling in ``fmt::fprintf``.
* Fix a number of warnings.
0.12.0 - 2014-10-25
-------------------
* [Breaking] Improved separation between formatting and buffer management.
``Writer`` is now a base class that cannot be instantiated directly.
The new ``MemoryWriter`` class implements the default buffer management
with small allocations done on stack. So ``fmt::Writer`` should be replaced
with ``fmt::MemoryWriter`` in variable declarations.
Old code:
.. code:: c++
fmt::Writer w;
New code:
.. code:: c++
fmt::MemoryWriter w;
If you pass ``fmt::Writer`` by reference, you can continue to do so:
.. code:: c++
void f(fmt::Writer &w);
This doesn't affect the formatting API.
* Support for custom memory allocators
(`#69 <https://github.com/cppformat/cppformat/issues/69>`_)
* Formatting functions now accept `signed char` and `unsigned char` strings as
arguments (`#73 <https://github.com/cppformat/cppformat/issues/73>`_):
.. code:: c++
auto s = format("GLSL version: {}", glGetString(GL_VERSION));
* Reduced code bloat. According to the new `benchmark results
<https://github.com/cppformat/cppformat#compile-time-and-code-bloat>`_,
cppformat is close to ``printf`` and by the order of magnitude better than
Boost Format in terms of compiled code size.
* Improved appearance of the documentation on mobile by using the `Sphinx
Bootstrap theme <http://ryan-roemer.github.io/sphinx-bootstrap-theme/>`_:
.. |old| image:: https://cloud.githubusercontent.com/assets/576385/4792130/
cd256436-5de3-11e4-9a62-c077d0c2b003.png
.. |new| image:: https://cloud.githubusercontent.com/assets/576385/4792131/
cd29896c-5de3-11e4-8f59-cac952942bf0.png
+-------+-------+
| Old | New |
+-------+-------+
| |old| | |new| |
+-------+-------+
0.11.0 - 2014-08-21
-------------------
* Safe printf implementation with a POSIX extension for positional arguments:
.. code:: c++
fmt::printf("Elapsed time: %.2f seconds", 1.23);
fmt::printf("%1$s, %3$d %2$s", weekday, month, day);
* Arguments of ``char`` type can now be formatted as integers
(Issue `#55 <https://github.com/cppformat/cppformat/issues/55>`_):
.. code:: c++
fmt::format("0x{0:02X}", 'a');
* Deprecated parts of the API removed.
* The library is now built and tested on MinGW with Appveyor in addition to
existing test platforms Linux/GCC, OS X/Clang, Windows/MSVC.
0.10.0 - 2014-07-01
-------------------
**Improved API**
* All formatting methods are now implemented as variadic functions instead
of using ``operator<<`` for feeding arbitrary arguments into a temporary
formatter object. This works both with C++11 where variadic templates are
used and with older standards where variadic functions are emulated by
providing lightweight wrapper functions defined with the ``FMT_VARIADIC``
macro. You can use this macro for defining your own portable variadic
functions:
.. code:: c++
void report_error(const char *format, const fmt::ArgList &args) {
fmt::print("Error: {}");
fmt::print(format, args);
}
FMT_VARIADIC(void, report_error, const char *)
report_error("file not found: {}", path);
Apart from a more natural syntax, this also improves performance as there
is no need to construct temporary formatter objects and control arguments'
lifetimes. Because the wrapper functions are very ligthweight, this doesn't
cause code bloat even in pre-C++11 mode.
* Simplified common case of formatting an ``std::string``. Now it requires a
single function call:
.. code:: c++
std::string s = format("The answer is {}.", 42);
Previously it required 2 function calls:
.. code:: c++
std::string s = str(Format("The answer is {}.") << 42);
Instead of unsafe ``c_str`` function, ``fmt::Writer`` should be used directly
to bypass creation of ``std::string``:
.. code:: c++
fmt::Writer w;
w.write("The answer is {}.", 42);
w.c_str(); // returns a C string
This doesn't do dynamic memory allocation for small strings and is less error
prone as the lifetime of the string is the same as for ``std::string::c_str``
which is well understood (hopefully).
* Improved consistency in naming functions that are a part of the public API.
Now all public functions are lowercase following the standard library
conventions. Previously it was a combination of lowercase and
CapitalizedWords.
Issue `#50 <https://github.com/cppformat/cppformat/issues/50>`_.
* Old functions are marked as deprecated and will be removed in the next
release.
**Other Changes**
* Experimental support for printf format specifications (work in progress):
.. code:: c++
fmt::printf("The answer is %d.", 42);
std::string s = fmt::sprintf("Look, a %s!", "string");
* Support for hexadecimal floating point format specifiers ``a`` and ``A``:
.. code:: c++
print("{:a}", -42.0); // Prints -0x1.5p+5
print("{:A}", -42.0); // Prints -0X1.5P+5
* CMake option ``FMT_SHARED`` that specifies whether to build format as a
shared library (off by default).
0.9.0 - 2014-05-13
------------------
* More efficient implementation of variadic formatting functions.
* ``Writer::Format`` now has a variadic overload:
.. code:: c++
Writer out;
out.Format("Look, I'm {}!", "variadic");
* For efficiency and consistency with other overloads, variadic overload of
the ``Format`` function now returns ``Writer`` instead of ``std::string``.
Use the ``str`` function to convert it to ``std::string``:
.. code:: c++
std::string s = str(Format("Look, I'm {}!", "variadic"));
* Replaced formatter actions with output sinks: ``NoAction`` -> ``NullSink``,
``Write`` -> ``FileSink``, ``ColorWriter`` -> ``ANSITerminalSink``.
This improves naming consistency and shouldn't affect client code unless
these classes are used directly which should be rarely needed.
* Added ``ThrowSystemError`` function that formats a message and throws
``SystemError`` containing the formatted message and system-specific error
description. For example, the following code
.. code:: c++
FILE *f = fopen(filename, "r");
if (!f)
ThrowSystemError(errno, "Failed to open file '{}'") << filename;
will throw ``SystemError`` exception with description
"Failed to open file '<filename>': No such file or directory" if file
doesn't exist.
* Support for AppVeyor continuous integration platform.
* ``Format`` now throws ``SystemError`` in case of I/O errors.
* Improve test infrastructure. Print functions are now tested by redirecting
the output to a pipe.
0.8.0 - 2014-04-14
------------------
* Initial release

View File

@ -1,4 +1,4 @@
Copyright (c) 2012 - 2015, Victor Zverovich Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved. All rights reserved.

View File

@ -1,409 +0,0 @@
C++ Format
==========
.. image:: https://travis-ci.org/cppformat/cppformat.png?branch=master
:target: https://travis-ci.org/cppformat/cppformat
.. image:: https://ci.appveyor.com/api/projects/status/qk0bhyhqp1ekpat8
:target: https://ci.appveyor.com/project/vitaut/cppformat
.. image:: https://webapi.biicode.com/v1/badges/vitaut/vitaut/cppformat/master?dummy
:target: https://www.biicode.com/vitaut/cppformat
.. image:: https://badges.gitter.im/Join%20Chat.svg
:alt: Join the chat at https://gitter.im/cppformat/cppformat
:target: https://gitter.im/cppformat/cppformat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
C++ Format is an open-source formatting library for C++.
It can be used as a safe alternative to printf or as a fast
alternative to IOStreams.
`Documentation <http://cppformat.github.io/latest/>`_
Features
--------
* Two APIs: faster concatenation-based write API and slower (but still
very fast) replacement-based format API with positional arguments for
localization.
* Write API similar to the one used by IOStreams but stateless allowing
faster implementation.
* Format API with `format string syntax
<http://cppformat.github.io/latest/syntax.html>`_
similar to the one used by `str.format
<http://docs.python.org/2/library/stdtypes.html#str.format>`_ in Python.
* Safe `printf implementation
<http://cppformat.github.io/latest/reference.html#printf-formatting-functions>`_
including the POSIX extension for positional arguments.
* Support for user-defined types.
* High speed: performance of the format API is close to that of
glibc's `printf <http://en.cppreference.com/w/cpp/io/c/fprintf>`_
and better than performance of IOStreams. See `Speed tests`_ and
`Fast integer to string conversion in C++
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
* Small code size both in terms of source code (format consists of a single
header file and a single source file) and compiled code.
See `Compile time and code bloat`_.
* Reliability: the library has an extensive set of `unit tests
<https://github.com/cppformat/cppformat/tree/master/test>`_.
* Safety: the library is fully type safe, errors in format strings are
reported using exceptions, automatic memory management prevents buffer
overflow errors.
* Ease of use: small self-contained code base, no external dependencies,
permissive BSD `license
<https://github.com/cppformat/cppformat/blob/master/LICENSE.rst>`_
* `Portability <http://cppformat.github.io#portability>`_ with consistent output
across platforms and support for older compilers.
* Clean warning-free codebase even on high warning levels
(-Wall -Wextra -pedantic).
* Support for wide strings.
* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro.
See the `documentation <http://cppformat.github.io/latest/>`_ for more details.
Examples
--------
This prints ``Hello, world!`` to stdout:
.. code:: c++
fmt::print("Hello, {}!", "world"); // uses Python-like format string syntax
fmt::printf("Hello, %s!", "world"); // uses printf format string syntax
Arguments can be accessed by position and arguments' indices can be repeated:
.. code:: c++
std::string s = fmt::format("{0}{1}{0}", "abra", "cad");
// s == "abracadabra"
C++ Format can be used as a safe portable replacement for ``itoa``:
.. code:: c++
fmt::MemoryWriter w;
w << 42; // replaces itoa(42, buffer, 10)
w << fmt::hex(42); // replaces itoa(42, buffer, 16)
// access the string using w.str() or w.c_str()
An object of any user-defined type for which there is an overloaded
:code:`std::ostream` insertion operator (``operator<<``) can be formatted:
.. code:: c++
class Date {
int year_, month_, day_;
public:
Date(int year, int month, int day) : year_(year), month_(month), day_(day) {}
friend std::ostream &operator<<(std::ostream &os, const Date &d) {
return os << d.year_ << '-' << d.month_ << '-' << d.day_;
}
};
std::string s = fmt::format("The date is {}", Date(2012, 12, 9));
// s == "The date is 2012-12-9"
You can use the `FMT_VARIADIC
<http://cppformat.github.io/latest/reference.html#utilities>`_
macro to create your own functions similar to `format
<http://cppformat.github.io/latest/reference.html#format>`_ and
`print <http://cppformat.github.io/latest/reference.html#print>`_
which take arbitrary arguments:
.. code:: c++
// Prints formatted error message.
void report_error(const char *format, fmt::ArgList args) {
fmt::print("Error: ");
fmt::print(format, args);
}
FMT_VARIADIC(void, report_error, const char *)
report_error("file not found: {}", path);
Note that you only need to define one function that takes ``fmt::ArgList``
argument. ``FMT_VARIADIC`` automatically defines necessary wrappers that
accept variable number of arguments.
Projects using this library
---------------------------
* `0 A.D. <http://play0ad.com/>`_: A free, open-source, cross-platform real-time strategy game
* `AMPL/MP <https://github.com/ampl/mp>`_:
An open-source library for mathematical programming
* `HarpyWar/pvpgn <https://github.com/HarpyWar/pvpgn>`_:
Player vs Player Gaming Network with tweaks
* `KBEngine <http://www.kbengine.org/>`_: An open-source MMOG server engine
* `Lifeline <https://github.com/peter-clark/lifeline>`_: A 2D game
* `PenUltima Online (POL) <http://www.polserver.com/>`_:
An MMO server, compatible with most Ultima Online clients
* `quasardb <https://www.quasardb.net/>`_: A distributed, high-performance, associative database
* `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable
* `Saddy <https://code.google.com/p/saddy/>`_:
Small crossplatform 2D graphic engine
* `Salesforce Analytics Cloud <http://www.salesforce.com/analytics-cloud/overview/>`_:
Business intelligence software
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: Open-source MMORPG framework
`More... <https://github.com/search?q=cppformat&type=Code>`_
If you are aware of other projects using this library, please let me know
by `email <mailto:victor.zverovich@gmail.com>`_ or by submitting an
`issue <https://github.com/cppformat/cppformat/issues>`_.
Motivation
----------
So why yet another formatting library?
There are plenty of methods for doing this task, from standard ones like
the printf family of function and IOStreams to Boost Format library and
FastFormat. The reason for creating a new library is that every existing
solution that I found either had serious issues or didn't provide
all the features I needed.
Printf
~~~~~~
The good thing about printf is that it is pretty fast and readily available
being a part of the C standard library. The main drawback is that it
doesn't support user-defined types. Printf also has safety issues although
they are mostly solved with `__attribute__ ((format (printf, ...))
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ in GCC.
There is a POSIX extension that adds positional arguments required for
`i18n <http://en.wikipedia.org/wiki/Internationalization_and_localization>`_
to printf but it is not a part of C99 and may not be available on some
platforms.
IOStreams
~~~~~~~~~
The main issue with IOStreams is best illustrated with an example:
.. code:: c++
std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";
which is a lot of typing compared to printf:
.. code:: c++
printf("%.2f\n", 1.23456);
Matthew Wilson, the author of FastFormat, referred to this situation with
IOStreams as "chevron hell". IOStreams doesn't support positional arguments
by design.
The good part is that IOStreams supports user-defined types and is safe
although error reporting is awkward.
Boost Format library
~~~~~~~~~~~~~~~~~~~~
This is a very powerful library which supports both printf-like format
strings and positional arguments. The main its drawback is performance.
According to various benchmarks it is much slower than other methods
considered here. Boost Format also has excessive build times and severe
code bloat issues (see `Benchmarks`_).
FastFormat
~~~~~~~~~~
This is an interesting library which is fast, safe and has positional
arguments. However it has significant limitations, citing its author:
Three features that have no hope of being accommodated within the
current design are:
* Leading zeros (or any other non-space padding)
* Octal/hexadecimal encoding
* Runtime width/alignment specification
It is also quite big and has a heavy dependency, STLSoft, which might be
too restrictive for using it in some projects.
Loki SafeFormat
~~~~~~~~~~~~~~~
SafeFormat is a formatting library which uses printf-like format strings
and is type safe. It doesn't support user-defined types or positional
arguments. It makes unconventional use of ``operator()`` for passing
format arguments.
Tinyformat
~~~~~~~~~~
This library supports printf-like format strings and is very small and
fast. Unfortunately it doesn't support positional arguments and wrapping
it in C++98 is somewhat difficult. Also its performance and code compactness
are limited by IOStreams.
Boost Spirit.Karma
~~~~~~~~~~~~~~~~~~
This is not really a formatting library but I decided to include it here
for completeness. As IOStreams it suffers from the problem of mixing
verbatim text with arguments. The library is pretty fast, but slower
on integer formatting than ``fmt::Writer`` on Karma's own benchmark,
see `Fast integer to string conversion in C++
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
Benchmarks
----------
Speed tests
~~~~~~~~~~~
The following speed tests results were generated by building
``tinyformat_test.cpp`` on Ubuntu GNU/Linux 14.04.1 with
``g++-4.8.2 -O3 -DSPEED_TEST -DHAVE_FORMAT``, and taking the best of three
runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"`` or
equivalent is filled 2000000 times with output sent to ``/dev/null``; for
further details see the `source
<https://github.com/cppformat/format-benchmark/blob/master/tinyformat_test.cpp>`_.
================= ============= ===========
Library Method Run Time, s
================= ============= ===========
EGLIBC 2.19 printf 1.30
libstdc++ 4.8.2 std::ostream 1.85
C++ Format 1.0 fmt::print 1.42
tinyformat 2.0.1 tfm::printf 2.25
Boost Format 1.54 boost::format 9.94
================= ============= ===========
As you can see ``boost::format`` is much slower than the alternative methods; this
is confirmed by `other tests <http://accu.org/index.php/journals/1539>`_.
Tinyformat is quite good coming close to IOStreams. Unfortunately tinyformat
cannot be faster than the IOStreams because it uses them internally.
Performance of cppformat is close to that of printf, being `faster than printf on integer
formatting <http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_,
but slower on floating-point formatting which dominates this benchmark.
Compile time and code bloat
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The script `bloat-test.py
<https://github.com/cppformat/format-benchmark/blob/master/bloat-test.py>`_
from `format-benchmark <https://github.com/cppformat/format-benchmark>`_
tests compile time and code bloat for nontrivial projects.
It generates 100 translation units and uses ``printf()`` or its alternative
five times in each to simulate a medium sized project. The resulting
executable size and compile time (g++-4.8.1, Ubuntu GNU/Linux 13.10,
best of three) is shown in the following tables.
**Optimized build (-O3)**
============ =============== ==================== ==================
Method Compile Time, s Executable size, KiB Stripped size, KiB
============ =============== ==================== ==================
printf 2.6 41 30
IOStreams 19.4 92 70
C++ Format 46.8 46 34
tinyformat 64.6 418 386
Boost Format 222.8 990 923
============ =============== ==================== ==================
As you can see, C++ Format has two times less overhead in terms of resulting
code size compared to IOStreams and comes pretty close to ``printf``.
Boost Format has by far the largest overheads.
**Non-optimized build**
============ =============== ==================== ==================
Method Compile Time, s Executable size, KiB Stripped size, KiB
============ =============== ==================== ==================
printf 2.1 41 30
IOStreams 19.7 86 62
C++ Format 47.9 108 86
tinyformat 27.7 234 190
Boost Format 122.6 884 763
============ =============== ==================== ==================
``libc``, ``libstdc++`` and ``libformat`` are all linked as shared
libraries to compare formatting function overhead only. Boost Format
and tinyformat are header-only libraries so they don't provide any
linkage options.
Running the tests
~~~~~~~~~~~~~~~~~
Please refer to `Building the library`__ for the instructions on how to build
the library and run the unit tests.
__ http://cppformat.github.io/latest/usage.html#building-the-library
Benchmarks reside in a separate repository,
`format-benchmarks <https://github.com/cppformat/format-benchmark>`_,
so to run the benchmarks you first need to clone this repository and
generate Makefiles with CMake::
$ git clone --recursive https://github.com/cppformat/format-benchmark.git
$ cd format-benchmark
$ cmake .
Then you can run the speed test::
$ make speed-test
or the bloat test::
$ make bloat-test
License
-------
C++ Format is distributed under the BSD `license
<https://github.com/cppformat/cppformat/blob/master/LICENSE.rst>`_.
The `Format String Syntax
<http://cppformat.github.io/latest/syntax.html>`_
section in the documentation is based on the one from Python `string module
documentation <http://docs.python.org/3/library/string.html#module-string>`_
adapted for the current library. For this reason the documentation is
distributed under the Python Software Foundation license available in
`doc/python-license.txt
<https://raw.github.com/cppformat/cppformat/master/doc/python-license.txt>`_.
It only applies if you distribute the documentation of C++ Format.
Links
-----
`API changes/compatibility report <http://upstream-tracker.org/versions/cppformat.html>`_
Acknowledgments
---------------
The benchmark section of this readme file and the performance tests are taken
from the excellent `tinyformat <https://github.com/c42f/tinyformat>`_ library
written by Chris Foster. Boost Format library is acknowledged transitively
since it had some influence on tinyformat.
Some ideas used in the implementation are borrowed from `Loki
<http://loki-lib.sourceforge.net/>`_ SafeFormat and `Diagnostic API
<http://clang.llvm.org/doxygen/classclang_1_1Diagnostic.html>`_ in
`Clang <http://clang.llvm.org/>`_.
Format string syntax and the documentation are based on Python's `str.format
<http://docs.python.org/2/library/stdtypes.html#str.format>`_.
Thanks `Doug Turnbull <https://github.com/softwaredoug>`_ for his valuable
comments and contribution to the design of the type-safe API and
`Gregory Czajkowski <https://github.com/gcflymoto>`_ for implementing binary
formatting. Thanks `Ruslan Baratov <https://github.com/ruslo>`_ for comprehensive
`comparison of integer formatting algorithms <https://github.com/ruslo/int-dec-format-tests>`_
and useful comments regarding performance, `Boris Kaul <https://github.com/localvoid>`_ for
`C++ counting digits benchmark <https://github.com/localvoid/cxx-benchmark-count-digits>`_.
Thanks to `CarterLi <https://github.com/CarterLi>`_ for contributing various
improvements to the code.

View File

@ -1,7 +1,7 @@
/* /*
Formatting library for C++ Formatting library for C++
Copyright (c) 2012 - 2015, Victor Zverovich Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -60,12 +60,6 @@ using fmt::internal::Arg;
# define FMT_CATCH(x) if (false) # define FMT_CATCH(x) if (false)
#endif #endif
#ifdef FMT_HEADER_ONLY
# define FMT_FUNC inline
#else
# define FMT_FUNC
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
# pragma warning(push) # pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant # pragma warning(disable: 4127) // conditional expression is constant
@ -129,7 +123,7 @@ struct IntChecker<true> {
const char RESET_COLOR[] = "\x1b[0m"; const char RESET_COLOR[] = "\x1b[0m";
typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef); typedef void (*FormatFunc)(Writer &, int, StringRef);
// Portable thread-safe version of strerror. // Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code. // Sets buffer to point to a string describing the error code.
@ -169,7 +163,7 @@ int safe_strerror(
} }
// Handle the case when strerror_r is not available. // Handle the case when strerror_r is not available.
int handle(fmt::internal::Null<>) { int handle(internal::Null<>) {
return fallback(strerror_s(buffer_, buffer_size_, error_code_)); return fallback(strerror_s(buffer_, buffer_size_, error_code_));
} }
@ -181,7 +175,7 @@ int safe_strerror(
} }
// Fallback to strerror if strerror_r and strerror_s are not available. // Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(fmt::internal::Null<>) { int fallback(internal::Null<>) {
errno = 0; errno = 0;
buffer_ = strerror(error_code_); buffer_ = strerror(error_code_);
return errno; return errno;
@ -199,8 +193,8 @@ int safe_strerror(
return StrError(error_code, buffer, buffer_size).run(); return StrError(error_code, buffer, buffer_size).run();
} }
void format_error_code(fmt::Writer &out, int error_code, void format_error_code(Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT { StringRef message) FMT_NOEXCEPT {
// Report error code making sure that the output fits into // Report error code making sure that the output fits into
// INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
// bad_alloc. // bad_alloc.
@ -209,22 +203,22 @@ void format_error_code(fmt::Writer &out, int error_code,
static const char ERROR_STR[] = "error "; static const char ERROR_STR[] = "error ";
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR. // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
typedef fmt::internal::IntTraits<int>::MainType MainType; typedef internal::IntTraits<int>::MainType MainType;
MainType abs_value = static_cast<MainType>(error_code); MainType abs_value = static_cast<MainType>(error_code);
if (internal::is_negative(error_code)) { if (internal::is_negative(error_code)) {
abs_value = 0 - abs_value; abs_value = 0 - abs_value;
++error_code_size; ++error_code_size;
} }
error_code_size += fmt::internal::count_digits(abs_value); error_code_size += internal::count_digits(abs_value);
if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size) if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)
out << message << SEP; out << message << SEP;
out << ERROR_STR << error_code; out << ERROR_STR << error_code;
assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE); assert(out.size() <= internal::INLINE_BUFFER_SIZE);
} }
void report_error(FormatFunc func, void report_error(FormatFunc func, int error_code,
int error_code, fmt::StringRef message) FMT_NOEXCEPT { StringRef message) FMT_NOEXCEPT {
fmt::MemoryWriter full_message; MemoryWriter full_message;
func(full_message, error_code, message); func(full_message, error_code, message);
// Use Writer::data instead of Writer::c_str to avoid potential memory // Use Writer::data instead of Writer::c_str to avoid potential memory
// allocation. // allocation.
@ -233,7 +227,7 @@ void report_error(FormatFunc func,
} }
// IsZeroInt::visit(arg) returns true iff arg is a zero integer. // IsZeroInt::visit(arg) returns true iff arg is a zero integer.
class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> { class IsZeroInt : public ArgVisitor<IsZeroInt, bool> {
public: public:
template <typename T> template <typename T>
bool visit_any_int(T value) { return value == 0; } bool visit_any_int(T value) { return value == 0; }
@ -241,44 +235,43 @@ class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
// Checks if an argument is a valid printf width specifier and sets // Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative. // left alignment if it is negative.
class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> { class WidthHandler : public ArgVisitor<WidthHandler, unsigned> {
private: private:
fmt::FormatSpec &spec_; FormatSpec &spec_;
FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
public: public:
explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {} explicit WidthHandler(FormatSpec &spec) : spec_(spec) {}
void report_unhandled_arg() { void report_unhandled_arg() {
FMT_THROW(fmt::FormatError("width is not integer")); FMT_THROW(FormatError("width is not integer"));
} }
template <typename T> template <typename T>
unsigned visit_any_int(T value) { unsigned visit_any_int(T value) {
typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType; typedef typename internal::IntTraits<T>::MainType UnsignedType;
UnsignedType width = static_cast<UnsignedType>(value); UnsignedType width = static_cast<UnsignedType>(value);
if (fmt::internal::is_negative(value)) { if (internal::is_negative(value)) {
spec_.align_ = fmt::ALIGN_LEFT; spec_.align_ = ALIGN_LEFT;
width = 0 - width; width = 0 - width;
} }
if (width > INT_MAX) if (width > INT_MAX)
FMT_THROW(fmt::FormatError("number is too big")); FMT_THROW(FormatError("number is too big"));
return static_cast<unsigned>(width); return static_cast<unsigned>(width);
} }
}; };
class PrecisionHandler : class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> {
public fmt::internal::ArgVisitor<PrecisionHandler, int> {
public: public:
void report_unhandled_arg() { void report_unhandled_arg() {
FMT_THROW(fmt::FormatError("precision is not integer")); FMT_THROW(FormatError("precision is not integer"));
} }
template <typename T> template <typename T>
int visit_any_int(T value) { int visit_any_int(T value) {
if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
FMT_THROW(fmt::FormatError("number is too big")); FMT_THROW(FormatError("number is too big"));
return static_cast<int>(value); return static_cast<int>(value);
} }
}; };
@ -298,15 +291,15 @@ struct is_same<T, T> {
// corresponding signed or unsigned type depending on the type specifier: // corresponding signed or unsigned type depending on the type specifier:
// 'd' and 'i' - signed, other - unsigned) // 'd' and 'i' - signed, other - unsigned)
template <typename T = void> template <typename T = void>
class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> { class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
private: private:
fmt::internal::Arg &arg_; internal::Arg &arg_;
wchar_t type_; wchar_t type_;
FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
public: public:
ArgConverter(fmt::internal::Arg &arg, wchar_t type) ArgConverter(internal::Arg &arg, wchar_t type)
: arg_(arg), type_(type) {} : arg_(arg), type_(type) {}
void visit_bool(bool value) { void visit_bool(bool value) {
@ -317,8 +310,8 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
template <typename U> template <typename U>
void visit_any_int(U value) { void visit_any_int(U value) {
bool is_signed = type_ == 'd' || type_ == 'i'; bool is_signed = type_ == 'd' || type_ == 'i';
using fmt::internal::Arg; using internal::Arg;
typedef typename fmt::internal::Conditional< typedef typename internal::Conditional<
is_same<T, void>::value, U, T>::type TargetType; is_same<T, void>::value, U, T>::type TargetType;
if (sizeof(TargetType) <= sizeof(int)) { if (sizeof(TargetType) <= sizeof(int)) {
// Extra casts are used to silence warnings. // Extra casts are used to silence warnings.
@ -327,7 +320,7 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
arg_.int_value = static_cast<int>(static_cast<TargetType>(value)); arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
} else { } else {
arg_.type = Arg::UINT; arg_.type = Arg::UINT;
typedef typename fmt::internal::MakeUnsigned<TargetType>::Type Unsigned; typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned;
arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value)); arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
} }
} else { } else {
@ -336,51 +329,43 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
// glibc's printf doesn't sign extend arguments of smaller types: // glibc's printf doesn't sign extend arguments of smaller types:
// std::printf("%lld", -42); // prints "4294967254" // std::printf("%lld", -42); // prints "4294967254"
// but we don't have to do the same because it's a UB. // but we don't have to do the same because it's a UB.
arg_.long_long_value = static_cast<fmt::LongLong>(value); arg_.long_long_value = static_cast<LongLong>(value);
} else { } else {
arg_.type = Arg::ULONG_LONG; arg_.type = Arg::ULONG_LONG;
arg_.ulong_long_value = arg_.ulong_long_value =
static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value); static_cast<typename internal::MakeUnsigned<U>::Type>(value);
} }
} }
} }
}; };
// Converts an integer argument to char for printf. // Converts an integer argument to char for printf.
class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> { class CharConverter : public ArgVisitor<CharConverter, void> {
private: private:
fmt::internal::Arg &arg_; internal::Arg &arg_;
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
public: public:
explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {} explicit CharConverter(internal::Arg &arg) : arg_(arg) {}
template <typename T> template <typename T>
void visit_any_int(T value) { void visit_any_int(T value) {
arg_.type = Arg::CHAR; arg_.type = internal::Arg::CHAR;
arg_.int_value = static_cast<char>(value); arg_.int_value = static_cast<char>(value);
} }
}; };
// Write the content of w to os.
void write(std::ostream &os, fmt::Writer &w) {
const char *data = w.data();
typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
UnsignedStreamSize size = w.size();
UnsignedStreamSize max_size =
internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
do {
UnsignedStreamSize n = size <= max_size ? size : max_size;
os.write(data, static_cast<std::streamsize>(n));
data += n;
size -= n;
} while (size != 0);
}
} // namespace } // namespace
namespace internal { namespace internal {
// This method is used to preserve binary compatibility with fmt 3.0.
// It can be removed in 4.0.
FMT_FUNC void format_system_error(
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
fmt::format_system_error(out, error_code, message);
}
template <typename Char> template <typename Char>
class PrintfArgFormatter : class PrintfArgFormatter :
public ArgFormatterBase<PrintfArgFormatter<Char>, Char> { public ArgFormatterBase<PrintfArgFormatter<Char>, Char> {
@ -456,7 +441,7 @@ FMT_FUNC void fmt::SystemError::init(
int err_code, CStringRef format_str, ArgList args) { int err_code, CStringRef format_str, ArgList args) {
error_code_ = err_code; error_code_ = err_code;
MemoryWriter w; MemoryWriter w;
internal::format_system_error(w, err_code, format(format_str, args)); format_system_error(w, err_code, format(format_str, args));
std::runtime_error &base = *this; std::runtime_error &base = *this;
base = std::runtime_error(w.str()); base = std::runtime_error(w.str());
} }
@ -614,12 +599,12 @@ FMT_FUNC void fmt::internal::format_windows_error(
#endif // FMT_USE_WINDOWS_H #endif // FMT_USE_WINDOWS_H
FMT_FUNC void fmt::internal::format_system_error( FMT_FUNC void fmt::format_system_error(
fmt::Writer &out, int error_code, fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT { fmt::StringRef message) FMT_NOEXCEPT {
FMT_TRY { FMT_TRY {
MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer; internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
buffer.resize(INLINE_BUFFER_SIZE); buffer.resize(internal::INLINE_BUFFER_SIZE);
for (;;) { for (;;) {
char *system_message = &buffer[0]; char *system_message = &buffer[0];
int result = safe_strerror(error_code, system_message, buffer.size()); int result = safe_strerror(error_code, system_message, buffer.size());
@ -876,7 +861,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
FMT_FUNC void fmt::report_system_error( FMT_FUNC void fmt::report_system_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT { int error_code, fmt::StringRef message) FMT_NOEXCEPT {
// 'fmt::' is for bcc32. // 'fmt::' is for bcc32.
fmt::report_error(internal::format_system_error, error_code, message); fmt::report_error(format_system_error, error_code, message);
} }
#if FMT_USE_WINDOWS_H #if FMT_USE_WINDOWS_H
@ -897,13 +882,6 @@ FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
print(stdout, format_str, args); print(stdout, format_str, args);
} }
FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str,
ArgList args) {
MemoryWriter w;
w.write(format_str, args);
write(os, w);
}
FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) { FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
char escape[] = "\x1b[30m"; char escape[] = "\x1b[30m";
escape[3] = static_cast<char>('0' + c); escape[3] = static_cast<char>('0' + c);
@ -919,13 +897,6 @@ FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size); return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
} }
FMT_FUNC int fmt::fprintf(std::ostream &os, CStringRef format, ArgList args) {
MemoryWriter w;
printf(w, format, args);
write(os, w);
return static_cast<int>(w.size());
}
#ifndef FMT_HEADER_ONLY #ifndef FMT_HEADER_ONLY
template struct fmt::internal::BasicData<void>; template struct fmt::internal::BasicData<void>;

61
external/CppFormat/ostream.cc vendored Normal file
View File

@ -0,0 +1,61 @@
/*
Formatting library for C++ - std::ostream support
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ostream.h"
namespace fmt {
namespace {
// Write the content of w to os.
void write(std::ostream &os, Writer &w) {
const char *data = w.data();
typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
UnsignedStreamSize size = w.size();
UnsignedStreamSize max_size =
internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
do {
UnsignedStreamSize n = size <= max_size ? size : max_size;
os.write(data, static_cast<std::streamsize>(n));
data += n;
size -= n;
} while (size != 0);
}
}
FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) {
MemoryWriter w;
w.write(format_str, args);
write(os, w);
}
FMT_FUNC int fprintf(std::ostream &os, CStringRef format, ArgList args) {
MemoryWriter w;
printf(w, format, args);
write(os, w);
return static_cast<int>(w.size());
}
} // namespace fmt

View File

@ -1,7 +1,7 @@
/* /*
Formatting library for C++ Formatting library for C++
Copyright (c) 2012 - 2015, Victor Zverovich Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -29,6 +29,7 @@
#define FMT_FORMAT_H_ #define FMT_FORMAT_H_
#include <cassert> #include <cassert>
#include <clocale>
#include <cmath> #include <cmath>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
@ -39,14 +40,6 @@
#include <vector> #include <vector>
#include <utility> #include <utility>
#ifndef FMT_USE_IOSTREAMS
# define FMT_USE_IOSTREAMS 1
#endif
#if FMT_USE_IOSTREAMS
# include <ostream>
#endif
#ifdef _SECURE_SCL #ifdef _SECURE_SCL
# define FMT_SECURE_SCL _SECURE_SCL # define FMT_SECURE_SCL _SECURE_SCL
#else #else
@ -57,7 +50,13 @@
# include <iterator> # include <iterator>
#endif #endif
#if defined(_MSC_VER) && _MSC_VER <= 1500 #ifdef _MSC_VER
# define FMT_MSC_VER _MSC_VER
#else
# define FMT_MSC_VER 0
#endif
#if FMT_MSC_VER && FMT_MSC_VER <= 1500
typedef unsigned __int32 uint32_t; typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t; typedef unsigned __int64 uint64_t;
typedef __int64 intmax_t; typedef __int64 intmax_t;
@ -98,7 +97,13 @@ typedef __int64 intmax_t;
# define FMT_GCC_EXTENSION # define FMT_GCC_EXTENSION
#endif #endif
#if defined(__clang__) && !defined(__INTEL_COMPILER) #if defined(__INTEL_COMPILER)
# define FMT_ICC_VERSION __INTEL_COMPILER
#elif defined(__ICL)
# define FMT_ICC_VERSION __ICL
#endif
#if defined(__clang__) && !defined(FMT_ICC_VERSION)
# pragma clang diagnostic push # pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdocumentation" # pragma clang diagnostic ignored "-Wdocumentation"
#endif #endif
@ -131,7 +136,7 @@ typedef __int64 intmax_t;
// since version 2013. // since version 2013.
# define FMT_USE_VARIADIC_TEMPLATES \ # define FMT_USE_VARIADIC_TEMPLATES \
(FMT_HAS_FEATURE(cxx_variadic_templates) || \ (FMT_HAS_FEATURE(cxx_variadic_templates) || \
(FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800) (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800)
#endif #endif
#ifndef FMT_USE_RVALUE_REFERENCES #ifndef FMT_USE_RVALUE_REFERENCES
@ -142,7 +147,7 @@ typedef __int64 intmax_t;
# else # else
# define FMT_USE_RVALUE_REFERENCES \ # define FMT_USE_RVALUE_REFERENCES \
(FMT_HAS_FEATURE(cxx_rvalue_references) || \ (FMT_HAS_FEATURE(cxx_rvalue_references) || \
(FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600) (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600)
# endif # endif
#endif #endif
@ -154,7 +159,7 @@ typedef __int64 intmax_t;
#if defined(__GNUC__) && !defined(__EXCEPTIONS) #if defined(__GNUC__) && !defined(__EXCEPTIONS)
# define FMT_EXCEPTIONS 0 # define FMT_EXCEPTIONS 0
#endif #endif
#if defined(_MSC_VER) && !_HAS_EXCEPTIONS #if FMT_MSC_VER && !_HAS_EXCEPTIONS
# define FMT_EXCEPTIONS 0 # define FMT_EXCEPTIONS 0
#endif #endif
#ifndef FMT_EXCEPTIONS #ifndef FMT_EXCEPTIONS
@ -169,7 +174,7 @@ typedef __int64 intmax_t;
# endif # endif
#endif #endif
// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). // Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature).
#ifndef FMT_USE_NOEXCEPT #ifndef FMT_USE_NOEXCEPT
# define FMT_USE_NOEXCEPT 0 # define FMT_USE_NOEXCEPT 0
#endif #endif
@ -178,7 +183,7 @@ typedef __int64 intmax_t;
# if FMT_EXCEPTIONS # if FMT_EXCEPTIONS
# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ # if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
_MSC_VER >= 1900 FMT_MSC_VER >= 1900
# define FMT_NOEXCEPT noexcept # define FMT_NOEXCEPT noexcept
# else # else
# define FMT_NOEXCEPT throw() # define FMT_NOEXCEPT throw()
@ -195,7 +200,7 @@ typedef __int64 intmax_t;
#endif #endif
#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ #if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \
(FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800 (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800
# define FMT_DELETED_OR_UNDEFINED = delete # define FMT_DELETED_OR_UNDEFINED = delete
# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ # define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \ TypeName(const TypeName&) = delete; \
@ -211,10 +216,12 @@ typedef __int64 intmax_t;
// All compilers which support UDLs also support variadic templates. This // All compilers which support UDLs also support variadic templates. This
// makes the fmt::literals implementation easier. However, an explicit check // makes the fmt::literals implementation easier. However, an explicit check
// for variadic templates is added here just in case. // for variadic templates is added here just in case.
// For Intel's compiler both it and the system gcc/msc must support UDLs.
# define FMT_USE_USER_DEFINED_LITERALS \ # define FMT_USE_USER_DEFINED_LITERALS \
FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \ FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \
(FMT_HAS_FEATURE(cxx_user_literals) || \ (FMT_HAS_FEATURE(cxx_user_literals) || \
(FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1900) (FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900) && \
(!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500)
#endif #endif
#ifndef FMT_ASSERT #ifndef FMT_ASSERT
@ -234,7 +241,7 @@ typedef __int64 intmax_t;
// otherwise support __builtin_clz and __builtin_clzll, so // otherwise support __builtin_clz and __builtin_clzll, so
// only define FMT_BUILTIN_CLZ using the MSVC intrinsics // only define FMT_BUILTIN_CLZ using the MSVC intrinsics
// if the clz and clzll builtins are not available. // if the clz and clzll builtins are not available.
#if defined(_MSC_VER) && !defined(FMT_BUILTIN_CLZLL) #if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL)
# include <intrin.h> // _BitScanReverse, _BitScanReverse64 # include <intrin.h> // _BitScanReverse, _BitScanReverse64
namespace fmt { namespace fmt {
@ -371,18 +378,13 @@ class BasicWriter;
typedef BasicWriter<char> Writer; typedef BasicWriter<char> Writer;
typedef BasicWriter<wchar_t> WWriter; typedef BasicWriter<wchar_t> WWriter;
namespace internal {
template <typename Char> template <typename Char>
class BasicArgFormatter; class ArgFormatter;
}
template <typename CharType, template <typename CharType,
typename ArgFormatter = internal::BasicArgFormatter<CharType> > typename ArgFormatter = fmt::ArgFormatter<CharType> >
class BasicFormatter; class BasicFormatter;
template <typename Char, typename T>
void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value);
/** /**
\rst \rst
A string reference. It can be constructed from a C string or ``std::string``. A string reference. It can be constructed from a C string or ``std::string``.
@ -834,6 +836,16 @@ struct FMT_API BasicData {
static const char DIGITS[]; static const char DIGITS[];
}; };
#ifndef FMT_USE_EXTERN_TEMPLATES
// Clang doesn't have a feature check for extern templates so we check
// for variadic templates which were introduced in the same version.
# define FMT_USE_EXTERN_TEMPLATES (__clang__ && FMT_USE_VARIADIC_TEMPLATES)
#endif
#if FMT_USE_EXTERN_TEMPLATES
extern template struct BasicData<void>;
#endif
typedef BasicData<> Data; typedef BasicData<> Data;
#ifdef FMT_BUILTIN_CLZLL #ifdef FMT_BUILTIN_CLZLL
@ -871,9 +883,56 @@ inline unsigned count_digits(uint32_t n) {
} }
#endif #endif
// A functor that doesn't add a thousands separator.
struct NoThousandsSep {
template <typename Char>
void operator()(Char *) {}
};
// A functor that adds a thousands separator.
class ThousandsSep {
private:
fmt::StringRef sep_;
// Index of a decimal digit with the least significant digit having index 0.
unsigned digit_index_;
public:
explicit ThousandsSep(fmt::StringRef sep) : sep_(sep), digit_index_(0) {}
template <typename Char>
void operator()(Char *&buffer) {
if (++digit_index_ % 3 != 0)
return;
buffer -= sep_.size();
std::uninitialized_copy(sep_.data(), sep_.data() + sep_.size(),
internal::make_ptr(buffer, sep_.size()));
}
};
// Returns the thousands separator for the current locale.
// On android the lconv structure is stubbed using an empty structure.
// The test is for the size only, not for the presense of
// thousands_sep in std::lconv, because if one would add thousands_sep
// at some point, the size of structure would be at least sizeof(char*).
template<typename Lconv, bool=(sizeof(Lconv) >= sizeof(char*))>
struct Locale {
static fmt::StringRef thousands_sep() { return ""; }
};
template<typename Lconv>
struct Locale<Lconv, true> {
static fmt::StringRef thousands_sep() {
return static_cast<Lconv*>(std::localeconv())->thousands_sep;
}
};
// Formats a decimal unsigned integer value writing into buffer. // Formats a decimal unsigned integer value writing into buffer.
template <typename UInt, typename Char> // thousands_sep is a functor that is called after writing each char to
inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { // add a thousands separator if necessary.
template <typename UInt, typename Char, typename ThousandsSep>
inline void format_decimal(Char *buffer, UInt value, unsigned num_digits,
ThousandsSep thousands_sep) {
buffer += num_digits; buffer += num_digits;
while (value >= 100) { while (value >= 100) {
// Integer division is slow so do it for a group of two digits instead // Integer division is slow so do it for a group of two digits instead
@ -882,7 +941,9 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
unsigned index = static_cast<unsigned>((value % 100) * 2); unsigned index = static_cast<unsigned>((value % 100) * 2);
value /= 100; value /= 100;
*--buffer = Data::DIGITS[index + 1]; *--buffer = Data::DIGITS[index + 1];
thousands_sep(buffer);
*--buffer = Data::DIGITS[index]; *--buffer = Data::DIGITS[index];
thousands_sep(buffer);
} }
if (value < 10) { if (value < 10) {
*--buffer = static_cast<char>('0' + value); *--buffer = static_cast<char>('0' + value);
@ -893,6 +954,11 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
*--buffer = Data::DIGITS[index]; *--buffer = Data::DIGITS[index];
} }
template <typename UInt, typename Char>
inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
return format_decimal(buffer, value, num_digits, NoThousandsSep());
}
#ifndef _WIN32 #ifndef _WIN32
# define FMT_USE_WINDOWS_H 0 # define FMT_USE_WINDOWS_H 0
#elif !defined(FMT_USE_WINDOWS_H) #elif !defined(FMT_USE_WINDOWS_H)
@ -940,9 +1006,6 @@ FMT_API void format_windows_error(fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT; fmt::StringRef message) FMT_NOEXCEPT;
#endif #endif
FMT_API void format_system_error(fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT;
// A formatting argument value. // A formatting argument value.
struct Value { struct Value {
template <typename Char> template <typename Char>
@ -1013,33 +1076,16 @@ struct WCharHelper<T, wchar_t> {
typedef char Yes[1]; typedef char Yes[1];
typedef char No[2]; typedef char No[2];
// These are non-members to workaround an overload resolution bug in bcc32.
Yes &convert(fmt::ULongLong);
Yes &convert(std::ostream &);
No &convert(...);
template <typename T> template <typename T>
T &get(); T &get();
struct DummyStream : std::ostream { // These are non-members to workaround an overload resolution bug in bcc32.
DummyStream(); // Suppress a bogus warning in MSVC. Yes &convert(fmt::ULongLong);
// Hide all operator<< overloads from std::ostream. No &convert(...);
void operator<<(Null<>);
};
No &operator<<(std::ostream &, int);
template<typename T, bool ENABLE_CONVERSION> template<typename T, bool ENABLE_CONVERSION>
struct ConvertToIntImpl { struct ConvertToIntImpl {
enum { value = false }; enum { value = ENABLE_CONVERSION };
};
template<typename T>
struct ConvertToIntImpl<T, true> {
// Convert to int only if T doesn't have an overloaded operator<<.
enum {
value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
};
}; };
template<typename T, bool ENABLE_CONVERSION> template<typename T, bool ENABLE_CONVERSION>
@ -1110,7 +1156,7 @@ class MakeValue : public Arg {
// characters and strings into narrow strings as in // characters and strings into narrow strings as in
// fmt::format("{}", L"test"); // fmt::format("{}", L"test");
// To fix this, use a wide format string: fmt::format(L"{}", L"test"). // To fix this, use a wide format string: fmt::format(L"{}", L"test").
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) #if !FMT_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED)
MakeValue(typename WCharHelper<wchar_t, Char>::Unsupported); MakeValue(typename WCharHelper<wchar_t, Char>::Unsupported);
#endif #endif
MakeValue(typename WCharHelper<wchar_t *, Char>::Unsupported); MakeValue(typename WCharHelper<wchar_t *, Char>::Unsupported);
@ -1269,123 +1315,6 @@ struct NamedArg : Arg {
: Arg(MakeArg< BasicFormatter<Char> >(value)), name(argname) {} : Arg(MakeArg< BasicFormatter<Char> >(value)), name(argname) {}
}; };
#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
// An argument visitor.
// To use ArgVisitor define a subclass that implements some or all of the
// visit methods with the same signatures as the methods in ArgVisitor,
// for example, visit_int(int).
// Specify the subclass name as the Impl template parameter. Then calling
// ArgVisitor::visit for some argument will dispatch to a visit method
// specific to the argument type. For example, if the argument type is
// double then visit_double(double) method of a subclass will be called.
// If the subclass doesn't contain a method with this signature, then
// a corresponding method of ArgVisitor will be called.
//
// Example:
// class MyArgVisitor : public ArgVisitor<MyArgVisitor, void> {
// public:
// void visit_int(int value) { print("{}", value); }
// void visit_double(double value) { print("{}", value ); }
// };
//
// ArgVisitor uses the curiously recurring template pattern:
// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
template <typename Impl, typename Result>
class ArgVisitor {
public:
void report_unhandled_arg() {}
Result visit_unhandled_arg() {
FMT_DISPATCH(report_unhandled_arg());
return Result();
}
Result visit_int(int value) {
return FMT_DISPATCH(visit_any_int(value));
}
Result visit_long_long(LongLong value) {
return FMT_DISPATCH(visit_any_int(value));
}
Result visit_uint(unsigned value) {
return FMT_DISPATCH(visit_any_int(value));
}
Result visit_ulong_long(ULongLong value) {
return FMT_DISPATCH(visit_any_int(value));
}
Result visit_bool(bool value) {
return FMT_DISPATCH(visit_any_int(value));
}
Result visit_char(int value) {
return FMT_DISPATCH(visit_any_int(value));
}
template <typename T>
Result visit_any_int(T) {
return FMT_DISPATCH(visit_unhandled_arg());
}
Result visit_double(double value) {
return FMT_DISPATCH(visit_any_double(value));
}
Result visit_long_double(long double value) {
return FMT_DISPATCH(visit_any_double(value));
}
template <typename T>
Result visit_any_double(T) {
return FMT_DISPATCH(visit_unhandled_arg());
}
Result visit_cstring(const char *) {
return FMT_DISPATCH(visit_unhandled_arg());
}
Result visit_string(Arg::StringValue<char>) {
return FMT_DISPATCH(visit_unhandled_arg());
}
Result visit_wstring(Arg::StringValue<wchar_t>) {
return FMT_DISPATCH(visit_unhandled_arg());
}
Result visit_pointer(const void *) {
return FMT_DISPATCH(visit_unhandled_arg());
}
Result visit_custom(Arg::CustomValue) {
return FMT_DISPATCH(visit_unhandled_arg());
}
Result visit(const Arg &arg) {
switch (arg.type) {
default:
FMT_ASSERT(false, "invalid argument type");
return Result();
case Arg::INT:
return FMT_DISPATCH(visit_int(arg.int_value));
case Arg::UINT:
return FMT_DISPATCH(visit_uint(arg.uint_value));
case Arg::LONG_LONG:
return FMT_DISPATCH(visit_long_long(arg.long_long_value));
case Arg::ULONG_LONG:
return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value));
case Arg::BOOL:
return FMT_DISPATCH(visit_bool(arg.int_value != 0));
case Arg::CHAR:
return FMT_DISPATCH(visit_char(arg.int_value));
case Arg::DOUBLE:
return FMT_DISPATCH(visit_double(arg.double_value));
case Arg::LONG_DOUBLE:
return FMT_DISPATCH(visit_long_double(arg.long_double_value));
case Arg::CSTRING:
return FMT_DISPATCH(visit_cstring(arg.string.value));
case Arg::STRING:
return FMT_DISPATCH(visit_string(arg.string));
case Arg::WSTRING:
return FMT_DISPATCH(visit_wstring(arg.wstring));
case Arg::POINTER:
return FMT_DISPATCH(visit_pointer(arg.pointer));
case Arg::CUSTOM:
return FMT_DISPATCH(visit_custom(arg.custom));
}
}
};
class RuntimeError : public std::runtime_error { class RuntimeError : public std::runtime_error {
protected: protected:
RuntimeError() : std::runtime_error("") {} RuntimeError() : std::runtime_error("") {}
@ -1462,6 +1391,165 @@ class ArgList {
} }
}; };
#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
/**
\rst
An argument visitor based on the `curiously recurring template pattern
<http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_.
To use `~fmt::ArgVisitor` define a subclass that implements some or all of the
visit methods with the same signatures as the methods in `~fmt::ArgVisitor`,
for example, `~fmt::ArgVisitor::visit_int()`.
Pass the subclass as the *Impl* template parameter. Then calling
`~fmt::ArgVisitor::visit` for some argument will dispatch to a visit method
specific to the argument type. For example, if the argument type is
``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass
will be called. If the subclass doesn't contain a method with this signature,
then a corresponding method of `~fmt::ArgVisitor` will be called.
**Example**::
class MyArgVisitor : public fmt::ArgVisitor<MyArgVisitor, void> {
public:
void visit_int(int value) { fmt::print("{}", value); }
void visit_double(double value) { fmt::print("{}", value ); }
};
\endrst
*/
template <typename Impl, typename Result>
class ArgVisitor {
private:
typedef internal::Arg Arg;
public:
void report_unhandled_arg() {}
Result visit_unhandled_arg() {
FMT_DISPATCH(report_unhandled_arg());
return Result();
}
/** Visits an ``int`` argument. **/
Result visit_int(int value) {
return FMT_DISPATCH(visit_any_int(value));
}
/** Visits a ``long long`` argument. **/
Result visit_long_long(LongLong value) {
return FMT_DISPATCH(visit_any_int(value));
}
/** Visits an ``unsigned`` argument. **/
Result visit_uint(unsigned value) {
return FMT_DISPATCH(visit_any_int(value));
}
/** Visits an ``unsigned long long`` argument. **/
Result visit_ulong_long(ULongLong value) {
return FMT_DISPATCH(visit_any_int(value));
}
/** Visits a ``bool`` argument. **/
Result visit_bool(bool value) {
return FMT_DISPATCH(visit_any_int(value));
}
/** Visits a ``char`` or ``wchar_t`` argument. **/
Result visit_char(int value) {
return FMT_DISPATCH(visit_any_int(value));
}
/** Visits an argument of any integral type. **/
template <typename T>
Result visit_any_int(T) {
return FMT_DISPATCH(visit_unhandled_arg());
}
/** Visits a ``double`` argument. **/
Result visit_double(double value) {
return FMT_DISPATCH(visit_any_double(value));
}
/** Visits a ``long double`` argument. **/
Result visit_long_double(long double value) {
return FMT_DISPATCH(visit_any_double(value));
}
/** Visits a ``double`` or ``long double`` argument. **/
template <typename T>
Result visit_any_double(T) {
return FMT_DISPATCH(visit_unhandled_arg());
}
/** Visits a null-terminated C string (``const char *``) argument. **/
Result visit_cstring(const char *) {
return FMT_DISPATCH(visit_unhandled_arg());
}
/** Visits a string argument. **/
Result visit_string(Arg::StringValue<char>) {
return FMT_DISPATCH(visit_unhandled_arg());
}
/** Visits a wide string argument. **/
Result visit_wstring(Arg::StringValue<wchar_t>) {
return FMT_DISPATCH(visit_unhandled_arg());
}
/** Visits a pointer argument. **/
Result visit_pointer(const void *) {
return FMT_DISPATCH(visit_unhandled_arg());
}
/** Visits an argument of a custom (user-defined) type. **/
Result visit_custom(Arg::CustomValue) {
return FMT_DISPATCH(visit_unhandled_arg());
}
/**
\rst
Visits an argument dispatching to the appropriate visit method based on
the argument type. For example, if the argument type is ``double`` then
the `~fmt::ArgVisitor::visit_double()` method of the *Impl* class will be
called.
\endrst
*/
Result visit(const Arg &arg) {
switch (arg.type) {
default:
FMT_ASSERT(false, "invalid argument type");
return Result();
case Arg::INT:
return FMT_DISPATCH(visit_int(arg.int_value));
case Arg::UINT:
return FMT_DISPATCH(visit_uint(arg.uint_value));
case Arg::LONG_LONG:
return FMT_DISPATCH(visit_long_long(arg.long_long_value));
case Arg::ULONG_LONG:
return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value));
case Arg::BOOL:
return FMT_DISPATCH(visit_bool(arg.int_value != 0));
case Arg::CHAR:
return FMT_DISPATCH(visit_char(arg.int_value));
case Arg::DOUBLE:
return FMT_DISPATCH(visit_double(arg.double_value));
case Arg::LONG_DOUBLE:
return FMT_DISPATCH(visit_long_double(arg.long_double_value));
case Arg::CSTRING:
return FMT_DISPATCH(visit_cstring(arg.string.value));
case Arg::STRING:
return FMT_DISPATCH(visit_string(arg.string));
case Arg::WSTRING:
return FMT_DISPATCH(visit_wstring(arg.wstring));
case Arg::POINTER:
return FMT_DISPATCH(visit_pointer(arg.pointer));
case Arg::CUSTOM:
return FMT_DISPATCH(visit_custom(arg.custom));
}
}
};
enum Alignment { enum Alignment {
ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC
}; };
@ -1688,7 +1776,8 @@ namespace internal {
template <typename Char> template <typename Char>
class ArgMap { class ArgMap {
private: private:
typedef std::vector<std::pair<fmt::BasicStringRef<Char>, internal::Arg> > MapType; typedef std::vector<
std::pair<fmt::BasicStringRef<Char>, internal::Arg> > MapType;
typedef typename MapType::value_type Pair; typedef typename MapType::value_type Pair;
MapType map_; MapType map_;
@ -1805,24 +1894,6 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> {
} }
}; };
// An argument formatter.
template <typename Char>
class BasicArgFormatter :
public ArgFormatterBase<BasicArgFormatter<Char>, Char> {
private:
BasicFormatter<Char> &formatter_;
const Char *format_;
public:
BasicArgFormatter(BasicFormatter<Char> &f, FormatSpec &s, const Char *fmt)
: ArgFormatterBase<BasicArgFormatter<Char>, Char>(f.writer(), s),
formatter_(f), format_(fmt) {}
void visit_custom(Arg::CustomValue c) {
c.format(&formatter_, c.value, &format_);
}
};
class FormatterBase { class FormatterBase {
private: private:
ArgList args_; ArgList args_;
@ -1890,6 +1961,59 @@ class PrintfFormatter : private FormatterBase {
}; };
} // namespace internal } // namespace internal
/**
\rst
An argument formatter based on the `curiously recurring template pattern
<http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_.
To use `~fmt::BasicArgFormatter` define a subclass that implements some or
all of the visit methods with the same signatures as the methods in
`~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`.
Pass the subclass as the *Impl* template parameter. When a formatting
function processes an argument, it will dispatch to a visit method
specific to the argument type. For example, if the argument type is
``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass
will be called. If the subclass doesn't contain a method with this signature,
then a corresponding method of `~fmt::BasicArgFormatter` or its superclass
will be called.
\endrst
*/
template <typename Impl, typename Char>
class BasicArgFormatter : public internal::ArgFormatterBase<Impl, Char> {
private:
BasicFormatter<Char, Impl> &formatter_;
const Char *format_;
public:
/**
\rst
Constructs an argument formatter object.
*formatter* is a reference to the main formatter object, *spec* contains
format specifier information for standard argument types, and *fmt* points
to the part of the format string being parsed for custom argument types.
\endrst
*/
BasicArgFormatter(BasicFormatter<Char, Impl> &formatter,
FormatSpec &spec, const Char *fmt)
: internal::ArgFormatterBase<Impl, Char>(formatter.writer(), spec),
formatter_(formatter), format_(fmt) {}
/** Formats argument of a custom (user-defined) type. */
void visit_custom(internal::Arg::CustomValue c) {
c.format(&formatter_, c.value, &format_);
}
};
/** The default argument formatter. */
template <typename Char>
class ArgFormatter : public BasicArgFormatter<ArgFormatter<Char>, Char> {
public:
/** Constructs an argument formatter object. */
ArgFormatter(BasicFormatter<Char> &formatter,
FormatSpec &spec, const Char *fmt)
: BasicArgFormatter<ArgFormatter<Char>, Char>(formatter, spec, fmt) {}
};
/** This template formats data and writes the output to a writer. */ /** This template formats data and writes the output to a writer. */
template <typename CharType, typename ArgFormatter> template <typename CharType, typename ArgFormatter>
class BasicFormatter : private internal::FormatterBase { class BasicFormatter : private internal::FormatterBase {
@ -1972,11 +2096,15 @@ struct ArgArray<N, true/*IsPacked*/> {
template <typename Formatter, typename T> template <typename Formatter, typename T>
static Value make(const T &value) { static Value make(const T &value) {
#ifdef __clang__
Value result = MakeValue<Formatter>(value); Value result = MakeValue<Formatter>(value);
// Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang: // Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang:
// https://github.com/cppformat/cppformat/issues/276 // https://github.com/fmtlib/fmt/issues/276
(void)result.custom.format; (void)result.custom.format;
return result; return result;
#else
return MakeValue<Formatter>(value);
#endif
} }
}; };
@ -2014,38 +2142,6 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
(t12.type << 48) | (t13.type << 52) | (t14.type << 56); (t12.type << 48) | (t13.type << 52) | (t14.type << 56);
} }
#endif #endif
template <class Char>
class FormatBuf : public std::basic_streambuf<Char> {
private:
typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
Buffer<Char> &buffer_;
Char *start_;
public:
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) {
this->setp(start_, start_ + buffer_.capacity());
}
int_type overflow(int_type ch = traits_type::eof()) {
if (!traits_type::eq_int_type(ch, traits_type::eof())) {
size_t size = this->size();
buffer_.resize(size);
buffer_.reserve(size * 2);
start_ = &buffer_[0];
start_[size] = traits_type::to_char_type(ch);
this->setp(start_+ size + 1, start_ + size * 2);
}
return ch;
}
size_t size() const {
return to_unsigned(this->pptr() - start_);
}
};
} // namespace internal } // namespace internal
# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n # define FMT_MAKE_TEMPLATE_ARG(n) typename T##n
@ -2164,17 +2260,10 @@ class SystemError : public internal::RuntimeError {
public: public:
/** /**
\rst \rst
Constructs a :class:`fmt::SystemError` object with the description Constructs a :class:`fmt::SystemError` object with a description
of the form formatted with `fmt::format_system_error`. *message* and additional
arguments passed into the constructor are formatted similarly to
.. parsed-literal:: `fmt::format`.
*<message>*: *<system-message>*
where *<message>* is the formatted message and *<system-message>* is
the system message corresponding to the error code.
*error_code* is a system error code as given by ``errno``.
If *error_code* is not a valid error code such as -1, the system message
may look like "Unknown error -1" and is platform-dependent.
**Example**:: **Example**::
@ -2195,6 +2284,25 @@ class SystemError : public internal::RuntimeError {
int error_code() const { return error_code_; } int error_code() const { return error_code_; }
}; };
/**
\rst
Formats an error returned by an operating system or a language runtime,
for example a file opening error, and writes it to *out* in the following
form:
.. parsed-literal::
*<message>*: *<system-message>*
where *<message>* is the passed message and *<system-message>* is
the system message corresponding to the error code.
*error_code* is a system error code as given by ``errno``.
If *error_code* is not a valid error code such as -1, the system message
may look like "Unknown error -1" and is platform-dependent.
\endrst
*/
FMT_API void format_system_error(fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT;
/** /**
\rst \rst
This template provides operations for formatting and writing data into This template provides operations for formatting and writing data into
@ -2482,6 +2590,8 @@ class BasicWriter {
} }
void clear() FMT_NOEXCEPT { buffer_.clear(); } void clear() FMT_NOEXCEPT { buffer_.clear(); }
Buffer<Char> &buffer() FMT_NOEXCEPT { return buffer_; }
}; };
template <typename Char> template <typename Char>
@ -2627,9 +2737,8 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
switch (spec.type()) { switch (spec.type()) {
case 0: case 'd': { case 0: case 'd': {
unsigned num_digits = internal::count_digits(abs_value); unsigned num_digits = internal::count_digits(abs_value);
CharPtr p = prepare_int_buffer( CharPtr p = prepare_int_buffer(num_digits, spec, prefix, prefix_size) + 1;
num_digits, spec, prefix, prefix_size) + 1 - num_digits; internal::format_decimal(get(p), abs_value, 0);
internal::format_decimal(get(p), abs_value, num_digits);
break; break;
} }
case 'x': case 'X': { case 'x': case 'X': {
@ -2684,6 +2793,15 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
} while ((n >>= 3) != 0); } while ((n >>= 3) != 0);
break; break;
} }
case 'n': {
unsigned num_digits = internal::count_digits(abs_value);
fmt::StringRef sep = internal::Locale<lconv>::thousands_sep();
unsigned size = static_cast<unsigned>(
num_digits + sep.size() * (num_digits - 1) / 3);
CharPtr p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1;
internal::format_decimal(get(p), abs_value, 0, internal::ThousandsSep(sep));
break;
}
default: default:
internal::report_unknown_type( internal::report_unknown_type(
spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer"); spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer");
@ -2704,7 +2822,7 @@ void BasicWriter<Char>::write_double(T value, const FormatSpec &spec) {
case 'e': case 'f': case 'g': case 'a': case 'e': case 'f': case 'g': case 'a':
break; break;
case 'F': case 'F':
#ifdef _MSC_VER #if FMT_MSC_VER
// MSVC's printf doesn't support 'F'. // MSVC's printf doesn't support 'F'.
type = 'f'; type = 'f';
#endif #endif
@ -2797,7 +2915,7 @@ void BasicWriter<Char>::write_double(T value, const FormatSpec &spec) {
Char *start = 0; Char *start = 0;
for (;;) { for (;;) {
std::size_t buffer_size = buffer_.capacity() - offset; std::size_t buffer_size = buffer_.capacity() - offset;
#ifdef _MSC_VER #if FMT_MSC_VER
// MSVC's vsnprintf_s doesn't work with zero size, so reserve // MSVC's vsnprintf_s doesn't work with zero size, so reserve
// space for at least one extra character to make the size non-zero. // space for at least one extra character to make the size non-zero.
// Note that the buffer's capacity will increase by more than 1. // Note that the buffer's capacity will increase by more than 1.
@ -2964,20 +3082,6 @@ class BasicArrayWriter : public BasicWriter<Char> {
typedef BasicArrayWriter<char> ArrayWriter; typedef BasicArrayWriter<char> ArrayWriter;
typedef BasicArrayWriter<wchar_t> WArrayWriter; typedef BasicArrayWriter<wchar_t> WArrayWriter;
// Formats a value.
template <typename Char, typename T>
void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value) {
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
internal::FormatBuf<Char> format_buf(buffer);
std::basic_ostream<Char> output(&format_buf);
output << value;
BasicStringRef<Char> str(&buffer[0], format_buf.size());
typedef internal::MakeArg< BasicFormatter<Char> > MakeArg;
format_str = f.format(format_str, MakeArg(str));
}
// Reports a system error without throwing an exception. // Reports a system error without throwing an exception.
// Can be used to report errors from destructors. // Can be used to report errors from destructors.
FMT_API void report_system_error(int error_code, FMT_API void report_system_error(int error_code,
@ -3407,32 +3511,6 @@ FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)
FMT_VARIADIC(int, printf, CStringRef) FMT_VARIADIC(int, printf, CStringRef)
FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
#if FMT_USE_IOSTREAMS
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
print(cerr, "Don't {}!", "panic");
\endrst
*/
FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
#endif
namespace internal { namespace internal {
template <typename Char> template <typename Char>
inline bool is_name_start(Char c) { inline bool is_name_start(Char c) {
@ -3782,12 +3860,15 @@ operator"" _a(const wchar_t *s, std::size_t) { return {s}; }
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
#if defined(__clang__) && !defined(__INTEL_COMPILER) #if defined(__clang__) && !defined(FMT_ICC_VERSION)
# pragma clang diagnostic pop # pragma clang diagnostic pop
#endif #endif
#ifdef FMT_HEADER_ONLY #ifdef FMT_HEADER_ONLY
# define FMT_FUNC inline
# include "format.cc" # include "format.cc"
#else
# define FMT_FUNC
#endif #endif
#endif // FMT_FORMAT_H_ #endif // FMT_FORMAT_H_

133
include/fmt/ostream.h Normal file
View File

@ -0,0 +1,133 @@
/*
Formatting library for C++ - std::ostream support
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
#include "format.h"
#include <ostream>
namespace fmt {
namespace internal {
template <class Char>
class FormatBuf : public std::basic_streambuf<Char> {
private:
typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
Buffer<Char> &buffer_;
Char *start_;
public:
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) {
this->setp(start_, start_ + buffer_.capacity());
}
int_type overflow(int_type ch = traits_type::eof()) {
if (!traits_type::eq_int_type(ch, traits_type::eof())) {
size_t buf_size = size();
buffer_.resize(buf_size);
buffer_.reserve(buf_size * 2);
start_ = &buffer_[0];
start_[buf_size] = traits_type::to_char_type(ch);
this->setp(start_+ buf_size + 1, start_ + buf_size * 2);
}
return ch;
}
size_t size() const {
return to_unsigned(this->pptr() - start_);
}
};
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<>);
};
No &operator<<(std::ostream &, int);
template<typename T>
struct ConvertToIntImpl<T, true> {
// Convert to int only if T doesn't have an overloaded operator<<.
enum {
value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
};
};
} // namespace internal
// Formats a value.
template <typename Char, typename ArgFormatter, typename T>
void format(BasicFormatter<Char, ArgFormatter> &f,
const Char *&format_str, const T &value) {
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
internal::FormatBuf<Char> format_buf(buffer);
std::basic_ostream<Char> output(&format_buf);
output << value;
BasicStringRef<Char> str(&buffer[0], format_buf.size());
typedef internal::MakeArg< BasicFormatter<Char> > MakeArg;
format_str = f.format(format_str, MakeArg(str));
}
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
print(cerr, "Don't {}!", "panic");
\endrst
*/
FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
} // namespace fmt
#ifdef FMT_HEADER_ONLY
# include "ostream.cc"
#endif
#endif // FMT_OSTREAM_H_

View File

@ -1,7 +1,7 @@
/* /*
A C++ interface to POSIX functions. A C++ interface to POSIX functions.
Copyright (c) 2014 - 2015, Victor Zverovich Copyright (c) 2014 - 2016, Victor Zverovich
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -145,7 +145,7 @@ public:
// A "move constructor" for moving from a temporary. // A "move constructor" for moving from a temporary.
BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {} BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {}
// A "move constructor" for for moving from an lvalue. // A "move constructor" for moving from an lvalue.
BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) { BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) {
f.file_ = 0; f.file_ = 0;
} }
@ -251,7 +251,7 @@ class File {
// A "move constructor" for moving from a temporary. // A "move constructor" for moving from a temporary.
File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {} File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
// A "move constructor" for for moving from an lvalue. // A "move constructor" for moving from an lvalue.
File(File &other) FMT_NOEXCEPT : fd_(other.fd_) { File(File &other) FMT_NOEXCEPT : fd_(other.fd_) {
other.fd_ = -1; other.fd_ = -1;
} }

36
include/fmt/stringf.h Normal file
View File

@ -0,0 +1,36 @@
/*
Formatting library for C++ - string utilities
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#ifndef FMT_STRING_H_
#define FMT_STRING_H_
#include "format.h"
namespace fmt {
/**
\rst
Converts *value* to ``std::string`` using the default format for type *T*.
**Example**::
#include "fmt/string.h"
std::string answer = fmt::to_string(42);
\endrst
*/
template <typename T>
std::string to_string(const T &value) {
fmt::MemoryWriter w;
w << value;
return w.str();
}
}
#endif // FMT_STRING_H_

64
include/fmt/timef.h Normal file
View File

@ -0,0 +1,64 @@
/*
Formatting library for C++ - time formatting
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FMT_TIME_H_
#define FMT_TIME_H_
#include "fmt/format.h"
#include <ctime>
namespace fmt {
template <typename ArgFormatter>
void format(BasicFormatter<char, ArgFormatter> &f,
const char *&format_str, const std::tm &tm) {
if (*format_str == ':')
++format_str;
const char *end = format_str;
while (*end && *end != '}')
++end;
if (*end != '}')
FMT_THROW(FormatError("missing '}' in format string"));
internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format;
format.append(format_str, end + 1);
format[format.size() - 1] = '\0';
Buffer<char> &buffer = f.writer().buffer();
std::size_t start = buffer.size();
for (;;) {
std::size_t size = buffer.capacity() - start;
std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm);
if (count != 0) {
buffer.resize(start + count);
break;
}
const std::size_t MIN_GROWTH = 10;
buffer.reserve(buffer.capacity() + size > MIN_GROWTH ? size : MIN_GROWTH);
}
format_str = end + 1;
}
}
#endif // FMT_TIME_H_