This commit is contained in:
Park Dong-Ha 2018-03-12 22:48:30 +09:00
commit d55dee7042
34 changed files with 1355 additions and 1441 deletions

View File

@ -42,8 +42,8 @@ Features
performance of IOStreams. See `Speed tests`_ and
`Fast integer to string conversion in C++
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
* Small code size both in terms of source code (the core library consists of a
single header file and a single source file) and compiled code.
* Small code size both in terms of source code (the core library consists of two
header files and a single source file) and compiled code.
See `Compile time and code bloat`_.
* Reliability: the library has an extensive set of `unit tests
<https://github.com/fmtlib/fmt/tree/master/test>`_.
@ -84,24 +84,24 @@ Format strings can be checked at compile time:
.. code:: c++
// test.cc
using namespace fmt::literals;
std::string s = "{2}"_format(42);
#include <fmt/format.h>
std::string s = fmt::format(fmt("{2}"), 42);
.. code::
$ g++ -Iinclude test.cc -std=c++14
...
test.cc:5:31: note: in instantiation of function template specialization
'fmt::internal::udl_formatter<char, '{', '2', '}'>::operator()<int>' requested
here
std::string s = "{2}"_format(42);
^
include/fmt/format.h:3838:7: note: non-constexpr function 'on_error' cannot be
used in a constant expression
on_error("argument index out of range");
^
test.cc:2:22: note: in instantiation of function template specialization 'fmt::format<S, int>' requested here
std::string s = fmt::format(fmt("{2}"), 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:2081:16: note: in call to '&checker.context_->on_error(&"argument index out of range"[0])'
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++
@ -159,6 +159,8 @@ Projects using this library
* `AMPL/MP <https://github.com/ampl/mp>`_:
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

View File

@ -4,52 +4,249 @@
API Reference
*************
All functions and classes provided by the fmt library reside
in namespace ``fmt`` and macros have prefix ``FMT_``. For brevity the
namespace is usually omitted in examples.
The {fmt} library API consists of the following parts:
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
syntax <syntax>` similar to the one used by Python's `str.format
<http://docs.python.org/3/library/stdtypes.html#str.format>`_ function.
All functions and types provided by the library reside in namespace ``fmt`` and
macros have prefix ``FMT_`` or ``fmt``.
.. _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.
*format_str* is a format string that contains literal text and replacement
fields surrounded by braces ``{}``. The fields are replaced with formatted
arguments in the resulting string.
*args* is an argument list representing arbitrary arguments.
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`_.
*args* is an argument list representing objects to be formatted.
.. _format:
.. doxygenfunction:: format(CStringRef, ArgList)
.. doxygenfunction:: operator""_format(const char *, std::size_t)
.. doxygenfunction:: format(string_view, const Args&...)
.. doxygenfunction:: vformat(string_view, format_args)
.. _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:
.. 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
------------------------
========================
The library supports `strftime
<http://en.cppreference.com/w/cpp/chrono/c/strftime>`_-like date and time
formatting::
#include "fmt/time.h"
#include <fmt/time.h>
std::time_t t = std::time(nullptr);
// 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
`strftime <http://en.cppreference.com/w/cpp/chrono/c/strftime>`_.
Formatting user-defined types
-----------------------------
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.
.. _ostream-api:
``std::ostream`` support
------------------------
========================
The header ``fmt/ostream.h`` provides ``std::ostream`` support including
formatting of user-defined types that have overloaded ``operator<<``::
``fmt/ostream.h`` provides ``std::ostream`` support including formatting of
user-defined types that have overloaded ``operator<<``::
#include "fmt/ostream.h"
#include <fmt/ostream.h>
class Date {
class date {
int year_, month_, day_;
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_;
}
};
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"
.. 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
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
-----------------
``printf`` formatting
=====================
The header ``fmt/printf.h`` provides ``printf``-like formatting functionality.
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
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)
.. doxygenclass:: fmt::PrintfFormatter
:members:
.. doxygenclass:: fmt::BasicPrintfArgFormatter
:members:
.. doxygenclass:: fmt::PrintfArgFormatter
:members:
.. doxygenfunction:: sprintf(string_view, const Args&...)
Write API
=========
@ -194,14 +306,14 @@ Write API
The write API provides classes for writing formatted data into character
streams. It is usually faster than the `format API`_ but, as IOStreams,
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
store output elsewhere by subclassing `~fmt::BasicWriter`.
.. doxygenclass:: fmt::BasicWriter
:members:
.. doxygenclass:: fmt::BasicMemoryWriter
.. doxygenclass:: fmt::basic_memory_writer
:members:
.. doxygenclass:: fmt::BasicArrayWriter
@ -220,64 +332,3 @@ store output elsewhere by subclassing `~fmt::BasicWriter`.
.. 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)

View File

@ -62,8 +62,8 @@ def create_build_env(dirname='virtualenv'):
def build_docs(version='dev', **kwargs):
doc_dir = kwargs.get('doc_dir', os.path.dirname(os.path.realpath(__file__)))
work_dir = kwargs.get('work_dir', '.')
include_dir = kwargs.get('include_dir',
os.path.join(os.path.dirname(doc_dir), 'fmt'))
include_dir = kwargs.get(
'include_dir', os.path.join(os.path.dirname(doc_dir), 'include', 'fmt'))
# Build docs.
cmd = ['doxygen', '-']
p = Popen(cmd, stdin=PIPE)
@ -74,8 +74,8 @@ def build_docs(version='dev', **kwargs):
GENERATE_MAN = NO
GENERATE_RTF = NO
CASE_SENSE_NAMES = NO
INPUT = {0}/container.h {0}/format.h {0}/ostream.h \
{0}/printf.h {0}/string.h
INPUT = {0}/core.h {0}/format.h {0}/ostream.h \
{0}/printf.h {0}/time.h
QUIET = YES
JAVADOC_AUTOBRIEF = YES
AUTOLINK_SUPPORT = NO

View File

@ -47,7 +47,7 @@ source_suffix = '.rst'
# General information about the project.
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
# |version| and |release|, also used in various other places throughout the

View File

@ -25,7 +25,7 @@ The replacement-based Format API provides a safe alternative to ``printf``,
``sprintf`` and friends with comparable or `better performance
<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
`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:
.. code:: c++

View File

@ -24,7 +24,7 @@
# define FMT_HAS_FEATURE(x) 0
#endif
#if defined(__has_include)
#ifdef __has_include
# define FMT_HAS_INCLUDE(x) __has_include(x)
#else
# define FMT_HAS_INCLUDE(x) 0
@ -36,7 +36,7 @@
# define FMT_GCC_VERSION 0
#endif
#if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION
#else
# define FMT_HAS_GXX_CXX11 0
@ -72,17 +72,26 @@
# endif
#endif
#if FMT_HAS_FEATURE(cxx_explicit_conversions)
# define FMT_EXPLICIT explicit
#else
# define FMT_EXPLICIT
#endif
#ifndef FMT_NULL
# if FMT_HAS_FEATURE(cxx_nullptr) || \
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
FMT_MSC_VER >= 1600
# define FMT_NULL nullptr
# define FMT_USE_NULLPTR 1
# else
# define FMT_NULL NULL
# 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.
#if defined(__GNUC__) && !defined(__EXCEPTIONS)
@ -148,19 +157,36 @@
#if (FMT_HAS_INCLUDE(<string_view>) && __cplusplus > 201402L) || \
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
# include <string_view>
namespace fmt { using std::basic_string_view; }
// std::experimental::basic_string_view::remove_prefix isn't constexpr in gcc 6.
# define FMT_USE_STD_STRING_VIEW
// std::experimental::basic_string_view::remove_prefix isn't constexpr until
// gcc 7.3.
#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)
# include <experimental/string_view>
namespace fmt { using std::experimental::basic_string_view; }
#else
# define FMT_USE_EXPERIMENTAL_STRING_VIEW
#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 {
// 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
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
*/
template <typename Char>
@ -170,10 +196,22 @@ class basic_string_view {
size_t size_;
public:
using char_type = Char;
using iterator = const Char *;
typedef Char char_type;
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. */
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
: 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. */
const Char *data() const { return data_; }
@ -240,12 +281,9 @@ class basic_string_view {
return lhs.compare(rhs) >= 0;
}
};
} // namespace fmt
#endif
namespace fmt {
using string_view = basic_string_view<char>;
using wstring_view = basic_string_view<wchar_t>;
typedef basic_string_view<char> string_view;
typedef basic_string_view<wchar_t> wstring_view;
template <typename Context>
class basic_arg;
@ -287,7 +325,8 @@ class basic_buffer {
virtual void grow(std::size_t capacity) = 0;
public:
using value_type = T;
typedef T value_type;
typedef const T &const_reference;
virtual ~basic_buffer() {}
@ -337,8 +376,8 @@ class basic_buffer {
const T &operator[](std::size_t index) const { return ptr_[index]; }
};
using buffer = basic_buffer<char>;
using wbuffer = basic_buffer<wchar_t>;
typedef basic_buffer<char> buffer;
typedef basic_buffer<wchar_t> wbuffer;
// A container-backed buffer.
template <typename Container>
@ -347,7 +386,7 @@ class container_buffer : public basic_buffer<typename Container::value_type> {
Container &container_;
protected:
virtual void grow(std::size_t capacity) {
void grow(std::size_t capacity) FMT_OVERRIDE {
container_.resize(capacity);
this->set(&container_[0], capacity);
}
@ -358,11 +397,6 @@ class container_buffer : public basic_buffer<typename Container::value_type> {
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 {
FMT_CONSTEXPR 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 {};
enum type {
NONE, NAMED_ARG,
none_type, name_arg_type,
// 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.
DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE,
CSTRING, STRING, POINTER, CUSTOM
double_type, long_double_type, last_numeric_type = long_double_type,
cstring_type, string_type, pointer_type, custom_type
};
FMT_CONSTEXPR bool is_integral(type t) {
FMT_ASSERT(t != internal::NAMED_ARG, "invalid argument type");
return t > internal::NONE && t <= internal::LAST_INTEGER_TYPE;
FMT_ASSERT(t != internal::name_arg_type, "invalid argument type");
return t > internal::none_type && t <= internal::last_integer_type;
}
FMT_CONSTEXPR bool is_arithmetic(type t) {
FMT_ASSERT(t != internal::NAMED_ARG, "invalid argument type");
return t > internal::NONE && t <= internal::LAST_NUMERIC_TYPE;
FMT_ASSERT(t != internal::name_arg_type, "invalid argument 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 {
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>
struct string_value {
const Char *value;
@ -445,7 +471,7 @@ struct custom_value {
template <typename Context>
class value {
public:
using char_type = typename Context::char_type;
typedef typename Context::char_type char_type;
union {
int int_value;
@ -501,7 +527,7 @@ class value {
// Get the formatter type through the context to allow different contexts
// have different extension points, e.g. `formatter<T>` for `format` and
// `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();
parse_ctx.advance_to(f.parse(parse_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);
#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) { \
return static_cast<ValueType>(val); \
}
FMT_MAKE_VALUE(BOOL, bool, int)
FMT_MAKE_VALUE(INT, short, int)
FMT_MAKE_VALUE(UINT, unsigned short, unsigned)
FMT_MAKE_VALUE(INT, int, int)
FMT_MAKE_VALUE(UINT, unsigned, unsigned)
FMT_MAKE_VALUE(bool_type, bool, int)
FMT_MAKE_VALUE(int_type, short, int)
FMT_MAKE_VALUE(uint_type, unsigned short, unsigned)
FMT_MAKE_VALUE(int_type, int, int)
FMT_MAKE_VALUE(uint_type, unsigned, unsigned)
// 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.
using long_type =
std::conditional<sizeof(long) == sizeof(int), int, long long>::type;
FMT_MAKE_VALUE((sizeof(long) == sizeof(int) ? INT : LONG_LONG), long, long_type)
using ulong_type =
std::conditional<sizeof(unsigned long) == sizeof(unsigned),
unsigned, unsigned long long>::type;
FMT_MAKE_VALUE((sizeof(unsigned long) == sizeof(unsigned) ? UINT : ULONG_LONG),
typedef std::conditional<sizeof(long) == sizeof(int), int, long long>::type
long_type;
FMT_MAKE_VALUE(
(sizeof(long) == sizeof(int) ? int_type : long_long_type), long, long_type)
typedef std::conditional<sizeof(unsigned long) == sizeof(unsigned),
unsigned, unsigned long long>::type ulong_type;
FMT_MAKE_VALUE(
(sizeof(unsigned long) == sizeof(unsigned) ? uint_type : ulong_long_type),
unsigned long, ulong_type)
FMT_MAKE_VALUE(LONG_LONG, long long, long long)
FMT_MAKE_VALUE(ULONG_LONG, unsigned long long, unsigned long long)
FMT_MAKE_VALUE(INT, signed char, int)
FMT_MAKE_VALUE(UINT, unsigned char, unsigned)
FMT_MAKE_VALUE(CHAR, char, int)
FMT_MAKE_VALUE(long_long_type, long long, long long)
FMT_MAKE_VALUE(ulong_long_type, unsigned long long, unsigned long long)
FMT_MAKE_VALUE(int_type, signed char, int)
FMT_MAKE_VALUE(uint_type, unsigned char, unsigned)
FMT_MAKE_VALUE(char_type, char, int)
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
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>();
return static_cast<int>(val);
}
#endif
FMT_MAKE_VALUE(DOUBLE, float, double)
FMT_MAKE_VALUE(DOUBLE, double, double)
FMT_MAKE_VALUE(LONG_DOUBLE, long double, long double)
FMT_MAKE_VALUE(double_type, float, double)
FMT_MAKE_VALUE(double_type, double, double)
FMT_MAKE_VALUE(long_double_type, long double, long double)
// Formatting of wide strings into a narrow buffer and multibyte strings
// 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, const char_type*, const char_type*)
FMT_MAKE_VALUE(cstring_type, typename C::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, const signed char*, const signed char*)
FMT_MAKE_VALUE(CSTRING, unsigned char*, const unsigned char*)
FMT_MAKE_VALUE(CSTRING, const unsigned char*, const unsigned char*)
FMT_MAKE_VALUE(STRING, basic_string_view<char_type>,
basic_string_view<char_type>)
FMT_MAKE_VALUE(STRING, const std::basic_string<char_type>&,
basic_string_view<char_type>)
FMT_MAKE_VALUE(POINTER, void*, const void*)
FMT_MAKE_VALUE(POINTER, const void*, const void*)
FMT_MAKE_VALUE(POINTER, std::nullptr_t, const void*)
FMT_MAKE_VALUE(cstring_type, signed char*, const signed char*)
FMT_MAKE_VALUE(cstring_type, const signed char*, const signed char*)
FMT_MAKE_VALUE(cstring_type, unsigned char*, const unsigned char*)
FMT_MAKE_VALUE(cstring_type, const unsigned char*, const unsigned char*)
FMT_MAKE_VALUE(string_type, basic_string_view<typename C::char_type>,
basic_string_view<typename C::char_type>)
FMT_MAKE_VALUE(string_type,
typename basic_string_view<typename C::char_type>::type,
basic_string_view<typename C::char_type>)
FMT_MAKE_VALUE(string_type, const std::basic_string<typename C::char_type>&,
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
// pointer cast it to "void *" or "const void *". In particular, this forbids
// formatting of "[const] volatile char *" which is printed as bool by
// iostreams.
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");
}
template <typename C, typename T>
inline typename std::enable_if<
convert_to_int<T>::value && std::is_enum<T>::value,
typed_value<C, INT>>::type
std::is_enum<T>::value && convert_to_int<T, typename C::char_type>::value,
typed_value<C, int_type>>::type
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<
!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; }
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) {
basic_arg<C> arg = make_arg<C>(val.value);
std::memcpy(val.data, &arg, sizeof(arg));
@ -606,10 +644,20 @@ typed_value<C, NAMED_ARG>
}
// Maximum number of arguments with packed types.
enum { MAX_PACKED_ARGS = 15 };
enum { max_packed_args = 15 };
template <typename Context>
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
@ -624,13 +672,13 @@ class basic_arg {
friend FMT_CONSTEXPR basic_arg<ContextType> internal::make_arg(const T &value);
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);
friend class basic_format_args<Context>;
friend class internal::arg_map<Context>;
using char_type = typename Context::char_type;
typedef typename Context::char_type char_type;
public:
class handle {
@ -643,17 +691,17 @@ class basic_arg {
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 {
return type_ != internal::NONE;
FMT_EXPLICIT operator bool() const FMT_NOEXCEPT {
return type_ != internal::none_type;
}
internal::type type() const { return type_; }
bool is_integral() const { return internal::is_integral(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
@ -665,8 +713,8 @@ class basic_parse_context : private ErrorHandler {
int next_arg_id_;
public:
using char_type = Char;
using iterator = typename basic_string_view<Char>::iterator;
typedef Char char_type;
typedef typename basic_string_view<Char>::iterator iterator;
explicit FMT_CONSTEXPR basic_parse_context(
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; }
};
using parse_context = basic_parse_context<char>;
using wparse_context = basic_parse_context<wchar_t>;
typedef basic_parse_context<char> parse_context;
typedef basic_parse_context<wchar_t> wparse_context;
namespace internal {
// A map from argument names to their values for named arguments.
@ -716,15 +764,15 @@ class arg_map {
private:
FMT_DISALLOW_COPY_AND_ASSIGN(arg_map);
using char_type = typename Context::char_type;
typedef typename Context::char_type char_type;
struct entry {
basic_string_view<char_type> name;
basic_arg<Context> arg;
};
entry *map_ = nullptr;
unsigned size_ = 0;
entry *map_;
unsigned size_;
void push_back(value<Context> val) {
const internal::named_arg_base<char_type> &named = val.as_named_arg();
@ -733,7 +781,7 @@ class arg_map {
}
public:
arg_map() {}
arg_map() : map_(FMT_NULL), size_(0) {}
void init(const basic_format_args<Context> &args);
~arg_map() { delete [] map_; }
@ -750,7 +798,7 @@ class arg_map {
template <typename OutputIt, typename Context, typename Char>
class context_base {
public:
using iterator = OutputIt;
typedef OutputIt iterator;
private:
basic_parse_context<Char> parse_context_;
@ -758,8 +806,8 @@ class context_base {
basic_format_args<Context> args_;
protected:
using char_type = Char;
using format_arg = basic_arg<Context>;
typedef Char char_type;
typedef basic_arg<Context> format_arg;
context_base(OutputIt out, basic_string_view<char_type> format_str,
basic_format_args<Context> args)
@ -794,7 +842,7 @@ class context_base {
void on_error(const char *message) { parse_context_.on_error(message); }
// Returns an iterator to the beginning of the output range.
auto begin() { return out_; }
iterator begin() { return out_; }
// Advances the begin iterator to ``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.
template <typename Container>
inline Container &get_container(std::back_insert_iterator<Container> it) {
using iterator = std::back_insert_iterator<Container>;
struct accessor: iterator {
accessor(iterator it) : iterator(it) {}
using iterator::container;
typedef std::back_insert_iterator<Container> bi_iterator;
struct accessor: bi_iterator {
accessor(bi_iterator it) : bi_iterator(it) {}
using bi_iterator::container;
};
return *accessor(it).container;
}
} // 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.
template <typename OutputIt, typename Char>
class basic_context :
public internal::context_base<OutputIt, basic_context<OutputIt, Char>, Char> {
public:
/** The character type for the output. */
using char_type = Char;
typedef Char char_type;
// using formatter_type = formatter<T, char_type>;
template <typename T>
using formatter_type = formatter<T, char_type>;
struct formatter_type { typedef formatter<T, char_type> type; };
private:
internal::arg_map<basic_context> map_;
FMT_DISALLOW_COPY_AND_ASSIGN(basic_context);
using base = internal::context_base<OutputIt, basic_context, Char>;
using format_arg = typename base::format_arg;
typedef internal::context_base<OutputIt, basic_context, Char> base;
typedef typename base::format_arg format_arg;
using base::get_arg;
public:
@ -872,19 +905,18 @@ class basic_context :
};
template <typename Char>
using buffer_context_t = basic_context<
std::back_insert_iterator<internal::basic_buffer<Char>>, Char>;
using context = buffer_context_t<char>;
using wcontext = buffer_context_t<wchar_t>;
struct buffer_context {
typedef basic_context<
std::back_insert_iterator<internal::basic_buffer<Char>>, Char> type;
};
typedef buffer_context<char>::type context;
typedef buffer_context<wchar_t>::type wcontext;
namespace internal {
template <typename Context, typename T>
class get_type {
private:
static const T& val();
public:
using value_type = decltype(make_value<Context>(val()));
struct get_type {
typedef decltype(make_value<Context>(
declval<typename std::decay<T>::type&>())) value_type;
static const type value = value_type::type_tag;
};
@ -923,10 +955,10 @@ class arg_store {
static const size_t NUM_ARGS = sizeof...(Args);
// 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<
IS_PACKED, internal::value<Context>, basic_arg<Context>>::type;
typedef typename std::conditional<
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.
value_type data_[NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1)];
@ -934,8 +966,15 @@ class arg_store {
public:
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)
: data_{internal::make_arg<IS_PACKED, Context>(args)...} {}
#endif
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>
class basic_format_args {
public:
using size_type = unsigned;
using format_arg = basic_arg<Context> ;
typedef unsigned size_type;
typedef basic_arg<Context> format_arg;
private:
// 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_;
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_.
// 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
@ -997,10 +1036,10 @@ class basic_format_args {
return index < num_args ? args_[index] : format_arg();
}
format_arg arg;
if (index > internal::MAX_PACKED_ARGS)
if (index > internal::max_packed_args)
return arg;
arg.type_ = type(index);
if (arg.type_ == internal::NONE)
if (arg.type_ == internal::none_type)
return arg;
internal::value<Context> &val = arg.value_;
val = values_[index];
@ -1019,19 +1058,25 @@ class basic_format_args {
/** Returns the argument at specified index. */
format_arg operator[](size_type index) const {
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;
}
unsigned max_size() const {
int64_t signed_types = static_cast<int64_t>(types_);
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>;
using wformat_args = basic_format_args<wcontext>;
/** An alias to ``basic_format_args<context>``. */
// 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 {
template <typename Char>
@ -1062,11 +1107,11 @@ struct named_arg : named_arg_base<Char> {
/**
\rst
Returns a named argument for formatting functions.
Returns a named argument to be used in a formatting function.
**Example**::
print("Elapsed time: {s:.2f} seconds", arg("s", 1.23));
fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23));
\endrst
*/
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
// arguments as in ``format("{}", arg("a", arg("b", 42)))``.
template <typename S, typename... T>
void arg(S, internal::named_arg<T...>) FMT_DELETED;
template <typename S, typename T, typename Char>
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
specify color (experimental).
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>
inline void print_colored(Color c, string_view format_str,
inline void print_colored(color c, string_view format_str,
const Args & ... args) {
vprint_colored(c, format_str, make_args(args...));
}
void vformat_to(internal::buffer &buf, string_view format_str,
format_args args);
void vformat_to(internal::wbuffer &buf, wstring_view format_str,
wformat_args args);
context::iterator vformat_to(internal::buffer &buf, string_view format_str,
format_args args);
wcontext::iterator vformat_to(internal::wbuffer &buf, wstring_view format_str,
wformat_args args);
template <typename Container>
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``. */
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,
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);
return std::back_inserter(container);
}
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**::
std::string message = format("The answer is {}", 42);
#include <fmt/core.h>
std::string message = fmt::format("The answer is {}", 42);
\endrst
*/
template <typename... 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>
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);
@ -1152,12 +1206,13 @@ FMT_API void vprint(std::FILE *f, string_view format_str, format_args args);
**Example**::
print(stderr, "Don't {}!", "panic");
fmt::print(stderr, "Don't {}!", "panic");
\endrst
*/
template <typename... 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);
@ -1168,12 +1223,13 @@ FMT_API void vprint(string_view format_str, format_args args);
**Example**::
print("Elapsed time: {0:.2f} seconds", 1.23);
fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
template <typename... 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

View File

@ -166,7 +166,7 @@ int safe_strerror(
void format_error_code(internal::buffer &out, int error_code,
string_view message) FMT_NOEXCEPT {
// 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.
out.resize(0);
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);
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(SEP);
}
w.write(ERROR_STR);
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,
@ -332,7 +332,7 @@ FMT_FUNC void internal::format_windows_error(
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
FMT_TRY {
wmemory_buffer buf;
buf.resize(INLINE_BUFFER_SIZE);
buf.resize(inline_buffer_size);
for (;;) {
wchar_t *system_message = &buf[0];
int result = FormatMessageW(
@ -364,7 +364,7 @@ FMT_FUNC void format_system_error(
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
FMT_TRY {
memory_buffer buf;
buf.resize(internal::INLINE_BUFFER_SIZE);
buf.resize(inline_buffer_size);
for (;;) {
char *system_message = &buf[0];
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);
}
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";
escape[3] = static_cast<char>('0' + c);
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 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(
char *buffer, std::size_t size, const char *format,

File diff suppressed because it is too large Load Diff

View File

@ -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:
struct null;
// Hide all operator<< from std::ostream.
// Hide all operator<< from std::basic_ostream<Char>.
void operator<<(null);
};
// Disable conversion to int if T has an overloaded operator<< which is a free
// function (not a member of std::ostream).
template <typename T>
class convert_to_int<T, true> {
template <typename T, typename Char>
class convert_to_int<T, Char, true> {
private:
template <typename U>
static decltype(
std::declval<test_stream&>() << std::declval<U>(), std::true_type())
test(int);
internal::declval<test_stream<Char>&>()
<< internal::declval<U>(), std::true_type()) test(int);
template <typename>
static std::false_type test(...);
typedef decltype(test<T>(0)) result;
public:
static const bool value = !decltype(test<T>(0))::value;
static const bool value = !result::value;
};
// 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<<.
template <typename T, typename Char>
struct formatter<T, Char,
typename std::enable_if<
!internal::format_type<buffer_context_t<Char>, T>::value>::type>
typename std::enable_if<!internal::format_type<
typename buffer_context<Char>::type, T>::value>::type>
: formatter<basic_string_view<Char>, Char> {
template <typename Context>
@ -130,7 +133,7 @@ inline void vprint(std::ostream &os, string_view format_str, format_args args) {
**Example**::
print(cerr, "Don't {}!", "panic");
fmt::print(cerr, "Don't {}!", "panic");
\endrst
*/
template <typename... Args>

View File

@ -71,7 +71,8 @@ fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT {
fmt::BufferedFile::BufferedFile(
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_)
FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str()));
}
@ -180,8 +181,8 @@ void fmt::File::dup2(int fd) {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) {
throw system_error(errno,
"cannot duplicate file descriptor {} to {}", fd_, fd);
FMT_THROW(system_error(errno,
"cannot duplicate file descriptor {} to {}", fd_, fd));
}
}

View File

@ -134,7 +134,7 @@ class BufferedFile {
public:
// 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.
FMT_API ~BufferedFile() FMT_DTOR_NOEXCEPT;
@ -353,7 +353,7 @@ class File {
long getpagesize();
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
!defined(__ANDROID__) && !defined(__CYGWIN__)
!defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__)
# define FMT_LOCALE
#endif

View File

@ -19,7 +19,7 @@ namespace internal {
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
template <bool IsSigned>
struct IntChecker {
struct int_checker {
template <typename T>
static bool fits_in_int(T value) {
unsigned max = std::numeric_limits<int>::max();
@ -29,7 +29,7 @@ struct IntChecker {
};
template <>
struct IntChecker<true> {
struct int_checker<true> {
template <typename T>
static bool fits_in_int(T value) {
return value >= std::numeric_limits<int>::min() &&
@ -38,12 +38,12 @@ struct IntChecker<true> {
static bool fits_in_int(int) { return true; }
};
class PrintfPrecisionHandler {
class printf_precision_handler: public function<int> {
public:
template <typename T>
typename std::enable_if<std::is_integral<T>::value, int>::type
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"));
return static_cast<int>(value);
}
@ -57,7 +57,7 @@ class PrintfPrecisionHandler {
};
// An argument visitor that returns true iff arg is a zero integer.
class IsZeroInt {
class is_zero_int: public function<bool> {
public:
template <typename T>
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 <>
struct make_unsigned_or_bool<bool> {
using type = bool;
typedef bool type;
};
template <typename T, typename Context>
class ArgConverter {
class arg_converter: public function<void> {
private:
typedef typename Context::char_type Char;
@ -85,7 +85,7 @@ class ArgConverter {
typename Context::char_type type_;
public:
ArgConverter(basic_arg<Context> &arg, Char type)
arg_converter(basic_arg<Context> &arg, Char type)
: arg_(arg), type_(type) {}
void operator()(bool value) {
@ -134,19 +134,19 @@ class ArgConverter {
// unsigned).
template <typename T, typename Context, typename Char>
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.
template <typename Context>
class CharConverter {
class char_converter: public function<void> {
private:
basic_arg<Context> &arg_;
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
FMT_DISALLOW_COPY_AND_ASSIGN(char_converter);
public:
explicit CharConverter(basic_arg<Context> &arg) : arg_(arg) {}
explicit char_converter(basic_arg<Context> &arg) : arg_(arg) {}
template <typename T>
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
// left alignment if it is negative.
template <typename Char>
class PrintfWidthHandler {
class printf_width_handler: public function<unsigned> {
private:
typedef basic_format_specs<Char> format_specs;
format_specs &spec_;
FMT_DISALLOW_COPY_AND_ASSIGN(PrintfWidthHandler);
FMT_DISALLOW_COPY_AND_ASSIGN(printf_width_handler);
public:
explicit PrintfWidthHandler(format_specs &spec) : spec_(spec) {}
explicit printf_width_handler(format_specs &spec) : spec_(spec) {}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, unsigned>::type
@ -213,12 +213,13 @@ class basic_printf_context;
\endrst
*/
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:
using char_type = typename Range::value_type;
using iterator = decltype(std::declval<Range>().begin());
using base = internal::arg_formatter_base<Range>;
using context_type = basic_printf_context<iterator, char_type>;
typedef typename Range::value_type char_type;
typedef decltype(internal::declval<Range>().begin()) iterator;
typedef internal::arg_formatter_base<Range> base;
typedef basic_printf_context<iterator, char_type> context_type;
context_type &context_;
@ -228,7 +229,7 @@ class printf_arg_formatter : public internal::arg_formatter_base<Range> {
}
public:
using format_specs = typename base::format_specs;
typedef typename base::format_specs format_specs;
/**
\rst
@ -290,7 +291,7 @@ class printf_arg_formatter : public internal::arg_formatter_base<Range> {
template <typename T>
struct printf_formatter {
template <typename ParseContext>
auto parse(ParseContext &ctx) { return ctx.begin(); }
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); }
template <typename FormatContext>
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> {
public:
/** The character type for the output. */
using char_type = Char;
typedef Char char_type;
template <typename T>
using formatter_type = printf_formatter<T>;
struct formatter_type { typedef printf_formatter<T> type; };
private:
using base = internal::context_base<OutputIt, basic_printf_context, Char>;
using format_arg = typename base::format_arg;
using format_specs = basic_format_specs<char_type>;
using iterator = internal::null_terminating_iterator<char_type>;
typedef internal::context_base<OutputIt, basic_printf_context, Char> base;
typedef typename base::format_arg format_arg;
typedef basic_format_specs<char_type> format_specs;
typedef internal::null_terminating_iterator<char_type> iterator;
void parse_flags(format_specs &spec, iterator &it);
@ -417,7 +418,7 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
} else if (*it == '*') {
++it;
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;
}
@ -453,14 +454,14 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
} else if (*it == '*') {
++it;
spec.precision_ =
visit(internal::PrintfPrecisionHandler(), get_arg(it));
visit(internal::printf_precision_handler(), get_arg(it));
} else {
spec.precision_ = 0;
}
}
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);
if (spec.fill_ == '0') {
if (arg.is_arithmetic())
@ -514,7 +515,7 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
break;
case 'c':
// TODO: handle wchar_t
visit(internal::CharConverter<basic_printf_context>(arg), arg);
visit(internal::char_converter<basic_printf_context>(arg), arg);
break;
}
}
@ -534,10 +535,12 @@ void printf(internal::basic_buffer<Char> &buf, basic_string_view<Char> format,
}
template <typename Buffer>
using printf_context = basic_printf_context<
std::back_insert_iterator<Buffer>, typename Buffer::value_type>;
struct printf_context {
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) {
memory_buffer buffer;
@ -557,12 +560,12 @@ inline std::string vsprintf(string_view format, printf_args args) {
template <typename... Args>
inline std::string sprintf(string_view format_str, const Args & ... args) {
return vsprintf(format_str,
make_args<printf_context<internal::buffer>>(args...));
make_args<typename printf_context<internal::buffer>::type>(args...));
}
inline std::wstring vsprintf(
wstring_view format,
basic_format_args<printf_context<internal::wbuffer>> args) {
basic_format_args<printf_context<internal::wbuffer>::type> args) {
wmemory_buffer buffer;
printf(buffer, format, args);
return to_string(buffer);
@ -570,7 +573,8 @@ inline std::wstring vsprintf(
template <typename... 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);
}
@ -593,7 +597,8 @@ inline int vfprintf(std::FILE *f, string_view format, printf_args args) {
*/
template <typename... 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);
}
@ -613,7 +618,7 @@ inline int vprintf(string_view format, printf_args args) {
template <typename... Args>
inline int printf(string_view format_str, const Args & ... args) {
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,
@ -630,13 +635,14 @@ inline int vfprintf(std::ostream &os, string_view format_str,
**Example**::
fprintf(cerr, "Don't %s!", "panic");
fmt::fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
template <typename... Args>
inline int fprintf(std::ostream &os, 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(os, format_str, vargs);
}
} // namespace fmt

View File

@ -40,6 +40,17 @@ if (FMT_USE_CPP14)
check_cxx_compiler_flag(-std=c++1y HAVE_STD_CPP1Y_FLAG)
if (HAVE_STD_CPP1Y_FLAG)
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 ()

View File

@ -1,29 +1,9 @@
/*
Assertion tests
Copyright (c) 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - assertion tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/core.h"
#include "gtest/gtest.h"
@ -37,5 +17,6 @@
#endif
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!");
}

View File

@ -47,22 +47,12 @@ endfunction ()
# check if the source file skeleton compiles
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.
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
# match the features detected in CMake.
if (SUPPORTS_USER_DEFINED_LITERALS)

View File

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

View File

@ -1,28 +1,22 @@
/*
Custom argument formatter tests
// Formatting library for C++ - 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
All rights reserved.
For the license information refer to format.h.
*/
#include "fmt/printf.h"
#include "fmt/format.h"
#include "gtest-extra.h"
using fmt::printf_arg_formatter;
// A custom argument formatter that doesn't print `-` for floating-point values
// rounded to 0.
class CustomArgFormatter :
class custom_arg_formatter :
public fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>> {
public:
using range = fmt::back_insert_range<fmt::internal::buffer>;
using iterator = decltype(std::declval<range>().begin());
using base = fmt::arg_formatter<range>;
typedef fmt::back_insert_range<fmt::internal::buffer> range;
typedef fmt::arg_formatter<range> base;
CustomArgFormatter(fmt::basic_context<iterator, char> &ctx,
fmt::format_specs &s)
custom_arg_formatter(fmt::context &ctx, fmt::format_specs &s)
: base(ctx, s) {}
using base::operator();
@ -37,7 +31,7 @@ class CustomArgFormatter :
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 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());
}

View File

@ -1,35 +1,15 @@
/*
Formatting library implementation tests.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - formatting library implementation tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#define FMT_NOEXCEPT
#undef FMT_SHARED
#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/printf.h"
@ -44,7 +24,7 @@
#undef max
template <typename T>
struct ValueExtractor {
struct ValueExtractor: fmt::internal::function<T> {
T operator()(T value) {
return value;
}
@ -59,7 +39,7 @@ struct ValueExtractor {
TEST(FormatTest, ArgConverter) {
long long value = std::numeric_limits<long long>::max();
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));
}
@ -114,7 +94,7 @@ TEST(FormatTest, FormatErrorCode) {
{
fmt::memory_buffer buffer;
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);
EXPECT_EQ(msg, to_string(buffer));
}
@ -124,10 +104,10 @@ TEST(FormatTest, FormatErrorCode) {
msg = fmt::format("error {}", codes[i]);
fmt::memory_buffer buffer;
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);
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());
buffer.resize(0);
// Test with a message that doesn't fit into the buffer.

View File

@ -1,29 +1,9 @@
/*
Formatting library tests.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - formatting library tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include <cctype>
#include <cfloat>
@ -89,7 +69,7 @@ void std_format(long double value, std::wstring &result) {
template <typename Char, typename T>
::testing::AssertionResult check_write(const T &value, const char *type) {
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);
writer.write(value);
std::basic_string<Char> actual = to_string(buffer);
@ -137,6 +117,8 @@ TEST(StringViewTest, Ctor) {
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) {
EXPECT_FALSE(std::is_copy_constructible<fmt::writer>::value);
}
@ -144,6 +126,7 @@ TEST(WriterTest, NotCopyConstructible) {
TEST(WriterTest, NotCopyAssignable) {
EXPECT_FALSE(std::is_copy_assignable<fmt::writer>::value);
}
#endif
TEST(WriterTest, Data) {
memory_buffer buf;
@ -209,11 +192,11 @@ TEST(WriterTest, WriteDoubleWithFilledBuffer) {
memory_buffer buf;
fmt::writer writer(buf);
// 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(1.2);
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);
}
@ -459,9 +442,9 @@ TEST(FormatterTest, ManyArgs) {
format_error, "argument index out of range");
EXPECT_THROW_MSG(TestFormat<21>::format("{21}"),
format_error, "argument index out of range");
enum { MAX_PACKED_ARGS = fmt::internal::MAX_PACKED_ARGS };
std::string format_str = fmt::format("{{{}}}", MAX_PACKED_ARGS + 1);
EXPECT_THROW_MSG(TestFormat<MAX_PACKED_ARGS>::format(format_str),
enum { max_packed_args = fmt::internal::max_packed_args };
std::string format_str = fmt::format("{{{}}}", max_packed_args + 1);
EXPECT_THROW_MSG(TestFormat<max_packed_args>::format(format_str),
format_error, "argument index out of range");
}
@ -549,6 +532,7 @@ TEST(FormatterTest, NumericAlign) {
format_error, "format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0:=8}", reinterpret_cast<void*>(0xface)),
format_error, "format specifier requires numeric argument");
EXPECT_EQ(" 1", fmt::format("{:= }", 1.0));
}
TEST(FormatterTest, CenterAlign) {
@ -1202,7 +1186,9 @@ TEST(FormatterTest, FormatPointer) {
EXPECT_EQ("0x" + std::string(sizeof(void*) * CHAR_BIT / 4, 'f'),
format("{0}", reinterpret_cast<void*>(~uintptr_t())));
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) {
@ -1213,6 +1199,30 @@ TEST(FormatterTest, FormatStringView) {
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 {
template <>
struct formatter<Date> {
@ -1224,7 +1234,7 @@ struct formatter<Date> {
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());
return ctx.begin();
}
@ -1242,7 +1252,7 @@ class Answer {};
namespace fmt {
template <>
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);
}
};
@ -1396,7 +1406,7 @@ TEST(FormatTest, Print) {
#if FMT_USE_FILE_DESCRIPTORS
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");
}
#endif
@ -1423,7 +1433,7 @@ TEST(FormatTest, JoinArg) {
EXPECT_EQ(L"(1, 2, 3)", format(L"({})", join(v1, v1 + 3, L", ")));
EXPECT_EQ("1, 2, 3", format("{0:{1}}", join(v1, v1 + 3, ", "), 1));
#if FMT_HAS_GXX_CXX11
#if FMT_USE_TRAILING_RETURN && (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 405)
EXPECT_EQ("(1, 2, 3)", format("({})", join(v1, ", ")));
EXPECT_EQ("(+01.20, +03.40)", format("({:+06.2f})", join(v2, ", ")));
#endif
@ -1500,6 +1510,12 @@ TEST(LiteralsTest, NamedArg) {
fmt::arg(L"third", 99)),
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
enum TestEnum { A };
@ -1508,7 +1524,7 @@ TEST(FormatTest, Enum) {
EXPECT_EQ("0", fmt::format("{}", A));
}
#if FMT_USE_STRONG_ENUMS
#if FMT_HAS_FEATURE(cxx_strong_enums)
enum TestFixedEnum : short { B };
TEST(FormatTest, FixedEnum) {
@ -1516,16 +1532,17 @@ TEST(FormatTest, FixedEnum) {
}
#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> {
private:
MOCK_METHOD1(call, void (int value));
public:
using base = fmt::internal::arg_formatter_base<buffer_range>;
using range = buffer_range;
typedef fmt::internal::arg_formatter_base<buffer_range> base;
typedef buffer_range range;
mock_arg_formatter(fmt::context &ctx, fmt::format_specs &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) {
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>
@ -1567,10 +1584,10 @@ struct variant {
namespace fmt {
template <>
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)
return dynamic_formatter::format(42, ctx);
return dynamic_formatter::format("foo", ctx);
return dynamic_formatter<>::format(42, ctx);
return dynamic_formatter<>::format("foo", ctx);
}
};
}
@ -1601,14 +1618,9 @@ TEST(FormatTest, DynamicFormatter) {
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) {
EXPECT_EQ("42", fmt::to_string(42));
EXPECT_EQ("0x1234", fmt::to_string(reinterpret_cast<void*>(0x1234)));
}
TEST(FormatTest, ToWString) {
@ -1719,7 +1731,7 @@ FMT_CONSTEXPR test_format_specs_handler parse_test_specs(const char *s) {
}
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("*^").fill == '*', "");
static_assert(parse_test_specs("+").res == handler::PLUS, "");
@ -1736,7 +1748,7 @@ TEST(FormatTest, ConstexprParseFormatSpecs) {
}
struct test_context {
using char_type = char;
typedef char char_type;
FMT_CONSTEXPR fmt::basic_arg<test_context> next_arg() {
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::format_specs specs;
test_context ctx;
test_context ctx{};
fmt::internal::specs_handler<test_context> h(specs, ctx);
parse_format_specs(s, h);
return specs;
@ -1786,7 +1798,7 @@ TEST(FormatTest, ConstexprSpecsHandler) {
FMT_CONSTEXPR fmt::internal::dynamic_format_specs<char>
parse_dynamic_specs(const char *s) {
fmt::internal::dynamic_format_specs<char> specs;
test_context ctx;
test_context ctx{};
fmt::internal::dynamic_specs_handler<test_context> h(specs, ctx);
parse_format_specs(s, h);
return specs;
@ -1811,13 +1823,13 @@ TEST(FormatTest, ConstexprDynamicSpecsHandler) {
FMT_CONSTEXPR test_format_specs_handler check_specs(const char *s) {
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);
return checker;
}
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("*^").fill == '*', "");
static_assert(check_specs("+").res == handler::PLUS, "");

View File

@ -1,29 +1,9 @@
/*
Tests of custom Google Test assertions.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - tests of custom Google Test assertions
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "gtest-extra.h"

View File

@ -1,29 +1,9 @@
/*
Custom Google Test assertions.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - custom Google Test assertions
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "gtest-extra.h"

View File

@ -1,29 +1,9 @@
/*
Custom Google Test assertions.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - custom Google Test assertions
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_GTEST_EXTRA_H_
#define FMT_GTEST_EXTRA_H_

View File

@ -1,29 +1,9 @@
/*
Mock allocator.
Copyright (c) 2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - mock allocator
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_MOCK_ALLOCATOR_H_
#define FMT_MOCK_ALLOCATOR_H_

View File

@ -1,29 +1,9 @@
/*
std::ostream support tests
Copyright (c) 2012-2016, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - std::ostream support tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/ostream.h"
@ -53,12 +33,12 @@ std::ostream &operator<<(std::ostream &os, TestEnum) {
enum TestEnum2 {A};
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("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> {
test_arg_formatter(fmt::context &ctx, fmt::format_specs &s)

View File

@ -1,29 +1,9 @@
/*
Tests of the C++ interface to POSIX functions that require mocks
Copyright (c) 2012-2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Tests of the C++ interface to POSIX functions that require mocks
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
// Disable bogus MSVC warnings.
#define _CRT_SECURE_NO_WARNINGS

View File

@ -1,29 +1,9 @@
/*
Mocks of POSIX functions
Copyright (c) 2012-2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - mocks of POSIX functions
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_POSIX_TEST_H
#define FMT_POSIX_TEST_H

View File

@ -1,29 +1,9 @@
/*
Tests of the C++ interface to POSIX functions
Copyright (c) 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - tests of the C++ interface to POSIX functions
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include <cstdlib> // std::exit
#include <cstring>

View File

@ -1,29 +1,9 @@
/*
printf tests.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - printf tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include <cctype>
#include <climits>

View File

@ -1,29 +1,9 @@
/*
Test version of FMT_ASSERT
Copyright (c) 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - test version of FMT_ASSERT
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_TEST_ASSERT_H
#define FMT_TEST_ASSERT_H

View File

@ -1,29 +1,9 @@
/*
Test main function.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - test main function.
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include <cstdlib>
#include <gtest/gtest.h>

View File

@ -1,11 +1,9 @@
/*
Time formatting tests
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
// Formatting library for C++ - time formatting tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifdef WIN32
#define _CRT_SECURE_NO_WARNINGS

View File

@ -1,29 +1,9 @@
/*
Utility tests.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - utility tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "test-assert.h"
@ -81,7 +61,7 @@ struct formatter<Test, Char> {
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)
-> decltype(ctx.begin()) {
@ -361,7 +341,7 @@ TEST(MemoryBufferTest, Allocator) {
{
basic_memory_buffer<char, 10, TestAllocator> buffer2((TestAllocator(&alloc)));
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));
buffer2.reserve(size);
EXPECT_CALL(alloc, deallocate(&mem, size));
@ -372,7 +352,7 @@ TEST(MemoryBufferTest, ExceptionInDeallocate) {
typedef AllocatorRef< MockAllocator<char> > TestAllocator;
StrictMock< MockAllocator<char> > 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);
{
EXPECT_CALL(alloc, allocate(size)).WillOnce(Return(&mem[0]));
@ -436,19 +416,21 @@ TEST(UtilTest, FormatArgs) {
}
struct custom_context {
using char_type = char;
typedef char char_type;
template <typename T>
struct formatter_type {
template <typename ParseContext>
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
struct type {
template <typename ParseContext>
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
const char *format(const T &, custom_context& ctx) {
ctx.called = true;
return 0;
}
const char *format(const T &, custom_context& ctx) {
ctx.called = true;
return 0;
}
};
};
bool called;
@ -476,12 +458,12 @@ bool operator==(custom_value<Char> lhs, custom_value<Char> rhs) {
}
}
template <typename T>
struct MockVisitor {
// Use a unique result type to make sure that there are no undesirable
// conversions.
struct Result {};
// Use a unique result type to make sure that there are no undesirable
// conversions.
struct Result {};
template <typename T>
struct MockVisitor: fmt::internal::function<Result> {
MockVisitor() {
ON_CALL(*this, visit(_)).WillByDefault(Return(Result()));
}
@ -523,12 +505,13 @@ VISIT_TYPE(float, double);
#define CHECK_ARG_(Char, expected, value) { \
testing::StrictMock<MockVisitor<decltype(expected)>> visitor; \
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)); \
}
#define CHECK_ARG(value) { \
typename VisitType<decltype(value)>::Type expected = value; \
#define CHECK_ARG(value, typename_) { \
typedef decltype(value) value_type; \
typename_ VisitType<value_type>::Type expected = value; \
CHECK_ARG_(char, 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) {
CHECK_ARG(test_value<TypeParam>());
CHECK_ARG(std::numeric_limits<TypeParam>::min());
CHECK_ARG(std::numeric_limits<TypeParam>::max());
CHECK_ARG(test_value<TypeParam>(), typename);
CHECK_ARG(std::numeric_limits<TypeParam>::min(), typename);
CHECK_ARG(std::numeric_limits<TypeParam>::max(), typename);
}
TEST(UtilTest, CharArg) {
@ -592,22 +575,25 @@ TEST(UtilTest, PointerArg) {
const void *cp = 0;
CHECK_ARG_(char, cp, p);
CHECK_ARG_(wchar_t, cp, p);
CHECK_ARG(cp);
CHECK_ARG(cp, );
}
TEST(UtilTest, CustomArg) {
::Test test;
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) {
struct check_custom {
Result operator()(fmt::basic_arg<fmt::context>::handle h) const {
fmt::memory_buffer buffer;
fmt::internal::basic_buffer<char> &base = buffer;
fmt::context ctx(std::back_inserter(base), "", fmt::format_args());
h.format(ctx);
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));
}
@ -841,15 +827,15 @@ TEST(UtilTest, ReportWindowsError) {
enum TestEnum2 {};
TEST(UtilTest, ConvertToInt) {
EXPECT_FALSE(fmt::internal::convert_to_int<char>::value);
EXPECT_FALSE(fmt::internal::convert_to_int<const char *>::value);
EXPECT_TRUE(fmt::internal::convert_to_int<TestEnum2>::value);
EXPECT_FALSE((fmt::internal::convert_to_int<char, char>::value));
EXPECT_FALSE((fmt::internal::convert_to_int<const char *, char>::value));
EXPECT_TRUE((fmt::internal::convert_to_int<TestEnum2, char>::value));
}
#if FMT_USE_ENUM_BASE
enum TestEnum : char {TestValue};
TEST(UtilTest, IsEnumConvertibleToInt) {
EXPECT_TRUE(fmt::internal::convert_to_int<TestEnum>::value);
EXPECT_TRUE((fmt::internal::convert_to_int<TestEnum, char>::value));
}
#endif

View File

@ -1,29 +1,9 @@
/*
Test utilities.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - test utilities
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "util.h"
#include <cstring>

View File

@ -1,29 +1,9 @@
/*
Test utilities.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - test utilities
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include <cstdarg>
#include <cstdio>