Bump fmt version to 6.2.0

This commit is contained in:
gabime
2020-04-15 00:51:03 +03:00
parent c89a5148b2
commit 7698bb0ae1
12 changed files with 1147 additions and 1033 deletions

View File

@@ -10,12 +10,15 @@
#include <cstdio> // std::FILE
#include <cstring>
#include <functional>
#include <iterator>
#include <memory>
#include <string>
#include <type_traits>
#include <vector>
// The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 60102
#define FMT_VERSION 60200
#ifdef __has_feature
# define FMT_HAS_FEATURE(x) __has_feature(x)
@@ -36,6 +39,18 @@
# define FMT_HAS_CPP_ATTRIBUTE(x) 0
#endif
#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
(__cplusplus >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \
(__cplusplus >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute))
#ifdef __clang__
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
#else
# define FMT_CLANG_VERSION 0
#endif
#if defined(__GNUC__) && !defined(__clang__)
# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
#else
@@ -117,16 +132,25 @@
# endif
#endif
// [[noreturn]] is disabled on MSVC because of bogus unreachable code warnings.
#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER
// [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code
// warnings.
#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \
!FMT_NVCC
# define FMT_NORETURN [[noreturn]]
#else
# define FMT_NORETURN
#endif
#ifndef FMT_MAYBE_UNUSED
# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused)
# define FMT_MAYBE_UNUSED [[maybe_unused]]
# else
# define FMT_MAYBE_UNUSED
# endif
#endif
#ifndef FMT_DEPRECATED
# if (FMT_HAS_CPP_ATTRIBUTE(deprecated) && __cplusplus >= 201402L) || \
FMT_MSC_VER >= 1900
# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900
# define FMT_DEPRECATED [[deprecated]]
# else
# if defined(__GNUC__) || defined(__clang__)
@@ -139,8 +163,8 @@
# endif
#endif
// Workaround broken [[deprecated]] in the Intel compiler and NVCC.
#if defined(__INTEL_COMPILER) || FMT_NVCC
// Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers.
#if defined(__INTEL_COMPILER) || defined(__PGI) || FMT_NVCC
# define FMT_DEPRECATED_ALIAS
#else
# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED
@@ -166,6 +190,12 @@
#endif
#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
# if FMT_MSC_VER
# define FMT_NO_W4275 __pragma(warning(suppress : 4275))
# else
# define FMT_NO_W4275
# endif
# define FMT_CLASS_API FMT_NO_W4275
# ifdef FMT_EXPORT
# define FMT_API __declspec(dllexport)
# elif defined(FMT_SHARED)
@@ -173,12 +203,24 @@
# define FMT_EXTERN_TEMPLATE_API FMT_API
# endif
#endif
#ifndef FMT_CLASS_API
# define FMT_CLASS_API
#endif
#ifndef FMT_API
# define FMT_API
# if FMT_GCC_VERSION || FMT_CLANG_VERSION
# define FMT_API __attribute__((visibility("default")))
# define FMT_EXTERN_TEMPLATE_API FMT_API
# define FMT_INSTANTIATION_DEF_API
# else
# define FMT_API
# endif
#endif
#ifndef FMT_EXTERN_TEMPLATE_API
# define FMT_EXTERN_TEMPLATE_API
#endif
#ifndef FMT_INSTANTIATION_DEF_API
# define FMT_INSTANTIATION_DEF_API FMT_API
#endif
#ifndef FMT_HEADER_ONLY
# define FMT_EXTERN extern
@@ -197,9 +239,16 @@
# define FMT_USE_EXPERIMENTAL_STRING_VIEW
#endif
#ifndef FMT_UNICODE
# define FMT_UNICODE !FMT_MSC_VER
#endif
#if FMT_UNICODE && FMT_MSC_VER
# pragma execution_character_set("utf-8")
#endif
FMT_BEGIN_NAMESPACE
// Implementations of enable_if_t and other types for pre-C++14 systems.
// Implementations of enable_if_t and other metafunctions for older systems.
template <bool B, class T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
template <bool B, class T, class F>
@@ -211,6 +260,8 @@ template <typename T>
using remove_const_t = typename std::remove_const<T>::type;
template <typename T>
using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
template <typename T> struct type_identity { using type = T; };
template <typename T> using type_identity_t = typename type_identity<T>::type;
struct monostate {};
@@ -221,19 +272,25 @@ struct monostate {};
namespace internal {
// A helper function to suppress bogus "conditional expression is constant"
// warnings.
template <typename T> FMT_CONSTEXPR T const_check(T value) { return value; }
// A workaround for gcc 4.8 to make void_t work in a SFINAE context.
template <typename... Ts> struct void_t_impl { using type = void; };
FMT_API void assert_fail(const char* file, int line, const char* message);
FMT_NORETURN FMT_API void assert_fail(const char* file, int line,
const char* message);
#ifndef FMT_ASSERT
# ifdef NDEBUG
# define FMT_ASSERT(condition, message)
// FMT_ASSERT is not empty to avoid -Werror=empty-body.
# define FMT_ASSERT(condition, message) ((void)0)
# else
# define FMT_ASSERT(condition, message) \
((condition) \
? void() \
: fmt::internal::assert_fail(__FILE__, __LINE__, (message)))
# define FMT_ASSERT(condition, message) \
((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \
? (void)0 \
: ::fmt::internal::assert_fail(__FILE__, __LINE__, (message)))
# endif
#endif
@@ -248,7 +305,7 @@ template <typename T> struct std_string_view {};
#ifdef FMT_USE_INT128
// Do nothing.
#elif defined(__SIZEOF_INT128__)
#elif defined(__SIZEOF_INT128__) && !FMT_NVCC
# define FMT_USE_INT128 1
using int128_t = __int128_t;
using uint128_t = __uint128_t;
@@ -266,6 +323,19 @@ FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
FMT_ASSERT(value >= 0, "negative value");
return static_cast<typename std::make_unsigned<Int>::type>(value);
}
constexpr unsigned char micro[] = "\u00B5";
template <typename Char> constexpr bool is_unicode() {
return FMT_UNICODE || sizeof(Char) != 1 ||
(sizeof(micro) == 3 && micro[0] == 0xC2 && micro[1] == 0xB5);
}
#ifdef __cpp_char8_t
using char8_type = char8_t;
#else
enum char8_type : unsigned char {};
#endif
} // namespace internal
template <typename... Ts>
@@ -284,7 +354,8 @@ template <typename Char> class basic_string_view {
size_t size_;
public:
using char_type = Char;
using char_type FMT_DEPRECATED_ALIAS = Char;
using value_type = Char;
using iterator = const Char*;
FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {}
@@ -300,6 +371,9 @@ template <typename Char> class basic_string_view {
the size with ``std::char_traits<Char>::length``.
\endrst
*/
#if __cplusplus >= 201703L // C++17's char_traits::length() is constexpr.
FMT_CONSTEXPR
#endif
basic_string_view(const Char* s)
: data_(s), size_(std::char_traits<Char>::length(s)) {}
@@ -365,15 +439,15 @@ using string_view = basic_string_view<char>;
using wstring_view = basic_string_view<wchar_t>;
#ifndef __cpp_char8_t
// A UTF-8 code unit type.
enum char8_t : unsigned char {};
// char8_t is deprecated; use char instead.
using char8_t FMT_DEPRECATED_ALIAS = internal::char8_type;
#endif
/** Specifies if ``T`` is a character type. Can be specialized by users. */
template <typename T> struct is_char : std::false_type {};
template <> struct is_char<char> : std::true_type {};
template <> struct is_char<wchar_t> : std::true_type {};
template <> struct is_char<char8_t> : std::true_type {};
template <> struct is_char<internal::char8_type> : std::true_type {};
template <> struct is_char<char16_t> : std::true_type {};
template <> struct is_char<char32_t> : std::true_type {};
@@ -442,7 +516,7 @@ struct is_string : std::is_class<decltype(to_string_view(std::declval<S>()))> {
template <typename S, typename = void> struct char_t_impl {};
template <typename S> struct char_t_impl<S, enable_if_t<is_string<S>::value>> {
using result = decltype(to_string_view(std::declval<S>()));
using type = typename result::char_type;
using type = typename result::value_type;
};
struct error_handler {
@@ -603,6 +677,9 @@ template <typename T> class buffer {
T* begin() FMT_NOEXCEPT { return ptr_; }
T* end() FMT_NOEXCEPT { return ptr_ + size_; }
const T* begin() const FMT_NOEXCEPT { return ptr_; }
const T* end() const FMT_NOEXCEPT { return ptr_ + size_; }
/** Returns the size of this buffer. */
std::size_t size() const FMT_NOEXCEPT { return size_; }
@@ -639,8 +716,10 @@ template <typename T> class buffer {
/** Appends data to the end of the buffer. */
template <typename U> void append(const U* begin, const U* end);
T& operator[](std::size_t index) { return ptr_[index]; }
const T& operator[](std::size_t index) const { return ptr_[index]; }
template <typename I> T& operator[](I index) { return ptr_[index]; }
template <typename I> const T& operator[](I index) const {
return ptr_[index];
}
};
// A container-backed buffer.
@@ -684,7 +763,7 @@ using has_fallback_formatter =
template <typename Char> struct named_arg_base;
template <typename T, typename Char> struct named_arg;
enum type {
enum class type {
none_type,
named_arg_type,
// Integer types should go first,
@@ -710,11 +789,12 @@ enum type {
// Maps core type T to the corresponding type enum constant.
template <typename T, typename Char>
struct type_constant : std::integral_constant<type, custom_type> {};
struct type_constant : std::integral_constant<type, type::custom_type> {};
#define FMT_TYPE_CONSTANT(Type, constant) \
template <typename Char> \
struct type_constant<Type, Char> : std::integral_constant<type, constant> {}
struct type_constant<Type, Char> \
: std::integral_constant<type, type::constant> {}
FMT_TYPE_CONSTANT(const named_arg_base<Char>&, named_arg_type);
FMT_TYPE_CONSTANT(int, int_type);
@@ -733,13 +813,13 @@ FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type);
FMT_TYPE_CONSTANT(const void*, pointer_type);
FMT_CONSTEXPR bool is_integral_type(type t) {
FMT_ASSERT(t != named_arg_type, "invalid argument type");
return t > none_type && t <= last_integer_type;
FMT_ASSERT(t != type::named_arg_type, "invalid argument type");
return t > type::none_type && t <= type::last_integer_type;
}
FMT_CONSTEXPR bool is_arithmetic_type(type t) {
FMT_ASSERT(t != named_arg_type, "invalid argument type");
return t > none_type && t <= last_numeric_type;
FMT_ASSERT(t != type::named_arg_type, "invalid argument type");
return t > type::none_type && t <= type::last_numeric_type;
}
template <typename Char> struct string_value {
@@ -869,7 +949,8 @@ template <typename Context> struct arg_mapper {
template <typename T,
FMT_ENABLE_IF(
std::is_constructible<basic_string_view<char_type>, T>::value &&
!is_string<T>::value)>
!is_string<T>::value && !has_formatter<T, Context>::value &&
!has_fallback_formatter<T, Context>::value)>
FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
return basic_string_view<char_type>(val);
}
@@ -878,7 +959,8 @@ template <typename Context> struct arg_mapper {
FMT_ENABLE_IF(
std::is_constructible<std_string_view<char_type>, T>::value &&
!std::is_constructible<basic_string_view<char_type>, T>::value &&
!is_string<T>::value && !has_formatter<T, Context>::value)>
!is_string<T>::value && !has_formatter<T, Context>::value &&
!has_fallback_formatter<T, Context>::value)>
FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
return std_string_view<char_type>(val);
}
@@ -907,18 +989,15 @@ template <typename Context> struct arg_mapper {
FMT_ENABLE_IF(std::is_enum<T>::value &&
!has_formatter<T, Context>::value &&
!has_fallback_formatter<T, Context>::value)>
FMT_CONSTEXPR auto map(const T& val) -> decltype(
map(static_cast<typename std::underlying_type<T>::type>(val))) {
FMT_CONSTEXPR auto map(const T& val)
-> decltype(std::declval<arg_mapper>().map(
static_cast<typename std::underlying_type<T>::type>(val))) {
return map(static_cast<typename std::underlying_type<T>::type>(val));
}
template <
typename T,
FMT_ENABLE_IF(
!is_string<T>::value && !is_char<T>::value &&
!std::is_constructible<basic_string_view<char_type>, T>::value &&
(has_formatter<T, Context>::value ||
(has_fallback_formatter<T, Context>::value &&
!std::is_constructible<std_string_view<char_type>, T>::value)))>
template <typename T,
FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value &&
(has_formatter<T, Context>::value ||
has_fallback_formatter<T, Context>::value))>
FMT_CONSTEXPR const T& map(const T& val) {
return val;
}
@@ -930,6 +1009,16 @@ template <typename Context> struct arg_mapper {
std::memcpy(val.data, &arg, sizeof(arg));
return val;
}
int map(...) {
constexpr bool formattable = sizeof(Context) == 0;
static_assert(
formattable,
"Cannot format argument. To make type T formattable provide a "
"formatter<T> specialization: "
"https://fmt.dev/latest/api.html#formatting-user-defined-types");
return 0;
}
};
// A type constant after applying arg_mapper<Context>.
@@ -981,10 +1070,10 @@ template <typename Context> class basic_format_arg {
internal::custom_value<Context> custom_;
};
FMT_CONSTEXPR basic_format_arg() : type_(internal::none_type) {}
FMT_CONSTEXPR basic_format_arg() : type_(internal::type::none_type) {}
FMT_CONSTEXPR explicit operator bool() const FMT_NOEXCEPT {
return type_ != internal::none_type;
return type_ != internal::type::none_type;
}
internal::type type() const { return type_; }
@@ -1006,47 +1095,47 @@ FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis,
-> decltype(vis(0)) {
using char_type = typename Context::char_type;
switch (arg.type_) {
case internal::none_type:
case internal::type::none_type:
break;
case internal::named_arg_type:
case internal::type::named_arg_type:
FMT_ASSERT(false, "invalid argument type");
break;
case internal::int_type:
case internal::type::int_type:
return vis(arg.value_.int_value);
case internal::uint_type:
case internal::type::uint_type:
return vis(arg.value_.uint_value);
case internal::long_long_type:
case internal::type::long_long_type:
return vis(arg.value_.long_long_value);
case internal::ulong_long_type:
case internal::type::ulong_long_type:
return vis(arg.value_.ulong_long_value);
#if FMT_USE_INT128
case internal::int128_type:
case internal::type::int128_type:
return vis(arg.value_.int128_value);
case internal::uint128_type:
case internal::type::uint128_type:
return vis(arg.value_.uint128_value);
#else
case internal::int128_type:
case internal::uint128_type:
case internal::type::int128_type:
case internal::type::uint128_type:
break;
#endif
case internal::bool_type:
case internal::type::bool_type:
return vis(arg.value_.bool_value);
case internal::char_type:
case internal::type::char_type:
return vis(arg.value_.char_value);
case internal::float_type:
case internal::type::float_type:
return vis(arg.value_.float_value);
case internal::double_type:
case internal::type::double_type:
return vis(arg.value_.double_value);
case internal::long_double_type:
case internal::type::long_double_type:
return vis(arg.value_.long_double_value);
case internal::cstring_type:
case internal::type::cstring_type:
return vis(arg.value_.string.data);
case internal::string_type:
case internal::type::string_type:
return vis(basic_string_view<char_type>(arg.value_.string.data,
arg.value_.string.size));
case internal::pointer_type:
case internal::type::pointer_type:
return vis(arg.value_.pointer);
case internal::custom_type:
case internal::type::custom_type:
return vis(typename basic_format_arg<Context>::handle(arg.value_.custom));
}
return vis(monostate());
@@ -1106,7 +1195,7 @@ template <typename> constexpr unsigned long long encode_types() { return 0; }
template <typename Context, typename Arg, typename... Args>
constexpr unsigned long long encode_types() {
return mapped_type_constant<Arg, Context>::value |
return static_cast<unsigned>(mapped_type_constant<Arg, Context>::value) |
(encode_types<Context, Args...>() << packed_arg_bits);
}
@@ -1129,6 +1218,43 @@ template <bool IS_PACKED, typename Context, typename T,
inline basic_format_arg<Context> make_arg(const T& value) {
return make_arg<Context>(value);
}
template <typename T> struct is_reference_wrapper : std::false_type {};
template <typename T>
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
class dynamic_arg_list {
// Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
// templates it doesn't complain about inability to deduce single translation
// unit for placing vtable. So storage_node_base is made a fake template.
template <typename = void> struct node {
virtual ~node() = default;
std::unique_ptr<node<>> next;
};
template <typename T> struct typed_node : node<> {
T value;
template <typename Arg>
FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
template <typename Char>
FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
: value(arg.data(), arg.size()) {}
};
std::unique_ptr<node<>> head_;
public:
template <typename T, typename Arg> const T& push(const Arg& arg) {
auto node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
auto& value = node->value;
node->next = std::move(head_);
head_ = std::move(node);
return value;
}
};
} // namespace internal
// Formatting context.
@@ -1191,7 +1317,13 @@ using wformat_context = buffer_context<wchar_t>;
such as `~fmt::vformat`.
\endrst
*/
template <typename Context, typename... Args> class format_arg_store {
template <typename Context, typename... Args>
class format_arg_store
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround a GCC template argument substitution bug.
: public basic_format_args<Context>
#endif
{
private:
static const size_t num_args = sizeof...(Args);
static const bool is_packed = num_args < internal::max_packed_args;
@@ -1210,7 +1342,12 @@ template <typename Context, typename... Args> class format_arg_store {
: internal::is_unpacked_bit | num_args;
format_arg_store(const Args&... args)
: data_{internal::make_arg<is_packed, Context>(args)...} {}
:
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
basic_format_args<Context>(*this),
#endif
data_{internal::make_arg<is_packed, Context>(args)...} {
}
};
/**
@@ -1227,7 +1364,112 @@ inline format_arg_store<Context, Args...> make_format_args(
return {args...};
}
/** Formatting arguments. */
/**
\rst
A dynamic version of `fmt::format_arg_store<>`.
It's equipped with a storage to potentially temporary objects which lifetime
could be shorter than the format arguments object.
It can be implicitly converted into `~fmt::basic_format_args` for passing
into type-erased formatting functions such as `~fmt::vformat`.
\endrst
*/
template <typename Context>
class dynamic_format_arg_store
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround a GCC template argument substitution bug.
: public basic_format_args<Context>
#endif
{
private:
using char_type = typename Context::char_type;
template <typename T> struct need_copy {
static constexpr internal::type mapped_type =
internal::mapped_type_constant<T, Context>::value;
enum {
value = !(internal::is_reference_wrapper<T>::value ||
std::is_same<T, basic_string_view<char_type>>::value ||
std::is_same<T, internal::std_string_view<char_type>>::value ||
(mapped_type != internal::type::cstring_type &&
mapped_type != internal::type::string_type &&
mapped_type != internal::type::custom_type &&
mapped_type != internal::type::named_arg_type))
};
};
template <typename T>
using stored_type = conditional_t<internal::is_string<T>::value,
std::basic_string<char_type>, T>;
// Storage of basic_format_arg must be contiguous.
std::vector<basic_format_arg<Context>> data_;
// Storage of arguments not fitting into basic_format_arg must grow
// without relocation because items in data_ refer to it.
internal::dynamic_arg_list dynamic_args_;
friend class basic_format_args<Context>;
unsigned long long get_types() const {
return internal::is_unpacked_bit | data_.size();
}
template <typename T> void emplace_arg(const T& arg) {
data_.emplace_back(internal::make_arg<Context>(arg));
}
public:
/**
\rst
Adds an argument into the dynamic store for later passing to a formating
function.
Note that custom types and string types (but not string views!) are copied
into the store with dynamic memory (in addition to resizing vector).
**Example**::
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(42);
store.push_back("abc");
store.push_back(1.5f);
std::string result = fmt::vformat("{} and {} and {}", store);
\endrst
*/
template <typename T> void push_back(const T& arg) {
static_assert(
!std::is_base_of<internal::named_arg_base<char_type>, T>::value,
"named arguments are not supported yet");
if (internal::const_check(need_copy<T>::value))
emplace_arg(dynamic_args_.push<stored_type<T>>(arg));
else
emplace_arg(arg);
}
/**
Adds a reference to the argument into the dynamic store for later passing to
a formating function.
*/
template <typename T> void push_back(std::reference_wrapper<T> arg) {
static_assert(
need_copy<T>::value,
"objects of built-in types and string views are always copied");
emplace_arg(arg.get());
}
};
/**
\rst
A view of a collection of formatting arguments. To avoid lifetime issues it
should only be used as a parameter type in type-erased functions such as
``vformat``::
void vlog(string_view format_str, format_args args); // OK
format_args args = make_format_args(42); // Error: dangling reference
\endrst
*/
template <typename Context> class basic_format_args {
public:
using size_type = int;
@@ -1269,7 +1511,7 @@ template <typename Context> class basic_format_args {
}
if (index > internal::max_packed_args) return arg;
arg.type_ = type(index);
if (arg.type_ == internal::none_type) return arg;
if (arg.type_ == internal::type::none_type) return arg;
internal::value<Context>& val = arg.value_;
val = values_[index];
return arg;
@@ -1289,6 +1531,17 @@ template <typename Context> class basic_format_args {
set_data(store.data_);
}
/**
\rst
Constructs a `basic_format_args` object from
`~fmt::dynamic_format_arg_store`.
\endrst
*/
basic_format_args(const dynamic_format_arg_store<Context>& store)
: types_(store.get_types()) {
set_data(store.data_.data());
}
/**
\rst
Constructs a `basic_format_args` object from a dynamic set of arguments.
@@ -1302,7 +1555,7 @@ template <typename Context> class basic_format_args {
/** Returns the argument at specified index. */
format_arg get(int index) const {
format_arg arg = do_get(index);
if (arg.type_ == internal::named_arg_type)
if (arg.type_ == internal::type::named_arg_type)
arg = arg.value_.named_arg->template deserialize<Context>();
return arg;
}
@@ -1319,12 +1572,12 @@ template <typename Context> class basic_format_args {
struct format_args : basic_format_args<format_context> {
template <typename... Args>
format_args(Args&&... args)
: basic_format_args<format_context>(std::forward<Args>(args)...) {}
: basic_format_args<format_context>(static_cast<Args&&>(args)...) {}
};
struct wformat_args : basic_format_args<wformat_context> {
template <typename... Args>
wformat_args(Args&&... args)
: basic_format_args<wformat_context>(std::forward<Args>(args)...) {}
: basic_format_args<wformat_context>(static_cast<Args&&>(args)...) {}
};
template <typename Container> struct is_contiguous : std::false_type {};
@@ -1358,7 +1611,10 @@ template <typename Char> struct named_arg_base {
}
};
template <typename T, typename Char> struct named_arg : named_arg_base<Char> {
struct view {};
template <typename T, typename Char>
struct named_arg : view, named_arg_base<Char> {
const T& value;
named_arg(basic_string_view<Char> name, const T& val)
@@ -1376,7 +1632,6 @@ inline void check_format_string(const S&) {
template <typename..., typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
void check_format_string(S);
struct view {};
template <bool...> struct bool_pack;
template <bool... Args>
using all_true =
@@ -1386,32 +1641,38 @@ template <typename... Args, typename S, typename Char = char_t<S>>
inline format_arg_store<buffer_context<Char>, remove_reference_t<Args>...>
make_args_checked(const S& format_str,
const remove_reference_t<Args>&... args) {
static_assert(all_true<(!std::is_base_of<view, remove_reference_t<Args>>() ||
!std::is_reference<Args>())...>::value,
"passing views as lvalues is disallowed");
check_format_string<remove_const_t<remove_reference_t<Args>>...>(format_str);
static_assert(
all_true<(!std::is_base_of<view, remove_reference_t<Args>>::value ||
!std::is_reference<Args>::value)...>::value,
"passing views as lvalues is disallowed");
check_format_string<Args...>(format_str);
return {args...};
}
template <typename Char>
std::basic_string<Char> vformat(basic_string_view<Char> format_str,
basic_format_args<buffer_context<Char>> args);
std::basic_string<Char> vformat(
basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args);
template <typename Char>
typename buffer_context<Char>::iterator vformat_to(
buffer<Char>& buf, basic_string_view<Char> format_str,
basic_format_args<buffer_context<Char>> args);
basic_format_args<buffer_context<type_identity_t<Char>>> args);
template <typename Char, typename Args,
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
inline void vprint_mojibake(std::FILE*, basic_string_view<Char>, const Args&) {}
FMT_API void vprint_mojibake(std::FILE*, string_view, format_args);
#ifndef _WIN32
inline void vprint_mojibake(std::FILE*, string_view, format_args) {}
#endif
} // namespace internal
/**
\rst
Returns a named argument to be used in a formatting function.
The named argument holds a reference and does not extend the lifetime
of its arguments.
Consequently, a dangling reference can accidentally be created.
The user should take care to only pass this function temporaries when
the named argument is itself a temporary, as per the following example.
Returns a named argument to be used in a formatting function. It should only
be used in a call to a formatting function.
**Example**::
@@ -1434,8 +1695,9 @@ void arg(S, internal::named_arg<T, Char>) = delete;
template <typename OutputIt, typename S, typename Char = char_t<S>,
FMT_ENABLE_IF(
internal::is_contiguous_back_insert_iterator<OutputIt>::value)>
OutputIt vformat_to(OutputIt out, const S& format_str,
basic_format_args<buffer_context<Char>> args) {
OutputIt vformat_to(
OutputIt out, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
using container = remove_reference_t<decltype(internal::get_container(out))>;
internal::container_buffer<container> buf((internal::get_container(out)));
internal::vformat_to(buf, to_string_view(format_str), args);
@@ -1448,14 +1710,14 @@ template <typename Container, typename S, typename... Args,
inline std::back_insert_iterator<Container> format_to(
std::back_insert_iterator<Container> out, const S& format_str,
Args&&... args) {
return vformat_to(
out, to_string_view(format_str),
{internal::make_args_checked<Args...>(format_str, args...)});
return vformat_to(out, to_string_view(format_str),
internal::make_args_checked<Args...>(format_str, args...));
}
template <typename S, typename Char = char_t<S>>
inline std::basic_string<Char> vformat(
const S& format_str, basic_format_args<buffer_context<Char>> args) {
const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
return internal::vformat(to_string_view(format_str), args);
}
@@ -1475,44 +1737,52 @@ template <typename S, typename... Args, typename Char = char_t<S>>
inline std::basic_string<Char> format(const S& format_str, Args&&... args) {
return internal::vformat(
to_string_view(format_str),
{internal::make_args_checked<Args...>(format_str, args...)});
internal::make_args_checked<Args...>(format_str, args...));
}
FMT_API void vprint(std::FILE* f, string_view format_str, format_args args);
FMT_API void vprint(string_view format_str, format_args args);
FMT_API void vprint(string_view, format_args);
FMT_API void vprint(std::FILE*, string_view, format_args);
/**
\rst
Prints formatted data to the file *f*. For wide format strings,
*f* should be in wide-oriented mode set via ``fwide(f, 1)`` or
``_setmode(_fileno(f), _O_U8TEXT)`` on Windows.
Formats ``args`` according to specifications in ``format_str`` and writes the
output to the file ``f``. Strings are assumed to be Unicode-encoded unless the
``FMT_UNICODE`` macro is set to 0.
**Example**::
fmt::print(stderr, "Don't {}!", "panic");
\endrst
*/
template <typename S, typename... Args,
FMT_ENABLE_IF(internal::is_string<S>::value)>
template <typename S, typename... Args, typename Char = char_t<S>>
inline void print(std::FILE* f, const S& format_str, Args&&... args) {
vprint(f, to_string_view(format_str),
internal::make_args_checked<Args...>(format_str, args...));
return internal::is_unicode<Char>()
? vprint(f, to_string_view(format_str),
internal::make_args_checked<Args...>(format_str, args...))
: internal::vprint_mojibake(
f, to_string_view(format_str),
internal::make_args_checked<Args...>(format_str, args...));
}
/**
\rst
Prints formatted data to ``stdout``.
Formats ``args`` according to specifications in ``format_str`` and writes
the output to ``stdout``. Strings are assumed to be Unicode-encoded unless
the ``FMT_UNICODE`` macro is set to 0.
**Example**::
fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
template <typename S, typename... Args,
FMT_ENABLE_IF(internal::is_string<S>::value)>
template <typename S, typename... Args, typename Char = char_t<S>>
inline void print(const S& format_str, Args&&... args) {
vprint(to_string_view(format_str),
internal::make_args_checked<Args...>(format_str, args...));
return internal::is_unicode<Char>()
? vprint(to_string_view(format_str),
internal::make_args_checked<Args...>(format_str, args...))
: internal::vprint_mojibake(
stdout, to_string_view(format_str),
internal::make_args_checked<Args...>(format_str, args...));
}
FMT_END_NAMESPACE