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:
parent
edf4d6cd38
commit
49a9983799
@ -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" />
|
||||||
|
@ -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" />
|
||||||
|
2
external/Common/posix.cc
vendored
2
external/Common/posix.cc
vendored
@ -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
|
||||||
|
335
external/CppFormat/ChangeLog.rst
vendored
335
external/CppFormat/ChangeLog.rst
vendored
@ -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
|
|
2
external/CppFormat/LICENSE.rst
vendored
2
external/CppFormat/LICENSE.rst
vendored
@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2012 - 2015, Victor Zverovich
|
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
|
409
external/CppFormat/README.rst
vendored
409
external/CppFormat/README.rst
vendored
@ -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.
|
|
127
external/CppFormat/format.cc
vendored
127
external/CppFormat/format.cc
vendored
@ -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
61
external/CppFormat/ostream.cc
vendored
Normal 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
|
@ -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
133
include/fmt/ostream.h
Normal 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_
|
@ -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
36
include/fmt/stringf.h
Normal 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
64
include/fmt/timef.h
Normal 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_
|
Loading…
Reference in New Issue
Block a user