externals: Update fmt subtree to 4.10

Merge commit '097203968f0a9b17628062f4adca63ea5cb97aa2' into HEAD
This commit is contained in:
MerryMage 2020-04-22 20:41:46 +01:00
commit 7639f6ebdc
21 changed files with 481 additions and 141 deletions

View file

@ -2,6 +2,14 @@ message(STATUS "CMake version: ${CMAKE_VERSION}")
cmake_minimum_required(VERSION 2.8.12)
if (POLICY CMP0048) # Version variables
cmake_policy(SET CMP0048 OLD)
endif ()
if (POLICY CMP0063) # Visibility
cmake_policy(SET CMP0063 OLD)
endif (POLICY CMP0063)
# Determine if fmt is built as a subproject (using add_subdirectory)
# or if it is the master project.
set(MASTER_PROJECT OFF)

View file

@ -1,7 +1,32 @@
4.1.0 - 2017-12-20
------------------
* Added ``fmt::to_wstring()`` in addition to ``fmt::to_string()`` (`#559 <https://github.com/fmtlib/fmt/pull/559>`_). Thanks `@alabuzhev (Alex Alabuzhev) <https://github.com/alabuzhev>`_.
* Added support for C++17 ``std::string_view`` (`#571 <https://github.com/fmtlib/fmt/pull/571>`_ and `#578 <https://github.com/fmtlib/fmt/pull/578>`_). Thanks `@thelostt (Mário Feroldi) <https://github.com/thelostt>`_ and `@mwinterb <https://github.com/mwinterb>`_.
* Enabled stream exceptions to catch errors (`#581 <https://github.com/fmtlib/fmt/issues/581>`_). Thanks `@crusader-mike <https://github.com/crusader-mike>`_.
* Allowed formatting of class hierarchies with ``fmt::format_arg()`` (`#547 <https://github.com/fmtlib/fmt/pull/547>`_). Thanks `@rollbear (Björn Fahller) <https://github.com/rollbear>`_.
* Removed limitations on character types
(`#563 <https://github.com/fmtlib/fmt/pull/563>`_).
Thanks `@Yelnats321 (Elnar Dakeshov) <https://github.com/Yelnats321>`_.
* Conditionally enabled use of ``std::allocator_traits`` (`#583 <https://github.com/fmtlib/fmt/pull/583>`_). Thanks `@mwinterb <https://github.com/mwinterb>`_.
* Added support for ``const`` variadic member function emulation with ``FMT_VARIADIC_CONST`` (`#591 <https://github.com/fmtlib/fmt/pull/591>`_). Thanks `@ludekvodicka (Ludek Vodicka) <https://github.com/ludekvodicka>`_.
* Various bugfixes: bad overflow check, unsupported implicit type conversion when determining formatting function, test segfaults (`#551 <https://github.com/fmtlib/fmt/issues/551>`_), ill-formed macros (`#542 <https://github.com/fmtlib/fmt/pull/542>`_) and ambiguous overloads (`#580 <https://github.com/fmtlib/fmt/issues/580>`_). Thanks `@xylosper (Byoung-young Lee) <https://github.com/xylosper>`_.
* Prevented warnings on MSVC (`#605 <https://github.com/fmtlib/fmt/pull/605>`_, `#602 <https://github.com/fmtlib/fmt/pull/602>`_, and `#545 <https://github.com/fmtlib/fmt/pull/545>`_), clang (`#582 <https://github.com/fmtlib/fmt/pull/582>`_), GCC (`#573 <https://github.com/fmtlib/fmt/issues/573>`_), various conversion warnings (`#609 <https://github.com/fmtlib/fmt/pull/609>`_, `#567 <https://github.com/fmtlib/fmt/pull/567>`_, `#553 <https://github.com/fmtlib/fmt/pull/553>`_ and `#553 <https://github.com/fmtlib/fmt/pull/553>`_), and added ``override`` and ``[[noreturn]]`` (`#549 <https://github.com/fmtlib/fmt/pull/549>`_ and `#555 <https://github.com/fmtlib/fmt/issues/555>`_). Thanks `@alabuzhev (Alex Alabuzhev) <https://github.com/alabuzhev>`_, `@virgiliofornazin (Virgilio Alexandre Fornazin) <https://gihtub.com/virgiliofornazin>`_, `@alexanderbock (Alexander Bock) <https://github.com/alexanderbock>`_, `@yumetodo <https://github.com/yumetodo>`_, `@VaderY (Császár Mátyás) <https://github.com/VaderY>`_, `@jpcima (JP Cimalando) <https://github.com/jpcima>`_, `@thelostt (Mário Feroldi) <https://github.com/thelostt>`_, and `@Manu343726 (Manu Sánchez) <https://github.com/Manu343726>`_.
* Improved CMake: Used GNUInstallDirs to set installation location (`#610 <https://github.com/fmtlib/fmt/pull/610>`_) and fixed warnings (`#536 <https://github.com/fmtlib/fmt/pull/536>`_ and `#556 <https://github.com/fmtlib/fmt/pull/556>`_). Thanks `@mikecrowe (Mike Crowe) <https://github.com/mikecrowe>`_, `@evgen231 <https://github.com/evgen231>`_ and `@henryiii (Henry Schreiner) <https://github.com/henryiii>`_.
4.0.0 - 2017-06-27
------------------
* Removed old compatibility headers ``cppformat/*.h`` and CMake options (`#527 <https://github.com/pull/527>`_). Thanks `@maddinat0r (Alex Martin) <https://github.com/maddinat0r>`_.
* Removed old compatibility headers ``cppformat/*.h`` and CMake options (`#527 <https://github.com/fmtlib/fmt/pull/527>`_). Thanks `@maddinat0r (Alex Martin) <https://github.com/maddinat0r>`_.
* Added ``string.h`` containing ``fmt::to_string()`` as alternative to ``std::to_string()`` as well as other string writer functionality (`#326 <https://github.com/fmtlib/fmt/issues/326>`_ and `#441 <https://github.com/fmtlib/fmt/pull/441>`_):

View file

@ -142,6 +142,8 @@ Projects using this library
* `Envoy <https://lyft.github.io/envoy/>`_: C++ L7 proxy and communication bus (Lyft)
* `FiveM <https://fivem.net/>`_: a modification framework for GTA V
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
Player vs Player Gaming Network with tweaks
@ -155,6 +157,8 @@ Projects using this library
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to generate randomized datasets
* `OpenSpace <http://openspaceproject.com/>`_: An open-source astrovisualization framework
* `PenUltima Online (POL) <http://www.polserver.com/>`_:
An MMO server, compatible with most Ultima Online clients

View file

@ -84,6 +84,36 @@ Note in the example above the ``format_arg`` function ignores the contents of
``format_arg`` in :file:`fmt/time.h` for an advanced example of how to use
the ``format_str`` argument to customize the formatted output.
This technique can also be used for formatting class hierarchies::
namespace local {
struct Parent {
Parent(int p) : p(p) {}
virtual void write(fmt::Writer &w) const {
w.write("Parent : p={}", p);
}
int p;
};
struct Child : Parent {
Child(int c, int p) : Parent(p), c(c) {}
virtual void write(fmt::Writer &w) const {
w.write("Child c={} : ", c);
Parent::write(w);
}
int c;
};
void format_arg(fmt::BasicFormatter<char> &f,
const char *&format_str, const Parent &p) {
p.write(f.writer());
}
}
Local::Child c(1,2);
Local::Parent &p = c;
fmt::print("via ref to base: {}\n", p);
fmt::print("direct to child: {}\n", c);
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.
@ -232,6 +262,8 @@ Utilities
.. doxygenfunction:: fmt::to_string(const T&)
.. doxygenfunction:: fmt::to_wstring(const T&)
.. doxygenclass:: fmt::BasicStringRef
:members:

View file

@ -6,6 +6,8 @@ import errno, os, shutil, sys, tempfile
from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE
from distutils.version import LooseVersion
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0']
def pip_install(package, commit=None, **kwargs):
"Install package using pip."
min_version = kwargs.get('min_version')
@ -93,11 +95,11 @@ def build_docs(version='dev', **kwargs):
if p.returncode != 0:
raise CalledProcessError(p.returncode, cmd)
html_dir = os.path.join(work_dir, 'html')
versions = ['3.0.0', '2.0.0', '1.1.0']
main_versions = reversed(versions[-3:])
check_call(['sphinx-build',
'-Dbreathe_projects.format=' + os.path.abspath(doxyxml_dir),
'-Dversion=' + version, '-Drelease=' + version,
'-Aversion=' + version, '-Aversions=' + ','.join(versions),
'-Aversion=' + version, '-Aversions=' + ','.join(main_versions),
'-b', 'html', doc_dir, html_dir])
try:
check_call(['lessc', '--clean-css',

View file

@ -143,6 +143,12 @@ 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``.
.. _portability:
Portability

View file

@ -335,6 +335,16 @@ Aligning the text and specifying a width::
format("{:*^30}", "centered"); // use '*' as a fill char
// Result: "***********centered***********"
Dynamic width::
format("{:<{}}", "left aligned", 30);
// Result: "left aligned "
Dynamic precision::
format("{:.{}f}", 3.14, 1);
// Result: "3.1"
Replacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign::
format("{:+f}; {:+f}", 3.14, -3.14); // show it always
@ -359,13 +369,6 @@ Replacing ``%x`` and ``%o`` and converting the value to different bases::
format("{:,}", 1234567890);
'1,234,567,890'
Expressing a percentage::
>>> points = 19
>>> total = 22
Format("Correct answers: {:.2%}") << points/total)
'Correct answers: 86.36%'
Using type-specific formatting::
>>> import datetime

View file

@ -41,6 +41,10 @@ current directory. Now you can build the library by running :command:`make`.
Once the library has been built you can invoke :command:`make test` to run
the tests.
You can control generation of the make ``test`` target with the ``FMT_TEST``
CMake option. This can be useful if you include fmt as a subdirectory in
your project but don't want to add fmt's tests to your ``test`` target.
If you use Windows and have Visual Studio installed, a :file:`FORMAT.sln`
file and several :file:`.vcproj` files will be created. You can then build them
using Visual Studio or msbuild.

View file

@ -49,8 +49,9 @@ endif ()
# Install targets.
if (FMT_INSTALL)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
set(FMT_CMAKE_DIR lib/cmake/fmt CACHE STRING
set(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING
"Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.")
set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake)
set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake)
@ -61,9 +62,12 @@ if (FMT_INSTALL)
set(INSTALL_TARGETS ${INSTALL_TARGETS} fmt-header-only)
endif ()
set(FMT_LIB_DIR lib CACHE STRING
set(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING
"Installation directory for libraries, relative to ${CMAKE_INSTALL_PREFIX}.")
set(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR}/fmt CACHE STRING
"Installation directory for include files, relative to ${CMAKE_INSTALL_PREFIX}.")
# Generate the version, config and target files into the build directory.
write_basic_package_version_file(
${version_config}
@ -86,5 +90,5 @@ if (FMT_INSTALL)
# Install the library and headers.
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
DESTINATION ${FMT_LIB_DIR})
install(FILES ${FMT_HEADERS} DESTINATION include/fmt)
install(FILES ${FMT_HEADERS} DESTINATION ${FMT_INC_DIR})
endif ()

View file

@ -72,9 +72,11 @@
// Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
FMT_MAYBE_UNUSED
static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
return fmt::internal::Null<>();
}
FMT_MAYBE_UNUSED
static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
return fmt::internal::Null<>();
}
@ -121,7 +123,7 @@ typedef void (*FormatFunc)(Writer &, int, StringRef);
// Buffer should be at least of size 1.
int safe_strerror(
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
class StrError {
private:
@ -159,6 +161,11 @@ int safe_strerror(
ERANGE : result;
}
#ifdef __c2__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
// Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(internal::Null<>) {
errno = 0;
@ -166,13 +173,15 @@ int safe_strerror(
return errno;
}
#ifdef __c2__
# pragma clang diagnostic pop
#endif
public:
StrError(int err_code, char *&buf, std::size_t buf_size)
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
int run() {
// Suppress a warning about unused strerror_r.
strerror_r(0, FMT_NULL, "");
return handle(strerror_r(error_code_, buffer_, buffer_size_));
}
};
@ -396,51 +405,6 @@ FMT_FUNC void format_system_error(
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
}
template <typename Char>
void internal::ArgMap<Char>::init(const ArgList &args) {
if (!map_.empty())
return;
typedef internal::NamedArg<Char> NamedArg;
const NamedArg *named_arg = FMT_NULL;
bool use_values =
args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
if (use_values) {
for (unsigned i = 0;/*nothing*/; ++i) {
internal::Arg::Type arg_type = args.type(i);
switch (arg_type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
return;
}
for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
internal::Arg::Type arg_type = args.type(i);
if (arg_type == internal::Arg::NAMED_ARG) {
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
}
}
for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
switch (args.args_[i].type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
}
template <typename Char>
void internal::FixedBuffer<Char>::grow(std::size_t) {
FMT_THROW(std::runtime_error("buffer overflow"));
@ -502,8 +466,6 @@ template struct internal::BasicData<void>;
template void internal::FixedBuffer<char>::grow(std::size_t);
template void internal::ArgMap<char>::init(const ArgList &args);
template FMT_API int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, double value);
@ -516,8 +478,6 @@ template FMT_API int internal::CharTraits<char>::format_float(
template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
template void internal::ArgMap<wchar_t>::init(const ArgList &args);
template FMT_API int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, double value);

View file

@ -28,6 +28,7 @@
#ifndef FMT_FORMAT_H_
#define FMT_FORMAT_H_
#define FMT_INCLUDE
#include <cassert>
#include <clocale>
#include <cmath>
@ -39,11 +40,26 @@
#include <string>
#include <vector>
#include <utility> // for std::pair
#undef FMT_INCLUDE
// The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 40000
#define FMT_VERSION 40100
#ifdef _SECURE_SCL
#if defined(__has_include)
# define FMT_HAS_INCLUDE(x) __has_include(x)
#else
# define FMT_HAS_INCLUDE(x) 0
#endif
#if (FMT_HAS_INCLUDE(<string_view>) && __cplusplus > 201402L) || \
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
# include <string_view>
# define FMT_HAS_STRING_VIEW 1
#else
# define FMT_HAS_STRING_VIEW 0
#endif
#if defined _SECURE_SCL && _SECURE_SCL
# define FMT_SECURE_SCL _SECURE_SCL
#else
# define FMT_SECURE_SCL 0
@ -97,7 +113,9 @@ typedef __int64 intmax_t;
# define FMT_HAS_GXX_CXX11 1
# endif
#else
# define FMT_GCC_VERSION 0
# define FMT_GCC_EXTENSION
# define FMT_HAS_GXX_CXX11 0
#endif
#if defined(__INTEL_COMPILER)
@ -135,6 +153,32 @@ typedef __int64 intmax_t;
# define FMT_HAS_CPP_ATTRIBUTE(x) 0
#endif
#if FMT_HAS_CPP_ATTRIBUTE(maybe_unused)
# define FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED
// VC++ 1910 support /std: option and that will set _MSVC_LANG macro
// Clang with Microsoft CodeGen doesn't define _MSVC_LANG macro
#elif defined(_MSVC_LANG) && _MSVC_LANG > 201402 && _MSC_VER >= 1910
# define FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED
#endif
#ifdef FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED
# define FMT_MAYBE_UNUSED [[maybe_unused]]
// g++/clang++ also support [[gnu::unused]]. However, we don't use it.
#elif defined(__GNUC__)
# define FMT_MAYBE_UNUSED __attribute__((unused))
#else
# define FMT_MAYBE_UNUSED
#endif
// Use the compiler's attribute noreturn
#if defined(__MINGW32__) || defined(__MINGW64__)
# define FMT_NORETURN __attribute__((noreturn))
#elif FMT_HAS_CPP_ATTRIBUTE(noreturn) && __cplusplus >= 201103L
# define FMT_NORETURN [[noreturn]]
#else
# define FMT_NORETURN
#endif
#ifndef FMT_USE_VARIADIC_TEMPLATES
// Variadic templates are available in GCC since version 4.4
// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++
@ -156,6 +200,12 @@ typedef __int64 intmax_t;
# endif
#endif
#if __cplusplus >= 201103L || FMT_MSC_VER >= 1700
# define FMT_USE_ALLOCATOR_TRAITS 1
#else
# define FMT_USE_ALLOCATOR_TRAITS 0
#endif
// Check if exceptions are disabled.
#if defined(__GNUC__) && !defined(__EXCEPTIONS)
# define FMT_EXCEPTIONS 0
@ -262,11 +312,14 @@ typedef __int64 intmax_t;
// makes the fmt::literals implementation easier. However, an explicit check
// for variadic templates is added here just in case.
// For Intel's compiler both it and the system gcc/msc must support UDLs.
# define FMT_USE_USER_DEFINED_LITERALS \
FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \
# if FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \
(FMT_HAS_FEATURE(cxx_user_literals) || \
(FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900) && \
(!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500)
# define FMT_USE_USER_DEFINED_LITERALS 1
# else
# define FMT_USE_USER_DEFINED_LITERALS 0
# endif
#endif
#ifndef FMT_USE_EXTERN_TEMPLATES
@ -305,7 +358,10 @@ typedef __int64 intmax_t;
namespace fmt {
namespace internal {
# pragma intrinsic(_BitScanReverse)
// avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning
# ifndef __clang__
# pragma intrinsic(_BitScanReverse)
# endif
inline uint32_t clz(uint32_t x) {
unsigned long r = 0;
_BitScanReverse(&r, x);
@ -319,7 +375,8 @@ inline uint32_t clz(uint32_t x) {
}
# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n)
# ifdef _WIN64
// avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning
# if defined(_WIN64) && !defined(__clang__)
# pragma intrinsic(_BitScanReverse64)
# endif
@ -505,6 +562,26 @@ class BasicStringRef {
const std::basic_string<Char, std::char_traits<Char>, Allocator> &s)
: data_(s.c_str()), size_(s.size()) {}
#if FMT_HAS_STRING_VIEW
/**
\rst
Constructs a string reference from a ``std::basic_string_view`` object.
\endrst
*/
BasicStringRef(
const std::basic_string_view<Char, std::char_traits<Char>> &s)
: data_(s.data()), size_(s.size()) {}
/**
\rst
Converts a string reference to an ``std::string_view`` object.
\endrst
*/
explicit operator std::basic_string_view<Char>() const FMT_NOEXCEPT {
return std::basic_string_view<Char>(data_, size_);
}
#endif
/**
\rst
Converts a string reference to an ``std::string`` object.
@ -609,7 +686,7 @@ class FormatError : public std::runtime_error {
explicit FormatError(CStringRef message)
: std::runtime_error(message.c_str()) {}
FormatError(const FormatError &ferr) : std::runtime_error(ferr) {}
FMT_API ~FormatError() FMT_DTOR_NOEXCEPT;
FMT_API ~FormatError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE;
};
namespace internal {
@ -726,7 +803,7 @@ template <typename T>
template <typename U>
void Buffer<T>::append(const U *begin, const U *end) {
FMT_ASSERT(end >= begin, "negative value");
std::size_t new_size = size_ + (end - begin);
std::size_t new_size = size_ + static_cast<std::size_t>(end - begin);
if (new_size > capacity_)
grow(new_size);
std::uninitialized_copy(begin, end,
@ -754,7 +831,7 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
public:
explicit MemoryBuffer(const Allocator &alloc = Allocator())
: Allocator(alloc), Buffer<T>(data_, SIZE) {}
~MemoryBuffer() { deallocate(); }
~MemoryBuffer() FMT_OVERRIDE { deallocate(); }
#if FMT_USE_RVALUE_REFERENCES
private:
@ -798,7 +875,12 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) {
std::size_t new_capacity = this->capacity_ + this->capacity_ / 2;
if (size > new_capacity)
new_capacity = size;
#if FMT_USE_ALLOCATOR_TRAITS
T *new_ptr =
std::allocator_traits<Allocator>::allocate(*this, new_capacity, FMT_NULL);
#else
T *new_ptr = this->allocate(new_capacity, FMT_NULL);
#endif
// The following code doesn't throw, so the raw pointer above doesn't leak.
std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_,
make_ptr(new_ptr, new_capacity));
@ -916,7 +998,7 @@ struct IntTraits {
TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType;
};
FMT_API void report_unknown_type(char code, const char *type);
FMT_API FMT_NORETURN void report_unknown_type(char code, const char *type);
// Static data is placed in this class template to allow header-only
// configuration.
@ -1155,17 +1237,17 @@ T &get();
Yes &convert(fmt::ULongLong);
No &convert(...);
template<typename T, bool ENABLE_CONVERSION>
template <typename T, bool ENABLE_CONVERSION>
struct ConvertToIntImpl {
enum { value = ENABLE_CONVERSION };
};
template<typename T, bool ENABLE_CONVERSION>
template <typename T, bool ENABLE_CONVERSION>
struct ConvertToIntImpl2 {
enum { value = false };
};
template<typename T>
template <typename T>
struct ConvertToIntImpl2<T, true> {
enum {
// Don't convert numeric types.
@ -1173,7 +1255,7 @@ struct ConvertToIntImpl2<T, true> {
};
};
template<typename T>
template <typename T>
struct ConvertToInt {
enum {
enable_conversion = sizeof(fmt::internal::convert(get<T>())) == sizeof(Yes)
@ -1190,16 +1272,16 @@ FMT_DISABLE_CONVERSION_TO_INT(float);
FMT_DISABLE_CONVERSION_TO_INT(double);
FMT_DISABLE_CONVERSION_TO_INT(long double);
template<bool B, class T = void>
template <bool B, class T = void>
struct EnableIf {};
template<class T>
template <class T>
struct EnableIf<true, T> { typedef T type; };
template<bool B, class T, class F>
template <bool B, class T, class F>
struct Conditional { typedef T type; };
template<class T, class F>
template <class T, class F>
struct Conditional<false, T, F> { typedef F type; };
// For bcc32 which doesn't understand ! in template arguments.
@ -1248,9 +1330,9 @@ inline fmt::StringRef thousands_sep(...) { return ""; }
typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED
#endif
template <typename Formatter, typename Char, typename T>
void format_arg(Formatter &, const Char *, const T &) {
FMT_STATIC_ASSERT(FalseType<T>::value,
template <typename Formatter>
void format_arg(Formatter&, ...) {
FMT_STATIC_ASSERT(FalseType<Formatter>::value,
"Cannot format argument. To enable the use of ostream "
"operator<< include fmt/ostream.h. Otherwise provide "
"an overload of format_arg.");
@ -1283,6 +1365,9 @@ class MakeValue : public Arg {
MakeValue(typename WCharHelper<wchar_t *, Char>::Unsupported);
MakeValue(typename WCharHelper<const wchar_t *, Char>::Unsupported);
MakeValue(typename WCharHelper<const std::wstring &, Char>::Unsupported);
#if FMT_HAS_STRING_VIEW
MakeValue(typename WCharHelper<const std::wstring_view &, Char>::Unsupported);
#endif
MakeValue(typename WCharHelper<WStringRef, Char>::Unsupported);
void set_string(StringRef str) {
@ -1352,6 +1437,20 @@ class MakeValue : public Arg {
FMT_MAKE_VALUE(unsigned char, uint_value, UINT)
FMT_MAKE_VALUE(char, int_value, CHAR)
#if __cplusplus >= 201103L
template <
typename T,
typename = typename std::enable_if<
std::is_enum<T>::value && ConvertToInt<T>::value>::type>
MakeValue(T value) { int_value = value; }
template <
typename T,
typename = typename std::enable_if<
std::is_enum<T>::value && ConvertToInt<T>::value>::type>
static uint64_t type(T) { return Arg::INT; }
#endif
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
MakeValue(typename WCharHelper<wchar_t, Char>::Supported value) {
int_value = value;
@ -1370,6 +1469,9 @@ class MakeValue : public Arg {
FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING)
FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING)
FMT_MAKE_STR_VALUE(const std::string &, STRING)
#if FMT_HAS_STRING_VIEW
FMT_MAKE_STR_VALUE(const std::string_view &, STRING)
#endif
FMT_MAKE_STR_VALUE(StringRef, STRING)
FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str())
@ -1382,6 +1484,9 @@ class MakeValue : public Arg {
FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING)
FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING)
FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING)
#if FMT_HAS_STRING_VIEW
FMT_MAKE_WSTR_VALUE(const std::wstring_view &, WSTRING)
#endif
FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING)
FMT_MAKE_VALUE(void *, pointer, POINTER)
@ -1447,7 +1552,7 @@ class RuntimeError : public std::runtime_error {
protected:
RuntimeError() : std::runtime_error("") {}
RuntimeError(const RuntimeError &rerr) : std::runtime_error(rerr) {}
FMT_API ~RuntimeError() FMT_DTOR_NOEXCEPT;
FMT_API ~RuntimeError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE;
};
template <typename Char>
@ -1921,7 +2026,7 @@ class ArgMap {
MapType map_;
public:
FMT_API void init(const ArgList &args);
void init(const ArgList &args);
const internal::Arg *find(const fmt::BasicStringRef<Char> &name) const {
// The list is unsorted, so just return the first matching name.
@ -1934,6 +2039,51 @@ class ArgMap {
}
};
template <typename Char>
void ArgMap<Char>::init(const ArgList &args) {
if (!map_.empty())
return;
typedef internal::NamedArg<Char> NamedArg;
const NamedArg *named_arg = FMT_NULL;
bool use_values =
args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
if (use_values) {
for (unsigned i = 0;/*nothing*/; ++i) {
internal::Arg::Type arg_type = args.type(i);
switch (arg_type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
return;
}
for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
internal::Arg::Type arg_type = args.type(i);
if (arg_type == internal::Arg::NAMED_ARG) {
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
}
}
for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
switch (args.args_[i].type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
}
template <typename Impl, typename Char, typename Spec = fmt::FormatSpec>
class ArgFormatterBase : public ArgVisitor<Impl, void> {
private:
@ -2220,7 +2370,8 @@ struct ArgArray;
template <std::size_t N>
struct ArgArray<N, true/*IsPacked*/> {
typedef Value Type[N > 0 ? N : 1];
// '+' is used to silence GCC -Wduplicated-branches warning.
typedef Value Type[N > 0 ? N : +1];
template <typename Formatter, typename T>
static Value make(const T &value) {
@ -2410,7 +2561,7 @@ class SystemError : public internal::RuntimeError {
FMT_DEFAULTED_COPY_CTOR(SystemError)
FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef)
FMT_API ~SystemError() FMT_DTOR_NOEXCEPT;
FMT_API ~SystemError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE;
int error_code() const { return error_code_; }
};
@ -3483,10 +3634,10 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED;
#define FMT_GET_ARG_NAME(type, index) arg##index
#if FMT_USE_VARIADIC_TEMPLATES
# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \
# define FMT_VARIADIC_(Const, Char, ReturnType, func, call, ...) \
template <typename... Args> \
ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \
const Args & ... args) { \
const Args & ... args) Const { \
typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \
typename ArgArray::Type array{ \
ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \
@ -3496,35 +3647,35 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED;
#else
// Defines a wrapper for a function taking __VA_ARGS__ arguments
// and n additional arguments of arbitrary types.
# define FMT_WRAP(Char, ReturnType, func, call, n, ...) \
# define FMT_WRAP(Const, Char, ReturnType, func, call, n, ...) \
template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \
inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \
FMT_GEN(n, FMT_MAKE_ARG)) { \
FMT_GEN(n, FMT_MAKE_ARG)) Const { \
fmt::internal::ArgArray<n>::Type arr; \
FMT_GEN(n, FMT_ASSIGN_##Char); \
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \
}
# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \
inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \
# define FMT_VARIADIC_(Const, Char, ReturnType, func, call, ...) \
inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) Const { \
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \
} \
FMT_WRAP(Char, ReturnType, func, call, 1, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 2, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 3, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 4, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 5, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 6, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 7, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 8, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 9, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 10, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 11, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 12, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 13, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 14, __VA_ARGS__) \
FMT_WRAP(Char, ReturnType, func, call, 15, __VA_ARGS__)
FMT_WRAP(Const, Char, ReturnType, func, call, 1, __VA_ARGS__) \
FMT_WRAP(Const, Char, ReturnType, func, call, 2, __VA_ARGS__) \
FMT_WRAP(Const, Char, ReturnType, func, call, 3, __VA_ARGS__) \
FMT_WRAP(Const, Char, ReturnType, func, call, 4, __VA_ARGS__) \
FMT_WRAP(Const, Char, ReturnType, func, call, 5, __VA_ARGS__) \
FMT_WRAP(Const, Char, ReturnType, func, call, 6, __VA_ARGS__) \
FMT_WRAP(Const, Char, ReturnType, func, call, 7, __VA_ARGS__) \
FMT_WRAP(Const, Char, ReturnType, func, call, 8, __VA_ARGS__) \
FMT_WRAP(Const, Char, ReturnType, func, call, 9, __VA_ARGS__) \
FMT_WRAP(Const, Char, ReturnType, func, call, 10, __VA_ARGS__) \
FMT_WRAP(Const, Char, ReturnType, func, call, 11, __VA_ARGS__) \
FMT_WRAP(Const, Char, ReturnType, func, call, 12, __VA_ARGS__) \
FMT_WRAP(Const, Char, ReturnType, func, call, 13, __VA_ARGS__) \
FMT_WRAP(Const, Char, ReturnType, func, call, 14, __VA_ARGS__) \
FMT_WRAP(Const, Char, ReturnType, func, call, 15, __VA_ARGS__)
#endif // FMT_USE_VARIADIC_TEMPLATES
/**
@ -3555,10 +3706,16 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED;
\endrst
*/
#define FMT_VARIADIC(ReturnType, func, ...) \
FMT_VARIADIC_(char, ReturnType, func, return func, __VA_ARGS__)
FMT_VARIADIC_(, char, ReturnType, func, return func, __VA_ARGS__)
#define FMT_VARIADIC_CONST(ReturnType, func, ...) \
FMT_VARIADIC_(const, char, ReturnType, func, return func, __VA_ARGS__)
#define FMT_VARIADIC_W(ReturnType, func, ...) \
FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__)
FMT_VARIADIC_(, wchar_t, ReturnType, func, return func, __VA_ARGS__)
#define FMT_VARIADIC_CONST_W(ReturnType, func, ...) \
FMT_VARIADIC_(const, wchar_t, ReturnType, func, return func, __VA_ARGS__)
#define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id)
@ -3601,17 +3758,19 @@ template <typename Char>
unsigned parse_nonnegative_int(const Char *&s) {
assert('0' <= *s && *s <= '9');
unsigned value = 0;
do {
unsigned new_value = value * 10 + (*s++ - '0');
// Check if value wrapped around.
if (new_value < value) {
value = (std::numeric_limits<unsigned>::max)();
break;
}
value = new_value;
} while ('0' <= *s && *s <= '9');
// Convert to unsigned to prevent a warning.
unsigned max_int = (std::numeric_limits<int>::max)();
unsigned big = max_int / 10;
do {
// Check for overflow.
if (value > big) {
value = max_int + 1;
break;
}
value = value * 10 + (*s - '0');
++s;
} while ('0' <= *s && *s <= '9');
// Convert to unsigned to prevent a warning.
if (value > max_int)
FMT_THROW(FormatError("number is too big"));
return value;
@ -3783,7 +3942,8 @@ const Char *BasicFormatter<Char, ArgFormatter>::format(
default:
FMT_THROW(FormatError("width is not integer"));
}
if (value > (std::numeric_limits<int>::max)())
unsigned max_int = (std::numeric_limits<int>::max)();
if (value > max_int)
FMT_THROW(FormatError("number is too big"));
spec.width_ = static_cast<int>(value);
}
@ -3821,7 +3981,8 @@ const Char *BasicFormatter<Char, ArgFormatter>::format(
default:
FMT_THROW(FormatError("precision is not integer"));
}
if (value > (std::numeric_limits<int>::max)())
unsigned max_int = (std::numeric_limits<int>::max)();
if (value > max_int)
FMT_THROW(FormatError("number is too big"));
spec.precision_ = static_cast<int>(value);
} else {

View file

@ -52,13 +52,15 @@ Yes &convert(std::ostream &);
struct DummyStream : std::ostream {
DummyStream(); // Suppress a bogus warning in MSVC.
// Hide all operator<< overloads from std::ostream.
void operator<<(Null<>);
template <typename T>
typename EnableIf<sizeof(T) == 0>::type operator<<(const T &);
};
No &operator<<(std::ostream &, int);
template<typename T>
template <typename T>
struct ConvertToIntImpl<T, true> {
// Convert to int only if T doesn't have an overloaded operator<<.
enum {
@ -78,6 +80,7 @@ void format_arg(BasicFormatter<Char, ArgFormatter_> &f,
internal::FormatBuf<Char> format_buf(buffer);
std::basic_ostream<Char> output(&format_buf);
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
output << value;
BasicStringRef<Char> str(&buffer[0], buffer.size());

View file

@ -110,7 +110,7 @@ class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
visit_any_int(value);
}
void visit_char(char value) {
void visit_char(int value) {
if (type_ != 's')
visit_any_int(value);
}
@ -125,7 +125,7 @@ class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
using internal::Arg;
typedef typename internal::Conditional<
is_same<T, void>::value, U, T>::type TargetType;
if (sizeof(TargetType) <= sizeof(int)) {
if (const_check(sizeof(TargetType) <= sizeof(int))) {
// Extra casts are used to silence warnings.
if (is_signed) {
arg_.type = Arg::INT;

View file

@ -7,6 +7,10 @@
For the license information refer to format.h.
*/
#ifdef FMT_INCLUDE
# error "Add the fmt's parent directory and not fmt itself to includes."
#endif
#ifndef FMT_STRING_H_
#define FMT_STRING_H_
@ -121,6 +125,24 @@ std::string to_string(const T &value) {
w << value;
return w.str();
}
/**
\rst
Converts *value* to ``std::wstring`` using the default format for type *T*.
**Example**::
#include "fmt/string.h"
std::wstring answer = fmt::to_wstring(42);
\endrst
*/
template <typename T>
std::wstring to_wstring(const T &value) {
fmt::WMemoryWriter w;
w << value;
return w.str();
}
}
#endif // FMT_STRING_H_

View file

@ -8,7 +8,7 @@ Usage:
"""
from __future__ import print_function
import datetime, docopt, fileinput, json, os
import datetime, docopt, errno, fileinput, json, os
import re, requests, shutil, sys, tempfile
from contextlib import contextmanager
from distutils.version import LooseVersion
@ -80,6 +80,7 @@ def create_build_env():
import build
env.build_dir = 'build'
env.versions = build.versions
# Virtualenv and repos are cached to speed up builds.
build.create_build_env(os.path.join(env.build_dir, 'virtualenv'))
@ -113,7 +114,7 @@ def update_site(env):
doc_repo = Git(os.path.join(env.build_dir, 'fmtlib.github.io'))
doc_repo.update('git@github.com:fmtlib/fmtlib.github.io')
for version in ['1.0.0', '1.1.0', '2.0.0', '3.0.0']:
for version in env.versions:
clean_checkout(env.fmt_repo, version)
target_doc_dir = os.path.join(env.fmt_repo.dir, 'doc')
# Remove the old theme.
@ -165,7 +166,11 @@ def update_site(env):
os.symlink(target, link)
# Copy docs to the website.
version_doc_dir = os.path.join(doc_repo.dir, version)
shutil.rmtree(version_doc_dir)
try:
shutil.rmtree(version_doc_dir)
except OSError as e:
if e.errno != errno.ENOENT:
raise
shutil.move(html_dir, version_doc_dir)
@ -204,27 +209,45 @@ def release(args):
line = '-' * title_len + '\n'
title_len = 0
sys.stdout.write(line)
# TODO: add new version to manage.py
# Add the version to the build script.
script = os.path.join('doc', 'build.py')
script_path = os.path.join(fmt_repo.dir, script)
for line in fileinput.input(script_path, inplace=True):
m = re.match(r'( *versions = )\[(.+)\]', line)
if m:
line = '{}[{}, \'{}\']\n'.format(m.group(1), m.group(2), version)
sys.stdout.write(line)
fmt_repo.checkout('-B', 'release')
fmt_repo.add(changelog, cmakelists)
fmt_repo.add(changelog, cmakelists, script)
fmt_repo.commit('-m', 'Update version')
# Build the docs and package.
run = Runner(fmt_repo.dir)
run('cmake', '.')
run('make', 'doc', 'package_source')
update_site(env)
# Create a release on GitHub.
fmt_repo.push('origin', 'release')
params = {'access_token': os.getenv('FMT_TOKEN')}
r = requests.post('https://api.github.com/repos/fmtlib/fmt/releases',
params={'access_token': os.getenv('FMT_TOKEN')},
params=params,
data=json.dumps({'tag_name': version,
'target_commitish': 'release',
'body': changes, 'draft': True}))
if r.status_code != 201:
raise Exception('Failed to create a release ' + str(r))
id = r.json()['id']
uploads_url = 'https://uploads.github.com/repos/fmtlib/fmt/releases'
package = 'fmt-{}.zip'.format(version)
with open('build/fmt/' + package, 'rb') as f:
r = requests.post(
'{}/{}/assets?name={}'.format(uploads_url, id, package),
params=params, files={package: f})
if r.status_code != 201:
raise Exception('Failed to upload an asset ' + str(r))
if __name__ == '__main__':

View file

@ -30,7 +30,7 @@ def install_dependencies():
'| sudo tee /etc/apt/sources.list.d/nodesource.list', shell=True)
check_call(['sudo', 'apt-get', 'update'])
check_call(['sudo', 'apt-get', 'install', 'python-virtualenv', 'nodejs'])
check_call(['npm', 'install', '-g', 'less', 'less-plugin-clean-css'])
check_call(['sudo', 'npm', 'install', '-g', 'less@2.6.1', 'less-plugin-clean-css'])
deb_file = 'doxygen_1.8.6-2_amd64.deb'
urllib.urlretrieve('http://mirrors.kernel.org/ubuntu/pool/main/d/doxygen/' +
deb_file, deb_file)

View file

@ -151,16 +151,31 @@ TEST(StringRefTest, Ctor) {
EXPECT_STREQ("defg", StringRef(std::string("defg")).data());
EXPECT_EQ(4u, StringRef(std::string("defg")).size());
#if FMT_HAS_STRING_VIEW
EXPECT_STREQ("hijk", StringRef(std::string_view("hijk")).data());
EXPECT_EQ(4u, StringRef(std::string_view("hijk")).size());
#endif
}
TEST(StringRefTest, ConvertToString) {
std::string s = StringRef("abc").to_string();
EXPECT_EQ("abc", s);
#if FMT_HAS_STRING_VIEW
StringRef str_ref("defg");
std::string_view sv = static_cast<std::string_view>(str_ref);
EXPECT_EQ("defg", sv);
#endif
}
TEST(CStringRefTest, Ctor) {
EXPECT_STREQ("abc", CStringRef("abc").c_str());
EXPECT_STREQ("defg", CStringRef(std::string("defg")).c_str());
#if FMT_HAS_STRING_VIEW
EXPECT_STREQ("hijk", CStringRef(std::string_view("hijk")).c_str());
#endif
}
#if FMT_USE_TYPE_TRAITS
@ -1378,6 +1393,12 @@ TEST(FormatterTest, FormatCStringRef) {
EXPECT_EQ("test", format("{0}", CStringRef("test")));
}
#if FMT_HAS_STRING_VIEW
TEST(FormatterTest, FormatStringView) {
EXPECT_EQ("test", format("{0}", std::string_view("test")));
}
#endif
void format_arg(fmt::BasicFormatter<char> &f, const char *, const Date &d) {
f.writer() << d.year() << '-' << d.month() << '-' << d.day();
}
@ -1609,6 +1630,24 @@ TEST(FormatTest, FormatMessageExample) {
format_message(42, "{} happened", "something"));
}
class test_class
{
public:
std::string format_message(int id, const char *format,const fmt::ArgList &args) const {
MemoryWriter w;
w.write("[{}] ", id);
w.write(format, args);
return w.str();
}
FMT_VARIADIC_CONST(std::string, format_message, int, const char *)
};
TEST(FormatTest, ConstFormatMessage) {
test_class c;
EXPECT_EQ("[42] something happened",
c.format_message(42, "{} happened", "something"));
}
#if FMT_USE_VARIADIC_TEMPLATES
template<typename... Args>
void print_error(const char *file, int line, const char *format,
@ -1660,6 +1699,14 @@ TEST(FormatTest, Enum) {
EXPECT_EQ("0", fmt::format("{}", A));
}
#if __cplusplus >= 201103L
enum TestFixedEnum : short { B };
TEST(FormatTest, FixedEnum) {
EXPECT_EQ("0", fmt::format("{}", B));
}
#endif
class MockArgFormatter :
public fmt::internal::ArgFormatterBase<MockArgFormatter, char> {
public:

View file

@ -36,7 +36,7 @@ class MockAllocator {
MockAllocator() {}
MockAllocator(const MockAllocator &) {}
typedef T value_type;
MOCK_METHOD2_T(allocate, T *(std::size_t n, const T *h));
MOCK_METHOD2_T(allocate, T *(std::size_t n, const void *h));
MOCK_METHOD2_T(deallocate, void (T *p, std::size_t n));
};
@ -78,8 +78,12 @@ class AllocatorRef {
Allocator *get() const { return alloc_; }
value_type *allocate(std::size_t n, const value_type *h) {
value_type *allocate(std::size_t n, const void *h) {
#if FMT_USE_ALLOCATOR_TRAITS
return std::allocator_traits<Allocator>::allocate(*alloc_, n, h);
#else
return alloc_->allocate(n, h);
#endif
}
void deallocate(value_type *p, std::size_t n) { alloc_->deallocate(p, n); }
};

View file

@ -172,3 +172,18 @@ TEST(OStreamTest, WriteToOStreamMaxSize) {
} while (size != 0);
fmt::internal::write(os, w);
}
struct ConvertibleToInt {
template <typename ValueType>
operator ValueType() const {
return 0;
}
friend std::ostream &operator<<(std::ostream &o, ConvertibleToInt) {
return o << "foo";
}
};
TEST(FormatTest, FormatConvertibleToInt) {
EXPECT_EQ("foo", fmt::format("{}", ConvertibleToInt()));
}

View file

@ -78,3 +78,7 @@ TEST(StringWriterTest, WString) {
TEST(StringTest, ToString) {
EXPECT_EQ("42", fmt::to_string(42));
}
TEST(StringTest, ToWString) {
EXPECT_EQ(L"42", fmt::to_wstring(42));
}

View file

@ -837,8 +837,21 @@ TEST(UtilTest, FormatSystemError) {
fmt::format_system_error(message, EDOM, "test");
EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), message.str());
message.clear();
fmt::format_system_error(
message, EDOM, fmt::StringRef(0, std::numeric_limits<size_t>::max()));
// Check if std::allocator throws on allocating max size_t / 2 chars.
size_t max_size = std::numeric_limits<size_t>::max() / 2;
bool throws_on_alloc = false;
try {
std::allocator<char> alloc;
alloc.deallocate(alloc.allocate(max_size), max_size);
} catch (std::bad_alloc) {
throws_on_alloc = true;
}
if (!throws_on_alloc) {
fmt::print("warning: std::allocator allocates {} chars", max_size);
return;
}
fmt::format_system_error(message, EDOM, fmt::StringRef(0, max_size));
EXPECT_EQ(fmt::format("error {}", EDOM), message.str());
}