This commit is contained in:
commit
d55dee7042
30
README.rst
30
README.rst
@ -42,8 +42,8 @@ Features
|
|||||||
performance of IOStreams. See `Speed tests`_ and
|
performance of IOStreams. See `Speed tests`_ and
|
||||||
`Fast integer to string conversion in C++
|
`Fast integer to string conversion in C++
|
||||||
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
|
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
|
||||||
* Small code size both in terms of source code (the core library consists of a
|
* Small code size both in terms of source code (the core library consists of two
|
||||||
single header file and a single source file) and compiled code.
|
header files and a single source file) and compiled code.
|
||||||
See `Compile time and code bloat`_.
|
See `Compile time and code bloat`_.
|
||||||
* Reliability: the library has an extensive set of `unit tests
|
* Reliability: the library has an extensive set of `unit tests
|
||||||
<https://github.com/fmtlib/fmt/tree/master/test>`_.
|
<https://github.com/fmtlib/fmt/tree/master/test>`_.
|
||||||
@ -84,24 +84,24 @@ Format strings can be checked at compile time:
|
|||||||
.. code:: c++
|
.. code:: c++
|
||||||
|
|
||||||
// test.cc
|
// test.cc
|
||||||
using namespace fmt::literals;
|
#include <fmt/format.h>
|
||||||
std::string s = "{2}"_format(42);
|
std::string s = fmt::format(fmt("{2}"), 42);
|
||||||
|
|
||||||
.. code::
|
.. code::
|
||||||
|
|
||||||
$ g++ -Iinclude test.cc -std=c++14
|
$ g++ -Iinclude test.cc -std=c++14
|
||||||
...
|
...
|
||||||
test.cc:5:31: note: in instantiation of function template specialization
|
test.cc:2:22: note: in instantiation of function template specialization 'fmt::format<S, int>' requested here
|
||||||
'fmt::internal::udl_formatter<char, '{', '2', '}'>::operator()<int>' requested
|
std::string s = fmt::format(fmt("{2}"), 42);
|
||||||
here
|
^
|
||||||
std::string s = "{2}"_format(42);
|
include/fmt/core.h:749:19: note: non-constexpr function 'on_error' cannot be used in a constant expression
|
||||||
^
|
ErrorHandler::on_error(message);
|
||||||
include/fmt/format.h:3838:7: note: non-constexpr function 'on_error' cannot be
|
^
|
||||||
used in a constant expression
|
include/fmt/format.h:2081:16: note: in call to '&checker.context_->on_error(&"argument index out of range"[0])'
|
||||||
on_error("argument index out of range");
|
context_.on_error("argument index out of range");
|
||||||
^
|
^
|
||||||
|
|
||||||
fmt can be used as a safe portable replacement for ``itoa``:
|
{fmt} can be used as a safe portable replacement for ``itoa``:
|
||||||
|
|
||||||
.. code:: c++
|
.. code:: c++
|
||||||
|
|
||||||
@ -160,6 +160,8 @@ Projects using this library
|
|||||||
* `AMPL/MP <https://github.com/ampl/mp>`_:
|
* `AMPL/MP <https://github.com/ampl/mp>`_:
|
||||||
An open-source library for mathematical programming
|
An open-source library for mathematical programming
|
||||||
|
|
||||||
|
* `AvioBook <https://www.aviobook.aero/en>`_: A comprehensive aircraft operations suite.
|
||||||
|
|
||||||
* `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater vehicle
|
* `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater vehicle
|
||||||
|
|
||||||
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
|
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
|
||||||
|
|||||||
425
doc/api.rst
425
doc/api.rst
@ -4,52 +4,249 @@
|
|||||||
API Reference
|
API Reference
|
||||||
*************
|
*************
|
||||||
|
|
||||||
All functions and classes provided by the fmt library reside
|
The {fmt} library API consists of the following parts:
|
||||||
in namespace ``fmt`` and macros have prefix ``FMT_``. For brevity the
|
|
||||||
namespace is usually omitted in examples.
|
|
||||||
|
|
||||||
Format API
|
* :ref:`fmt/core.h <core-api>`: the core API providing argument handling
|
||||||
==========
|
facilities and a lightweight subset of formatting functions
|
||||||
|
* :ref:`fmt/format.h <format-api>`: the full format API providing compile-time
|
||||||
|
format string checks, output iterator and user-defined type support
|
||||||
|
* :ref:`fmt/time.h <time-api>`: date and time formatting
|
||||||
|
* :ref:`fmt/ostream.h <ostream-api>`: ``std::ostream`` support
|
||||||
|
* :ref:`fmt/printf.h <printf-api>`: ``printf`` formatting
|
||||||
|
|
||||||
The following functions defined in ``fmt/format.h`` use :ref:`format string
|
All functions and types provided by the library reside in namespace ``fmt`` and
|
||||||
syntax <syntax>` similar to the one used by Python's `str.format
|
macros have prefix ``FMT_`` or ``fmt``.
|
||||||
<http://docs.python.org/3/library/stdtypes.html#str.format>`_ function.
|
|
||||||
|
.. _core-api:
|
||||||
|
|
||||||
|
Core API
|
||||||
|
========
|
||||||
|
|
||||||
|
``fmt/core.h`` defines the core API which provides argument handling facilities
|
||||||
|
and a lightweight subset of formatting functions.
|
||||||
|
|
||||||
|
The following functions use :ref:`format string syntax <syntax>`
|
||||||
|
imilar to that of Python's `str.format
|
||||||
|
<http://docs.python.org/3/library/stdtypes.html#str.format>`_.
|
||||||
They take *format_str* and *args* as arguments.
|
They take *format_str* and *args* as arguments.
|
||||||
|
|
||||||
*format_str* is a format string that contains literal text and replacement
|
*format_str* is a format string that contains literal text and replacement
|
||||||
fields surrounded by braces ``{}``. The fields are replaced with formatted
|
fields surrounded by braces ``{}``. The fields are replaced with formatted
|
||||||
arguments in the resulting string.
|
arguments in the resulting string.
|
||||||
|
|
||||||
*args* is an argument list representing arbitrary arguments.
|
*args* is an argument list representing objects to be formatted.
|
||||||
|
|
||||||
The `performance of the format API
|
|
||||||
<https://github.com/fmtlib/fmt/blob/master/README.rst#speed-tests>`_ is close
|
|
||||||
to that of glibc's ``printf`` and better than the performance of IOStreams.
|
|
||||||
For even better speed use the `write API`_.
|
|
||||||
|
|
||||||
.. _format:
|
.. _format:
|
||||||
|
|
||||||
.. doxygenfunction:: format(CStringRef, ArgList)
|
.. doxygenfunction:: format(string_view, const Args&...)
|
||||||
|
.. doxygenfunction:: vformat(string_view, format_args)
|
||||||
.. doxygenfunction:: operator""_format(const char *, std::size_t)
|
|
||||||
|
|
||||||
.. _print:
|
.. _print:
|
||||||
|
|
||||||
.. doxygenfunction:: print(CStringRef, ArgList)
|
.. doxygenfunction:: print(string_view, const Args&...)
|
||||||
|
.. doxygenfunction:: vprint(string_view, format_args)
|
||||||
|
|
||||||
.. doxygenfunction:: print(std::FILE *, CStringRef, ArgList)
|
.. doxygenfunction:: print(std::FILE *, string_view, const Args&...)
|
||||||
|
.. doxygenfunction:: vprint(std::FILE *, string_view, format_args)
|
||||||
|
|
||||||
.. doxygenclass:: fmt::BasicFormatter
|
.. _format-api:
|
||||||
|
|
||||||
|
Named arguments
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. doxygenfunction:: fmt::arg(string_view, const T&)
|
||||||
|
|
||||||
|
Argument lists
|
||||||
|
--------------
|
||||||
|
|
||||||
|
.. doxygenclass:: fmt::basic_format_args
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
.. doxygenstruct:: fmt::format_args
|
||||||
|
|
||||||
|
.. doxygenfunction:: fmt::make_args(const Args&...)
|
||||||
|
|
||||||
|
Compatibility
|
||||||
|
-------------
|
||||||
|
|
||||||
|
.. doxygenclass:: fmt::basic_string_view
|
||||||
|
:members:
|
||||||
|
|
||||||
|
Format API
|
||||||
|
==========
|
||||||
|
|
||||||
|
``fmt/format.h`` defines the full format API providing compile-time format
|
||||||
|
string checks, output iterator and user-defined type support.
|
||||||
|
|
||||||
|
Compile-time format string checks
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
.. doxygendefine:: fmt
|
||||||
|
|
||||||
|
Formatting user-defined types
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
To make a user-defined type formattable, specialize the ``formatter<T>`` struct
|
||||||
|
template and implement ``parse`` and ``format`` methods::
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
struct point { double x, y; };
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
template <>
|
||||||
|
struct formatter<point> {
|
||||||
|
template <typename ParseContext>
|
||||||
|
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); }
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const point &p, FormatContext &ctx) {
|
||||||
|
return format_to(ctx.begin(), "({:.1f}, {:.1f})", p.x, p.y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Then you can pass objects of type ``point`` to any formatting function::
|
||||||
|
|
||||||
|
point p = {1, 2};
|
||||||
|
std::string s = fmt::format("{}", p);
|
||||||
|
// s == "(1.0, 2.0)"
|
||||||
|
|
||||||
|
In the example above the ``formatter<point>::parse`` function ignores the
|
||||||
|
contents of the format string referred to by ``ctx.begin()`` so the object will
|
||||||
|
always be formatted in the same way. See ``formatter<tm>::parse`` in
|
||||||
|
:file:`fmt/time.h` for an advanced example of how to parse the format string and
|
||||||
|
customize the formatted output.
|
||||||
|
|
||||||
|
This section shows how to define a custom format function for a user-defined
|
||||||
|
type. The next section describes how to get ``fmt`` to use a conventional stream
|
||||||
|
output ``operator<<`` when one is defined for a user-defined type.
|
||||||
|
|
||||||
|
Output iterator support
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
.. doxygenfunction:: fmt::format_to(OutputIt, string_view, const Args&...)
|
||||||
|
|
||||||
|
Literal-based API
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The following user-defined literals are defined in ``fmt/format.h``.
|
||||||
|
|
||||||
|
.. doxygenfunction:: operator""_format(const char *, std::size_t)
|
||||||
|
|
||||||
|
.. doxygenfunction:: operator""_a(const char *, std::size_t)
|
||||||
|
|
||||||
|
Utilities
|
||||||
|
---------
|
||||||
|
|
||||||
|
.. doxygenfunction:: fmt::to_string(const T&)
|
||||||
|
|
||||||
|
.. doxygenclass:: fmt::basic_memory_buffer
|
||||||
|
:protected-members:
|
||||||
|
:members:
|
||||||
|
|
||||||
|
System errors
|
||||||
|
-------------
|
||||||
|
|
||||||
|
.. doxygenclass:: fmt::system_error
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. doxygenfunction:: fmt::format_system_error
|
||||||
|
|
||||||
|
.. doxygenclass:: fmt::windows_error
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. _formatstrings:
|
||||||
|
|
||||||
|
Custom allocators
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The {fmt} library supports custom dynamic memory allocators.
|
||||||
|
A custom allocator class can be specified as a template argument to
|
||||||
|
:class:`fmt::basic_memory_buffer`::
|
||||||
|
|
||||||
|
using custom_memory_buffer =
|
||||||
|
fmt::basic_memory_buffer<char, fmt::inline_buffer_size, custom_allocator>;
|
||||||
|
|
||||||
|
It is also possible to write a formatting function that uses a custom
|
||||||
|
allocator::
|
||||||
|
|
||||||
|
using custom_string =
|
||||||
|
std::basic_string<char, std::char_traits<char>, custom_allocator>;
|
||||||
|
|
||||||
|
custom_string vformat(custom_allocator alloc, fmt::string_view format_str,
|
||||||
|
fmt::format_args args) {
|
||||||
|
custom_memory_buffer buf(alloc);
|
||||||
|
fmt::vformat_to(buf, format_str, args);
|
||||||
|
return custom_string(buf.data(), buf.size(), alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ...Args>
|
||||||
|
inline custom_string format(custom_allocator alloc,
|
||||||
|
fmt::string_view format_str,
|
||||||
|
const Args & ... args) {
|
||||||
|
return vformat(alloc, format_str, fmt::make_args(args...));
|
||||||
|
}
|
||||||
|
Custom formatting of built-in types
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
It is possible to change the way arguments are formatted by providing a
|
||||||
|
custom argument formatter class::
|
||||||
|
|
||||||
|
using arg_formatter =
|
||||||
|
fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>>;
|
||||||
|
|
||||||
|
// A custom argument formatter that formats negative integers as unsigned
|
||||||
|
// with the ``x`` format specifier.
|
||||||
|
class custom_arg_formatter : public arg_formatter {
|
||||||
|
public:
|
||||||
|
custom_arg_formatter(fmt::context &ctx, fmt::format_specs &spec)
|
||||||
|
: arg_formatter(ctx, spec) {}
|
||||||
|
|
||||||
|
using arg_formatter::operator();
|
||||||
|
|
||||||
|
void operator()(int value) {
|
||||||
|
if (spec().type() == 'x')
|
||||||
|
(*this)(static_cast<unsigned>(value)); // convert to unsigned and format
|
||||||
|
else
|
||||||
|
arg_formatter::operator()(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) {
|
||||||
|
fmt::memory_buffer buffer;
|
||||||
|
// Pass custom argument formatter as a template arg to vformat_to.
|
||||||
|
fmt::vformat_to<custom_arg_formatter>(buffer, format_str, args);
|
||||||
|
return fmt::to_string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ...Args>
|
||||||
|
inline std::string custom_format(
|
||||||
|
fmt::string_view format_str, const Args &... args) {
|
||||||
|
return custom_vformat(format_str, fmt::make_args(args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string s = custom_format("{:x}", -42); // s == "ffffffd6"
|
||||||
|
|
||||||
|
.. doxygenclass:: fmt::ArgVisitor
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. doxygenclass:: fmt::arg_formatter_base
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. doxygenclass:: fmt::arg_formatter
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. _time-api:
|
||||||
|
|
||||||
Date and time formatting
|
Date and time formatting
|
||||||
------------------------
|
========================
|
||||||
|
|
||||||
The library supports `strftime
|
The library supports `strftime
|
||||||
<http://en.cppreference.com/w/cpp/chrono/c/strftime>`_-like date and time
|
<http://en.cppreference.com/w/cpp/chrono/c/strftime>`_-like date and time
|
||||||
formatting::
|
formatting::
|
||||||
|
|
||||||
#include "fmt/time.h"
|
#include <fmt/time.h>
|
||||||
|
|
||||||
std::time_t t = std::time(nullptr);
|
std::time_t t = std::time(nullptr);
|
||||||
// Prints "The date is 2016-04-29." (with the current date)
|
// Prints "The date is 2016-04-29." (with the current date)
|
||||||
@ -58,111 +255,35 @@ formatting::
|
|||||||
The format string syntax is described in the documentation of
|
The format string syntax is described in the documentation of
|
||||||
`strftime <http://en.cppreference.com/w/cpp/chrono/c/strftime>`_.
|
`strftime <http://en.cppreference.com/w/cpp/chrono/c/strftime>`_.
|
||||||
|
|
||||||
Formatting user-defined types
|
.. _ostream-api:
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
To make a user-defined type formattable, specialize the ``formatter<T>`` struct
|
|
||||||
template and implement ``parse`` and ``format`` methods::
|
|
||||||
|
|
||||||
struct MyStruct { double x, y; };
|
|
||||||
|
|
||||||
namespace fmt {
|
|
||||||
template <>
|
|
||||||
struct formatter<MyStruct> {
|
|
||||||
template <typename ParseContext>
|
|
||||||
auto parse(ParseContext &ctx) { return ctx.begin(); }
|
|
||||||
|
|
||||||
template <typename FormatContext>
|
|
||||||
auto format(const MyStruct &s, FormatContext &ctx) {
|
|
||||||
fmt::format_to(ctx.begin(), "[MyStruct: x={:.1f}, y={:.2f}]", s.x, s.y);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Then you can pass objects of type ``MyStruct`` to any formatting function::
|
|
||||||
|
|
||||||
MyStruct m = {1, 2};
|
|
||||||
std::string s = fmt::format("m={}", m);
|
|
||||||
// s == "m=[MyStruct: x=1.0, y=2.00]"
|
|
||||||
|
|
||||||
In the example above the ``formatter<MyStruct>::parse`` function ignores the
|
|
||||||
contents of the format string referred to by ``ctx.begin()`` so the object will
|
|
||||||
always be formatted as specified. See ``formatter<tm>::parse`` in
|
|
||||||
:file:`fmt/time.h` for an advanced example of how to parse the format string and
|
|
||||||
customize the formatted output.
|
|
||||||
|
|
||||||
This section shows how to define a custom format function for a user-defined
|
|
||||||
type. The next section describes how to get ``fmt`` to use a conventional stream
|
|
||||||
output ``operator<<`` when one is defined for a user-defined type.
|
|
||||||
|
|
||||||
``std::ostream`` support
|
``std::ostream`` support
|
||||||
------------------------
|
========================
|
||||||
|
|
||||||
The header ``fmt/ostream.h`` provides ``std::ostream`` support including
|
``fmt/ostream.h`` provides ``std::ostream`` support including formatting of
|
||||||
formatting of user-defined types that have overloaded ``operator<<``::
|
user-defined types that have overloaded ``operator<<``::
|
||||||
|
|
||||||
#include "fmt/ostream.h"
|
#include <fmt/ostream.h>
|
||||||
|
|
||||||
class Date {
|
class date {
|
||||||
int year_, month_, day_;
|
int year_, month_, day_;
|
||||||
public:
|
public:
|
||||||
Date(int year, int month, int day): year_(year), month_(month), day_(day) {}
|
date(int year, int month, int day): year_(year), month_(month), day_(day) {}
|
||||||
|
|
||||||
friend std::ostream &operator<<(std::ostream &os, const Date &d) {
|
friend std::ostream &operator<<(std::ostream &os, const date &d) {
|
||||||
return os << d.year_ << '-' << d.month_ << '-' << d.day_;
|
return os << d.year_ << '-' << d.month_ << '-' << d.day_;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string s = fmt::format("The date is {}", Date(2012, 12, 9));
|
std::string s = fmt::format("The date is {}", date(2012, 12, 9));
|
||||||
// s == "The date is 2012-12-9"
|
// s == "The date is 2012-12-9"
|
||||||
|
|
||||||
.. doxygenfunction:: print(std::ostream&, CStringRef, ArgList)
|
.. doxygenfunction:: print(std::ostream&, string_view, const Args&...)
|
||||||
|
|
||||||
Argument formatters
|
.. _printf-api:
|
||||||
-------------------
|
|
||||||
|
|
||||||
It is possible to change the way arguments are formatted by providing a
|
``printf`` formatting
|
||||||
custom argument formatter class::
|
=====================
|
||||||
|
|
||||||
// A custom argument formatter that formats negative integers as unsigned
|
|
||||||
// with the ``x`` format specifier.
|
|
||||||
class CustomArgFormatter :
|
|
||||||
public fmt::BasicArgFormatter<CustomArgFormatter, char> {
|
|
||||||
public:
|
|
||||||
CustomArgFormatter(fmt::BasicFormatter<char, CustomArgFormatter> &f,
|
|
||||||
fmt::FormatSpec &s, const char *fmt)
|
|
||||||
: fmt::BasicArgFormatter<CustomArgFormatter, char>(f, s, fmt) {}
|
|
||||||
|
|
||||||
void visit_int(int value) {
|
|
||||||
if (spec().type() == 'x')
|
|
||||||
visit_uint(value); // convert to unsigned and format
|
|
||||||
else
|
|
||||||
fmt::BasicArgFormatter<CustomArgFormatter, char>::visit_int(value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string custom_format(const char *format_str, fmt::ArgList args) {
|
|
||||||
fmt::MemoryWriter writer;
|
|
||||||
// Pass custom argument formatter as a template arg to BasicFormatter.
|
|
||||||
fmt::BasicFormatter<char, CustomArgFormatter> formatter(args, writer);
|
|
||||||
formatter.format(format_str);
|
|
||||||
return writer.str();
|
|
||||||
}
|
|
||||||
FMT_VARIADIC(std::string, custom_format, const char *)
|
|
||||||
|
|
||||||
std::string s = custom_format("{:x}", -42); // s == "ffffffd6"
|
|
||||||
|
|
||||||
.. doxygenclass:: fmt::ArgVisitor
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. doxygenclass:: fmt::BasicArgFormatter
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. doxygenclass:: fmt::ArgFormatter
|
|
||||||
:members:
|
|
||||||
|
|
||||||
Printf formatting
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
The header ``fmt/printf.h`` provides ``printf``-like formatting functionality.
|
The header ``fmt/printf.h`` provides ``printf``-like formatting functionality.
|
||||||
The following functions use `printf format string syntax
|
The following functions use `printf format string syntax
|
||||||
@ -171,22 +292,13 @@ the POSIX extension for positional arguments. Unlike their standard
|
|||||||
counterparts, the ``fmt`` functions are type-safe and throw an exception if an
|
counterparts, the ``fmt`` functions are type-safe and throw an exception if an
|
||||||
argument type doesn't match its format specification.
|
argument type doesn't match its format specification.
|
||||||
|
|
||||||
.. doxygenfunction:: printf(CStringRef, ArgList)
|
.. doxygenfunction:: printf(string_view, const Args&...)
|
||||||
|
|
||||||
.. doxygenfunction:: fprintf(std::FILE *, CStringRef, ArgList)
|
.. doxygenfunction:: fprintf(std::FILE *, string_view, const Args&...)
|
||||||
|
|
||||||
.. doxygenfunction:: fprintf(std::ostream&, CStringRef, ArgList)
|
.. doxygenfunction:: fprintf(std::ostream&, string_view, const Args&...)
|
||||||
|
|
||||||
.. doxygenfunction:: sprintf(CStringRef, ArgList)
|
.. doxygenfunction:: sprintf(string_view, const Args&...)
|
||||||
|
|
||||||
.. doxygenclass:: fmt::PrintfFormatter
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. doxygenclass:: fmt::BasicPrintfArgFormatter
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. doxygenclass:: fmt::PrintfArgFormatter
|
|
||||||
:members:
|
|
||||||
|
|
||||||
Write API
|
Write API
|
||||||
=========
|
=========
|
||||||
@ -194,14 +306,14 @@ Write API
|
|||||||
The write API provides classes for writing formatted data into character
|
The write API provides classes for writing formatted data into character
|
||||||
streams. It is usually faster than the `format API`_ but, as IOStreams,
|
streams. It is usually faster than the `format API`_ but, as IOStreams,
|
||||||
may result in larger compiled code size. The main writer class is
|
may result in larger compiled code size. The main writer class is
|
||||||
`~fmt::BasicMemoryWriter` which stores its output in a memory buffer and
|
`~fmt::basic_memory_writer` which stores its output in a memory buffer and
|
||||||
provides direct access to it. It is possible to create custom writers that
|
provides direct access to it. It is possible to create custom writers that
|
||||||
store output elsewhere by subclassing `~fmt::BasicWriter`.
|
store output elsewhere by subclassing `~fmt::BasicWriter`.
|
||||||
|
|
||||||
.. doxygenclass:: fmt::BasicWriter
|
.. doxygenclass:: fmt::BasicWriter
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. doxygenclass:: fmt::BasicMemoryWriter
|
.. doxygenclass:: fmt::basic_memory_writer
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. doxygenclass:: fmt::BasicArrayWriter
|
.. doxygenclass:: fmt::BasicArrayWriter
|
||||||
@ -220,64 +332,3 @@ store output elsewhere by subclassing `~fmt::BasicWriter`.
|
|||||||
|
|
||||||
.. doxygenfunction:: pad(int, unsigned, Char)
|
.. doxygenfunction:: pad(int, unsigned, Char)
|
||||||
|
|
||||||
Utilities
|
|
||||||
=========
|
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::arg(StringRef, const T&)
|
|
||||||
|
|
||||||
.. doxygenfunction:: operator""_a(const char *, std::size_t)
|
|
||||||
|
|
||||||
.. doxygendefine:: FMT_CAPTURE
|
|
||||||
|
|
||||||
.. doxygendefine:: FMT_VARIADIC
|
|
||||||
|
|
||||||
.. doxygenclass:: fmt::ArgList
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::to_string(const T&)
|
|
||||||
|
|
||||||
.. doxygenclass:: fmt::BasicStringRef
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. doxygenclass:: fmt::BasicCStringRef
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. doxygenclass:: fmt::Buffer
|
|
||||||
:protected-members:
|
|
||||||
:members:
|
|
||||||
|
|
||||||
System errors
|
|
||||||
=============
|
|
||||||
|
|
||||||
.. doxygenclass:: fmt::SystemError
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::format_system_error
|
|
||||||
|
|
||||||
.. doxygenclass:: fmt::WindowsError
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. _formatstrings:
|
|
||||||
|
|
||||||
Custom allocators
|
|
||||||
=================
|
|
||||||
|
|
||||||
The fmt library supports custom dynamic memory allocators.
|
|
||||||
A custom allocator class can be specified as a template argument to
|
|
||||||
:class:`fmt::BasicMemoryWriter`::
|
|
||||||
|
|
||||||
typedef fmt::BasicMemoryWriter<char, CustomAllocator> CustomMemoryWriter;
|
|
||||||
|
|
||||||
It is also possible to write a formatting function that uses a custom
|
|
||||||
allocator::
|
|
||||||
|
|
||||||
typedef std::basic_string<char, std::char_traits<char>, CustomAllocator>
|
|
||||||
CustomString;
|
|
||||||
|
|
||||||
CustomString format(CustomAllocator alloc, fmt::CStringRef format_str,
|
|
||||||
fmt::ArgList args) {
|
|
||||||
CustomMemoryWriter writer(alloc);
|
|
||||||
writer.write(format_str, args);
|
|
||||||
return CustomString(writer.data(), writer.size(), alloc);
|
|
||||||
}
|
|
||||||
FMT_VARIADIC(CustomString, format, CustomAllocator, fmt::CStringRef)
|
|
||||||
|
|||||||
@ -62,8 +62,8 @@ def create_build_env(dirname='virtualenv'):
|
|||||||
def build_docs(version='dev', **kwargs):
|
def build_docs(version='dev', **kwargs):
|
||||||
doc_dir = kwargs.get('doc_dir', os.path.dirname(os.path.realpath(__file__)))
|
doc_dir = kwargs.get('doc_dir', os.path.dirname(os.path.realpath(__file__)))
|
||||||
work_dir = kwargs.get('work_dir', '.')
|
work_dir = kwargs.get('work_dir', '.')
|
||||||
include_dir = kwargs.get('include_dir',
|
include_dir = kwargs.get(
|
||||||
os.path.join(os.path.dirname(doc_dir), 'fmt'))
|
'include_dir', os.path.join(os.path.dirname(doc_dir), 'include', 'fmt'))
|
||||||
# Build docs.
|
# Build docs.
|
||||||
cmd = ['doxygen', '-']
|
cmd = ['doxygen', '-']
|
||||||
p = Popen(cmd, stdin=PIPE)
|
p = Popen(cmd, stdin=PIPE)
|
||||||
@ -74,8 +74,8 @@ def build_docs(version='dev', **kwargs):
|
|||||||
GENERATE_MAN = NO
|
GENERATE_MAN = NO
|
||||||
GENERATE_RTF = NO
|
GENERATE_RTF = NO
|
||||||
CASE_SENSE_NAMES = NO
|
CASE_SENSE_NAMES = NO
|
||||||
INPUT = {0}/container.h {0}/format.h {0}/ostream.h \
|
INPUT = {0}/core.h {0}/format.h {0}/ostream.h \
|
||||||
{0}/printf.h {0}/string.h
|
{0}/printf.h {0}/time.h
|
||||||
QUIET = YES
|
QUIET = YES
|
||||||
JAVADOC_AUTOBRIEF = YES
|
JAVADOC_AUTOBRIEF = YES
|
||||||
AUTOLINK_SUPPORT = NO
|
AUTOLINK_SUPPORT = NO
|
||||||
|
|||||||
@ -47,7 +47,7 @@ source_suffix = '.rst'
|
|||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'fmt'
|
project = u'fmt'
|
||||||
copyright = u'2012-2015, Victor Zverovich'
|
copyright = u'2012-present, Victor Zverovich'
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
# |version| and |release|, also used in various other places throughout the
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
|||||||
@ -25,7 +25,7 @@ The replacement-based Format API provides a safe alternative to ``printf``,
|
|||||||
``sprintf`` and friends with comparable or `better performance
|
``sprintf`` and friends with comparable or `better performance
|
||||||
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
|
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
|
||||||
The `format string syntax <syntax.html>`_ is similar to the one used by
|
The `format string syntax <syntax.html>`_ is similar to the one used by
|
||||||
`str.format <http://docs.python.org/2/library/stdtypes.html#str.format>`_
|
`str.format <http://docs.python.org/3/library/stdtypes.html#str.format>`_
|
||||||
in Python:
|
in Python:
|
||||||
|
|
||||||
.. code:: c++
|
.. code:: c++
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
# define FMT_HAS_FEATURE(x) 0
|
# define FMT_HAS_FEATURE(x) 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__has_include)
|
#ifdef __has_include
|
||||||
# define FMT_HAS_INCLUDE(x) __has_include(x)
|
# define FMT_HAS_INCLUDE(x) __has_include(x)
|
||||||
#else
|
#else
|
||||||
# define FMT_HAS_INCLUDE(x) 0
|
# define FMT_HAS_INCLUDE(x) 0
|
||||||
@ -36,7 +36,7 @@
|
|||||||
# define FMT_GCC_VERSION 0
|
# define FMT_GCC_VERSION 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__
|
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||||
# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION
|
# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION
|
||||||
#else
|
#else
|
||||||
# define FMT_HAS_GXX_CXX11 0
|
# define FMT_HAS_GXX_CXX11 0
|
||||||
@ -72,17 +72,26 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if FMT_HAS_FEATURE(cxx_explicit_conversions)
|
||||||
|
# define FMT_EXPLICIT explicit
|
||||||
|
#else
|
||||||
|
# define FMT_EXPLICIT
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef FMT_NULL
|
#ifndef FMT_NULL
|
||||||
# if FMT_HAS_FEATURE(cxx_nullptr) || \
|
# if FMT_HAS_FEATURE(cxx_nullptr) || \
|
||||||
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
|
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
|
||||||
FMT_MSC_VER >= 1600
|
FMT_MSC_VER >= 1600
|
||||||
# define FMT_NULL nullptr
|
# define FMT_NULL nullptr
|
||||||
|
# define FMT_USE_NULLPTR 1
|
||||||
# else
|
# else
|
||||||
# define FMT_NULL NULL
|
# define FMT_NULL NULL
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FMT_USE_STRONG_ENUMS FMT_HAS_FEATURE(cxx_strong_enums)
|
#ifndef FMT_USE_NULLPTR
|
||||||
|
# define FMT_USE_NULLPTR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
// Check if exceptions are disabled.
|
// Check if exceptions are disabled.
|
||||||
#if defined(__GNUC__) && !defined(__EXCEPTIONS)
|
#if defined(__GNUC__) && !defined(__EXCEPTIONS)
|
||||||
@ -148,19 +157,36 @@
|
|||||||
#if (FMT_HAS_INCLUDE(<string_view>) && __cplusplus > 201402L) || \
|
#if (FMT_HAS_INCLUDE(<string_view>) && __cplusplus > 201402L) || \
|
||||||
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
|
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
|
||||||
# include <string_view>
|
# include <string_view>
|
||||||
namespace fmt { using std::basic_string_view; }
|
# define FMT_USE_STD_STRING_VIEW
|
||||||
// std::experimental::basic_string_view::remove_prefix isn't constexpr in gcc 6.
|
// std::experimental::basic_string_view::remove_prefix isn't constexpr until
|
||||||
|
// gcc 7.3.
|
||||||
#elif (FMT_HAS_INCLUDE(<experimental/string_view>) && \
|
#elif (FMT_HAS_INCLUDE(<experimental/string_view>) && \
|
||||||
(FMT_GCC_VERSION == 0 || FMT_GCC_VERSION >= 700) && \
|
(FMT_GCC_VERSION == 0 || FMT_GCC_VERSION >= 730) && \
|
||||||
__cplusplus >= 201402L)
|
__cplusplus >= 201402L)
|
||||||
# include <experimental/string_view>
|
# include <experimental/string_view>
|
||||||
namespace fmt { using std::experimental::basic_string_view; }
|
# define FMT_USE_EXPERIMENTAL_STRING_VIEW
|
||||||
#else
|
#endif
|
||||||
|
|
||||||
|
// std::result_of is defined in <functional> in gcc 4.4.
|
||||||
|
#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 404
|
||||||
|
# include <functional>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace fmt {
|
namespace fmt {
|
||||||
|
|
||||||
|
// An implementation of declval for pre-C++11 compilers such as gcc 4.
|
||||||
|
namespace internal {
|
||||||
|
template <typename T>
|
||||||
|
typename std::add_rvalue_reference<T>::type declval() FMT_NOEXCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
|
An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
|
||||||
subset of the API.
|
subset of the API. ``fmt::basic_string_view`` is used for format strings even
|
||||||
|
if ``std::string_view`` is available to prevent issues when a library is
|
||||||
|
compiled with a different ``-std`` option than the client code (which is not
|
||||||
|
recommended).
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
@ -170,10 +196,22 @@ class basic_string_view {
|
|||||||
size_t size_;
|
size_t size_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using char_type = Char;
|
typedef Char char_type;
|
||||||
using iterator = const Char *;
|
typedef const Char *iterator;
|
||||||
|
|
||||||
FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(0), size_(0) {}
|
// Standard basic_string_view type.
|
||||||
|
#if defined(FMT_USE_STD_STRING_VIEW)
|
||||||
|
typedef std::basic_string_view<Char> type;
|
||||||
|
#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
|
||||||
|
typedef std::experimental::basic_string_view<Char> type;
|
||||||
|
#else
|
||||||
|
struct type {
|
||||||
|
const char *data() const { return FMT_NULL; }
|
||||||
|
size_t size() const { return 0; };
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(FMT_NULL), size_(0) {}
|
||||||
|
|
||||||
/** Constructs a string reference object from a C string and a size. */
|
/** Constructs a string reference object from a C string and a size. */
|
||||||
FMT_CONSTEXPR basic_string_view(const Char *s, size_t size) FMT_NOEXCEPT
|
FMT_CONSTEXPR basic_string_view(const Char *s, size_t size) FMT_NOEXCEPT
|
||||||
@ -198,6 +236,9 @@ class basic_string_view {
|
|||||||
const std::basic_string<Char, Alloc> &s) FMT_NOEXCEPT
|
const std::basic_string<Char, Alloc> &s) FMT_NOEXCEPT
|
||||||
: data_(s.c_str()), size_(s.size()) {}
|
: data_(s.c_str()), size_(s.size()) {}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR basic_string_view(type s) FMT_NOEXCEPT
|
||||||
|
: data_(s.data()), size_(s.size()) {}
|
||||||
|
|
||||||
/** Returns a pointer to the string data. */
|
/** Returns a pointer to the string data. */
|
||||||
const Char *data() const { return data_; }
|
const Char *data() const { return data_; }
|
||||||
|
|
||||||
@ -240,12 +281,9 @@ class basic_string_view {
|
|||||||
return lhs.compare(rhs) >= 0;
|
return lhs.compare(rhs) >= 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace fmt
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace fmt {
|
typedef basic_string_view<char> string_view;
|
||||||
using string_view = basic_string_view<char>;
|
typedef basic_string_view<wchar_t> wstring_view;
|
||||||
using wstring_view = basic_string_view<wchar_t>;
|
|
||||||
|
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
class basic_arg;
|
class basic_arg;
|
||||||
@ -287,7 +325,8 @@ class basic_buffer {
|
|||||||
virtual void grow(std::size_t capacity) = 0;
|
virtual void grow(std::size_t capacity) = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using value_type = T;
|
typedef T value_type;
|
||||||
|
typedef const T &const_reference;
|
||||||
|
|
||||||
virtual ~basic_buffer() {}
|
virtual ~basic_buffer() {}
|
||||||
|
|
||||||
@ -337,8 +376,8 @@ class basic_buffer {
|
|||||||
const T &operator[](std::size_t index) const { return ptr_[index]; }
|
const T &operator[](std::size_t index) const { return ptr_[index]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
using buffer = basic_buffer<char>;
|
typedef basic_buffer<char> buffer;
|
||||||
using wbuffer = basic_buffer<wchar_t>;
|
typedef basic_buffer<wchar_t> wbuffer;
|
||||||
|
|
||||||
// A container-backed buffer.
|
// A container-backed buffer.
|
||||||
template <typename Container>
|
template <typename Container>
|
||||||
@ -347,7 +386,7 @@ class container_buffer : public basic_buffer<typename Container::value_type> {
|
|||||||
Container &container_;
|
Container &container_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void grow(std::size_t capacity) {
|
void grow(std::size_t capacity) FMT_OVERRIDE {
|
||||||
container_.resize(capacity);
|
container_.resize(capacity);
|
||||||
this->set(&container_[0], capacity);
|
this->set(&container_[0], capacity);
|
||||||
}
|
}
|
||||||
@ -358,11 +397,6 @@ class container_buffer : public basic_buffer<typename Container::value_type> {
|
|||||||
container_(c) {}
|
container_(c) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// A helper function to suppress bogus "conditional expression is constant"
|
|
||||||
// warnings.
|
|
||||||
template <typename T>
|
|
||||||
inline T const_check(T value) { return value; }
|
|
||||||
|
|
||||||
struct error_handler {
|
struct error_handler {
|
||||||
FMT_CONSTEXPR error_handler() {}
|
FMT_CONSTEXPR error_handler() {}
|
||||||
FMT_CONSTEXPR error_handler(const error_handler &) {}
|
FMT_CONSTEXPR error_handler(const error_handler &) {}
|
||||||
@ -395,40 +429,32 @@ template <typename T, typename Char>
|
|||||||
struct is_named_arg<named_arg<T, Char>> : std::true_type {};
|
struct is_named_arg<named_arg<T, Char>> : std::true_type {};
|
||||||
|
|
||||||
enum type {
|
enum type {
|
||||||
NONE, NAMED_ARG,
|
none_type, name_arg_type,
|
||||||
// Integer types should go first,
|
// Integer types should go first,
|
||||||
INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR,
|
int_type, uint_type, long_long_type, ulong_long_type, bool_type, char_type,
|
||||||
|
last_integer_type = char_type,
|
||||||
// followed by floating-point types.
|
// followed by floating-point types.
|
||||||
DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE,
|
double_type, long_double_type, last_numeric_type = long_double_type,
|
||||||
CSTRING, STRING, POINTER, CUSTOM
|
cstring_type, string_type, pointer_type, custom_type
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_CONSTEXPR bool is_integral(type t) {
|
FMT_CONSTEXPR bool is_integral(type t) {
|
||||||
FMT_ASSERT(t != internal::NAMED_ARG, "invalid argument type");
|
FMT_ASSERT(t != internal::name_arg_type, "invalid argument type");
|
||||||
return t > internal::NONE && t <= internal::LAST_INTEGER_TYPE;
|
return t > internal::none_type && t <= internal::last_integer_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR bool is_arithmetic(type t) {
|
FMT_CONSTEXPR bool is_arithmetic(type t) {
|
||||||
FMT_ASSERT(t != internal::NAMED_ARG, "invalid argument type");
|
FMT_ASSERT(t != internal::name_arg_type, "invalid argument type");
|
||||||
return t > internal::NONE && t <= internal::LAST_NUMERIC_TYPE;
|
return t > internal::none_type && t <= internal::last_numeric_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, bool ENABLE = true>
|
template <typename T, typename Char, bool ENABLE = true>
|
||||||
struct convert_to_int {
|
struct convert_to_int {
|
||||||
enum {
|
enum {
|
||||||
value = !std::is_arithmetic<T>::value && std::is_convertible<T, int>::value
|
value = !std::is_arithmetic<T>::value && std::is_convertible<T, int>::value
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FMT_DISABLE_CONVERSION_TO_INT(Type) \
|
|
||||||
template <> \
|
|
||||||
struct convert_to_int<Type> { enum { value = 0 }; }
|
|
||||||
|
|
||||||
// Silence warnings about convering float to int.
|
|
||||||
FMT_DISABLE_CONVERSION_TO_INT(float);
|
|
||||||
FMT_DISABLE_CONVERSION_TO_INT(double);
|
|
||||||
FMT_DISABLE_CONVERSION_TO_INT(long double);
|
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
struct string_value {
|
struct string_value {
|
||||||
const Char *value;
|
const Char *value;
|
||||||
@ -445,7 +471,7 @@ struct custom_value {
|
|||||||
template <typename Context>
|
template <typename Context>
|
||||||
class value {
|
class value {
|
||||||
public:
|
public:
|
||||||
using char_type = typename Context::char_type;
|
typedef typename Context::char_type char_type;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
int int_value;
|
int int_value;
|
||||||
@ -501,7 +527,7 @@ class value {
|
|||||||
// Get the formatter type through the context to allow different contexts
|
// Get the formatter type through the context to allow different contexts
|
||||||
// have different extension points, e.g. `formatter<T>` for `format` and
|
// have different extension points, e.g. `formatter<T>` for `format` and
|
||||||
// `printf_formatter<T>` for `printf`.
|
// `printf_formatter<T>` for `printf`.
|
||||||
typename Context::template formatter_type<T> f;
|
typename Context::template formatter_type<T>::type f;
|
||||||
auto &&parse_ctx = ctx.parse_context();
|
auto &&parse_ctx = ctx.parse_context();
|
||||||
parse_ctx.advance_to(f.parse(parse_ctx));
|
parse_ctx.advance_to(f.parse(parse_ctx));
|
||||||
ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx));
|
ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx));
|
||||||
@ -520,85 +546,97 @@ template <typename Context, typename T>
|
|||||||
FMT_CONSTEXPR basic_arg<Context> make_arg(const T &value);
|
FMT_CONSTEXPR basic_arg<Context> make_arg(const T &value);
|
||||||
|
|
||||||
#define FMT_MAKE_VALUE(TAG, ArgType, ValueType) \
|
#define FMT_MAKE_VALUE(TAG, ArgType, ValueType) \
|
||||||
template <typename C, typename char_type = typename C::char_type> \
|
template <typename C> \
|
||||||
FMT_CONSTEXPR typed_value<C, TAG> make_value(ArgType val) { \
|
FMT_CONSTEXPR typed_value<C, TAG> make_value(ArgType val) { \
|
||||||
return static_cast<ValueType>(val); \
|
return static_cast<ValueType>(val); \
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_MAKE_VALUE(BOOL, bool, int)
|
FMT_MAKE_VALUE(bool_type, bool, int)
|
||||||
FMT_MAKE_VALUE(INT, short, int)
|
FMT_MAKE_VALUE(int_type, short, int)
|
||||||
FMT_MAKE_VALUE(UINT, unsigned short, unsigned)
|
FMT_MAKE_VALUE(uint_type, unsigned short, unsigned)
|
||||||
FMT_MAKE_VALUE(INT, int, int)
|
FMT_MAKE_VALUE(int_type, int, int)
|
||||||
FMT_MAKE_VALUE(UINT, unsigned, unsigned)
|
FMT_MAKE_VALUE(uint_type, unsigned, unsigned)
|
||||||
|
|
||||||
// To minimize the number of types we need to deal with, long is translated
|
// To minimize the number of types we need to deal with, long is translated
|
||||||
// either to int or to long long depending on its size.
|
// either to int or to long long depending on its size.
|
||||||
using long_type =
|
typedef std::conditional<sizeof(long) == sizeof(int), int, long long>::type
|
||||||
std::conditional<sizeof(long) == sizeof(int), int, long long>::type;
|
long_type;
|
||||||
FMT_MAKE_VALUE((sizeof(long) == sizeof(int) ? INT : LONG_LONG), long, long_type)
|
FMT_MAKE_VALUE(
|
||||||
using ulong_type =
|
(sizeof(long) == sizeof(int) ? int_type : long_long_type), long, long_type)
|
||||||
std::conditional<sizeof(unsigned long) == sizeof(unsigned),
|
typedef std::conditional<sizeof(unsigned long) == sizeof(unsigned),
|
||||||
unsigned, unsigned long long>::type;
|
unsigned, unsigned long long>::type ulong_type;
|
||||||
FMT_MAKE_VALUE((sizeof(unsigned long) == sizeof(unsigned) ? UINT : ULONG_LONG),
|
FMT_MAKE_VALUE(
|
||||||
|
(sizeof(unsigned long) == sizeof(unsigned) ? uint_type : ulong_long_type),
|
||||||
unsigned long, ulong_type)
|
unsigned long, ulong_type)
|
||||||
|
|
||||||
FMT_MAKE_VALUE(LONG_LONG, long long, long long)
|
FMT_MAKE_VALUE(long_long_type, long long, long long)
|
||||||
FMT_MAKE_VALUE(ULONG_LONG, unsigned long long, unsigned long long)
|
FMT_MAKE_VALUE(ulong_long_type, unsigned long long, unsigned long long)
|
||||||
FMT_MAKE_VALUE(INT, signed char, int)
|
FMT_MAKE_VALUE(int_type, signed char, int)
|
||||||
FMT_MAKE_VALUE(UINT, unsigned char, unsigned)
|
FMT_MAKE_VALUE(uint_type, unsigned char, unsigned)
|
||||||
FMT_MAKE_VALUE(CHAR, char, int)
|
FMT_MAKE_VALUE(char_type, char, int)
|
||||||
|
|
||||||
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||||
template <typename C>
|
template <typename C>
|
||||||
inline typed_value<C, CHAR> make_value(wchar_t val) {
|
inline typed_value<C, char_type> make_value(wchar_t val) {
|
||||||
require_wchar<typename C::char_type>();
|
require_wchar<typename C::char_type>();
|
||||||
return static_cast<int>(val);
|
return static_cast<int>(val);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FMT_MAKE_VALUE(DOUBLE, float, double)
|
FMT_MAKE_VALUE(double_type, float, double)
|
||||||
FMT_MAKE_VALUE(DOUBLE, double, double)
|
FMT_MAKE_VALUE(double_type, double, double)
|
||||||
FMT_MAKE_VALUE(LONG_DOUBLE, long double, long double)
|
FMT_MAKE_VALUE(long_double_type, long double, long double)
|
||||||
|
|
||||||
// Formatting of wide strings into a narrow buffer and multibyte strings
|
// Formatting of wide strings into a narrow buffer and multibyte strings
|
||||||
// into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606).
|
// into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606).
|
||||||
FMT_MAKE_VALUE(CSTRING, char_type*, const char_type*)
|
FMT_MAKE_VALUE(cstring_type, typename C::char_type*,
|
||||||
FMT_MAKE_VALUE(CSTRING, const char_type*, const char_type*)
|
const typename C::char_type*)
|
||||||
|
FMT_MAKE_VALUE(cstring_type, const typename C::char_type*,
|
||||||
|
const typename C::char_type*)
|
||||||
|
|
||||||
FMT_MAKE_VALUE(CSTRING, signed char*, const signed char*)
|
FMT_MAKE_VALUE(cstring_type, signed char*, const signed char*)
|
||||||
FMT_MAKE_VALUE(CSTRING, const signed char*, const signed char*)
|
FMT_MAKE_VALUE(cstring_type, const signed char*, const signed char*)
|
||||||
FMT_MAKE_VALUE(CSTRING, unsigned char*, const unsigned char*)
|
FMT_MAKE_VALUE(cstring_type, unsigned char*, const unsigned char*)
|
||||||
FMT_MAKE_VALUE(CSTRING, const unsigned char*, const unsigned char*)
|
FMT_MAKE_VALUE(cstring_type, const unsigned char*, const unsigned char*)
|
||||||
FMT_MAKE_VALUE(STRING, basic_string_view<char_type>,
|
FMT_MAKE_VALUE(string_type, basic_string_view<typename C::char_type>,
|
||||||
basic_string_view<char_type>)
|
basic_string_view<typename C::char_type>)
|
||||||
FMT_MAKE_VALUE(STRING, const std::basic_string<char_type>&,
|
FMT_MAKE_VALUE(string_type,
|
||||||
basic_string_view<char_type>)
|
typename basic_string_view<typename C::char_type>::type,
|
||||||
FMT_MAKE_VALUE(POINTER, void*, const void*)
|
basic_string_view<typename C::char_type>)
|
||||||
FMT_MAKE_VALUE(POINTER, const void*, const void*)
|
FMT_MAKE_VALUE(string_type, const std::basic_string<typename C::char_type>&,
|
||||||
FMT_MAKE_VALUE(POINTER, std::nullptr_t, const void*)
|
basic_string_view<typename C::char_type>)
|
||||||
|
FMT_MAKE_VALUE(pointer_type, void*, const void*)
|
||||||
|
FMT_MAKE_VALUE(pointer_type, const void*, const void*)
|
||||||
|
|
||||||
|
#if FMT_USE_NULLPTR
|
||||||
|
FMT_MAKE_VALUE(pointer_type, std::nullptr_t, const void*)
|
||||||
|
#endif
|
||||||
|
|
||||||
// Formatting of arbitrary pointers is disallowed. If you want to output a
|
// Formatting of arbitrary pointers is disallowed. If you want to output a
|
||||||
// pointer cast it to "void *" or "const void *". In particular, this forbids
|
// pointer cast it to "void *" or "const void *". In particular, this forbids
|
||||||
// formatting of "[const] volatile char *" which is printed as bool by
|
// formatting of "[const] volatile char *" which is printed as bool by
|
||||||
// iostreams.
|
// iostreams.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void make_value(const T *p) {
|
void make_value(const T *) {
|
||||||
static_assert(!sizeof(T), "formatting of non-void pointers is disallowed");
|
static_assert(!sizeof(T), "formatting of non-void pointers is disallowed");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename C, typename T>
|
template <typename C, typename T>
|
||||||
inline typename std::enable_if<
|
inline typename std::enable_if<
|
||||||
convert_to_int<T>::value && std::is_enum<T>::value,
|
std::is_enum<T>::value && convert_to_int<T, typename C::char_type>::value,
|
||||||
typed_value<C, INT>>::type
|
typed_value<C, int_type>>::type
|
||||||
make_value(const T &val) { return static_cast<int>(val); }
|
make_value(const T &val) { return static_cast<int>(val); }
|
||||||
|
|
||||||
template <typename C, typename T>
|
template <typename C, typename T, typename Char = typename C::char_type>
|
||||||
inline typename std::enable_if<
|
inline typename std::enable_if<
|
||||||
!convert_to_int<T>::value, typed_value<C, CUSTOM>>::type
|
!convert_to_int<T, Char>::value &&
|
||||||
|
!std::is_convertible<T, basic_string_view<Char>>::value &&
|
||||||
|
!std::is_convertible<T, std::basic_string<Char>>::value,
|
||||||
|
typed_value<C, custom_type>>::type
|
||||||
make_value(const T &val) { return val; }
|
make_value(const T &val) { return val; }
|
||||||
|
|
||||||
template <typename C, typename T>
|
template <typename C, typename T>
|
||||||
typed_value<C, NAMED_ARG>
|
typed_value<C, name_arg_type>
|
||||||
make_value(const named_arg<T, typename C::char_type> &val) {
|
make_value(const named_arg<T, typename C::char_type> &val) {
|
||||||
basic_arg<C> arg = make_arg<C>(val.value);
|
basic_arg<C> arg = make_arg<C>(val.value);
|
||||||
std::memcpy(val.data, &arg, sizeof(arg));
|
std::memcpy(val.data, &arg, sizeof(arg));
|
||||||
@ -606,10 +644,20 @@ typed_value<C, NAMED_ARG>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Maximum number of arguments with packed types.
|
// Maximum number of arguments with packed types.
|
||||||
enum { MAX_PACKED_ARGS = 15 };
|
enum { max_packed_args = 15 };
|
||||||
|
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
class arg_map;
|
class arg_map;
|
||||||
|
|
||||||
|
template <typename>
|
||||||
|
struct result_of;
|
||||||
|
|
||||||
|
template <typename F, typename... Args>
|
||||||
|
struct result_of<F(Args...)> {
|
||||||
|
// A workaround for gcc 4.4 that doesn't allow F to be a reference.
|
||||||
|
typedef typename std::result_of<
|
||||||
|
typename std::remove_reference<F>::type(Args...)>::type type;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// A formatting argument. It is a trivially copyable/constructible type to
|
// A formatting argument. It is a trivially copyable/constructible type to
|
||||||
@ -624,13 +672,13 @@ class basic_arg {
|
|||||||
friend FMT_CONSTEXPR basic_arg<ContextType> internal::make_arg(const T &value);
|
friend FMT_CONSTEXPR basic_arg<ContextType> internal::make_arg(const T &value);
|
||||||
|
|
||||||
template <typename Visitor, typename Ctx>
|
template <typename Visitor, typename Ctx>
|
||||||
friend FMT_CONSTEXPR typename std::result_of<Visitor(int)>::type
|
friend FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
|
||||||
visit(Visitor &&vis, basic_arg<Ctx> arg);
|
visit(Visitor &&vis, basic_arg<Ctx> arg);
|
||||||
|
|
||||||
friend class basic_format_args<Context>;
|
friend class basic_format_args<Context>;
|
||||||
friend class internal::arg_map<Context>;
|
friend class internal::arg_map<Context>;
|
||||||
|
|
||||||
using char_type = typename Context::char_type;
|
typedef typename Context::char_type char_type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class handle {
|
class handle {
|
||||||
@ -643,17 +691,17 @@ class basic_arg {
|
|||||||
internal::custom_value<Context> custom_;
|
internal::custom_value<Context> custom_;
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_CONSTEXPR basic_arg() : type_(internal::NONE) {}
|
FMT_CONSTEXPR basic_arg() : type_(internal::none_type) {}
|
||||||
|
|
||||||
explicit operator bool() const FMT_NOEXCEPT {
|
FMT_EXPLICIT operator bool() const FMT_NOEXCEPT {
|
||||||
return type_ != internal::NONE;
|
return type_ != internal::none_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal::type type() const { return type_; }
|
internal::type type() const { return type_; }
|
||||||
|
|
||||||
bool is_integral() const { return internal::is_integral(type_); }
|
bool is_integral() const { return internal::is_integral(type_); }
|
||||||
bool is_arithmetic() const { return internal::is_arithmetic(type_); }
|
bool is_arithmetic() const { return internal::is_arithmetic(type_); }
|
||||||
bool is_pointer() const { return type_ == internal::POINTER; }
|
bool is_pointer() const { return type_ == internal::pointer_type; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parsing context consisting of a format string range being parsed and an
|
// Parsing context consisting of a format string range being parsed and an
|
||||||
@ -665,8 +713,8 @@ class basic_parse_context : private ErrorHandler {
|
|||||||
int next_arg_id_;
|
int next_arg_id_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using char_type = Char;
|
typedef Char char_type;
|
||||||
using iterator = typename basic_string_view<Char>::iterator;
|
typedef typename basic_string_view<Char>::iterator iterator;
|
||||||
|
|
||||||
explicit FMT_CONSTEXPR basic_parse_context(
|
explicit FMT_CONSTEXPR basic_parse_context(
|
||||||
basic_string_view<Char> format_str, ErrorHandler eh = ErrorHandler())
|
basic_string_view<Char> format_str, ErrorHandler eh = ErrorHandler())
|
||||||
@ -706,8 +754,8 @@ class basic_parse_context : private ErrorHandler {
|
|||||||
FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; }
|
FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
using parse_context = basic_parse_context<char>;
|
typedef basic_parse_context<char> parse_context;
|
||||||
using wparse_context = basic_parse_context<wchar_t>;
|
typedef basic_parse_context<wchar_t> wparse_context;
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
// A map from argument names to their values for named arguments.
|
// A map from argument names to their values for named arguments.
|
||||||
@ -716,15 +764,15 @@ class arg_map {
|
|||||||
private:
|
private:
|
||||||
FMT_DISALLOW_COPY_AND_ASSIGN(arg_map);
|
FMT_DISALLOW_COPY_AND_ASSIGN(arg_map);
|
||||||
|
|
||||||
using char_type = typename Context::char_type;
|
typedef typename Context::char_type char_type;
|
||||||
|
|
||||||
struct entry {
|
struct entry {
|
||||||
basic_string_view<char_type> name;
|
basic_string_view<char_type> name;
|
||||||
basic_arg<Context> arg;
|
basic_arg<Context> arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
entry *map_ = nullptr;
|
entry *map_;
|
||||||
unsigned size_ = 0;
|
unsigned size_;
|
||||||
|
|
||||||
void push_back(value<Context> val) {
|
void push_back(value<Context> val) {
|
||||||
const internal::named_arg_base<char_type> &named = val.as_named_arg();
|
const internal::named_arg_base<char_type> &named = val.as_named_arg();
|
||||||
@ -733,7 +781,7 @@ class arg_map {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
arg_map() {}
|
arg_map() : map_(FMT_NULL), size_(0) {}
|
||||||
void init(const basic_format_args<Context> &args);
|
void init(const basic_format_args<Context> &args);
|
||||||
~arg_map() { delete [] map_; }
|
~arg_map() { delete [] map_; }
|
||||||
|
|
||||||
@ -750,7 +798,7 @@ class arg_map {
|
|||||||
template <typename OutputIt, typename Context, typename Char>
|
template <typename OutputIt, typename Context, typename Char>
|
||||||
class context_base {
|
class context_base {
|
||||||
public:
|
public:
|
||||||
using iterator = OutputIt;
|
typedef OutputIt iterator;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
basic_parse_context<Char> parse_context_;
|
basic_parse_context<Char> parse_context_;
|
||||||
@ -758,8 +806,8 @@ class context_base {
|
|||||||
basic_format_args<Context> args_;
|
basic_format_args<Context> args_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using char_type = Char;
|
typedef Char char_type;
|
||||||
using format_arg = basic_arg<Context>;
|
typedef basic_arg<Context> format_arg;
|
||||||
|
|
||||||
context_base(OutputIt out, basic_string_view<char_type> format_str,
|
context_base(OutputIt out, basic_string_view<char_type> format_str,
|
||||||
basic_format_args<Context> args)
|
basic_format_args<Context> args)
|
||||||
@ -794,7 +842,7 @@ class context_base {
|
|||||||
void on_error(const char *message) { parse_context_.on_error(message); }
|
void on_error(const char *message) { parse_context_.on_error(message); }
|
||||||
|
|
||||||
// Returns an iterator to the beginning of the output range.
|
// Returns an iterator to the beginning of the output range.
|
||||||
auto begin() { return out_; }
|
iterator begin() { return out_; }
|
||||||
|
|
||||||
// Advances the begin iterator to ``it``.
|
// Advances the begin iterator to ``it``.
|
||||||
void advance_to(iterator it) { out_ = it; }
|
void advance_to(iterator it) { out_ = it; }
|
||||||
@ -803,49 +851,34 @@ class context_base {
|
|||||||
// Extracts a reference to the container from back_insert_iterator.
|
// Extracts a reference to the container from back_insert_iterator.
|
||||||
template <typename Container>
|
template <typename Container>
|
||||||
inline Container &get_container(std::back_insert_iterator<Container> it) {
|
inline Container &get_container(std::back_insert_iterator<Container> it) {
|
||||||
using iterator = std::back_insert_iterator<Container>;
|
typedef std::back_insert_iterator<Container> bi_iterator;
|
||||||
struct accessor: iterator {
|
struct accessor: bi_iterator {
|
||||||
accessor(iterator it) : iterator(it) {}
|
accessor(bi_iterator it) : bi_iterator(it) {}
|
||||||
using iterator::container;
|
using bi_iterator::container;
|
||||||
};
|
};
|
||||||
return *accessor(it).container;
|
return *accessor(it).container;
|
||||||
}
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
template <typename OutputIt, typename T = typename OutputIt::value_type>
|
|
||||||
class output_range {
|
|
||||||
private:
|
|
||||||
OutputIt it_;
|
|
||||||
|
|
||||||
// Unused yet.
|
|
||||||
using sentinel = void;
|
|
||||||
sentinel end() const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using value_type = T;
|
|
||||||
|
|
||||||
explicit output_range(OutputIt it): it_(it) {}
|
|
||||||
OutputIt begin() const { return it_; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Formatting context.
|
// Formatting context.
|
||||||
template <typename OutputIt, typename Char>
|
template <typename OutputIt, typename Char>
|
||||||
class basic_context :
|
class basic_context :
|
||||||
public internal::context_base<OutputIt, basic_context<OutputIt, Char>, Char> {
|
public internal::context_base<OutputIt, basic_context<OutputIt, Char>, Char> {
|
||||||
public:
|
public:
|
||||||
/** The character type for the output. */
|
/** The character type for the output. */
|
||||||
using char_type = Char;
|
typedef Char char_type;
|
||||||
|
|
||||||
|
// using formatter_type = formatter<T, char_type>;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using formatter_type = formatter<T, char_type>;
|
struct formatter_type { typedef formatter<T, char_type> type; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
internal::arg_map<basic_context> map_;
|
internal::arg_map<basic_context> map_;
|
||||||
|
|
||||||
FMT_DISALLOW_COPY_AND_ASSIGN(basic_context);
|
FMT_DISALLOW_COPY_AND_ASSIGN(basic_context);
|
||||||
|
|
||||||
using base = internal::context_base<OutputIt, basic_context, Char>;
|
typedef internal::context_base<OutputIt, basic_context, Char> base;
|
||||||
using format_arg = typename base::format_arg;
|
typedef typename base::format_arg format_arg;
|
||||||
using base::get_arg;
|
using base::get_arg;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -872,19 +905,18 @@ class basic_context :
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
using buffer_context_t = basic_context<
|
struct buffer_context {
|
||||||
std::back_insert_iterator<internal::basic_buffer<Char>>, Char>;
|
typedef basic_context<
|
||||||
using context = buffer_context_t<char>;
|
std::back_insert_iterator<internal::basic_buffer<Char>>, Char> type;
|
||||||
using wcontext = buffer_context_t<wchar_t>;
|
};
|
||||||
|
typedef buffer_context<char>::type context;
|
||||||
|
typedef buffer_context<wchar_t>::type wcontext;
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
template <typename Context, typename T>
|
template <typename Context, typename T>
|
||||||
class get_type {
|
struct get_type {
|
||||||
private:
|
typedef decltype(make_value<Context>(
|
||||||
static const T& val();
|
declval<typename std::decay<T>::type&>())) value_type;
|
||||||
|
|
||||||
public:
|
|
||||||
using value_type = decltype(make_value<Context>(val()));
|
|
||||||
static const type value = value_type::type_tag;
|
static const type value = value_type::type_tag;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -923,10 +955,10 @@ class arg_store {
|
|||||||
static const size_t NUM_ARGS = sizeof...(Args);
|
static const size_t NUM_ARGS = sizeof...(Args);
|
||||||
|
|
||||||
// Packed is a macro on MinGW so use IS_PACKED instead.
|
// Packed is a macro on MinGW so use IS_PACKED instead.
|
||||||
static const bool IS_PACKED = NUM_ARGS < internal::MAX_PACKED_ARGS;
|
static const bool IS_PACKED = NUM_ARGS < internal::max_packed_args;
|
||||||
|
|
||||||
using value_type = typename std::conditional<
|
typedef typename std::conditional<
|
||||||
IS_PACKED, internal::value<Context>, basic_arg<Context>>::type;
|
IS_PACKED, internal::value<Context>, basic_arg<Context>>::type value_type;
|
||||||
|
|
||||||
// If the arguments are not packed, add one more element to mark the end.
|
// If the arguments are not packed, add one more element to mark the end.
|
||||||
value_type data_[NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1)];
|
value_type data_[NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1)];
|
||||||
@ -934,8 +966,15 @@ class arg_store {
|
|||||||
public:
|
public:
|
||||||
static const uint64_t TYPES;
|
static const uint64_t TYPES;
|
||||||
|
|
||||||
|
#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 405 && !defined(__clang__)
|
||||||
|
// Workaround an array initialization bug in gcc 4.5 and earlier.
|
||||||
|
arg_store(const Args &... args) {
|
||||||
|
data_ = {internal::make_arg<IS_PACKED, Context>(args)...};
|
||||||
|
}
|
||||||
|
#else
|
||||||
arg_store(const Args &... args)
|
arg_store(const Args &... args)
|
||||||
: data_{internal::make_arg<IS_PACKED, Context>(args)...} {}
|
: data_{internal::make_arg<IS_PACKED, Context>(args)...} {}
|
||||||
|
#endif
|
||||||
|
|
||||||
basic_format_args<Context> operator*() const { return *this; }
|
basic_format_args<Context> operator*() const { return *this; }
|
||||||
|
|
||||||
@ -961,15 +1000,15 @@ inline arg_store<context, Args...> make_args(const Args & ... args) {
|
|||||||
template <typename Context>
|
template <typename Context>
|
||||||
class basic_format_args {
|
class basic_format_args {
|
||||||
public:
|
public:
|
||||||
using size_type = unsigned;
|
typedef unsigned size_type;
|
||||||
using format_arg = basic_arg<Context> ;
|
typedef basic_arg<Context> format_arg;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// To reduce compiled code size per formatting function call, types of first
|
// To reduce compiled code size per formatting function call, types of first
|
||||||
// MAX_PACKED_ARGS arguments are passed in the types_ field.
|
// max_packed_args arguments are passed in the types_ field.
|
||||||
uint64_t types_;
|
uint64_t types_;
|
||||||
union {
|
union {
|
||||||
// If the number of arguments is less than MAX_PACKED_ARGS, the argument
|
// If the number of arguments is less than max_packed_args, the argument
|
||||||
// values are stored in values_, otherwise they are stored in args_.
|
// values are stored in values_, otherwise they are stored in args_.
|
||||||
// This is done to reduce compiled code size as storing larger objects
|
// This is done to reduce compiled code size as storing larger objects
|
||||||
// may require more code (at least on x86-64) even if the same amount of
|
// may require more code (at least on x86-64) even if the same amount of
|
||||||
@ -997,10 +1036,10 @@ class basic_format_args {
|
|||||||
return index < num_args ? args_[index] : format_arg();
|
return index < num_args ? args_[index] : format_arg();
|
||||||
}
|
}
|
||||||
format_arg arg;
|
format_arg arg;
|
||||||
if (index > internal::MAX_PACKED_ARGS)
|
if (index > internal::max_packed_args)
|
||||||
return arg;
|
return arg;
|
||||||
arg.type_ = type(index);
|
arg.type_ = type(index);
|
||||||
if (arg.type_ == internal::NONE)
|
if (arg.type_ == internal::none_type)
|
||||||
return arg;
|
return arg;
|
||||||
internal::value<Context> &val = arg.value_;
|
internal::value<Context> &val = arg.value_;
|
||||||
val = values_[index];
|
val = values_[index];
|
||||||
@ -1019,19 +1058,25 @@ class basic_format_args {
|
|||||||
/** Returns the argument at specified index. */
|
/** Returns the argument at specified index. */
|
||||||
format_arg operator[](size_type index) const {
|
format_arg operator[](size_type index) const {
|
||||||
format_arg arg = get(index);
|
format_arg arg = get(index);
|
||||||
return arg.type_ == internal::NAMED_ARG ?
|
return arg.type_ == internal::name_arg_type ?
|
||||||
arg.value_.as_named_arg().template deserialize<Context>() : arg;
|
arg.value_.as_named_arg().template deserialize<Context>() : arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned max_size() const {
|
unsigned max_size() const {
|
||||||
int64_t signed_types = static_cast<int64_t>(types_);
|
int64_t signed_types = static_cast<int64_t>(types_);
|
||||||
return signed_types < 0 ?
|
return signed_types < 0 ?
|
||||||
-signed_types : static_cast<int64_t>(internal::MAX_PACKED_ARGS);
|
-signed_types : static_cast<int64_t>(internal::max_packed_args);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using format_args = basic_format_args<context>;
|
/** An alias to ``basic_format_args<context>``. */
|
||||||
using wformat_args = basic_format_args<wcontext>;
|
// It is a separate type rather than a typedef to make symbols readable.
|
||||||
|
struct format_args: basic_format_args<context> {
|
||||||
|
template <typename ...Args>
|
||||||
|
format_args(Args && ... arg)
|
||||||
|
: basic_format_args<context>(std::forward<Args>(arg)...) {};
|
||||||
|
};
|
||||||
|
typedef basic_format_args<wcontext> wformat_args;
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
@ -1062,11 +1107,11 @@ struct named_arg : named_arg_base<Char> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Returns a named argument for formatting functions.
|
Returns a named argument to be used in a formatting function.
|
||||||
|
|
||||||
**Example**::
|
**Example**::
|
||||||
|
|
||||||
print("Elapsed time: {s:.2f} seconds", arg("s", 1.23));
|
fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23));
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -1081,29 +1126,29 @@ inline internal::named_arg<T, wchar_t> arg(wstring_view name, const T &arg) {
|
|||||||
|
|
||||||
// This function template is deleted intentionally to disable nested named
|
// This function template is deleted intentionally to disable nested named
|
||||||
// arguments as in ``format("{}", arg("a", arg("b", 42)))``.
|
// arguments as in ``format("{}", arg("a", arg("b", 42)))``.
|
||||||
template <typename S, typename... T>
|
template <typename S, typename T, typename Char>
|
||||||
void arg(S, internal::named_arg<T...>) FMT_DELETED;
|
void arg(S, internal::named_arg<T, Char>) FMT_DELETED;
|
||||||
|
|
||||||
enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE };
|
enum color { black, red, green, yellow, blue, magenta, cyan, white };
|
||||||
|
|
||||||
FMT_API void vprint_colored(Color c, string_view format, format_args args);
|
FMT_API void vprint_colored(color c, string_view format, format_args args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Formats a string and prints it to stdout using ANSI escape sequences to
|
Formats a string and prints it to stdout using ANSI escape sequences to
|
||||||
specify color (experimental).
|
specify color (experimental).
|
||||||
Example:
|
Example:
|
||||||
print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23);
|
fmt::print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23);
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline void print_colored(Color c, string_view format_str,
|
inline void print_colored(color c, string_view format_str,
|
||||||
const Args & ... args) {
|
const Args & ... args) {
|
||||||
vprint_colored(c, format_str, make_args(args...));
|
vprint_colored(c, format_str, make_args(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
void vformat_to(internal::buffer &buf, string_view format_str,
|
context::iterator vformat_to(internal::buffer &buf, string_view format_str,
|
||||||
format_args args);
|
format_args args);
|
||||||
void vformat_to(internal::wbuffer &buf, wstring_view format_str,
|
wcontext::iterator vformat_to(internal::wbuffer &buf, wstring_view format_str,
|
||||||
wformat_args args);
|
wformat_args args);
|
||||||
|
|
||||||
template <typename Container>
|
template <typename Container>
|
||||||
struct is_contiguous : std::false_type {};
|
struct is_contiguous : std::false_type {};
|
||||||
@ -1116,11 +1161,14 @@ struct is_contiguous<fmt::internal::basic_buffer<Char>> : std::true_type {};
|
|||||||
|
|
||||||
/** Formats a string and writes the output to ``out``. */
|
/** Formats a string and writes the output to ``out``. */
|
||||||
template <typename Container>
|
template <typename Container>
|
||||||
typename std::enable_if<is_contiguous<Container>::value>::type
|
typename std::enable_if<
|
||||||
|
is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type
|
||||||
vformat_to(std::back_insert_iterator<Container> out,
|
vformat_to(std::back_insert_iterator<Container> out,
|
||||||
string_view format_str, format_args args) {
|
string_view format_str, format_args args) {
|
||||||
internal::container_buffer<Container> buf(internal::get_container(out));
|
auto& container = internal::get_container(out);
|
||||||
|
internal::container_buffer<Container> buf(container);
|
||||||
vformat_to(buf, format_str, args);
|
vformat_to(buf, format_str, args);
|
||||||
|
return std::back_inserter(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string vformat(string_view format_str, format_args args);
|
std::string vformat(string_view format_str, format_args args);
|
||||||
@ -1132,16 +1180,22 @@ std::wstring vformat(wstring_view format_str, wformat_args args);
|
|||||||
|
|
||||||
**Example**::
|
**Example**::
|
||||||
|
|
||||||
std::string message = format("The answer is {}", 42);
|
#include <fmt/core.h>
|
||||||
|
std::string message = fmt::format("The answer is {}", 42);
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline std::string format(string_view format_str, const Args & ... args) {
|
inline std::string format(string_view format_str, const Args & ... args) {
|
||||||
return vformat(format_str, make_args(args...));
|
// This should be just
|
||||||
|
// return vformat(format_str, make_args(args...));
|
||||||
|
// but gcc has trouble optimizing the latter, so break it down.
|
||||||
|
arg_store<context, Args...> as(args...);
|
||||||
|
return vformat(format_str, as);
|
||||||
}
|
}
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline std::wstring format(wstring_view format_str, const Args & ... args) {
|
inline std::wstring format(wstring_view format_str, const Args & ... args) {
|
||||||
return vformat(format_str, make_args<wcontext>(args...));
|
arg_store<wcontext, Args...> as(args...);
|
||||||
|
return vformat(format_str, as);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_API void vprint(std::FILE *f, string_view format_str, format_args args);
|
FMT_API void vprint(std::FILE *f, string_view format_str, format_args args);
|
||||||
@ -1152,12 +1206,13 @@ FMT_API void vprint(std::FILE *f, string_view format_str, format_args args);
|
|||||||
|
|
||||||
**Example**::
|
**Example**::
|
||||||
|
|
||||||
print(stderr, "Don't {}!", "panic");
|
fmt::print(stderr, "Don't {}!", "panic");
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline void print(std::FILE *f, string_view format_str, const Args & ... args) {
|
inline void print(std::FILE *f, string_view format_str, const Args & ... args) {
|
||||||
vprint(f, format_str, make_args(args...));
|
arg_store<context, Args...> as(args...);
|
||||||
|
vprint(f, format_str, as);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_API void vprint(string_view format_str, format_args args);
|
FMT_API void vprint(string_view format_str, format_args args);
|
||||||
@ -1168,12 +1223,13 @@ FMT_API void vprint(string_view format_str, format_args args);
|
|||||||
|
|
||||||
**Example**::
|
**Example**::
|
||||||
|
|
||||||
print("Elapsed time: {0:.2f} seconds", 1.23);
|
fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline void print(string_view format_str, const Args & ... args) {
|
inline void print(string_view format_str, const Args & ... args) {
|
||||||
vprint(format_str, make_args(args...));
|
arg_store<context, Args...> as(args...);
|
||||||
|
vprint(format_str, as);
|
||||||
}
|
}
|
||||||
} // namespace fmt
|
} // namespace fmt
|
||||||
|
|
||||||
|
|||||||
@ -166,7 +166,7 @@ int safe_strerror(
|
|||||||
void format_error_code(internal::buffer &out, int error_code,
|
void format_error_code(internal::buffer &out, int error_code,
|
||||||
string_view message) FMT_NOEXCEPT {
|
string_view 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.
|
||||||
out.resize(0);
|
out.resize(0);
|
||||||
static const char SEP[] = ": ";
|
static const char SEP[] = ": ";
|
||||||
@ -181,13 +181,13 @@ void format_error_code(internal::buffer &out, int error_code,
|
|||||||
}
|
}
|
||||||
error_code_size += internal::count_digits(abs_value);
|
error_code_size += internal::count_digits(abs_value);
|
||||||
writer w(out);
|
writer w(out);
|
||||||
if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) {
|
if (message.size() <= inline_buffer_size - error_code_size) {
|
||||||
w.write(message);
|
w.write(message);
|
||||||
w.write(SEP);
|
w.write(SEP);
|
||||||
}
|
}
|
||||||
w.write(ERROR_STR);
|
w.write(ERROR_STR);
|
||||||
w.write(error_code);
|
w.write(error_code);
|
||||||
assert(out.size() <= internal::INLINE_BUFFER_SIZE);
|
assert(out.size() <= inline_buffer_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void report_error(FormatFunc func, int error_code,
|
void report_error(FormatFunc func, int error_code,
|
||||||
@ -332,7 +332,7 @@ FMT_FUNC void internal::format_windows_error(
|
|||||||
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
|
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
|
||||||
FMT_TRY {
|
FMT_TRY {
|
||||||
wmemory_buffer buf;
|
wmemory_buffer buf;
|
||||||
buf.resize(INLINE_BUFFER_SIZE);
|
buf.resize(inline_buffer_size);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
wchar_t *system_message = &buf[0];
|
wchar_t *system_message = &buf[0];
|
||||||
int result = FormatMessageW(
|
int result = FormatMessageW(
|
||||||
@ -364,7 +364,7 @@ FMT_FUNC void format_system_error(
|
|||||||
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
|
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
|
||||||
FMT_TRY {
|
FMT_TRY {
|
||||||
memory_buffer buf;
|
memory_buffer buf;
|
||||||
buf.resize(internal::INLINE_BUFFER_SIZE);
|
buf.resize(inline_buffer_size);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char *system_message = &buf[0];
|
char *system_message = &buf[0];
|
||||||
int result = safe_strerror(error_code, system_message, buf.size());
|
int result = safe_strerror(error_code, system_message, buf.size());
|
||||||
@ -414,7 +414,7 @@ FMT_FUNC void vprint(string_view format_str, format_args args) {
|
|||||||
vprint(stdout, format_str, args);
|
vprint(stdout, format_str, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_FUNC void vprint_colored(Color c, string_view format, format_args args) {
|
FMT_FUNC void vprint_colored(color c, string_view format, format_args args) {
|
||||||
char escape[] = "\x1b[30m";
|
char escape[] = "\x1b[30m";
|
||||||
escape[3] = static_cast<char>('0' + c);
|
escape[3] = static_cast<char>('0' + c);
|
||||||
std::fputs(escape, stdout);
|
std::fputs(escape, stdout);
|
||||||
@ -434,7 +434,8 @@ template char internal::thousands_sep(locale_provider *lp);
|
|||||||
|
|
||||||
template void basic_fixed_buffer<char>::grow(std::size_t);
|
template void basic_fixed_buffer<char>::grow(std::size_t);
|
||||||
|
|
||||||
template void internal::arg_map<context>::init(const format_args &args);
|
template void internal::arg_map<context>::init(
|
||||||
|
const basic_format_args<context> &args);
|
||||||
|
|
||||||
template FMT_API int internal::char_traits<char>::format_float(
|
template FMT_API int internal::char_traits<char>::format_float(
|
||||||
char *buffer, std::size_t size, const char *format,
|
char *buffer, std::size_t size, const char *format,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -46,28 +46,31 @@ class FormatBuf : public std::basic_streambuf<Char> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct test_stream : std::ostream {
|
template <typename Char>
|
||||||
|
struct test_stream : std::basic_ostream<Char> {
|
||||||
private:
|
private:
|
||||||
struct null;
|
struct null;
|
||||||
// Hide all operator<< from std::ostream.
|
// Hide all operator<< from std::basic_ostream<Char>.
|
||||||
void operator<<(null);
|
void operator<<(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Disable conversion to int if T has an overloaded operator<< which is a free
|
// Disable conversion to int if T has an overloaded operator<< which is a free
|
||||||
// function (not a member of std::ostream).
|
// function (not a member of std::ostream).
|
||||||
template <typename T>
|
template <typename T, typename Char>
|
||||||
class convert_to_int<T, true> {
|
class convert_to_int<T, Char, true> {
|
||||||
private:
|
private:
|
||||||
template <typename U>
|
template <typename U>
|
||||||
static decltype(
|
static decltype(
|
||||||
std::declval<test_stream&>() << std::declval<U>(), std::true_type())
|
internal::declval<test_stream<Char>&>()
|
||||||
test(int);
|
<< internal::declval<U>(), std::true_type()) test(int);
|
||||||
|
|
||||||
template <typename>
|
template <typename>
|
||||||
static std::false_type test(...);
|
static std::false_type test(...);
|
||||||
|
|
||||||
|
typedef decltype(test<T>(0)) result;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const bool value = !decltype(test<T>(0))::value;
|
static const bool value = !result::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Write the content of buf to os.
|
// Write the content of buf to os.
|
||||||
@ -104,8 +107,8 @@ struct format_enum<T,
|
|||||||
// Formats an object of type T that has an overloaded ostream operator<<.
|
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||||
template <typename T, typename Char>
|
template <typename T, typename Char>
|
||||||
struct formatter<T, Char,
|
struct formatter<T, Char,
|
||||||
typename std::enable_if<
|
typename std::enable_if<!internal::format_type<
|
||||||
!internal::format_type<buffer_context_t<Char>, T>::value>::type>
|
typename buffer_context<Char>::type, T>::value>::type>
|
||||||
: formatter<basic_string_view<Char>, Char> {
|
: formatter<basic_string_view<Char>, Char> {
|
||||||
|
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
@ -130,7 +133,7 @@ inline void vprint(std::ostream &os, string_view format_str, format_args args) {
|
|||||||
|
|
||||||
**Example**::
|
**Example**::
|
||||||
|
|
||||||
print(cerr, "Don't {}!", "panic");
|
fmt::print(cerr, "Don't {}!", "panic");
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
|
|||||||
@ -71,7 +71,8 @@ fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT {
|
|||||||
|
|
||||||
fmt::BufferedFile::BufferedFile(
|
fmt::BufferedFile::BufferedFile(
|
||||||
fmt::cstring_view filename, fmt::cstring_view mode) {
|
fmt::cstring_view filename, fmt::cstring_view mode) {
|
||||||
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0);
|
FMT_RETRY_VAL(file_,
|
||||||
|
FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), FMT_NULL);
|
||||||
if (!file_)
|
if (!file_)
|
||||||
FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str()));
|
FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str()));
|
||||||
}
|
}
|
||||||
@ -180,8 +181,8 @@ void fmt::File::dup2(int fd) {
|
|||||||
int result = 0;
|
int result = 0;
|
||||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||||
if (result == -1) {
|
if (result == -1) {
|
||||||
throw system_error(errno,
|
FMT_THROW(system_error(errno,
|
||||||
"cannot duplicate file descriptor {} to {}", fd_, fd);
|
"cannot duplicate file descriptor {} to {}", fd_, fd));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -134,7 +134,7 @@ class BufferedFile {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructs a BufferedFile object which doesn't represent any file.
|
// Constructs a BufferedFile object which doesn't represent any file.
|
||||||
BufferedFile() FMT_NOEXCEPT : file_(0) {}
|
BufferedFile() FMT_NOEXCEPT : file_(FMT_NULL) {}
|
||||||
|
|
||||||
// Destroys the object closing the file it represents if any.
|
// Destroys the object closing the file it represents if any.
|
||||||
FMT_API ~BufferedFile() FMT_DTOR_NOEXCEPT;
|
FMT_API ~BufferedFile() FMT_DTOR_NOEXCEPT;
|
||||||
@ -353,7 +353,7 @@ class File {
|
|||||||
long getpagesize();
|
long getpagesize();
|
||||||
|
|
||||||
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
|
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
|
||||||
!defined(__ANDROID__) && !defined(__CYGWIN__)
|
!defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__)
|
||||||
# define FMT_LOCALE
|
# define FMT_LOCALE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ namespace internal {
|
|||||||
// Checks if a value fits in int - used to avoid warnings about comparing
|
// Checks if a value fits in int - used to avoid warnings about comparing
|
||||||
// signed and unsigned integers.
|
// signed and unsigned integers.
|
||||||
template <bool IsSigned>
|
template <bool IsSigned>
|
||||||
struct IntChecker {
|
struct int_checker {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static bool fits_in_int(T value) {
|
static bool fits_in_int(T value) {
|
||||||
unsigned max = std::numeric_limits<int>::max();
|
unsigned max = std::numeric_limits<int>::max();
|
||||||
@ -29,7 +29,7 @@ struct IntChecker {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct IntChecker<true> {
|
struct int_checker<true> {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static bool fits_in_int(T value) {
|
static bool fits_in_int(T value) {
|
||||||
return value >= std::numeric_limits<int>::min() &&
|
return value >= std::numeric_limits<int>::min() &&
|
||||||
@ -38,12 +38,12 @@ struct IntChecker<true> {
|
|||||||
static bool fits_in_int(int) { return true; }
|
static bool fits_in_int(int) { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class PrintfPrecisionHandler {
|
class printf_precision_handler: public function<int> {
|
||||||
public:
|
public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<std::is_integral<T>::value, int>::type
|
typename std::enable_if<std::is_integral<T>::value, int>::type
|
||||||
operator()(T value) {
|
operator()(T value) {
|
||||||
if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
||||||
FMT_THROW(format_error("number is too big"));
|
FMT_THROW(format_error("number is too big"));
|
||||||
return static_cast<int>(value);
|
return static_cast<int>(value);
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ class PrintfPrecisionHandler {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// An argument visitor that returns true iff arg is a zero integer.
|
// An argument visitor that returns true iff arg is a zero integer.
|
||||||
class IsZeroInt {
|
class is_zero_int: public function<bool> {
|
||||||
public:
|
public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<std::is_integral<T>::value, bool>::type
|
typename std::enable_if<std::is_integral<T>::value, bool>::type
|
||||||
@ -73,11 +73,11 @@ struct make_unsigned_or_bool : std::make_unsigned<T> {};
|
|||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct make_unsigned_or_bool<bool> {
|
struct make_unsigned_or_bool<bool> {
|
||||||
using type = bool;
|
typedef bool type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename Context>
|
template <typename T, typename Context>
|
||||||
class ArgConverter {
|
class arg_converter: public function<void> {
|
||||||
private:
|
private:
|
||||||
typedef typename Context::char_type Char;
|
typedef typename Context::char_type Char;
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ class ArgConverter {
|
|||||||
typename Context::char_type type_;
|
typename Context::char_type type_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ArgConverter(basic_arg<Context> &arg, Char type)
|
arg_converter(basic_arg<Context> &arg, Char type)
|
||||||
: arg_(arg), type_(type) {}
|
: arg_(arg), type_(type) {}
|
||||||
|
|
||||||
void operator()(bool value) {
|
void operator()(bool value) {
|
||||||
@ -134,19 +134,19 @@ class ArgConverter {
|
|||||||
// unsigned).
|
// unsigned).
|
||||||
template <typename T, typename Context, typename Char>
|
template <typename T, typename Context, typename Char>
|
||||||
void convert_arg(basic_arg<Context> &arg, Char type) {
|
void convert_arg(basic_arg<Context> &arg, Char type) {
|
||||||
visit(ArgConverter<T, Context>(arg, type), arg);
|
visit(arg_converter<T, Context>(arg, type), arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts an integer argument to char for printf.
|
// Converts an integer argument to char for printf.
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
class CharConverter {
|
class char_converter: public function<void> {
|
||||||
private:
|
private:
|
||||||
basic_arg<Context> &arg_;
|
basic_arg<Context> &arg_;
|
||||||
|
|
||||||
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
|
FMT_DISALLOW_COPY_AND_ASSIGN(char_converter);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CharConverter(basic_arg<Context> &arg) : arg_(arg) {}
|
explicit char_converter(basic_arg<Context> &arg) : arg_(arg) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<std::is_integral<T>::value>::type
|
typename std::enable_if<std::is_integral<T>::value>::type
|
||||||
@ -163,16 +163,16 @@ class CharConverter {
|
|||||||
// 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.
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
class PrintfWidthHandler {
|
class printf_width_handler: public function<unsigned> {
|
||||||
private:
|
private:
|
||||||
typedef basic_format_specs<Char> format_specs;
|
typedef basic_format_specs<Char> format_specs;
|
||||||
|
|
||||||
format_specs &spec_;
|
format_specs &spec_;
|
||||||
|
|
||||||
FMT_DISALLOW_COPY_AND_ASSIGN(PrintfWidthHandler);
|
FMT_DISALLOW_COPY_AND_ASSIGN(printf_width_handler);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PrintfWidthHandler(format_specs &spec) : spec_(spec) {}
|
explicit printf_width_handler(format_specs &spec) : spec_(spec) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<std::is_integral<T>::value, unsigned>::type
|
typename std::enable_if<std::is_integral<T>::value, unsigned>::type
|
||||||
@ -213,12 +213,13 @@ class basic_printf_context;
|
|||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
class printf_arg_formatter : public internal::arg_formatter_base<Range> {
|
class printf_arg_formatter:
|
||||||
|
public internal::function<void>, public internal::arg_formatter_base<Range> {
|
||||||
private:
|
private:
|
||||||
using char_type = typename Range::value_type;
|
typedef typename Range::value_type char_type;
|
||||||
using iterator = decltype(std::declval<Range>().begin());
|
typedef decltype(internal::declval<Range>().begin()) iterator;
|
||||||
using base = internal::arg_formatter_base<Range>;
|
typedef internal::arg_formatter_base<Range> base;
|
||||||
using context_type = basic_printf_context<iterator, char_type>;
|
typedef basic_printf_context<iterator, char_type> context_type;
|
||||||
|
|
||||||
context_type &context_;
|
context_type &context_;
|
||||||
|
|
||||||
@ -228,7 +229,7 @@ class printf_arg_formatter : public internal::arg_formatter_base<Range> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using format_specs = typename base::format_specs;
|
typedef typename base::format_specs format_specs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
@ -290,7 +291,7 @@ class printf_arg_formatter : public internal::arg_formatter_base<Range> {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
struct printf_formatter {
|
struct printf_formatter {
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
auto parse(ParseContext &ctx) { return ctx.begin(); }
|
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); }
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const T &value, FormatContext &ctx) -> decltype(ctx.begin()) {
|
auto format(const T &value, FormatContext &ctx) -> decltype(ctx.begin()) {
|
||||||
@ -306,16 +307,16 @@ class basic_printf_context :
|
|||||||
OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> {
|
OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> {
|
||||||
public:
|
public:
|
||||||
/** The character type for the output. */
|
/** The character type for the output. */
|
||||||
using char_type = Char;
|
typedef Char char_type;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using formatter_type = printf_formatter<T>;
|
struct formatter_type { typedef printf_formatter<T> type; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using base = internal::context_base<OutputIt, basic_printf_context, Char>;
|
typedef internal::context_base<OutputIt, basic_printf_context, Char> base;
|
||||||
using format_arg = typename base::format_arg;
|
typedef typename base::format_arg format_arg;
|
||||||
using format_specs = basic_format_specs<char_type>;
|
typedef basic_format_specs<char_type> format_specs;
|
||||||
using iterator = internal::null_terminating_iterator<char_type>;
|
typedef internal::null_terminating_iterator<char_type> iterator;
|
||||||
|
|
||||||
void parse_flags(format_specs &spec, iterator &it);
|
void parse_flags(format_specs &spec, iterator &it);
|
||||||
|
|
||||||
@ -417,7 +418,7 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
|
|||||||
} else if (*it == '*') {
|
} else if (*it == '*') {
|
||||||
++it;
|
++it;
|
||||||
spec.width_ =
|
spec.width_ =
|
||||||
visit(internal::PrintfWidthHandler<char_type>(spec), get_arg(it));
|
visit(internal::printf_width_handler<char_type>(spec), get_arg(it));
|
||||||
}
|
}
|
||||||
return arg_index;
|
return arg_index;
|
||||||
}
|
}
|
||||||
@ -453,14 +454,14 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
|
|||||||
} else if (*it == '*') {
|
} else if (*it == '*') {
|
||||||
++it;
|
++it;
|
||||||
spec.precision_ =
|
spec.precision_ =
|
||||||
visit(internal::PrintfPrecisionHandler(), get_arg(it));
|
visit(internal::printf_precision_handler(), get_arg(it));
|
||||||
} else {
|
} else {
|
||||||
spec.precision_ = 0;
|
spec.precision_ = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
format_arg arg = get_arg(it, arg_index);
|
format_arg arg = get_arg(it, arg_index);
|
||||||
if (spec.flag(HASH_FLAG) && visit(internal::IsZeroInt(), arg))
|
if (spec.flag(HASH_FLAG) && visit(internal::is_zero_int(), arg))
|
||||||
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
|
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
|
||||||
if (spec.fill_ == '0') {
|
if (spec.fill_ == '0') {
|
||||||
if (arg.is_arithmetic())
|
if (arg.is_arithmetic())
|
||||||
@ -514,7 +515,7 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
|
|||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
// TODO: handle wchar_t
|
// TODO: handle wchar_t
|
||||||
visit(internal::CharConverter<basic_printf_context>(arg), arg);
|
visit(internal::char_converter<basic_printf_context>(arg), arg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -534,10 +535,12 @@ void printf(internal::basic_buffer<Char> &buf, basic_string_view<Char> format,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Buffer>
|
template <typename Buffer>
|
||||||
using printf_context = basic_printf_context<
|
struct printf_context {
|
||||||
std::back_insert_iterator<Buffer>, typename Buffer::value_type>;
|
typedef basic_printf_context<
|
||||||
|
std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;
|
||||||
|
};
|
||||||
|
|
||||||
using printf_args = basic_format_args<printf_context<internal::buffer>>;
|
typedef basic_format_args<printf_context<internal::buffer>::type> printf_args;
|
||||||
|
|
||||||
inline std::string vsprintf(string_view format, printf_args args) {
|
inline std::string vsprintf(string_view format, printf_args args) {
|
||||||
memory_buffer buffer;
|
memory_buffer buffer;
|
||||||
@ -557,12 +560,12 @@ inline std::string vsprintf(string_view format, printf_args args) {
|
|||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline std::string sprintf(string_view format_str, const Args & ... args) {
|
inline std::string sprintf(string_view format_str, const Args & ... args) {
|
||||||
return vsprintf(format_str,
|
return vsprintf(format_str,
|
||||||
make_args<printf_context<internal::buffer>>(args...));
|
make_args<typename printf_context<internal::buffer>::type>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::wstring vsprintf(
|
inline std::wstring vsprintf(
|
||||||
wstring_view format,
|
wstring_view format,
|
||||||
basic_format_args<printf_context<internal::wbuffer>> args) {
|
basic_format_args<printf_context<internal::wbuffer>::type> args) {
|
||||||
wmemory_buffer buffer;
|
wmemory_buffer buffer;
|
||||||
printf(buffer, format, args);
|
printf(buffer, format, args);
|
||||||
return to_string(buffer);
|
return to_string(buffer);
|
||||||
@ -570,7 +573,8 @@ inline std::wstring vsprintf(
|
|||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline std::wstring sprintf(wstring_view format_str, const Args & ... args) {
|
inline std::wstring sprintf(wstring_view format_str, const Args & ... args) {
|
||||||
auto vargs = make_args<printf_context<internal::wbuffer>>(args...);
|
auto vargs = make_args<
|
||||||
|
typename printf_context<internal::wbuffer>::type>(args...);
|
||||||
return vsprintf(format_str, vargs);
|
return vsprintf(format_str, vargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,7 +597,8 @@ inline int vfprintf(std::FILE *f, string_view format, printf_args args) {
|
|||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args) {
|
inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args) {
|
||||||
auto vargs = make_args<printf_context<internal::buffer>>(args...);
|
auto vargs = make_args<
|
||||||
|
typename printf_context<internal::buffer>::type>(args...);
|
||||||
return vfprintf(f, format_str, vargs);
|
return vfprintf(f, format_str, vargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -613,7 +618,7 @@ inline int vprintf(string_view format, printf_args args) {
|
|||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline int printf(string_view format_str, const Args & ... args) {
|
inline int printf(string_view format_str, const Args & ... args) {
|
||||||
return vprintf(format_str,
|
return vprintf(format_str,
|
||||||
make_args<printf_context<internal::buffer>>(args...));
|
make_args<typename printf_context<internal::buffer>::type>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int vfprintf(std::ostream &os, string_view format_str,
|
inline int vfprintf(std::ostream &os, string_view format_str,
|
||||||
@ -630,13 +635,14 @@ inline int vfprintf(std::ostream &os, string_view format_str,
|
|||||||
|
|
||||||
**Example**::
|
**Example**::
|
||||||
|
|
||||||
fprintf(cerr, "Don't %s!", "panic");
|
fmt::fprintf(cerr, "Don't %s!", "panic");
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline int fprintf(std::ostream &os, string_view format_str,
|
inline int fprintf(std::ostream &os, string_view format_str,
|
||||||
const Args & ... args) {
|
const Args & ... args) {
|
||||||
auto vargs = make_args<printf_context<internal::buffer>>(args...);
|
auto vargs = make_args<
|
||||||
|
typename printf_context<internal::buffer>::type>(args...);
|
||||||
return vfprintf(os, format_str, vargs);
|
return vfprintf(os, format_str, vargs);
|
||||||
}
|
}
|
||||||
} // namespace fmt
|
} // namespace fmt
|
||||||
|
|||||||
@ -40,6 +40,17 @@ if (FMT_USE_CPP14)
|
|||||||
check_cxx_compiler_flag(-std=c++1y HAVE_STD_CPP1Y_FLAG)
|
check_cxx_compiler_flag(-std=c++1y HAVE_STD_CPP1Y_FLAG)
|
||||||
if (HAVE_STD_CPP1Y_FLAG)
|
if (HAVE_STD_CPP1Y_FLAG)
|
||||||
set(CPP14_FLAG -std=c++1y)
|
set(CPP14_FLAG -std=c++1y)
|
||||||
|
else ()
|
||||||
|
# Fallback on c++11 if c++14 is not available.
|
||||||
|
check_cxx_compiler_flag(-std=c++11 HAVE_STD_CPP11_FLAG)
|
||||||
|
if (HAVE_STD_CPP11_FLAG)
|
||||||
|
set(CPP14_FLAG -std=c++11)
|
||||||
|
else ()
|
||||||
|
check_cxx_compiler_flag(-std=c++0x HAVE_STD_CPP0X_FLAG)
|
||||||
|
if (HAVE_STD_CPP0X_FLAG)
|
||||||
|
set(CPP14_FLAG -std=c++0x)
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - assertion tests
|
||||||
Assertion tests
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2015, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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 "fmt/core.h"
|
#include "fmt/core.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
@ -37,5 +17,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
TEST(AssertTest, Fail) {
|
TEST(AssertTest, Fail) {
|
||||||
EXPECT_DEBUG_DEATH_IF_SUPPORTED(FMT_ASSERT(false, "don't panic!"), "don't panic!");
|
EXPECT_DEBUG_DEATH_IF_SUPPORTED(
|
||||||
|
FMT_ASSERT(false, "don't panic!"), "don't panic!");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,22 +47,12 @@ endfunction ()
|
|||||||
# check if the source file skeleton compiles
|
# check if the source file skeleton compiles
|
||||||
expect_compile("")
|
expect_compile("")
|
||||||
|
|
||||||
# MakeArg doesn't accept [const] volatile char *.
|
|
||||||
expect_compile_error("volatile char s[] = \"test\"; (fmt::internal::MakeArg<char>)(s);")
|
|
||||||
expect_compile_error("const volatile char s[] = \"test\"; (fmt::internal::MakeArg<char>)(s);")
|
|
||||||
|
|
||||||
# MakeArg<char> doesn't accept wchar_t.
|
|
||||||
expect_compile_error("fmt::internal::MakeValue<char>(L'a');")
|
|
||||||
expect_compile_error("fmt::internal::MakeValue<char>(L\"test\");")
|
|
||||||
|
|
||||||
# Writing a wide character to a character stream Writer is forbidden.
|
|
||||||
expect_compile_error("fmt::MemoryWriter() << L'a';")
|
|
||||||
expect_compile_error("fmt::MemoryWriter() << fmt::pad(\"abc\", 5, L' ');")
|
|
||||||
expect_compile_error("fmt::MemoryWriter() << fmt::pad(42, 5, L' ');")
|
|
||||||
|
|
||||||
# Formatting a wide character with a narrow format string is forbidden.
|
# Formatting a wide character with a narrow format string is forbidden.
|
||||||
expect_compile_error("fmt::format(\"{}\", L'a';")
|
expect_compile_error("fmt::format(\"{}\", L'a';")
|
||||||
|
|
||||||
|
# Formatting a wide string with a narrow format string is forbidden.
|
||||||
|
expect_compile_error("fmt::format(\"{}\", L\"foo\";")
|
||||||
|
|
||||||
# Make sure that compiler features detected in the header
|
# Make sure that compiler features detected in the header
|
||||||
# match the features detected in CMake.
|
# match the features detected in CMake.
|
||||||
if (SUPPORTS_USER_DEFINED_LITERALS)
|
if (SUPPORTS_USER_DEFINED_LITERALS)
|
||||||
|
|||||||
@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
Tests of container utilities
|
|
||||||
|
|
||||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
For the license information refer to format.h.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fmt/container.h"
|
|
||||||
#include "gtest/gtest.h"
|
|
||||||
|
|
||||||
using fmt::internal::ContainerBuffer;
|
|
||||||
|
|
||||||
TEST(ContainerBufferTest, Empty) {
|
|
||||||
std::string data;
|
|
||||||
ContainerBuffer<std::string> buffer(data);
|
|
||||||
EXPECT_EQ(0u, buffer.size());
|
|
||||||
EXPECT_EQ(0u, buffer.capacity());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ContainerBufferTest, Reserve) {
|
|
||||||
std::string data;
|
|
||||||
ContainerBuffer<std::string> buffer(data);
|
|
||||||
std::size_t capacity = std::string().capacity() + 10;
|
|
||||||
buffer.reserve(capacity);
|
|
||||||
EXPECT_EQ(0u, buffer.size());
|
|
||||||
EXPECT_EQ(capacity, buffer.capacity());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ContainerBufferTest, Resize) {
|
|
||||||
std::string data;
|
|
||||||
ContainerBuffer<std::string> buffer(data);
|
|
||||||
std::size_t size = std::string().capacity() + 10;
|
|
||||||
buffer.resize(size);
|
|
||||||
EXPECT_EQ(size, buffer.size());
|
|
||||||
EXPECT_EQ(size, buffer.capacity());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ContainerBufferTest, Append) {
|
|
||||||
std::string data("Why so");
|
|
||||||
const std::string serious(" serious");
|
|
||||||
ContainerBuffer<std::string> buffer(data);
|
|
||||||
buffer.append(serious.c_str(), serious.c_str() + serious.length());
|
|
||||||
EXPECT_EQ("Why so serious", data);
|
|
||||||
EXPECT_EQ(data.length(), buffer.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BasicContainerWriterTest, String) {
|
|
||||||
std::string data;
|
|
||||||
fmt::BasicContainerWriter<std::string> out(data);
|
|
||||||
out << "The answer is " << 42 << "\n";
|
|
||||||
EXPECT_EQ("The answer is 42\n", data);
|
|
||||||
EXPECT_EQ(17u, out.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BasicContainerWriterTest, WString) {
|
|
||||||
std::wstring data;
|
|
||||||
fmt::BasicContainerWriter<std::wstring> out(data);
|
|
||||||
out << "The answer is " << 42 << "\n";
|
|
||||||
EXPECT_EQ(L"The answer is 42\n", data);
|
|
||||||
EXPECT_EQ(17u, out.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BasicContainerWriterTest, Vector) {
|
|
||||||
std::vector<char> data;
|
|
||||||
fmt::BasicContainerWriter<std::vector<char> > out(data);
|
|
||||||
out << "The answer is " << 42 << "\n";
|
|
||||||
EXPECT_EQ(17u, data.size());
|
|
||||||
EXPECT_EQ(out.size(), data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BasicContainerWriterTest, StringAppend) {
|
|
||||||
std::string data("The");
|
|
||||||
fmt::BasicContainerWriter<std::string> out(data);
|
|
||||||
EXPECT_EQ(3u, data.size());
|
|
||||||
EXPECT_EQ(3u, out.size());
|
|
||||||
out << " answer is " << 42 << "\n";
|
|
||||||
EXPECT_EQ("The answer is 42\n", data);
|
|
||||||
EXPECT_EQ(17u, out.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BasicContainerWriterTest, VectorAppend) {
|
|
||||||
std::vector<char> data;
|
|
||||||
data.push_back('T');
|
|
||||||
data.push_back('h');
|
|
||||||
data.push_back('e');
|
|
||||||
fmt::BasicContainerWriter<std::vector<char> > out(data);
|
|
||||||
EXPECT_EQ(3u, data.size());
|
|
||||||
EXPECT_EQ(3u, out.size());
|
|
||||||
out << " answer is " << 42 << "\n";
|
|
||||||
EXPECT_EQ(17u, data.size());
|
|
||||||
EXPECT_EQ(17u, out.size());
|
|
||||||
}
|
|
||||||
@ -1,28 +1,22 @@
|
|||||||
/*
|
// Formatting library for C++ - custom argument formatter tests
|
||||||
Custom argument formatter tests
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
Copyright (c) 2016, Victor Zverovich
|
#include "fmt/format.h"
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
For the license information refer to format.h.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fmt/printf.h"
|
|
||||||
#include "gtest-extra.h"
|
#include "gtest-extra.h"
|
||||||
|
|
||||||
using fmt::printf_arg_formatter;
|
|
||||||
|
|
||||||
// A custom argument formatter that doesn't print `-` for floating-point values
|
// A custom argument formatter that doesn't print `-` for floating-point values
|
||||||
// rounded to 0.
|
// rounded to 0.
|
||||||
class CustomArgFormatter :
|
class custom_arg_formatter :
|
||||||
public fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>> {
|
public fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>> {
|
||||||
public:
|
public:
|
||||||
using range = fmt::back_insert_range<fmt::internal::buffer>;
|
typedef fmt::back_insert_range<fmt::internal::buffer> range;
|
||||||
using iterator = decltype(std::declval<range>().begin());
|
typedef fmt::arg_formatter<range> base;
|
||||||
using base = fmt::arg_formatter<range>;
|
|
||||||
|
|
||||||
CustomArgFormatter(fmt::basic_context<iterator, char> &ctx,
|
custom_arg_formatter(fmt::context &ctx, fmt::format_specs &s)
|
||||||
fmt::format_specs &s)
|
|
||||||
: base(ctx, s) {}
|
: base(ctx, s) {}
|
||||||
|
|
||||||
using base::operator();
|
using base::operator();
|
||||||
@ -37,7 +31,7 @@ class CustomArgFormatter :
|
|||||||
std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) {
|
std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) {
|
||||||
fmt::memory_buffer buffer;
|
fmt::memory_buffer buffer;
|
||||||
// Pass custom argument formatter as a template arg to vwrite.
|
// Pass custom argument formatter as a template arg to vwrite.
|
||||||
fmt::do_vformat_to<CustomArgFormatter>(buffer, format_str, args);
|
fmt::vformat_to<custom_arg_formatter>(buffer, format_str, args);
|
||||||
return std::string(buffer.data(), buffer.size());
|
return std::string(buffer.data(), buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,35 +1,15 @@
|
|||||||
/*
|
// Formatting library for C++ - formatting library implementation tests
|
||||||
Formatting library implementation tests.
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2012-2014, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define FMT_NOEXCEPT
|
#define FMT_NOEXCEPT
|
||||||
#undef FMT_SHARED
|
#undef FMT_SHARED
|
||||||
#include "test-assert.h"
|
#include "test-assert.h"
|
||||||
|
|
||||||
// Include format.cc instead of format.h to test implementation-specific stuff.
|
// Include format.cc instead of format.h to test implementation.
|
||||||
#include "fmt/format.cc"
|
#include "fmt/format.cc"
|
||||||
#include "fmt/printf.h"
|
#include "fmt/printf.h"
|
||||||
|
|
||||||
@ -44,7 +24,7 @@
|
|||||||
#undef max
|
#undef max
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct ValueExtractor {
|
struct ValueExtractor: fmt::internal::function<T> {
|
||||||
T operator()(T value) {
|
T operator()(T value) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -59,7 +39,7 @@ struct ValueExtractor {
|
|||||||
TEST(FormatTest, ArgConverter) {
|
TEST(FormatTest, ArgConverter) {
|
||||||
long long value = std::numeric_limits<long long>::max();
|
long long value = std::numeric_limits<long long>::max();
|
||||||
auto arg = fmt::internal::make_arg<fmt::context>(value);
|
auto arg = fmt::internal::make_arg<fmt::context>(value);
|
||||||
visit(fmt::internal::ArgConverter<long long, fmt::context>(arg, 'd'), arg);
|
visit(fmt::internal::arg_converter<long long, fmt::context>(arg, 'd'), arg);
|
||||||
EXPECT_EQ(value, visit(ValueExtractor<long long>(), arg));
|
EXPECT_EQ(value, visit(ValueExtractor<long long>(), arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +94,7 @@ TEST(FormatTest, FormatErrorCode) {
|
|||||||
{
|
{
|
||||||
fmt::memory_buffer buffer;
|
fmt::memory_buffer buffer;
|
||||||
std::string prefix(
|
std::string prefix(
|
||||||
fmt::internal::INLINE_BUFFER_SIZE - msg.size() - sep.size() + 1, 'x');
|
fmt::inline_buffer_size - msg.size() - sep.size() + 1, 'x');
|
||||||
fmt::format_error_code(buffer, 42, prefix);
|
fmt::format_error_code(buffer, 42, prefix);
|
||||||
EXPECT_EQ(msg, to_string(buffer));
|
EXPECT_EQ(msg, to_string(buffer));
|
||||||
}
|
}
|
||||||
@ -124,10 +104,10 @@ TEST(FormatTest, FormatErrorCode) {
|
|||||||
msg = fmt::format("error {}", codes[i]);
|
msg = fmt::format("error {}", codes[i]);
|
||||||
fmt::memory_buffer buffer;
|
fmt::memory_buffer buffer;
|
||||||
std::string prefix(
|
std::string prefix(
|
||||||
fmt::internal::INLINE_BUFFER_SIZE - msg.size() - sep.size(), 'x');
|
fmt::inline_buffer_size - msg.size() - sep.size(), 'x');
|
||||||
fmt::format_error_code(buffer, codes[i], prefix);
|
fmt::format_error_code(buffer, codes[i], prefix);
|
||||||
EXPECT_EQ(prefix + sep + msg, to_string(buffer));
|
EXPECT_EQ(prefix + sep + msg, to_string(buffer));
|
||||||
std::size_t size = fmt::internal::INLINE_BUFFER_SIZE;
|
std::size_t size = fmt::inline_buffer_size;
|
||||||
EXPECT_EQ(size, buffer.size());
|
EXPECT_EQ(size, buffer.size());
|
||||||
buffer.resize(0);
|
buffer.resize(0);
|
||||||
// Test with a message that doesn't fit into the buffer.
|
// Test with a message that doesn't fit into the buffer.
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - formatting library tests
|
||||||
Formatting library tests.
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2012-2014, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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 <cctype>
|
#include <cctype>
|
||||||
#include <cfloat>
|
#include <cfloat>
|
||||||
@ -89,7 +69,7 @@ void std_format(long double value, std::wstring &result) {
|
|||||||
template <typename Char, typename T>
|
template <typename Char, typename T>
|
||||||
::testing::AssertionResult check_write(const T &value, const char *type) {
|
::testing::AssertionResult check_write(const T &value, const char *type) {
|
||||||
fmt::basic_memory_buffer<Char> buffer;
|
fmt::basic_memory_buffer<Char> buffer;
|
||||||
using range = fmt::back_insert_range<fmt::internal::basic_buffer<Char>>;
|
typedef fmt::back_insert_range<fmt::internal::basic_buffer<Char>> range;
|
||||||
fmt::basic_writer<range> writer(buffer);
|
fmt::basic_writer<range> writer(buffer);
|
||||||
writer.write(value);
|
writer.write(value);
|
||||||
std::basic_string<Char> actual = to_string(buffer);
|
std::basic_string<Char> actual = to_string(buffer);
|
||||||
@ -137,6 +117,8 @@ TEST(StringViewTest, Ctor) {
|
|||||||
EXPECT_EQ(4u, string_view(std::string("defg")).size());
|
EXPECT_EQ(4u, string_view(std::string("defg")).size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GCC 4.6 doesn't have std::is_copy_*.
|
||||||
|
#if FMT_GCC_VERSION && FMT_GCC_VERSION >= 407
|
||||||
TEST(WriterTest, NotCopyConstructible) {
|
TEST(WriterTest, NotCopyConstructible) {
|
||||||
EXPECT_FALSE(std::is_copy_constructible<fmt::writer>::value);
|
EXPECT_FALSE(std::is_copy_constructible<fmt::writer>::value);
|
||||||
}
|
}
|
||||||
@ -144,6 +126,7 @@ TEST(WriterTest, NotCopyConstructible) {
|
|||||||
TEST(WriterTest, NotCopyAssignable) {
|
TEST(WriterTest, NotCopyAssignable) {
|
||||||
EXPECT_FALSE(std::is_copy_assignable<fmt::writer>::value);
|
EXPECT_FALSE(std::is_copy_assignable<fmt::writer>::value);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
TEST(WriterTest, Data) {
|
TEST(WriterTest, Data) {
|
||||||
memory_buffer buf;
|
memory_buffer buf;
|
||||||
@ -209,11 +192,11 @@ TEST(WriterTest, WriteDoubleWithFilledBuffer) {
|
|||||||
memory_buffer buf;
|
memory_buffer buf;
|
||||||
fmt::writer writer(buf);
|
fmt::writer writer(buf);
|
||||||
// Fill the buffer.
|
// Fill the buffer.
|
||||||
for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE; ++i)
|
for (int i = 0; i < fmt::inline_buffer_size; ++i)
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writer.write(1.2);
|
writer.write(1.2);
|
||||||
fmt::string_view sv(buf.data(), buf.size());
|
fmt::string_view sv(buf.data(), buf.size());
|
||||||
sv.remove_prefix(fmt::internal::INLINE_BUFFER_SIZE);
|
sv.remove_prefix(fmt::inline_buffer_size);
|
||||||
EXPECT_EQ("1.2", sv);
|
EXPECT_EQ("1.2", sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,9 +442,9 @@ TEST(FormatterTest, ManyArgs) {
|
|||||||
format_error, "argument index out of range");
|
format_error, "argument index out of range");
|
||||||
EXPECT_THROW_MSG(TestFormat<21>::format("{21}"),
|
EXPECT_THROW_MSG(TestFormat<21>::format("{21}"),
|
||||||
format_error, "argument index out of range");
|
format_error, "argument index out of range");
|
||||||
enum { MAX_PACKED_ARGS = fmt::internal::MAX_PACKED_ARGS };
|
enum { max_packed_args = fmt::internal::max_packed_args };
|
||||||
std::string format_str = fmt::format("{{{}}}", MAX_PACKED_ARGS + 1);
|
std::string format_str = fmt::format("{{{}}}", max_packed_args + 1);
|
||||||
EXPECT_THROW_MSG(TestFormat<MAX_PACKED_ARGS>::format(format_str),
|
EXPECT_THROW_MSG(TestFormat<max_packed_args>::format(format_str),
|
||||||
format_error, "argument index out of range");
|
format_error, "argument index out of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,6 +532,7 @@ TEST(FormatterTest, NumericAlign) {
|
|||||||
format_error, "format specifier requires numeric argument");
|
format_error, "format specifier requires numeric argument");
|
||||||
EXPECT_THROW_MSG(format("{0:=8}", reinterpret_cast<void*>(0xface)),
|
EXPECT_THROW_MSG(format("{0:=8}", reinterpret_cast<void*>(0xface)),
|
||||||
format_error, "format specifier requires numeric argument");
|
format_error, "format specifier requires numeric argument");
|
||||||
|
EXPECT_EQ(" 1", fmt::format("{:= }", 1.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, CenterAlign) {
|
TEST(FormatterTest, CenterAlign) {
|
||||||
@ -1202,7 +1186,9 @@ TEST(FormatterTest, FormatPointer) {
|
|||||||
EXPECT_EQ("0x" + std::string(sizeof(void*) * CHAR_BIT / 4, 'f'),
|
EXPECT_EQ("0x" + std::string(sizeof(void*) * CHAR_BIT / 4, 'f'),
|
||||||
format("{0}", reinterpret_cast<void*>(~uintptr_t())));
|
format("{0}", reinterpret_cast<void*>(~uintptr_t())));
|
||||||
EXPECT_EQ("0x1234", format("{}", fmt::ptr(reinterpret_cast<int*>(0x1234))));
|
EXPECT_EQ("0x1234", format("{}", fmt::ptr(reinterpret_cast<int*>(0x1234))));
|
||||||
EXPECT_EQ("0x0", format("{}", nullptr));
|
#if FMT_USE_NULLPTR
|
||||||
|
EXPECT_EQ("0x0", format("{}", FMT_NULL));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, FormatString) {
|
TEST(FormatterTest, FormatString) {
|
||||||
@ -1213,6 +1199,30 @@ TEST(FormatterTest, FormatStringView) {
|
|||||||
EXPECT_EQ("test", format("{0}", string_view("test")));
|
EXPECT_EQ("test", format("{0}", string_view("test")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef FMT_USE_STD_STRING_VIEW
|
||||||
|
TEST(FormatterTest, FormatStringView) {
|
||||||
|
EXPECT_EQ("test", format("{0}", std::string_view("test")));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct ConvertibleToString {
|
||||||
|
std::string s;
|
||||||
|
ConvertibleToString() : s("foo") {}
|
||||||
|
operator const std::string &() const { return s; }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(FormatterTest, FormatConvertibleToString) {
|
||||||
|
EXPECT_EQ("foo", format("{}", ConvertibleToString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ConvertibleToStringView {
|
||||||
|
operator fmt::string_view() const { return "foo"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(FormatterTest, FormatConvertibleToStringView) {
|
||||||
|
EXPECT_EQ("foo", format("{}", ConvertibleToStringView()));
|
||||||
|
}
|
||||||
|
|
||||||
namespace fmt {
|
namespace fmt {
|
||||||
template <>
|
template <>
|
||||||
struct formatter<Date> {
|
struct formatter<Date> {
|
||||||
@ -1224,7 +1234,7 @@ struct formatter<Date> {
|
|||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto format(const Date &d, context &ctx) {
|
auto format(const Date &d, context &ctx) -> decltype(ctx.begin()) {
|
||||||
format_to(ctx.begin(), "{}-{}-{}", d.year(), d.month(), d.day());
|
format_to(ctx.begin(), "{}-{}-{}", d.year(), d.month(), d.day());
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
@ -1242,7 +1252,7 @@ class Answer {};
|
|||||||
namespace fmt {
|
namespace fmt {
|
||||||
template <>
|
template <>
|
||||||
struct formatter<Answer> : formatter<int> {
|
struct formatter<Answer> : formatter<int> {
|
||||||
auto format(Answer, fmt::context &ctx) {
|
auto format(Answer, fmt::context &ctx) -> decltype(ctx.begin()) {
|
||||||
return formatter<int>::format(42, ctx);
|
return formatter<int>::format(42, ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1396,7 +1406,7 @@ TEST(FormatTest, Print) {
|
|||||||
|
|
||||||
#if FMT_USE_FILE_DESCRIPTORS
|
#if FMT_USE_FILE_DESCRIPTORS
|
||||||
TEST(FormatTest, PrintColored) {
|
TEST(FormatTest, PrintColored) {
|
||||||
EXPECT_WRITE(stdout, fmt::print_colored(fmt::RED, "Hello, {}!\n", "world"),
|
EXPECT_WRITE(stdout, fmt::print_colored(fmt::red, "Hello, {}!\n", "world"),
|
||||||
"\x1b[31mHello, world!\n\x1b[0m");
|
"\x1b[31mHello, world!\n\x1b[0m");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1423,7 +1433,7 @@ TEST(FormatTest, JoinArg) {
|
|||||||
EXPECT_EQ(L"(1, 2, 3)", format(L"({})", join(v1, v1 + 3, L", ")));
|
EXPECT_EQ(L"(1, 2, 3)", format(L"({})", join(v1, v1 + 3, L", ")));
|
||||||
EXPECT_EQ("1, 2, 3", format("{0:{1}}", join(v1, v1 + 3, ", "), 1));
|
EXPECT_EQ("1, 2, 3", format("{0:{1}}", join(v1, v1 + 3, ", "), 1));
|
||||||
|
|
||||||
#if FMT_HAS_GXX_CXX11
|
#if FMT_USE_TRAILING_RETURN && (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 405)
|
||||||
EXPECT_EQ("(1, 2, 3)", format("({})", join(v1, ", ")));
|
EXPECT_EQ("(1, 2, 3)", format("({})", join(v1, ", ")));
|
||||||
EXPECT_EQ("(+01.20, +03.40)", format("({:+06.2f})", join(v2, ", ")));
|
EXPECT_EQ("(+01.20, +03.40)", format("({:+06.2f})", join(v2, ", ")));
|
||||||
#endif
|
#endif
|
||||||
@ -1500,6 +1510,12 @@ TEST(LiteralsTest, NamedArg) {
|
|||||||
fmt::arg(L"third", 99)),
|
fmt::arg(L"third", 99)),
|
||||||
udl_a_w);
|
udl_a_w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(FormatTest, UdlTemplate) {
|
||||||
|
EXPECT_EQ("foo", "foo"_format());
|
||||||
|
EXPECT_EQ(" 42", "{0:10}"_format(42));
|
||||||
|
EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), 42));
|
||||||
|
}
|
||||||
#endif // FMT_USE_USER_DEFINED_LITERALS
|
#endif // FMT_USE_USER_DEFINED_LITERALS
|
||||||
|
|
||||||
enum TestEnum { A };
|
enum TestEnum { A };
|
||||||
@ -1508,7 +1524,7 @@ TEST(FormatTest, Enum) {
|
|||||||
EXPECT_EQ("0", fmt::format("{}", A));
|
EXPECT_EQ("0", fmt::format("{}", A));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_USE_STRONG_ENUMS
|
#if FMT_HAS_FEATURE(cxx_strong_enums)
|
||||||
enum TestFixedEnum : short { B };
|
enum TestFixedEnum : short { B };
|
||||||
|
|
||||||
TEST(FormatTest, FixedEnum) {
|
TEST(FormatTest, FixedEnum) {
|
||||||
@ -1516,16 +1532,17 @@ TEST(FormatTest, FixedEnum) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using buffer_range = fmt::back_insert_range<fmt::internal::buffer>;
|
typedef fmt::back_insert_range<fmt::internal::buffer> buffer_range;
|
||||||
|
|
||||||
class mock_arg_formatter :
|
class mock_arg_formatter:
|
||||||
|
public fmt::internal::function<void>,
|
||||||
public fmt::internal::arg_formatter_base<buffer_range> {
|
public fmt::internal::arg_formatter_base<buffer_range> {
|
||||||
private:
|
private:
|
||||||
MOCK_METHOD1(call, void (int value));
|
MOCK_METHOD1(call, void (int value));
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using base = fmt::internal::arg_formatter_base<buffer_range>;
|
typedef fmt::internal::arg_formatter_base<buffer_range> base;
|
||||||
using range = buffer_range;
|
typedef buffer_range range;
|
||||||
|
|
||||||
mock_arg_formatter(fmt::context &ctx, fmt::format_specs &s)
|
mock_arg_formatter(fmt::context &ctx, fmt::format_specs &s)
|
||||||
: base(fmt::internal::get_container(ctx.begin()), s) {
|
: base(fmt::internal::get_container(ctx.begin()), s) {
|
||||||
@ -1541,7 +1558,7 @@ class mock_arg_formatter :
|
|||||||
|
|
||||||
void custom_vformat(fmt::string_view format_str, fmt::format_args args) {
|
void custom_vformat(fmt::string_view format_str, fmt::format_args args) {
|
||||||
fmt::memory_buffer buffer;
|
fmt::memory_buffer buffer;
|
||||||
fmt::do_vformat_to<mock_arg_formatter>(buffer, format_str, args);
|
fmt::vformat_to<mock_arg_formatter>(buffer, format_str, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
@ -1567,10 +1584,10 @@ struct variant {
|
|||||||
namespace fmt {
|
namespace fmt {
|
||||||
template <>
|
template <>
|
||||||
struct formatter<variant> : dynamic_formatter<> {
|
struct formatter<variant> : dynamic_formatter<> {
|
||||||
auto format(variant value, context& ctx) {
|
auto format(variant value, context& ctx) -> decltype(ctx.begin()) {
|
||||||
if (value.type == variant::INT)
|
if (value.type == variant::INT)
|
||||||
return dynamic_formatter::format(42, ctx);
|
return dynamic_formatter<>::format(42, ctx);
|
||||||
return dynamic_formatter::format("foo", ctx);
|
return dynamic_formatter<>::format("foo", ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1601,14 +1618,9 @@ TEST(FormatTest, DynamicFormatter) {
|
|||||||
format_error, "precision not allowed for this argument type");
|
format_error, "precision not allowed for this argument type");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatTest, UdlTemplate) {
|
|
||||||
EXPECT_EQ("foo", "foo"_format());
|
|
||||||
EXPECT_EQ(" 42", "{0:10}"_format(42));
|
|
||||||
EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), 42));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FormatTest, ToString) {
|
TEST(FormatTest, ToString) {
|
||||||
EXPECT_EQ("42", fmt::to_string(42));
|
EXPECT_EQ("42", fmt::to_string(42));
|
||||||
|
EXPECT_EQ("0x1234", fmt::to_string(reinterpret_cast<void*>(0x1234)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatTest, ToWString) {
|
TEST(FormatTest, ToWString) {
|
||||||
@ -1719,7 +1731,7 @@ FMT_CONSTEXPR test_format_specs_handler parse_test_specs(const char *s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatTest, ConstexprParseFormatSpecs) {
|
TEST(FormatTest, ConstexprParseFormatSpecs) {
|
||||||
using handler = test_format_specs_handler;
|
typedef test_format_specs_handler handler;
|
||||||
static_assert(parse_test_specs("<").align == fmt::ALIGN_LEFT, "");
|
static_assert(parse_test_specs("<").align == fmt::ALIGN_LEFT, "");
|
||||||
static_assert(parse_test_specs("*^").fill == '*', "");
|
static_assert(parse_test_specs("*^").fill == '*', "");
|
||||||
static_assert(parse_test_specs("+").res == handler::PLUS, "");
|
static_assert(parse_test_specs("+").res == handler::PLUS, "");
|
||||||
@ -1736,7 +1748,7 @@ TEST(FormatTest, ConstexprParseFormatSpecs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct test_context {
|
struct test_context {
|
||||||
using char_type = char;
|
typedef char char_type;
|
||||||
|
|
||||||
FMT_CONSTEXPR fmt::basic_arg<test_context> next_arg() {
|
FMT_CONSTEXPR fmt::basic_arg<test_context> next_arg() {
|
||||||
return fmt::internal::make_arg<test_context>(11);
|
return fmt::internal::make_arg<test_context>(11);
|
||||||
@ -1760,7 +1772,7 @@ struct test_context {
|
|||||||
|
|
||||||
FMT_CONSTEXPR fmt::format_specs parse_specs(const char *s) {
|
FMT_CONSTEXPR fmt::format_specs parse_specs(const char *s) {
|
||||||
fmt::format_specs specs;
|
fmt::format_specs specs;
|
||||||
test_context ctx;
|
test_context ctx{};
|
||||||
fmt::internal::specs_handler<test_context> h(specs, ctx);
|
fmt::internal::specs_handler<test_context> h(specs, ctx);
|
||||||
parse_format_specs(s, h);
|
parse_format_specs(s, h);
|
||||||
return specs;
|
return specs;
|
||||||
@ -1786,7 +1798,7 @@ TEST(FormatTest, ConstexprSpecsHandler) {
|
|||||||
FMT_CONSTEXPR fmt::internal::dynamic_format_specs<char>
|
FMT_CONSTEXPR fmt::internal::dynamic_format_specs<char>
|
||||||
parse_dynamic_specs(const char *s) {
|
parse_dynamic_specs(const char *s) {
|
||||||
fmt::internal::dynamic_format_specs<char> specs;
|
fmt::internal::dynamic_format_specs<char> specs;
|
||||||
test_context ctx;
|
test_context ctx{};
|
||||||
fmt::internal::dynamic_specs_handler<test_context> h(specs, ctx);
|
fmt::internal::dynamic_specs_handler<test_context> h(specs, ctx);
|
||||||
parse_format_specs(s, h);
|
parse_format_specs(s, h);
|
||||||
return specs;
|
return specs;
|
||||||
@ -1811,13 +1823,13 @@ TEST(FormatTest, ConstexprDynamicSpecsHandler) {
|
|||||||
|
|
||||||
FMT_CONSTEXPR test_format_specs_handler check_specs(const char *s) {
|
FMT_CONSTEXPR test_format_specs_handler check_specs(const char *s) {
|
||||||
fmt::internal::specs_checker<test_format_specs_handler>
|
fmt::internal::specs_checker<test_format_specs_handler>
|
||||||
checker(test_format_specs_handler(), fmt::internal::DOUBLE);
|
checker(test_format_specs_handler(), fmt::internal::double_type);
|
||||||
parse_format_specs(s, checker);
|
parse_format_specs(s, checker);
|
||||||
return checker;
|
return checker;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatTest, ConstexprSpecsChecker) {
|
TEST(FormatTest, ConstexprSpecsChecker) {
|
||||||
using handler = test_format_specs_handler;
|
typedef test_format_specs_handler handler;
|
||||||
static_assert(check_specs("<").align == fmt::ALIGN_LEFT, "");
|
static_assert(check_specs("<").align == fmt::ALIGN_LEFT, "");
|
||||||
static_assert(check_specs("*^").fill == '*', "");
|
static_assert(check_specs("*^").fill == '*', "");
|
||||||
static_assert(check_specs("+").res == handler::PLUS, "");
|
static_assert(check_specs("+").res == handler::PLUS, "");
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - tests of custom Google Test assertions
|
||||||
Tests of custom Google Test assertions.
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2012-2014, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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 "gtest-extra.h"
|
#include "gtest-extra.h"
|
||||||
|
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - custom Google Test assertions
|
||||||
Custom Google Test assertions.
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2012-2014, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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 "gtest-extra.h"
|
#include "gtest-extra.h"
|
||||||
|
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - custom Google Test assertions
|
||||||
Custom Google Test assertions.
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2012-2014, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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_GTEST_EXTRA_H_
|
#ifndef FMT_GTEST_EXTRA_H_
|
||||||
#define FMT_GTEST_EXTRA_H_
|
#define FMT_GTEST_EXTRA_H_
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - mock allocator
|
||||||
Mock allocator.
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2014, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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_MOCK_ALLOCATOR_H_
|
#ifndef FMT_MOCK_ALLOCATOR_H_
|
||||||
#define FMT_MOCK_ALLOCATOR_H_
|
#define FMT_MOCK_ALLOCATOR_H_
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - std::ostream support tests
|
||||||
std::ostream support tests
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2012-2016, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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 "fmt/ostream.h"
|
#include "fmt/ostream.h"
|
||||||
|
|
||||||
@ -53,12 +33,12 @@ std::ostream &operator<<(std::ostream &os, TestEnum) {
|
|||||||
enum TestEnum2 {A};
|
enum TestEnum2 {A};
|
||||||
|
|
||||||
TEST(OStreamTest, Enum) {
|
TEST(OStreamTest, Enum) {
|
||||||
EXPECT_FALSE(fmt::internal::convert_to_int<TestEnum>::value);
|
EXPECT_FALSE((fmt::internal::convert_to_int<TestEnum, char>::value));
|
||||||
EXPECT_EQ("TestEnum", fmt::format("{}", TestEnum()));
|
EXPECT_EQ("TestEnum", fmt::format("{}", TestEnum()));
|
||||||
EXPECT_EQ("0", fmt::format("{}", A));
|
EXPECT_EQ("0", fmt::format("{}", A));
|
||||||
}
|
}
|
||||||
|
|
||||||
using range = fmt::back_insert_range<fmt::internal::buffer>;
|
typedef fmt::back_insert_range<fmt::internal::buffer> range;
|
||||||
|
|
||||||
struct test_arg_formatter: fmt::arg_formatter<range> {
|
struct test_arg_formatter: fmt::arg_formatter<range> {
|
||||||
test_arg_formatter(fmt::context &ctx, fmt::format_specs &s)
|
test_arg_formatter(fmt::context &ctx, fmt::format_specs &s)
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Tests of the C++ interface to POSIX functions that require mocks
|
||||||
Tests of the C++ interface to POSIX functions that require mocks
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2012-2015, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Disable bogus MSVC warnings.
|
// Disable bogus MSVC warnings.
|
||||||
#define _CRT_SECURE_NO_WARNINGS
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - mocks of POSIX functions
|
||||||
Mocks of POSIX functions
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2012-2015, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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_POSIX_TEST_H
|
#ifndef FMT_POSIX_TEST_H
|
||||||
#define FMT_POSIX_TEST_H
|
#define FMT_POSIX_TEST_H
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - tests of the C++ interface to POSIX functions
|
||||||
Tests of the C++ interface to POSIX functions
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2015, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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 <cstdlib> // std::exit
|
#include <cstdlib> // std::exit
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - printf tests
|
||||||
printf tests.
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2012-2014, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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 <cctype>
|
#include <cctype>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - test version of FMT_ASSERT
|
||||||
Test version of FMT_ASSERT
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2015, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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_TEST_ASSERT_H
|
#ifndef FMT_TEST_ASSERT_H
|
||||||
#define FMT_TEST_ASSERT_H
|
#define FMT_TEST_ASSERT_H
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - test main function.
|
||||||
Test main function.
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2012-2014, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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 <cstdlib>
|
#include <cstdlib>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - time formatting tests
|
||||||
Time formatting tests
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
For the license information refer to format.h.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#define _CRT_SECURE_NO_WARNINGS
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - utility tests
|
||||||
Utility tests.
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2012-2014, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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 "test-assert.h"
|
#include "test-assert.h"
|
||||||
|
|
||||||
@ -81,7 +61,7 @@ struct formatter<Test, Char> {
|
|||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
using iterator = std::back_insert_iterator<basic_buffer<Char>>;
|
typedef std::back_insert_iterator<basic_buffer<Char>> iterator;
|
||||||
|
|
||||||
auto format(Test, basic_context<iterator, char> &ctx)
|
auto format(Test, basic_context<iterator, char> &ctx)
|
||||||
-> decltype(ctx.begin()) {
|
-> decltype(ctx.begin()) {
|
||||||
@ -361,7 +341,7 @@ TEST(MemoryBufferTest, Allocator) {
|
|||||||
{
|
{
|
||||||
basic_memory_buffer<char, 10, TestAllocator> buffer2((TestAllocator(&alloc)));
|
basic_memory_buffer<char, 10, TestAllocator> buffer2((TestAllocator(&alloc)));
|
||||||
EXPECT_EQ(&alloc, buffer2.get_allocator().get());
|
EXPECT_EQ(&alloc, buffer2.get_allocator().get());
|
||||||
std::size_t size = 2 * fmt::internal::INLINE_BUFFER_SIZE;
|
std::size_t size = 2 * fmt::inline_buffer_size;
|
||||||
EXPECT_CALL(alloc, allocate(size)).WillOnce(Return(&mem));
|
EXPECT_CALL(alloc, allocate(size)).WillOnce(Return(&mem));
|
||||||
buffer2.reserve(size);
|
buffer2.reserve(size);
|
||||||
EXPECT_CALL(alloc, deallocate(&mem, size));
|
EXPECT_CALL(alloc, deallocate(&mem, size));
|
||||||
@ -372,7 +352,7 @@ TEST(MemoryBufferTest, ExceptionInDeallocate) {
|
|||||||
typedef AllocatorRef< MockAllocator<char> > TestAllocator;
|
typedef AllocatorRef< MockAllocator<char> > TestAllocator;
|
||||||
StrictMock< MockAllocator<char> > alloc;
|
StrictMock< MockAllocator<char> > alloc;
|
||||||
basic_memory_buffer<char, 10, TestAllocator> buffer((TestAllocator(&alloc)));
|
basic_memory_buffer<char, 10, TestAllocator> buffer((TestAllocator(&alloc)));
|
||||||
std::size_t size = 2 * fmt::internal::INLINE_BUFFER_SIZE;
|
std::size_t size = 2 * fmt::inline_buffer_size;
|
||||||
std::vector<char> mem(size);
|
std::vector<char> mem(size);
|
||||||
{
|
{
|
||||||
EXPECT_CALL(alloc, allocate(size)).WillOnce(Return(&mem[0]));
|
EXPECT_CALL(alloc, allocate(size)).WillOnce(Return(&mem[0]));
|
||||||
@ -436,19 +416,21 @@ TEST(UtilTest, FormatArgs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct custom_context {
|
struct custom_context {
|
||||||
using char_type = char;
|
typedef char char_type;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct formatter_type {
|
struct formatter_type {
|
||||||
template <typename ParseContext>
|
struct type {
|
||||||
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
|
template <typename ParseContext>
|
||||||
return ctx.begin();
|
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
|
||||||
}
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
const char *format(const T &, custom_context& ctx) {
|
const char *format(const T &, custom_context& ctx) {
|
||||||
ctx.called = true;
|
ctx.called = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
bool called;
|
bool called;
|
||||||
@ -476,12 +458,12 @@ bool operator==(custom_value<Char> lhs, custom_value<Char> rhs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
// Use a unique result type to make sure that there are no undesirable
|
||||||
struct MockVisitor {
|
// conversions.
|
||||||
// Use a unique result type to make sure that there are no undesirable
|
struct Result {};
|
||||||
// conversions.
|
|
||||||
struct Result {};
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct MockVisitor: fmt::internal::function<Result> {
|
||||||
MockVisitor() {
|
MockVisitor() {
|
||||||
ON_CALL(*this, visit(_)).WillByDefault(Return(Result()));
|
ON_CALL(*this, visit(_)).WillByDefault(Return(Result()));
|
||||||
}
|
}
|
||||||
@ -523,12 +505,13 @@ VISIT_TYPE(float, double);
|
|||||||
#define CHECK_ARG_(Char, expected, value) { \
|
#define CHECK_ARG_(Char, expected, value) { \
|
||||||
testing::StrictMock<MockVisitor<decltype(expected)>> visitor; \
|
testing::StrictMock<MockVisitor<decltype(expected)>> visitor; \
|
||||||
EXPECT_CALL(visitor, visit(expected)); \
|
EXPECT_CALL(visitor, visit(expected)); \
|
||||||
using iterator = std::back_insert_iterator<basic_buffer<Char>>; \
|
typedef std::back_insert_iterator<basic_buffer<Char>> iterator; \
|
||||||
fmt::visit(visitor, make_arg<fmt::basic_context<iterator, Char>>(value)); \
|
fmt::visit(visitor, make_arg<fmt::basic_context<iterator, Char>>(value)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_ARG(value) { \
|
#define CHECK_ARG(value, typename_) { \
|
||||||
typename VisitType<decltype(value)>::Type expected = value; \
|
typedef decltype(value) value_type; \
|
||||||
|
typename_ VisitType<value_type>::Type expected = value; \
|
||||||
CHECK_ARG_(char, expected, value) \
|
CHECK_ARG_(char, expected, value) \
|
||||||
CHECK_ARG_(wchar_t, expected, value) \
|
CHECK_ARG_(wchar_t, expected, value) \
|
||||||
}
|
}
|
||||||
@ -554,9 +537,9 @@ typename std::enable_if<std::is_floating_point<T>::value, T>::type
|
|||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(NumericArgTest, MakeAndVisit) {
|
TYPED_TEST(NumericArgTest, MakeAndVisit) {
|
||||||
CHECK_ARG(test_value<TypeParam>());
|
CHECK_ARG(test_value<TypeParam>(), typename);
|
||||||
CHECK_ARG(std::numeric_limits<TypeParam>::min());
|
CHECK_ARG(std::numeric_limits<TypeParam>::min(), typename);
|
||||||
CHECK_ARG(std::numeric_limits<TypeParam>::max());
|
CHECK_ARG(std::numeric_limits<TypeParam>::max(), typename);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(UtilTest, CharArg) {
|
TEST(UtilTest, CharArg) {
|
||||||
@ -592,22 +575,25 @@ TEST(UtilTest, PointerArg) {
|
|||||||
const void *cp = 0;
|
const void *cp = 0;
|
||||||
CHECK_ARG_(char, cp, p);
|
CHECK_ARG_(char, cp, p);
|
||||||
CHECK_ARG_(wchar_t, cp, p);
|
CHECK_ARG_(wchar_t, cp, p);
|
||||||
CHECK_ARG(cp);
|
CHECK_ARG(cp, );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(UtilTest, CustomArg) {
|
struct check_custom {
|
||||||
::Test test;
|
Result operator()(fmt::basic_arg<fmt::context>::handle h) const {
|
||||||
using handle = typename fmt::basic_arg<fmt::context>::handle;
|
|
||||||
using visitor = MockVisitor<handle>;
|
|
||||||
testing::StrictMock<visitor> v;
|
|
||||||
EXPECT_CALL(v, visit(_)).WillOnce(testing::Invoke([&](handle h) {
|
|
||||||
fmt::memory_buffer buffer;
|
fmt::memory_buffer buffer;
|
||||||
fmt::internal::basic_buffer<char> &base = buffer;
|
fmt::internal::basic_buffer<char> &base = buffer;
|
||||||
fmt::context ctx(std::back_inserter(base), "", fmt::format_args());
|
fmt::context ctx(std::back_inserter(base), "", fmt::format_args());
|
||||||
h.format(ctx);
|
h.format(ctx);
|
||||||
EXPECT_EQ("test", std::string(buffer.data(), buffer.size()));
|
EXPECT_EQ("test", std::string(buffer.data(), buffer.size()));
|
||||||
return visitor::Result();
|
return Result();
|
||||||
}));
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(UtilTest, CustomArg) {
|
||||||
|
::Test test;
|
||||||
|
typedef MockVisitor<fmt::basic_arg<fmt::context>::handle> visitor;
|
||||||
|
testing::StrictMock<visitor> v;
|
||||||
|
EXPECT_CALL(v, visit(_)).WillOnce(testing::Invoke(check_custom()));
|
||||||
fmt::visit(v, make_arg<fmt::context>(test));
|
fmt::visit(v, make_arg<fmt::context>(test));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -841,15 +827,15 @@ TEST(UtilTest, ReportWindowsError) {
|
|||||||
enum TestEnum2 {};
|
enum TestEnum2 {};
|
||||||
|
|
||||||
TEST(UtilTest, ConvertToInt) {
|
TEST(UtilTest, ConvertToInt) {
|
||||||
EXPECT_FALSE(fmt::internal::convert_to_int<char>::value);
|
EXPECT_FALSE((fmt::internal::convert_to_int<char, char>::value));
|
||||||
EXPECT_FALSE(fmt::internal::convert_to_int<const char *>::value);
|
EXPECT_FALSE((fmt::internal::convert_to_int<const char *, char>::value));
|
||||||
EXPECT_TRUE(fmt::internal::convert_to_int<TestEnum2>::value);
|
EXPECT_TRUE((fmt::internal::convert_to_int<TestEnum2, char>::value));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_USE_ENUM_BASE
|
#if FMT_USE_ENUM_BASE
|
||||||
enum TestEnum : char {TestValue};
|
enum TestEnum : char {TestValue};
|
||||||
TEST(UtilTest, IsEnumConvertibleToInt) {
|
TEST(UtilTest, IsEnumConvertibleToInt) {
|
||||||
EXPECT_TRUE(fmt::internal::convert_to_int<TestEnum>::value);
|
EXPECT_TRUE((fmt::internal::convert_to_int<TestEnum, char>::value));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
32
test/util.cc
32
test/util.cc
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - test utilities
|
||||||
Test utilities.
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2012-2014, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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 "util.h"
|
#include "util.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|||||||
32
test/util.h
32
test/util.h
@ -1,29 +1,9 @@
|
|||||||
/*
|
// Formatting library for C++ - test utilities
|
||||||
Test utilities.
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
Copyright (c) 2012-2014, Victor Zverovich
|
// All rights reserved.
|
||||||
All rights reserved.
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
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 <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user