This commit is contained in:
Remotion 2018-05-21 13:10:15 +02:00
commit 48415bc740
15 changed files with 167 additions and 114 deletions

View File

@ -95,8 +95,8 @@ function(add_headers VAR)
endfunction()
# Define the fmt library, its includes and the needed defines.
add_headers(FMT_HEADERS core.h format.h format-inl.h locale.h ostream.h printf.h
time.h ranges.h)
add_headers(FMT_HEADERS core.h format.h format-inl.h ostream.h printf.h time.h
ranges.h)
set(FMT_SOURCES src/format.cc)
if (HAVE_OPEN)
add_headers(FMT_HEADERS posix.h)

View File

@ -20,6 +20,7 @@
.. code:: c++
#include <fmt/format.h>
std::string s = format(fmt("{:d}"), "foo");
gives a compile-time error because ``d`` is an invalid specifier for strings
@ -133,7 +134,9 @@
vreport_error(format, fmt::make_format_args(args...));
}
* Added the ``make_printf_args`` function for capturing ``printf`` arguments.
* Added the ``make_printf_args`` function for capturing ``printf`` arguments (
`#687 <https://github.com/fmtlib/fmt/issues/687>`_,
`#694 <https://github.com/fmtlib/fmt/pull/694>`_).
Thanks `@Kronuz (Germán Méndez Bravo) <https://github.com/Kronuz>`_.
* Added prefix ``v`` to non-variadic functions taking ``format_args`` to
@ -146,6 +149,34 @@
template <typename... Args>
std::string format(string_view format_str, const Args & ... args);
* Added experimental support for formatting ranges, containers and tuple-like
types in ``fmt/ranges.h`` (`#735 <https://github.com/fmtlib/fmt/pull/735>`_):
.. code:: c++
#include <fmt/ranges.h>
std::vector<int> v = {1, 2, 3};
fmt::print("{}", v); // prints {1, 2, 3}
Thanks `@Remotion (Remo) <https://github.com/Remotion>`_.
* Implemented ``wchar_t`` date and time formatting
(`#712 <https://github.com/fmtlib/fmt/pull/712>`_):
.. code:: c++
#include <fmt/time.h>
std::time_t t = std::time(nullptr);
auto s = fmt::format(L"The date is {:%Y-%m-%d}.", *std::localtime(&t));
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_.
* Provided more wide string overloads
(`#724 <https://github.com/fmtlib/fmt/pull/724>`_).
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_.
* Switched from a custom null-terminated string view class to ``string_view``
in the format API and provided ``fmt::string_view`` which implements a subset
of ``std::string_view`` API for pre-C++17 systems.
@ -188,6 +219,8 @@
* Implemented more efficient handling of large number of format arguments.
* Introduced an inline namespace for symbol versioning.
* Added debug postfix ``d`` to the `fmt`` library name
(`#636 <https://github.com/fmtlib/fmt/issues/636>`_).
@ -229,12 +262,21 @@
`#656 <https://github.com/fmtlib/fmt/pull/656>`_,
`#679 <https://github.com/fmtlib/fmt/pull/679>`_,
`#681 <https://github.com/fmtlib/fmt/pull/681>`_,
`#705 <https://github.com/fmtlib/fmt/pull/705>`_).
`#705 <https://github.com/fmtlib/fmt/pull/705>`_,
`#715 <https://github.com/fmtlib/fmt/issues/715>`_,
`#717 <https://github.com/fmtlib/fmt/pull/717>`_,
`#720 <https://github.com/fmtlib/fmt/pull/720>`_,
`#723 <https://github.com/fmtlib/fmt/pull/723>`_,
`#726 <https://github.com/fmtlib/fmt/pull/726>`_,
`#730 <https://github.com/fmtlib/fmt/pull/730>`_,
`#739 <https://github.com/fmtlib/fmt/pull/739>`_).
Thanks `@peterbell10 <https://github.com/peterbell10>`_,
`@LarsGullik <https://github.com/LarsGullik>`_,
`@foonathan (Jonathan Müller) <https://github.com/foonathan>`_,
`@eliaskosunen (Elias Kosunen) <https://github.com/eliaskosunen>`_, and
`@christianparpart (Christian Parpart) <https://github.com/christianparpart>`_.
`@eliaskosunen (Elias Kosunen) <https://github.com/eliaskosunen>`_,
`@christianparpart (Christian Parpart) <https://github.com/christianparpart>`_,
`@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_,
and `@mwinterb <https://github.com/mwinterb>`_.
* Worked around an MSVC bug and fixed several warnings
(`#653 <https://github.com/fmtlib/fmt/pull/653>`_).
@ -260,10 +302,17 @@
(`#660 <https://github.com/fmtlib/fmt/pull/660>`_).
Thanks `@hubslave <https://github.com/hubslave>`_.
* Fixed compilation on FreeBSD 12
(`#732 <https://github.com/fmtlib/fmt/pull/732>`_).
Thanks `@dankm <https://github.com/dankm>`_.
* Fixed compilation when there is a mismatch between ``-std`` options between
the library and user code
(`#664 <https://github.com/fmtlib/fmt/issues/664>`_).
* Fixed compilation with GCC 7 and ``-std=c++11``
(`#734 <https://github.com/fmtlib/fmt/issues/734>`_).
* Improved generated binary code on GCC 7 and older
(`#668 <https://github.com/fmtlib/fmt/issues/668>`_).
@ -286,6 +335,17 @@
* Fixed compile checks for mixing narrow and wide strings
(`#690 <https://github.com/fmtlib/fmt/issues/690>`_).
* Disabled unsafe implicit conversion to ``std::string``
(`#729 <https://github.com/fmtlib/fmt/issues/729>`_).
* Fixed handling of reused format specs (as in ``fmt::join``) for pointers
(`#725 <https://github.com/fmtlib/fmt/pull/725>`_).
Thanks `@mwinterb <https://github.com/mwinterb>`_.
* Fixed installation of ``fmt/ranges.h``
(`#738 <https://github.com/fmtlib/fmt/pull/738>`_).
Thanks `@sv1990 <https://github.com/sv1990>`_.
4.1.0 - 2017-12-20
------------------

View File

@ -164,6 +164,10 @@ Utilities
System errors
-------------
fmt does not use ``errno`` to communicate errors to the user, but it may call
system functions which set ``errno``. Users should not make any assumptions about
the value of ``errno`` being preserved by library functions.
.. doxygenclass:: fmt::system_error
:members:

View File

@ -2,8 +2,7 @@ Overview
========
**fmt** (formerly cppformat) is an open-source formatting library.
It can be used as a safe alternative to printf or as a fast
alternative to C++ IOStreams.
It can be used as a fast and safe alternative to printf and IOStreams.
.. raw:: html
@ -30,9 +29,9 @@ in Python:
.. code:: c++
fmt::format("The answer is {}", 42);
fmt::format("The answer is {}.", 42);
The ``fmt::format`` function returns a string "The answer is 42". You can use
The ``fmt::format`` function returns a string "The answer is 42.". You can use
``fmt::memory_buffer`` to avoid constructing ``std::string``:
.. code:: c++
@ -94,19 +93,25 @@ Safety
------
The library is fully type safe, automatic memory management prevents buffer
overflow, errors in format strings are reported using exceptions. For example,
the code
overflow, errors in format strings are reported using exceptions or at compile
tim. For example, the code
.. code:: c++
fmt::format("The answer is {:d}", "forty-two");
throws a ``format_error`` exception with description
"unknown format code 'd' for string", because the argument
``"forty-two"`` is a string while the format code ``d``
only applies to integers.
throws a ``format_error`` exception with description "unknown format code 'd' for
string", because the argument ``"forty-two"`` is a string while the format code
``d`` only applies to integers, while
Where possible, errors are caught at compile time. For example, the code
.. code:: c++
format(fmt("The answer is {:d}"), "forty-two");
reports a compile-time error for the same reason on compilers that support
relaxed ``constexpr``.
The following code
.. code:: c++
@ -124,16 +129,10 @@ its numeric value being written to the stream (i.e. 1070 instead of letter 'ю'
which is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is
needed.
Note that fmt does not use the value of the ``errno`` global to communicate
errors to the user, but it may call system functions which set ``errno``. Since
fmt does not attempt to preserve the value of ``errno``, users should not make
any assumptions about it and always set it to ``0`` before making any system
calls that convey error information via ``errno``.
Compact binary code
-------------------
Each call to a formatting function results in a compact binary code. For example
The library is designed to produce compact per-call compiled code. For example
(`godbolt <https://godbolt.org/g/TZU4KF>`_),
.. code:: c++
@ -167,33 +166,19 @@ compiles to just
Portability
-----------
The library is highly portable. Here is an incomplete list of operating systems
and compilers where it has been tested and known to work:
The library is highly portable and relies only on a small set of C++11 features:
* 64-bit (amd64) GNU/Linux with GCC 4.4.3,
`4.6.3 <https://travis-ci.org/fmtlib/fmt>`_, 4.7.2, 4.8.1, and Intel C++
Compiler (ICC) 14.0.2
* variadic templates
* type traits
* rvalue references
* decltype
* trailing return types
* deleted functions
* 32-bit (i386) GNU/Linux with GCC 4.4.3, 4.6.3
* Mac OS X with GCC 4.2.1 and Clang 4.2, 5.1.0
* 64-bit Windows with Visual C++ 2010, 2013 and
`2015 <https://ci.appveyor.com/project/vitaut/fmt>`_
* 32-bit Windows with Visual C++ 2010
Although the library uses C++11 features when available, it also works with
older compilers and standard library implementations. The only thing to keep in
mind for C++98 portability:
* Variadic templates: minimum GCC 4.4, Clang 2.9 or VS2013. This feature allows
the Format API to accept an unlimited number of arguments. With older
compilers the maximum is 15.
* User-defined literals: minimum GCC 4.7, Clang 3.1 or VS2015. The suffixes
``_format`` and ``_a`` are functionally equivalent to the functions
``fmt::format`` and ``fmt::arg``.
These are available since GCC 4.4, Clang 2.9 and MSVC 18.0 (2013). For older
compilers use fmt `version 4.x
<https://github.com/fmtlib/fmt/releases/tag/4.1.0>`_ which continues to be
maintained and only requires C++98.
The output of all formatting functions is consistent across platforms. In
particular, formatting a floating-point infinity always gives ``inf`` while the
@ -211,7 +196,7 @@ Ease of Use
-----------
fmt has a small self-contained code base with the core library consisting of
a single header file and a single source file and no external dependencies.
just three header files and no external dependencies.
A permissive BSD `license <https://github.com/fmtlib/fmt#license>`_ allows
using the library both in open-source and commercial projects.

View File

@ -616,7 +616,8 @@ FMT_MAKE_VALUE(pointer_type, std::nullptr_t, const void*)
// formatting of "[const] volatile char *" which is printed as bool by
// iostreams.
template <typename C, typename T>
typed_value<C, pointer_type> make_value(const T *) {
typename std::enable_if<!std::is_same<T, typename C::char_type>::value>::type
make_value(const T *) {
static_assert(!sizeof(T), "formatting of non-void pointers is disallowed");
}
@ -1240,12 +1241,12 @@ inline std::string format(string_view format_str, const Args & ... args) {
// This should be just
// return vformat(format_str, make_format_args(args...));
// but gcc has trouble optimizing the latter, so break it down.
format_arg_store<format_context, Args...> as(args...);
format_arg_store<format_context, Args...> as{args...};
return vformat(format_str, as);
}
template <typename... Args>
inline std::wstring format(wstring_view format_str, const Args & ... args) {
format_arg_store<wformat_context, Args...> as(args...);
format_arg_store<wformat_context, Args...> as{args...};
return vformat(format_str, as);
}
@ -1286,7 +1287,7 @@ FMT_API void vprint(wstring_view format_str, wformat_args args);
*/
template <typename... Args>
inline void print(string_view format_str, const Args & ... args) {
format_arg_store<format_context, Args...> as(args...);
format_arg_store<format_context, Args...> as{args...};
vprint(format_str, as);
}

View File

@ -9,7 +9,6 @@
#define FMT_FORMAT_INL_H_
#include "format.h"
#include "locale.h"
#include <string.h>
@ -19,6 +18,7 @@
#include <cmath>
#include <cstdarg>
#include <cstddef> // for std::ptrdiff_t
#include <locale>
#if defined(_WIN32) && defined(__MINGW32__)
# include <cstring>
@ -205,6 +205,15 @@ void report_error(FormatFunc func, int error_code,
}
} // namespace
class locale {
private:
std::locale locale_;
public:
explicit locale(std::locale loc = std::locale()) : locale_(loc) {}
std::locale get() { return locale_; }
};
template <typename Char>
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
std::locale loc = lp ? lp->locale().get() : std::locale();

View File

@ -304,7 +304,7 @@ fp operator*(fp x, fp y);
// Compute k such that its cached power c_k = c_k.f * pow(2, c_k.e) satisfies
// min_exponent <= c_k.e + e <= min_exponent + 3.
inline int compute_cached_power_index(int e, int min_exponent) {
constexpr double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
return static_cast<int>(std::ceil((min_exponent - e + 63) * one_over_log2_10));
}
@ -2236,7 +2236,9 @@ void handle_dynamic_spec(
/** The default argument formatter. */
template <typename Range>
class arg_formatter:
public internal::function<void>, public internal::arg_formatter_base<Range> {
public internal::function<
typename internal::arg_formatter_base<Range>::iterator>,
public internal::arg_formatter_base<Range> {
private:
typedef typename Range::value_type char_type;
typedef internal::arg_formatter_base<Range> base;

View File

@ -1,25 +0,0 @@
// Formatting library for C++ - locale support
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_LOCALE_H_
#define FMT_LOCALE_H_
#include "format.h"
#include <locale>
FMT_BEGIN_NAMESPACE
class locale {
private:
std::locale locale_;
public:
explicit locale(std::locale loc = std::locale()) : locale_(loc) {}
std::locale get() { return locale_; }
};
FMT_END_NAMESPACE
#endif // FMT_LOCALE_

View File

@ -140,13 +140,13 @@ inline void vprint(std::basic_ostream<Char> &os,
template <typename... Args>
inline void print(std::ostream &os, string_view format_str,
const Args & ... args) {
vprint(os, format_str, make_format_args<format_context>(args...));
vprint<char>(os, format_str, make_format_args<format_context>(args...));
}
template <typename... Args>
inline void print(std::wostream &os, wstring_view format_str,
const Args & ... args) {
vprint(os, format_str, make_format_args<wformat_context>(args...));
vprint<wchar_t>(os, format_str, make_format_args<wformat_context>(args...));
}
FMT_END_NAMESPACE

View File

@ -215,7 +215,9 @@ class basic_printf_context;
*/
template <typename Range>
class printf_arg_formatter:
public internal::function<void>, public internal::arg_formatter_base<Range> {
public internal::function<
typename internal::arg_formatter_base<Range>::iterator>,
public internal::arg_formatter_base<Range> {
private:
typedef typename Range::value_type char_type;
typedef decltype(internal::declval<Range>().begin()) iterator;
@ -627,7 +629,7 @@ template <typename... Args>
inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args) {
auto vargs = make_format_args<
typename printf_context<internal::buffer>::type>(args...);
return vfprintf(f, format_str, vargs);
return vfprintf<char>(f, format_str, vargs);
}
template <typename... Args>

View File

@ -34,18 +34,20 @@ template <typename Char, typename Enable = void>
struct formatting_range : formatting_base<Char> {
static FMT_CONSTEXPR_DECL const std::size_t range_length_limit =
FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range.
Char prefix = '{';
Char delimiter = ',';
Char postfix = '}';
Char prefix;
Char delimiter;
Char postfix;
formatting_range() : prefix('{'), delimiter(','), postfix('}') {}
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
};
template <typename Char, typename Enable = void>
struct formatting_tuple : formatting_base<Char> {
Char prefix = '(';
Char delimiter = ',';
Char postfix = ')';
Char prefix;
Char delimiter;
Char postfix;
formatting_tuple() : prefix('('), delimiter(','), postfix(')') {}
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
};
@ -54,9 +56,8 @@ namespace internal {
template <typename RangeT, typename OutputIterator>
void copy(const RangeT &range, OutputIterator out) {
for (const auto &it : range) {
*out++ = it;
}
for (auto it = range.begin(), end = range.end(); it != end; ++it)
*out++ = *it;
}
template <typename OutputIterator>
@ -83,7 +84,7 @@ class is_like_std_string {
public:
static FMT_CONSTEXPR_DECL const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
};
template <typename... Ts>
@ -95,8 +96,8 @@ struct is_range_ : std::false_type {};
template <typename T>
struct is_range_<T,typename std::conditional<
false,
conditional_helper<decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end())>,
conditional_helper<decltype(internal::declval<T>().begin()),
decltype(internal::declval<T>().end())>,
void>::type> : std::true_type {};
template <typename T>
@ -111,13 +112,13 @@ class is_tuple_like_ {
template <typename U>
static auto check(U *p) ->
decltype(std::tuple_size<U>::value,
std::declval<typename std::tuple_element<0, U>::type>(), int());
internal::declval<typename std::tuple_element<0, U>::type>(), int());
template <typename>
static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
};
template <typename T>
@ -125,7 +126,16 @@ struct is_tuple_like {
static FMT_CONSTEXPR_DECL const bool value =
is_tuple_like_<T>::value && !is_range_<T>::value;
};
} // namespace internal
#if FMT_HAS_FEATURE(__cpp_lib_integer_sequence)
# define FMT_USE_INTEGER_SEQUENCE 1
#else
# define FMT_USE_INTEGER_SEQUENCE 0
#endif
#if FMT_USE_INTEGER_SEQUENCE
namespace internal {
template <size_t... Is, class Tuple, class F>
void for_each(std::index_sequence<Is...>, Tuple &&tup, F &&f) noexcept {
using std::get;
@ -183,6 +193,7 @@ struct formatter<TupleT, Char,
return ctx.out();
}
};
#endif // FMT_USE_INTEGER_SEQUENCE
template <typename RangeT, typename Char>
struct formatter< RangeT, Char,
@ -196,11 +207,12 @@ struct formatter< RangeT, Char,
}
template <typename FormatContext>
auto format(const RangeT &values, FormatContext &ctx) -> decltype(ctx.out()) {
typename FormatContext::iterator format(
const RangeT &values, FormatContext &ctx) {
auto out = ctx.out();
internal::copy(formatting.prefix, out);
std::size_t i = 0;
for (const auto &it : values) {
for (auto it = values.begin(), end = values.end(); it != end; ++it) {
if (i > 0) {
if (formatting.add_prepostfix_space) {
*out++ = ' ';
@ -208,9 +220,9 @@ struct formatter< RangeT, Char,
internal::copy(formatting.delimiter, out);
}
if (formatting.add_delimiter_spaces && i > 0) {
format_to(out, " {}", it);
format_to(out, " {}", *it);
} else {
format_to(out, "{}", it);
format_to(out, "{}", *it);
}
if (++i > formatting.range_length_limit) {
format_to(out, " ... <other elements>");

View File

@ -223,9 +223,9 @@ buffered_file file::fdopen(const char *mode) {
if (!f)
FMT_THROW(system_error(errno,
"cannot associate stream with file descriptor"));
buffered_file file(f);
buffered_file bf(f);
fd_ = -1;
return file;
return bf;
}
long getpagesize() {

View File

@ -1394,7 +1394,8 @@ TEST(FormatTest, FixedEnum) {
typedef fmt::back_insert_range<fmt::internal::buffer> buffer_range;
class mock_arg_formatter:
public fmt::internal::function<void>,
public fmt::internal::function<
fmt::internal::arg_formatter_base<buffer_range>::iterator>,
public fmt::internal::arg_formatter_base<buffer_range> {
private:
MOCK_METHOD1(call, void (int value));

View File

@ -30,6 +30,7 @@ TEST(RangesTest, FormatVector2) {
EXPECT_EQ("{{1, 2}, {3, 5}, {7, 11}}", ivf);
}
#if FMT_USE_INTEGER_SEQUENCE
TEST(RangesTest, FormatMap) {
std::map<std::string, int32_t> simap{{"one", 1}, {"two", 2}};
EXPECT_EQ("{(one, 1), (two, 2)}", fmt::format("{}", simap));
@ -46,7 +47,7 @@ TEST(RangesTest, FormatTuple) {
EXPECT_EQ("(42, 3.14159, this is tuple)", fmt::format("{}", tu1));
}
/// check if 'if constexpr' is supported.
/// Check if 'if constexpr' is supported.
#if (__cplusplus > 201402L) || \
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
@ -86,3 +87,4 @@ TEST(RangesTest, FormatStruct) {
#endif // (__cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >
// 201402L && _MSC_VER >= 1910)
#endif // FMT_USE_INTEGER_SEQUENCE

View File

@ -17,7 +17,6 @@
# include <type_traits>
#endif
#include "fmt/locale.h"
#include "gmock/gmock.h"
#include "gtest-extra.h"
#include "mock-allocator.h"
@ -397,13 +396,14 @@ TEST(FixedBufferTest, BufferOverflow) {
EXPECT_THROW_MSG(buffer.resize(11), std::runtime_error, "buffer overflow");
}
struct uint32_pair {
uint32_t u[2];
};
TEST(UtilTest, BitCast) {
struct S {
uint32_t u[2];
};
auto s = fmt::internal::bit_cast<S>(uint64_t(42));
auto s = fmt::internal::bit_cast<uint32_pair>(uint64_t{42});
EXPECT_EQ(fmt::internal::bit_cast<uint64_t>(s), 42u);
s = fmt::internal::bit_cast<S>(uint64_t(~0ull));
s = fmt::internal::bit_cast<uint32_pair>(uint64_t(~0ull));
EXPECT_EQ(fmt::internal::bit_cast<uint64_t>(s), ~0ull);
}