mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-01-19 03:57:14 +01:00
Update fmt library.
This commit is contained in:
parent
7a255f065f
commit
eea5dd7743
232
vendor/Fmt/include/fmt/args.h
vendored
Normal file
232
vendor/Fmt/include/fmt/args.h
vendored
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
// Formatting library for C++ - dynamic format arguments
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_ARGS_H_
|
||||||
|
#define FMT_ARGS_H_
|
||||||
|
|
||||||
|
#include <functional> // std::reference_wrapper
|
||||||
|
#include <memory> // std::unique_ptr
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename T> struct is_reference_wrapper : std::false_type {};
|
||||||
|
template <typename T>
|
||||||
|
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
|
||||||
|
|
||||||
|
template <typename T> const T& unwrap(const T& v) { return v; }
|
||||||
|
template <typename T> const T& unwrap(const std::reference_wrapper<T>& v) {
|
||||||
|
return static_cast<const T&>(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
|
||||||
|
auto& value = new_node->value;
|
||||||
|
new_node->next = std::move(head_);
|
||||||
|
head_ = std::move(new_node);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
A dynamic version of `fmt::format_arg_store`.
|
||||||
|
It's equipped with a storage to potentially temporary objects which lifetimes
|
||||||
|
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 detail::type mapped_type =
|
||||||
|
detail::mapped_type_constant<T, Context>::value;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
value = !(detail::is_reference_wrapper<T>::value ||
|
||||||
|
std::is_same<T, basic_string_view<char_type>>::value ||
|
||||||
|
std::is_same<T, detail::std_string_view<char_type>>::value ||
|
||||||
|
(mapped_type != detail::type::cstring_type &&
|
||||||
|
mapped_type != detail::type::string_type &&
|
||||||
|
mapped_type != detail::type::custom_type))
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using stored_type = conditional_t<detail::is_string<T>::value &&
|
||||||
|
!has_formatter<T, Context>::value &&
|
||||||
|
!detail::is_reference_wrapper<T>::value,
|
||||||
|
std::basic_string<char_type>, T>;
|
||||||
|
|
||||||
|
// Storage of basic_format_arg must be contiguous.
|
||||||
|
std::vector<basic_format_arg<Context>> data_;
|
||||||
|
std::vector<detail::named_arg_info<char_type>> named_info_;
|
||||||
|
|
||||||
|
// Storage of arguments not fitting into basic_format_arg must grow
|
||||||
|
// without relocation because items in data_ refer to it.
|
||||||
|
detail::dynamic_arg_list dynamic_args_;
|
||||||
|
|
||||||
|
friend class basic_format_args<Context>;
|
||||||
|
|
||||||
|
unsigned long long get_types() const {
|
||||||
|
return detail::is_unpacked_bit | data_.size() |
|
||||||
|
(named_info_.empty()
|
||||||
|
? 0ULL
|
||||||
|
: static_cast<unsigned long long>(detail::has_named_args_bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
const basic_format_arg<Context>* data() const {
|
||||||
|
return named_info_.empty() ? data_.data() : data_.data() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void emplace_arg(const T& arg) {
|
||||||
|
data_.emplace_back(detail::make_arg<Context>(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void emplace_arg(const detail::named_arg<char_type, T>& arg) {
|
||||||
|
if (named_info_.empty()) {
|
||||||
|
constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr};
|
||||||
|
data_.insert(data_.begin(), {zero_ptr, 0});
|
||||||
|
}
|
||||||
|
data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value)));
|
||||||
|
auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
|
||||||
|
data->pop_back();
|
||||||
|
};
|
||||||
|
std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
|
||||||
|
guard{&data_, pop_one};
|
||||||
|
named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
|
||||||
|
data_[0].value_.named_args = {named_info_.data(), named_info_.size()};
|
||||||
|
guard.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Adds an argument into the dynamic store for later passing to a formatting
|
||||||
|
function.
|
||||||
|
|
||||||
|
Note that custom types and string types (but not string views) are copied
|
||||||
|
into the store dynamically allocating memory if necessary.
|
||||||
|
|
||||||
|
**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) {
|
||||||
|
if (detail::const_check(need_copy<T>::value))
|
||||||
|
emplace_arg(dynamic_args_.push<stored_type<T>>(arg));
|
||||||
|
else
|
||||||
|
emplace_arg(detail::unwrap(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Adds a reference to the argument into the dynamic store for later passing to
|
||||||
|
a formatting function.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
|
char band[] = "Rolling Stones";
|
||||||
|
store.push_back(std::cref(band));
|
||||||
|
band[9] = 'c'; // Changing str affects the output.
|
||||||
|
std::string result = fmt::vformat("{}", store);
|
||||||
|
// result == "Rolling Scones"
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adds named argument into the dynamic store for later passing to a formatting
|
||||||
|
function. ``std::reference_wrapper`` is supported to avoid copying of the
|
||||||
|
argument. The name is always copied into the store.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
void push_back(const detail::named_arg<char_type, T>& arg) {
|
||||||
|
const char_type* arg_name =
|
||||||
|
dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str();
|
||||||
|
if (detail::const_check(need_copy<T>::value)) {
|
||||||
|
emplace_arg(
|
||||||
|
fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value)));
|
||||||
|
} else {
|
||||||
|
emplace_arg(fmt::arg(arg_name, arg.value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Erase all elements from the store */
|
||||||
|
void clear() {
|
||||||
|
data_.clear();
|
||||||
|
named_info_.clear();
|
||||||
|
dynamic_args_ = detail::dynamic_arg_list();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Reserves space to store at least *new_cap* arguments including
|
||||||
|
*new_cap_named* named arguments.
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
void reserve(size_t new_cap, size_t new_cap_named) {
|
||||||
|
FMT_ASSERT(new_cap >= new_cap_named,
|
||||||
|
"Set of arguments includes set of named arguments");
|
||||||
|
data_.reserve(new_cap);
|
||||||
|
named_info_.reserve(new_cap_named);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // FMT_ARGS_H_
|
214
vendor/Fmt/include/fmt/chrono.h
vendored
214
vendor/Fmt/include/fmt/chrono.h
vendored
@ -8,6 +8,7 @@
|
|||||||
#ifndef FMT_CHRONO_H_
|
#ifndef FMT_CHRONO_H_
|
||||||
#define FMT_CHRONO_H_
|
#define FMT_CHRONO_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
@ -288,7 +289,11 @@ inline null<> gmtime_r(...) { return null<>(); }
|
|||||||
inline null<> gmtime_s(...) { return null<>(); }
|
inline null<> gmtime_s(...) { return null<>(); }
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
// Thread-safe replacement for std::localtime
|
/**
|
||||||
|
Converts given time since epoch as ``std::time_t`` value into calendar time,
|
||||||
|
expressed in local time. Unlike ``std::localtime``, this function is
|
||||||
|
thread-safe on most platforms.
|
||||||
|
*/
|
||||||
inline std::tm localtime(std::time_t time) {
|
inline std::tm localtime(std::time_t time) {
|
||||||
struct dispatcher {
|
struct dispatcher {
|
||||||
std::time_t time_;
|
std::time_t time_;
|
||||||
@ -330,7 +335,11 @@ inline std::tm localtime(
|
|||||||
return localtime(std::chrono::system_clock::to_time_t(time_point));
|
return localtime(std::chrono::system_clock::to_time_t(time_point));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thread-safe replacement for std::gmtime
|
/**
|
||||||
|
Converts given time since epoch as ``std::time_t`` value into calendar time,
|
||||||
|
expressed in Coordinated Universal Time (UTC). Unlike ``std::gmtime``, this
|
||||||
|
function is thread-safe on most platforms.
|
||||||
|
*/
|
||||||
inline std::tm gmtime(std::time_t time) {
|
inline std::tm gmtime(std::time_t time) {
|
||||||
struct dispatcher {
|
struct dispatcher {
|
||||||
std::time_t time_;
|
std::time_t time_;
|
||||||
@ -374,12 +383,21 @@ inline std::tm gmtime(
|
|||||||
namespace detail {
|
namespace detail {
|
||||||
inline size_t strftime(char* str, size_t count, const char* format,
|
inline size_t strftime(char* str, size_t count, const char* format,
|
||||||
const std::tm* time) {
|
const std::tm* time) {
|
||||||
return std::strftime(str, count, format, time);
|
// Assign to a pointer to suppress GCCs -Wformat-nonliteral
|
||||||
|
// First assign the nullptr to suppress -Wsuggest-attribute=format
|
||||||
|
std::size_t (*strftime)(char*, std::size_t, const char*, const std::tm*) =
|
||||||
|
nullptr;
|
||||||
|
strftime = std::strftime;
|
||||||
|
return strftime(str, count, format, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline size_t strftime(wchar_t* str, size_t count, const wchar_t* format,
|
inline size_t strftime(wchar_t* str, size_t count, const wchar_t* format,
|
||||||
const std::tm* time) {
|
const std::tm* time) {
|
||||||
return std::wcsftime(str, count, format, time);
|
// See above
|
||||||
|
std::size_t (*wcsftime)(wchar_t*, std::size_t, const wchar_t*,
|
||||||
|
const std::tm*) = nullptr;
|
||||||
|
wcsftime = std::wcsftime;
|
||||||
|
return wcsftime(str, count, format, time);
|
||||||
}
|
}
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
@ -396,19 +414,21 @@ struct formatter<std::chrono::time_point<std::chrono::system_clock>, Char>
|
|||||||
|
|
||||||
template <typename Char> struct formatter<std::tm, Char> {
|
template <typename Char> struct formatter<std::tm, Char> {
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
auto it = ctx.begin();
|
auto it = ctx.begin();
|
||||||
if (it != ctx.end() && *it == ':') ++it;
|
if (it != ctx.end() && *it == ':') ++it;
|
||||||
auto end = it;
|
auto end = it;
|
||||||
while (end != ctx.end() && *end != '}') ++end;
|
while (end != ctx.end() && *end != '}') ++end;
|
||||||
tm_format.reserve(detail::to_unsigned(end - it + 1));
|
specs = {it, detail::to_unsigned(end - it)};
|
||||||
tm_format.append(it, end);
|
|
||||||
tm_format.push_back('\0');
|
|
||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) {
|
auto format(const std::tm& tm, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
basic_memory_buffer<Char> tm_format;
|
||||||
|
tm_format.append(specs.begin(), specs.end());
|
||||||
|
tm_format.push_back('\0');
|
||||||
basic_memory_buffer<Char> buf;
|
basic_memory_buffer<Char> buf;
|
||||||
size_t start = buf.size();
|
size_t start = buf.size();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -431,34 +451,68 @@ template <typename Char> struct formatter<std::tm, Char> {
|
|||||||
return std::copy(buf.begin(), buf.end(), ctx.out());
|
return std::copy(buf.begin(), buf.end(), ctx.out());
|
||||||
}
|
}
|
||||||
|
|
||||||
basic_memory_buffer<Char> tm_format;
|
basic_string_view<Char> specs;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template <typename Period> FMT_CONSTEXPR const char* get_units() {
|
template <typename Period> FMT_CONSTEXPR const char* get_units() {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::atto>() { return "as"; }
|
template <> FMT_CONSTEXPR inline const char* get_units<std::atto>() {
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::femto>() { return "fs"; }
|
return "as";
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::pico>() { return "ps"; }
|
}
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::nano>() { return "ns"; }
|
template <> FMT_CONSTEXPR inline const char* get_units<std::femto>() {
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::micro>() { return "µs"; }
|
return "fs";
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::milli>() { return "ms"; }
|
}
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::centi>() { return "cs"; }
|
template <> FMT_CONSTEXPR inline const char* get_units<std::pico>() {
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::deci>() { return "ds"; }
|
return "ps";
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::ratio<1>>() { return "s"; }
|
}
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::deca>() { return "das"; }
|
template <> FMT_CONSTEXPR inline const char* get_units<std::nano>() {
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::hecto>() { return "hs"; }
|
return "ns";
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::kilo>() { return "ks"; }
|
}
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::mega>() { return "Ms"; }
|
template <> FMT_CONSTEXPR inline const char* get_units<std::micro>() {
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::giga>() { return "Gs"; }
|
return "µs";
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::tera>() { return "Ts"; }
|
}
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::peta>() { return "Ps"; }
|
template <> FMT_CONSTEXPR inline const char* get_units<std::milli>() {
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::exa>() { return "Es"; }
|
return "ms";
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::ratio<60>>() {
|
}
|
||||||
|
template <> FMT_CONSTEXPR inline const char* get_units<std::centi>() {
|
||||||
|
return "cs";
|
||||||
|
}
|
||||||
|
template <> FMT_CONSTEXPR inline const char* get_units<std::deci>() {
|
||||||
|
return "ds";
|
||||||
|
}
|
||||||
|
template <> FMT_CONSTEXPR inline const char* get_units<std::ratio<1>>() {
|
||||||
|
return "s";
|
||||||
|
}
|
||||||
|
template <> FMT_CONSTEXPR inline const char* get_units<std::deca>() {
|
||||||
|
return "das";
|
||||||
|
}
|
||||||
|
template <> FMT_CONSTEXPR inline const char* get_units<std::hecto>() {
|
||||||
|
return "hs";
|
||||||
|
}
|
||||||
|
template <> FMT_CONSTEXPR inline const char* get_units<std::kilo>() {
|
||||||
|
return "ks";
|
||||||
|
}
|
||||||
|
template <> FMT_CONSTEXPR inline const char* get_units<std::mega>() {
|
||||||
|
return "Ms";
|
||||||
|
}
|
||||||
|
template <> FMT_CONSTEXPR inline const char* get_units<std::giga>() {
|
||||||
|
return "Gs";
|
||||||
|
}
|
||||||
|
template <> FMT_CONSTEXPR inline const char* get_units<std::tera>() {
|
||||||
|
return "Ts";
|
||||||
|
}
|
||||||
|
template <> FMT_CONSTEXPR inline const char* get_units<std::peta>() {
|
||||||
|
return "Ps";
|
||||||
|
}
|
||||||
|
template <> FMT_CONSTEXPR inline const char* get_units<std::exa>() {
|
||||||
|
return "Es";
|
||||||
|
}
|
||||||
|
template <> FMT_CONSTEXPR inline const char* get_units<std::ratio<60>>() {
|
||||||
return "m";
|
return "m";
|
||||||
}
|
}
|
||||||
template <> FMT_CONSTEXPR const char* get_units<std::ratio<3600>>() {
|
template <> FMT_CONSTEXPR inline const char* get_units<std::ratio<3600>>() {
|
||||||
return "h";
|
return "h";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -629,28 +683,29 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
|
|||||||
struct chrono_format_checker {
|
struct chrono_format_checker {
|
||||||
FMT_NORETURN void report_no_date() { FMT_THROW(format_error("no date")); }
|
FMT_NORETURN void report_no_date() { FMT_THROW(format_error("no date")); }
|
||||||
|
|
||||||
template <typename Char> void on_text(const Char*, const Char*) {}
|
template <typename Char>
|
||||||
|
FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
|
||||||
FMT_NORETURN void on_abbr_weekday() { report_no_date(); }
|
FMT_NORETURN void on_abbr_weekday() { report_no_date(); }
|
||||||
FMT_NORETURN void on_full_weekday() { report_no_date(); }
|
FMT_NORETURN void on_full_weekday() { report_no_date(); }
|
||||||
FMT_NORETURN void on_dec0_weekday(numeric_system) { report_no_date(); }
|
FMT_NORETURN void on_dec0_weekday(numeric_system) { report_no_date(); }
|
||||||
FMT_NORETURN void on_dec1_weekday(numeric_system) { report_no_date(); }
|
FMT_NORETURN void on_dec1_weekday(numeric_system) { report_no_date(); }
|
||||||
FMT_NORETURN void on_abbr_month() { report_no_date(); }
|
FMT_NORETURN void on_abbr_month() { report_no_date(); }
|
||||||
FMT_NORETURN void on_full_month() { report_no_date(); }
|
FMT_NORETURN void on_full_month() { report_no_date(); }
|
||||||
void on_24_hour(numeric_system) {}
|
FMT_CONSTEXPR void on_24_hour(numeric_system) {}
|
||||||
void on_12_hour(numeric_system) {}
|
FMT_CONSTEXPR void on_12_hour(numeric_system) {}
|
||||||
void on_minute(numeric_system) {}
|
FMT_CONSTEXPR void on_minute(numeric_system) {}
|
||||||
void on_second(numeric_system) {}
|
FMT_CONSTEXPR void on_second(numeric_system) {}
|
||||||
FMT_NORETURN void on_datetime(numeric_system) { report_no_date(); }
|
FMT_NORETURN void on_datetime(numeric_system) { report_no_date(); }
|
||||||
FMT_NORETURN void on_loc_date(numeric_system) { report_no_date(); }
|
FMT_NORETURN void on_loc_date(numeric_system) { report_no_date(); }
|
||||||
FMT_NORETURN void on_loc_time(numeric_system) { report_no_date(); }
|
FMT_NORETURN void on_loc_time(numeric_system) { report_no_date(); }
|
||||||
FMT_NORETURN void on_us_date() { report_no_date(); }
|
FMT_NORETURN void on_us_date() { report_no_date(); }
|
||||||
FMT_NORETURN void on_iso_date() { report_no_date(); }
|
FMT_NORETURN void on_iso_date() { report_no_date(); }
|
||||||
void on_12_hour_time() {}
|
FMT_CONSTEXPR void on_12_hour_time() {}
|
||||||
void on_24_hour_time() {}
|
FMT_CONSTEXPR void on_24_hour_time() {}
|
||||||
void on_iso_time() {}
|
FMT_CONSTEXPR void on_iso_time() {}
|
||||||
void on_am_pm() {}
|
FMT_CONSTEXPR void on_am_pm() {}
|
||||||
void on_duration_value() {}
|
FMT_CONSTEXPR void on_duration_value() {}
|
||||||
void on_duration_unit() {}
|
FMT_CONSTEXPR void on_duration_unit() {}
|
||||||
FMT_NORETURN void on_utc_offset() { report_no_date(); }
|
FMT_NORETURN void on_utc_offset() { report_no_date(); }
|
||||||
FMT_NORETURN void on_tz_name() { report_no_date(); }
|
FMT_NORETURN void on_tz_name() { report_no_date(); }
|
||||||
};
|
};
|
||||||
@ -676,7 +731,8 @@ inline bool isfinite(T value) {
|
|||||||
// Converts value to int and checks that it's in the range [0, upper).
|
// Converts value to int and checks that it's in the range [0, upper).
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||||
inline int to_nonnegative_int(T value, int upper) {
|
inline int to_nonnegative_int(T value, int upper) {
|
||||||
FMT_ASSERT(value >= 0 && value <= upper, "invalid value");
|
FMT_ASSERT(value >= 0 && to_unsigned(value) <= to_unsigned(upper),
|
||||||
|
"invalid value");
|
||||||
(void)upper;
|
(void)upper;
|
||||||
return static_cast<int>(value);
|
return static_cast<int>(value);
|
||||||
}
|
}
|
||||||
@ -754,15 +810,21 @@ inline std::chrono::duration<Rep, std::milli> get_milliseconds(
|
|||||||
return std::chrono::duration<Rep, std::milli>(static_cast<Rep>(ms));
|
return std::chrono::duration<Rep, std::milli>(static_cast<Rep>(ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename Rep, typename OutputIt>
|
template <typename Char, typename Rep, typename OutputIt,
|
||||||
OutputIt format_duration_value(OutputIt out, Rep val, int precision) {
|
FMT_ENABLE_IF(std::is_integral<Rep>::value)>
|
||||||
const Char pr_f[] = {'{', ':', '.', '{', '}', 'f', '}', 0};
|
OutputIt format_duration_value(OutputIt out, Rep val, int) {
|
||||||
if (precision >= 0) return format_to(out, pr_f, val, precision);
|
return write<Char>(out, val);
|
||||||
const Char fp_f[] = {'{', ':', 'g', '}', 0};
|
|
||||||
const Char format[] = {'{', '}', 0};
|
|
||||||
return format_to(out, std::is_floating_point<Rep>::value ? fp_f : format,
|
|
||||||
val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Char, typename Rep, typename OutputIt,
|
||||||
|
FMT_ENABLE_IF(std::is_floating_point<Rep>::value)>
|
||||||
|
OutputIt format_duration_value(OutputIt out, Rep val, int precision) {
|
||||||
|
auto specs = basic_format_specs<Char>();
|
||||||
|
specs.precision = precision;
|
||||||
|
specs.type = precision > 0 ? 'f' : 'g';
|
||||||
|
return write<Char>(out, val, specs);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Char, typename OutputIt>
|
template <typename Char, typename OutputIt>
|
||||||
OutputIt copy_unit(string_view unit, OutputIt out, Char) {
|
OutputIt copy_unit(string_view unit, OutputIt out, Char) {
|
||||||
return std::copy(unit.begin(), unit.end(), out);
|
return std::copy(unit.begin(), unit.end(), out);
|
||||||
@ -780,10 +842,15 @@ template <typename Char, typename Period, typename OutputIt>
|
|||||||
OutputIt format_duration_unit(OutputIt out) {
|
OutputIt format_duration_unit(OutputIt out) {
|
||||||
if (const char* unit = get_units<Period>())
|
if (const char* unit = get_units<Period>())
|
||||||
return copy_unit(string_view(unit), out, Char());
|
return copy_unit(string_view(unit), out, Char());
|
||||||
const Char num_f[] = {'[', '{', '}', ']', 's', 0};
|
*out++ = '[';
|
||||||
if (const_check(Period::den == 1)) return format_to(out, num_f, Period::num);
|
out = write<Char>(out, Period::num);
|
||||||
const Char num_def_f[] = {'[', '{', '}', '/', '{', '}', ']', 's', 0};
|
if (const_check(Period::den != 1)) {
|
||||||
return format_to(out, num_def_f, Period::num, Period::den);
|
*out++ = '/';
|
||||||
|
out = write<Char>(out, Period::den);
|
||||||
|
}
|
||||||
|
*out++ = ']';
|
||||||
|
*out++ = 's';
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext, typename OutputIt, typename Rep,
|
template <typename FormatContext, typename OutputIt, typename Rep,
|
||||||
@ -1011,11 +1078,11 @@ template <typename Rep, typename Period, typename Char>
|
|||||||
struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||||
private:
|
private:
|
||||||
basic_format_specs<Char> specs;
|
basic_format_specs<Char> specs;
|
||||||
int precision;
|
int precision = -1;
|
||||||
using arg_ref_type = detail::arg_ref<Char>;
|
using arg_ref_type = detail::arg_ref<Char>;
|
||||||
arg_ref_type width_ref;
|
arg_ref_type width_ref;
|
||||||
arg_ref_type precision_ref;
|
arg_ref_type precision_ref;
|
||||||
mutable basic_string_view<Char> format_str;
|
basic_string_view<Char> format_str;
|
||||||
using duration = std::chrono::duration<Rep, Period>;
|
using duration = std::chrono::duration<Rep, Period>;
|
||||||
|
|
||||||
struct spec_handler {
|
struct spec_handler {
|
||||||
@ -1038,17 +1105,21 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void on_error(const char* msg) { FMT_THROW(format_error(msg)); }
|
void on_error(const char* msg) { FMT_THROW(format_error(msg)); }
|
||||||
void on_fill(basic_string_view<Char> fill) { f.specs.fill = fill; }
|
FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) {
|
||||||
void on_align(align_t align) { f.specs.align = align; }
|
f.specs.fill = fill;
|
||||||
void on_width(int width) { f.specs.width = width; }
|
}
|
||||||
void on_precision(int _precision) { f.precision = _precision; }
|
FMT_CONSTEXPR void on_align(align_t align) { f.specs.align = align; }
|
||||||
void end_precision() {}
|
FMT_CONSTEXPR void on_width(int width) { f.specs.width = width; }
|
||||||
|
FMT_CONSTEXPR void on_precision(int _precision) {
|
||||||
|
f.precision = _precision;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR void end_precision() {}
|
||||||
|
|
||||||
template <typename Id> void on_dynamic_width(Id arg_id) {
|
template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
|
||||||
f.width_ref = make_arg_ref(arg_id);
|
f.width_ref = make_arg_ref(arg_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Id> void on_dynamic_precision(Id arg_id) {
|
template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {
|
||||||
f.precision_ref = make_arg_ref(arg_id);
|
f.precision_ref = make_arg_ref(arg_id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1078,8 +1149,6 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
formatter() : precision(-1) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
|
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
|
||||||
-> decltype(ctx.begin()) {
|
-> decltype(ctx.begin()) {
|
||||||
auto range = do_parse(ctx);
|
auto range = do_parse(ctx);
|
||||||
@ -1089,27 +1158,30 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const duration& d, FormatContext& ctx) -> decltype(ctx.out()) {
|
auto format(const duration& d, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
auto specs_copy = specs;
|
||||||
|
auto precision_copy = precision;
|
||||||
auto begin = format_str.begin(), end = format_str.end();
|
auto begin = format_str.begin(), end = format_str.end();
|
||||||
// As a possible future optimization, we could avoid extra copying if width
|
// As a possible future optimization, we could avoid extra copying if width
|
||||||
// is not specified.
|
// is not specified.
|
||||||
basic_memory_buffer<Char> buf;
|
basic_memory_buffer<Char> buf;
|
||||||
auto out = std::back_inserter(buf);
|
auto out = std::back_inserter(buf);
|
||||||
detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref,
|
detail::handle_dynamic_spec<detail::width_checker>(specs_copy.width,
|
||||||
ctx);
|
width_ref, ctx);
|
||||||
detail::handle_dynamic_spec<detail::precision_checker>(precision,
|
detail::handle_dynamic_spec<detail::precision_checker>(precision_copy,
|
||||||
precision_ref, ctx);
|
precision_ref, ctx);
|
||||||
if (begin == end || *begin == '}') {
|
if (begin == end || *begin == '}') {
|
||||||
out = detail::format_duration_value<Char>(out, d.count(), precision);
|
out = detail::format_duration_value<Char>(out, d.count(), precision_copy);
|
||||||
detail::format_duration_unit<Char, Period>(out);
|
detail::format_duration_unit<Char, Period>(out);
|
||||||
} else {
|
} else {
|
||||||
detail::chrono_formatter<FormatContext, decltype(out), Rep, Period> f(
|
detail::chrono_formatter<FormatContext, decltype(out), Rep, Period> f(
|
||||||
ctx, out, d);
|
ctx, out, d);
|
||||||
f.precision = precision;
|
f.precision = precision_copy;
|
||||||
parse_chrono_format(begin, end, f);
|
parse_chrono_format(begin, end, f);
|
||||||
}
|
}
|
||||||
return detail::write(
|
return detail::write(
|
||||||
ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
|
ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs_copy);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
87
vendor/Fmt/include/fmt/color.h
vendored
87
vendor/Fmt/include/fmt/color.h
vendored
@ -10,6 +10,13 @@
|
|||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
|
// __declspec(deprecated) is broken in some MSVC versions.
|
||||||
|
#if FMT_MSC_VER
|
||||||
|
# define FMT_DEPRECATED_NONMSVC
|
||||||
|
#else
|
||||||
|
# define FMT_DEPRECATED_NONMSVC FMT_DEPRECATED
|
||||||
|
#endif
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
enum class color : uint32_t {
|
enum class color : uint32_t {
|
||||||
@ -223,7 +230,7 @@ struct color_type {
|
|||||||
};
|
};
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
// Experimental text formatting support.
|
/** A text style consisting of foreground and background colors and emphasis. */
|
||||||
class text_style {
|
class text_style {
|
||||||
public:
|
public:
|
||||||
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
|
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
|
||||||
@ -260,33 +267,14 @@ class text_style {
|
|||||||
return lhs |= rhs;
|
return lhs |= rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR text_style& operator&=(const text_style& rhs) {
|
FMT_DEPRECATED_NONMSVC FMT_CONSTEXPR text_style& operator&=(
|
||||||
if (!set_foreground_color) {
|
|
||||||
set_foreground_color = rhs.set_foreground_color;
|
|
||||||
foreground_color = rhs.foreground_color;
|
|
||||||
} else if (rhs.set_foreground_color) {
|
|
||||||
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
|
|
||||||
FMT_THROW(format_error("can't AND a terminal color"));
|
|
||||||
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!set_background_color) {
|
|
||||||
set_background_color = rhs.set_background_color;
|
|
||||||
background_color = rhs.background_color;
|
|
||||||
} else if (rhs.set_background_color) {
|
|
||||||
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
|
|
||||||
FMT_THROW(format_error("can't AND a terminal color"));
|
|
||||||
background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
|
|
||||||
static_cast<uint8_t>(rhs.ems));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend FMT_CONSTEXPR text_style operator&(text_style lhs,
|
|
||||||
const text_style& rhs) {
|
const text_style& rhs) {
|
||||||
return lhs &= rhs;
|
return and_assign(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_DEPRECATED_NONMSVC friend FMT_CONSTEXPR text_style
|
||||||
|
operator&(text_style lhs, const text_style& rhs) {
|
||||||
|
return lhs.and_assign(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
|
||||||
@ -326,8 +314,34 @@ class text_style {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEPRECATED!
|
||||||
|
FMT_CONSTEXPR text_style& and_assign(const text_style& rhs) {
|
||||||
|
if (!set_foreground_color) {
|
||||||
|
set_foreground_color = rhs.set_foreground_color;
|
||||||
|
foreground_color = rhs.foreground_color;
|
||||||
|
} else if (rhs.set_foreground_color) {
|
||||||
|
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
|
||||||
|
FMT_THROW(format_error("can't AND a terminal color"));
|
||||||
|
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!set_background_color) {
|
||||||
|
set_background_color = rhs.set_background_color;
|
||||||
|
background_color = rhs.background_color;
|
||||||
|
} else if (rhs.set_background_color) {
|
||||||
|
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
|
||||||
|
FMT_THROW(format_error("can't AND a terminal color"));
|
||||||
|
background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
|
||||||
|
static_cast<uint8_t>(rhs.ems));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground)
|
friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground)
|
||||||
FMT_NOEXCEPT;
|
FMT_NOEXCEPT;
|
||||||
|
|
||||||
friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background)
|
friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background)
|
||||||
FMT_NOEXCEPT;
|
FMT_NOEXCEPT;
|
||||||
|
|
||||||
@ -338,15 +352,18 @@ class text_style {
|
|||||||
emphasis ems;
|
emphasis ems;
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_CONSTEXPR text_style fg(detail::color_type foreground) FMT_NOEXCEPT {
|
/** Creates a text style from the foreground (text) color. */
|
||||||
return text_style(/*is_foreground=*/true, foreground);
|
FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) FMT_NOEXCEPT {
|
||||||
|
return text_style(true, foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR text_style bg(detail::color_type background) FMT_NOEXCEPT {
|
/** Creates a text style from the background color. */
|
||||||
return text_style(/*is_foreground=*/false, background);
|
FMT_CONSTEXPR inline text_style bg(detail::color_type background) FMT_NOEXCEPT {
|
||||||
|
return text_style(false, background);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
|
FMT_CONSTEXPR inline text_style operator|(emphasis lhs,
|
||||||
|
emphasis rhs) FMT_NOEXCEPT {
|
||||||
return text_style(lhs) | rhs;
|
return text_style(lhs) | rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,11 +540,15 @@ void print(std::FILE* f, const text_style& ts, const S& format_str,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
\rst
|
||||||
Formats a string and prints it to stdout using ANSI escape sequences to
|
Formats a string and prints it to stdout using ANSI escape sequences to
|
||||||
specify text formatting.
|
specify text formatting.
|
||||||
Example:
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||||
"Elapsed time: {0:.2f} seconds", 1.23);
|
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||||
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename S, typename... Args,
|
template <typename S, typename... Args,
|
||||||
FMT_ENABLE_IF(detail::is_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_string<S>::value)>
|
||||||
|
347
vendor/Fmt/include/fmt/compile.h
vendored
347
vendor/Fmt/include/fmt/compile.h
vendored
@ -8,13 +8,102 @@
|
|||||||
#ifndef FMT_COMPILE_H_
|
#ifndef FMT_COMPILE_H_
|
||||||
#define FMT_COMPILE_H_
|
#define FMT_COMPILE_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
|
#ifndef FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||||
|
# if defined(__cpp_nontype_template_parameter_class) && \
|
||||||
|
(!FMT_GCC_VERSION || FMT_GCC_VERSION >= 903)
|
||||||
|
# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 1
|
||||||
|
# else
|
||||||
|
# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 0
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename OutputIt> class truncating_iterator_base {
|
||||||
|
protected:
|
||||||
|
OutputIt out_;
|
||||||
|
size_t limit_;
|
||||||
|
size_t count_ = 0;
|
||||||
|
|
||||||
|
truncating_iterator_base() : out_(), limit_(0) {}
|
||||||
|
|
||||||
|
truncating_iterator_base(OutputIt out, size_t limit)
|
||||||
|
: out_(out), limit_(limit) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
using iterator_category = std::output_iterator_tag;
|
||||||
|
using value_type = typename std::iterator_traits<OutputIt>::value_type;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using pointer = void;
|
||||||
|
using reference = void;
|
||||||
|
using _Unchecked_type =
|
||||||
|
truncating_iterator_base; // Mark iterator as checked.
|
||||||
|
|
||||||
|
OutputIt base() const { return out_; }
|
||||||
|
size_t count() const { return count_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// An output iterator that truncates the output and counts the number of objects
|
||||||
|
// written to it.
|
||||||
|
template <typename OutputIt,
|
||||||
|
typename Enable = typename std::is_void<
|
||||||
|
typename std::iterator_traits<OutputIt>::value_type>::type>
|
||||||
|
class truncating_iterator;
|
||||||
|
|
||||||
|
template <typename OutputIt>
|
||||||
|
class truncating_iterator<OutputIt, std::false_type>
|
||||||
|
: public truncating_iterator_base<OutputIt> {
|
||||||
|
mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = typename truncating_iterator_base<OutputIt>::value_type;
|
||||||
|
|
||||||
|
truncating_iterator() = default;
|
||||||
|
|
||||||
|
truncating_iterator(OutputIt out, size_t limit)
|
||||||
|
: truncating_iterator_base<OutputIt>(out, limit) {}
|
||||||
|
|
||||||
|
truncating_iterator& operator++() {
|
||||||
|
if (this->count_++ < this->limit_) ++this->out_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
truncating_iterator operator++(int) {
|
||||||
|
auto it = *this;
|
||||||
|
++*this;
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_type& operator*() const {
|
||||||
|
return this->count_ < this->limit_ ? *this->out_ : blackhole_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename OutputIt>
|
||||||
|
class truncating_iterator<OutputIt, std::true_type>
|
||||||
|
: public truncating_iterator_base<OutputIt> {
|
||||||
|
public:
|
||||||
|
truncating_iterator() = default;
|
||||||
|
|
||||||
|
truncating_iterator(OutputIt out, size_t limit)
|
||||||
|
: truncating_iterator_base<OutputIt>(out, limit) {}
|
||||||
|
|
||||||
|
template <typename T> truncating_iterator& operator=(T val) {
|
||||||
|
if (this->count_++ < this->limit_) *this->out_++ = val;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
truncating_iterator& operator++() { return *this; }
|
||||||
|
truncating_iterator& operator++(int) { return *this; }
|
||||||
|
truncating_iterator& operator*() { return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
// A compile-time string which is compiled into fast formatting code.
|
// A compile-time string which is compiled into fast formatting code.
|
||||||
class compiled_string {};
|
class compiled_string {};
|
||||||
|
|
||||||
@ -36,6 +125,24 @@ struct is_compiled_string : std::is_base_of<compiled_string, S> {};
|
|||||||
*/
|
*/
|
||||||
#define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::detail::compiled_string)
|
#define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::detail::compiled_string)
|
||||||
|
|
||||||
|
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||||
|
template <typename Char, size_t N> struct fixed_string {
|
||||||
|
constexpr fixed_string(const Char (&str)[N]) {
|
||||||
|
copy_str<Char, const Char*, Char*>(static_cast<const Char*>(str), str + N,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
Char data[N]{};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, size_t N, fixed_string<Char, N> Str>
|
||||||
|
struct udl_compiled_string : compiled_string {
|
||||||
|
using char_type = Char;
|
||||||
|
constexpr operator basic_string_view<char_type>() const {
|
||||||
|
return {Str.data, N - 1};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename T, typename... Tail>
|
template <typename T, typename... Tail>
|
||||||
const T& first(const T& value, const Tail&...) {
|
const T& first(const T& value, const Tail&...) {
|
||||||
return value;
|
return value;
|
||||||
@ -175,9 +282,9 @@ class format_string_compiler : public error_handler {
|
|||||||
repl.arg_id = part_.part_kind == part::kind::arg_index
|
repl.arg_id = part_.part_kind == part::kind::arg_index
|
||||||
? arg_ref<Char>(part_.val.arg_index)
|
? arg_ref<Char>(part_.val.arg_index)
|
||||||
: arg_ref<Char>(part_.val.str);
|
: arg_ref<Char>(part_.val.str);
|
||||||
auto part = part::make_replacement(repl);
|
auto replacement_part = part::make_replacement(repl);
|
||||||
part.arg_id_end = begin;
|
replacement_part.arg_id_end = begin;
|
||||||
handler_(part);
|
handler_(replacement_part);
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -195,9 +302,15 @@ template <typename OutputIt, typename Context, typename Id>
|
|||||||
void format_arg(
|
void format_arg(
|
||||||
basic_format_parse_context<typename Context::char_type>& parse_ctx,
|
basic_format_parse_context<typename Context::char_type>& parse_ctx,
|
||||||
Context& ctx, Id arg_id) {
|
Context& ctx, Id arg_id) {
|
||||||
|
auto arg = ctx.arg(arg_id);
|
||||||
|
if (arg.type() == type::custom_type) {
|
||||||
|
visit_format_arg(custom_formatter<Context>(parse_ctx, ctx), arg);
|
||||||
|
} else {
|
||||||
ctx.advance_to(visit_format_arg(
|
ctx.advance_to(visit_format_arg(
|
||||||
arg_formatter<OutputIt, typename Context::char_type>(ctx, &parse_ctx),
|
default_arg_formatter<OutputIt, typename Context::char_type>{
|
||||||
ctx.arg(arg_id)));
|
ctx.out(), ctx.args(), ctx.locale()},
|
||||||
|
arg));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vformat_to is defined in a subnamespace to prevent ADL.
|
// vformat_to is defined in a subnamespace to prevent ADL.
|
||||||
@ -257,9 +370,8 @@ auto vformat_to(OutputIt out, CompiledFormat& cf,
|
|||||||
if (specs.precision >= 0) checker.check_precision();
|
if (specs.precision >= 0) checker.check_precision();
|
||||||
|
|
||||||
advance_to(parse_ctx, part.arg_id_end);
|
advance_to(parse_ctx, part.arg_id_end);
|
||||||
ctx.advance_to(
|
ctx.advance_to(visit_format_arg(
|
||||||
visit_format_arg(arg_formatter<OutputIt, typename Context::char_type>(
|
arg_formatter<OutputIt, typename Context::char_type>(ctx, specs),
|
||||||
ctx, nullptr, &specs),
|
|
||||||
arg));
|
arg));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -393,7 +505,7 @@ template <typename Char> struct text {
|
|||||||
using char_type = Char;
|
using char_type = Char;
|
||||||
|
|
||||||
template <typename OutputIt, typename... Args>
|
template <typename OutputIt, typename... Args>
|
||||||
OutputIt format(OutputIt out, const Args&...) const {
|
constexpr OutputIt format(OutputIt out, const Args&...) const {
|
||||||
return write<Char>(out, data);
|
return write<Char>(out, data);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -412,7 +524,7 @@ template <typename Char> struct code_unit {
|
|||||||
using char_type = Char;
|
using char_type = Char;
|
||||||
|
|
||||||
template <typename OutputIt, typename... Args>
|
template <typename OutputIt, typename... Args>
|
||||||
OutputIt format(OutputIt out, const Args&...) const {
|
constexpr OutputIt format(OutputIt out, const Args&...) const {
|
||||||
return write<Char>(out, value);
|
return write<Char>(out, value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -425,23 +537,60 @@ template <typename Char, typename T, int N> struct field {
|
|||||||
using char_type = Char;
|
using char_type = Char;
|
||||||
|
|
||||||
template <typename OutputIt, typename... Args>
|
template <typename OutputIt, typename... Args>
|
||||||
OutputIt format(OutputIt out, const Args&... args) const {
|
constexpr OutputIt format(OutputIt out, const Args&... args) const {
|
||||||
|
if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) {
|
||||||
|
const auto& arg = get<N>(args...).value;
|
||||||
|
return write<Char>(out, arg);
|
||||||
|
} else {
|
||||||
// This ensures that the argument type is convertile to `const T&`.
|
// This ensures that the argument type is convertile to `const T&`.
|
||||||
const T& arg = get<N>(args...);
|
const T& arg = get<N>(args...);
|
||||||
return write<Char>(out, arg);
|
return write<Char>(out, arg);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char, typename T, int N>
|
template <typename Char, typename T, int N>
|
||||||
struct is_compiled_format<field<Char, T, N>> : std::true_type {};
|
struct is_compiled_format<field<Char, T, N>> : std::true_type {};
|
||||||
|
|
||||||
|
// A replacement field that refers to argument with name.
|
||||||
|
template <typename Char> struct runtime_named_field {
|
||||||
|
using char_type = Char;
|
||||||
|
basic_string_view<Char> name;
|
||||||
|
|
||||||
|
template <typename OutputIt, typename T>
|
||||||
|
constexpr static bool try_format_argument(
|
||||||
|
OutputIt& out,
|
||||||
|
// [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9
|
||||||
|
[[maybe_unused]] basic_string_view<Char> arg_name, const T& arg) {
|
||||||
|
if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) {
|
||||||
|
if (arg_name == arg.name) {
|
||||||
|
out = write<Char>(out, arg.value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename... Args>
|
||||||
|
constexpr OutputIt format(OutputIt out, const Args&... args) const {
|
||||||
|
bool found = (try_format_argument(out, name, args) || ...);
|
||||||
|
if (!found) {
|
||||||
|
throw format_error("argument with specified name is not found");
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
struct is_compiled_format<runtime_named_field<Char>> : std::true_type {};
|
||||||
|
|
||||||
// A replacement field that refers to argument N and has format specifiers.
|
// A replacement field that refers to argument N and has format specifiers.
|
||||||
template <typename Char, typename T, int N> struct spec_field {
|
template <typename Char, typename T, int N> struct spec_field {
|
||||||
using char_type = Char;
|
using char_type = Char;
|
||||||
mutable formatter<T, Char> fmt;
|
formatter<T, Char> fmt;
|
||||||
|
|
||||||
template <typename OutputIt, typename... Args>
|
template <typename OutputIt, typename... Args>
|
||||||
OutputIt format(OutputIt out, const Args&... args) const {
|
constexpr OutputIt format(OutputIt out, const Args&... args) const {
|
||||||
// This ensures that the argument type is convertile to `const T&`.
|
// This ensures that the argument type is convertile to `const T&`.
|
||||||
const T& arg = get<N>(args...);
|
const T& arg = get<N>(args...);
|
||||||
const auto& vargs =
|
const auto& vargs =
|
||||||
@ -460,7 +609,7 @@ template <typename L, typename R> struct concat {
|
|||||||
using char_type = typename L::char_type;
|
using char_type = typename L::char_type;
|
||||||
|
|
||||||
template <typename OutputIt, typename... Args>
|
template <typename OutputIt, typename... Args>
|
||||||
OutputIt format(OutputIt out, const Args&... args) const {
|
constexpr OutputIt format(OutputIt out, const Args&... args) const {
|
||||||
out = lhs.format(out, args...);
|
out = lhs.format(out, args...);
|
||||||
return rhs.format(out, args...);
|
return rhs.format(out, args...);
|
||||||
}
|
}
|
||||||
@ -508,14 +657,51 @@ template <typename T, typename Char> struct parse_specs_result {
|
|||||||
int next_arg_id;
|
int next_arg_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr int manual_indexing_id = -1;
|
||||||
|
|
||||||
template <typename T, typename Char>
|
template <typename T, typename Char>
|
||||||
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
|
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
|
||||||
size_t pos, int arg_id) {
|
size_t pos, int next_arg_id) {
|
||||||
str.remove_prefix(pos);
|
str.remove_prefix(pos);
|
||||||
auto ctx = basic_format_parse_context<Char>(str, {}, arg_id + 1);
|
auto ctx = basic_format_parse_context<Char>(str, {}, next_arg_id);
|
||||||
auto f = formatter<T, Char>();
|
auto f = formatter<T, Char>();
|
||||||
auto end = f.parse(ctx);
|
auto end = f.parse(ctx);
|
||||||
return {f, pos + (end - str.data()) + 1, ctx.next_arg_id()};
|
return {f, pos + fmt::detail::to_unsigned(end - str.data()) + 1,
|
||||||
|
next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char> struct arg_id_handler {
|
||||||
|
constexpr void on_error(const char* message) { throw format_error(message); }
|
||||||
|
|
||||||
|
constexpr int on_arg_id() {
|
||||||
|
FMT_ASSERT(false, "handler cannot be used with automatic indexing");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int on_arg_id(int id) {
|
||||||
|
arg_id = arg_ref<Char>(id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int on_arg_id(basic_string_view<Char> id) {
|
||||||
|
arg_id = arg_ref<Char>(id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_ref<Char> arg_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char> struct parse_arg_id_result {
|
||||||
|
arg_ref<Char> arg_id;
|
||||||
|
const Char* arg_id_end;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <int ID, typename Char>
|
||||||
|
constexpr auto parse_arg_id(const Char* begin, const Char* end) {
|
||||||
|
auto handler = arg_id_handler<Char>{arg_ref<Char>{}};
|
||||||
|
auto adapter = id_adapter<arg_id_handler<Char>, Char>{handler, 0};
|
||||||
|
auto arg_id_end = parse_arg_id(begin, end, adapter);
|
||||||
|
return parse_arg_id_result<Char>{handler.arg_id, arg_id_end};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compiles a non-empty format string and returns the compiled representation
|
// Compiles a non-empty format string and returns the compiled representation
|
||||||
@ -525,24 +711,59 @@ constexpr auto compile_format_string(S format_str) {
|
|||||||
using char_type = typename S::char_type;
|
using char_type = typename S::char_type;
|
||||||
constexpr basic_string_view<char_type> str = format_str;
|
constexpr basic_string_view<char_type> str = format_str;
|
||||||
if constexpr (str[POS] == '{') {
|
if constexpr (str[POS] == '{') {
|
||||||
if (POS + 1 == str.size())
|
if constexpr (POS + 1 == str.size())
|
||||||
throw format_error("unmatched '{' in format string");
|
throw format_error("unmatched '{' in format string");
|
||||||
if constexpr (str[POS + 1] == '{') {
|
if constexpr (str[POS + 1] == '{') {
|
||||||
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
||||||
} else if constexpr (str[POS + 1] == '}') {
|
} else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') {
|
||||||
using type = get_type<ID, Args>;
|
static_assert(ID != manual_indexing_id,
|
||||||
return parse_tail<Args, POS + 2, ID + 1>(field<char_type, type, ID>(),
|
"cannot switch from manual to automatic argument indexing");
|
||||||
format_str);
|
using id_type = get_type<ID, Args>;
|
||||||
} else if constexpr (str[POS + 1] == ':') {
|
if constexpr (str[POS + 1] == '}') {
|
||||||
using type = get_type<ID, Args>;
|
constexpr auto next_id =
|
||||||
constexpr auto result = parse_specs<type>(str, POS + 2, ID);
|
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
|
||||||
return parse_tail<Args, result.end, result.next_arg_id>(
|
return parse_tail<Args, POS + 2, next_id>(
|
||||||
spec_field<char_type, type, ID>{result.fmt}, format_str);
|
field<char_type, id_type, ID>(), format_str);
|
||||||
} else {
|
} else {
|
||||||
return unknown_format();
|
constexpr auto result = parse_specs<id_type>(str, POS + 2, ID + 1);
|
||||||
|
return parse_tail<Args, result.end, result.next_arg_id>(
|
||||||
|
spec_field<char_type, id_type, ID>{result.fmt}, format_str);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
constexpr auto arg_id_result =
|
||||||
|
parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size());
|
||||||
|
constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data();
|
||||||
|
constexpr char_type c =
|
||||||
|
arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type();
|
||||||
|
static_assert(c == '}' || c == ':', "missing '}' in format string");
|
||||||
|
if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) {
|
||||||
|
static_assert(
|
||||||
|
ID == manual_indexing_id || ID == 0,
|
||||||
|
"cannot switch from automatic to manual argument indexing");
|
||||||
|
constexpr auto arg_index = arg_id_result.arg_id.val.index;
|
||||||
|
using id_type = get_type<arg_index, Args>;
|
||||||
|
if constexpr (c == '}') {
|
||||||
|
return parse_tail<Args, arg_id_end_pos + 1, manual_indexing_id>(
|
||||||
|
field<char_type, id_type, arg_index>(), format_str);
|
||||||
|
} else if constexpr (c == ':') {
|
||||||
|
constexpr auto result =
|
||||||
|
parse_specs<id_type>(str, arg_id_end_pos + 1, 0);
|
||||||
|
return parse_tail<Args, result.end, result.next_arg_id>(
|
||||||
|
spec_field<char_type, id_type, arg_index>{result.fmt},
|
||||||
|
format_str);
|
||||||
|
}
|
||||||
|
} else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) {
|
||||||
|
if constexpr (c == '}') {
|
||||||
|
return parse_tail<Args, arg_id_end_pos + 1, ID>(
|
||||||
|
runtime_named_field<char_type>{arg_id_result.arg_id.val.name},
|
||||||
|
format_str);
|
||||||
|
} else if constexpr (c == ':') {
|
||||||
|
return unknown_format(); // no type info for specs parsing
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if constexpr (str[POS] == '}') {
|
} else if constexpr (str[POS] == '}') {
|
||||||
if (POS + 1 == str.size())
|
if constexpr (POS + 1 == str.size())
|
||||||
throw format_error("unmatched '}' in format string");
|
throw format_error("unmatched '}' in format string");
|
||||||
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
||||||
} else {
|
} else {
|
||||||
@ -568,13 +789,8 @@ constexpr auto compile(S format_str) {
|
|||||||
constexpr auto result =
|
constexpr auto result =
|
||||||
detail::compile_format_string<detail::type_list<Args...>, 0, 0>(
|
detail::compile_format_string<detail::type_list<Args...>, 0, 0>(
|
||||||
format_str);
|
format_str);
|
||||||
if constexpr (std::is_same<remove_cvref_t<decltype(result)>,
|
|
||||||
detail::unknown_format>()) {
|
|
||||||
return detail::compiled_format<S, Args...>(to_string_view(format_str));
|
|
||||||
} else {
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
template <typename... Args, typename S,
|
template <typename... Args, typename S,
|
||||||
@ -615,7 +831,7 @@ FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
|
|||||||
|
|
||||||
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||||
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
|
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
|
||||||
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
constexpr OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
return cf.format(out, args...);
|
return cf.format(out, args...);
|
||||||
}
|
}
|
||||||
@ -641,18 +857,35 @@ FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
|
|||||||
#ifdef __cpp_if_constexpr
|
#ifdef __cpp_if_constexpr
|
||||||
if constexpr (std::is_same<typename S::char_type, char>::value) {
|
if constexpr (std::is_same<typename S::char_type, char>::value) {
|
||||||
constexpr basic_string_view<typename S::char_type> str = S();
|
constexpr basic_string_view<typename S::char_type> str = S();
|
||||||
if (str.size() == 2 && str[0] == '{' && str[1] == '}')
|
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {
|
||||||
return fmt::to_string(detail::first(args...));
|
const auto& first = detail::first(args...);
|
||||||
|
if constexpr (detail::is_named_arg<
|
||||||
|
remove_cvref_t<decltype(first)>>::value) {
|
||||||
|
return fmt::to_string(first.value);
|
||||||
|
} else {
|
||||||
|
return fmt::to_string(first);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
constexpr auto compiled = detail::compile<Args...>(S());
|
constexpr auto compiled = detail::compile<Args...>(S());
|
||||||
|
#ifdef __cpp_if_constexpr
|
||||||
|
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||||
|
detail::unknown_format>()) {
|
||||||
|
return format(static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
} else {
|
||||||
return format(compiled, std::forward<Args>(args)...);
|
return format(compiled, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return format(compiled, std::forward<Args>(args)...);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||||
FMT_ENABLE_IF(std::is_base_of<detail::basic_compiled_format,
|
FMT_ENABLE_IF(std::is_base_of<detail::basic_compiled_format,
|
||||||
CompiledFormat>::value)>
|
CompiledFormat>::value)>
|
||||||
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
constexpr OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
using char_type = typename CompiledFormat::char_type;
|
using char_type = typename CompiledFormat::char_type;
|
||||||
using context = format_context_t<OutputIt, char_type>;
|
using context = format_context_t<OutputIt, char_type>;
|
||||||
@ -662,9 +895,20 @@ OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
|||||||
|
|
||||||
template <typename OutputIt, typename S, typename... Args,
|
template <typename OutputIt, typename S, typename... Args,
|
||||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
OutputIt format_to(OutputIt out, const S&, const Args&... args) {
|
FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
|
||||||
constexpr auto compiled = detail::compile<Args...>(S());
|
constexpr auto compiled = detail::compile<Args...>(S());
|
||||||
return format_to(out, compiled, args...);
|
#ifdef __cpp_if_constexpr
|
||||||
|
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||||
|
detail::unknown_format>()) {
|
||||||
|
return format_to(out,
|
||||||
|
static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
} else {
|
||||||
|
return format_to(out, compiled, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return format_to(out, compiled, std::forward<Args>(args)...);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename CompiledFormat, typename... Args>
|
template <typename OutputIt, typename CompiledFormat, typename... Args>
|
||||||
@ -684,18 +928,31 @@ auto format_to_n(OutputIt out, size_t n, const CompiledFormat& cf,
|
|||||||
template <typename OutputIt, typename S, typename... Args,
|
template <typename OutputIt, typename S, typename... Args,
|
||||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n, const S&,
|
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n, const S&,
|
||||||
const Args&... args) {
|
Args&&... args) {
|
||||||
constexpr auto compiled = detail::compile<Args...>(S());
|
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), S(),
|
||||||
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), compiled,
|
std::forward<Args>(args)...);
|
||||||
args...);
|
|
||||||
return {it.base(), it.count()};
|
return {it.base(), it.count()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename CompiledFormat, typename... Args>
|
template <typename CompiledFormat, typename... Args,
|
||||||
|
FMT_ENABLE_IF(std::is_base_of<detail::basic_compiled_format,
|
||||||
|
CompiledFormat>::value ||
|
||||||
|
detail::is_compiled_string<CompiledFormat>::value)>
|
||||||
size_t formatted_size(const CompiledFormat& cf, const Args&... args) {
|
size_t formatted_size(const CompiledFormat& cf, const Args&... args) {
|
||||||
return format_to(detail::counting_iterator(), cf, args...).count();
|
return format_to(detail::counting_iterator(), cf, args...).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||||
|
inline namespace literals {
|
||||||
|
template <detail::fixed_string Str>
|
||||||
|
constexpr detail::udl_compiled_string<remove_cvref_t<decltype(Str.data[0])>,
|
||||||
|
sizeof(Str.data), Str>
|
||||||
|
operator""_cf() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} // namespace literals
|
||||||
|
#endif
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_COMPILE_H_
|
#endif // FMT_COMPILE_H_
|
||||||
|
479
vendor/Fmt/include/fmt/core.h
vendored
479
vendor/Fmt/include/fmt/core.h
vendored
@ -10,12 +10,9 @@
|
|||||||
|
|
||||||
#include <cstdio> // std::FILE
|
#include <cstdio> // std::FILE
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
// The fmt library version in the form major * 10000 + minor * 100 + patch.
|
// The fmt library version in the form major * 10000 + minor * 100 + patch.
|
||||||
#define FMT_VERSION 70103
|
#define FMT_VERSION 70103
|
||||||
@ -28,8 +25,10 @@
|
|||||||
|
|
||||||
#if defined(__GNUC__) && !defined(__clang__)
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||||
|
# define FMT_GCC_PRAGMA(arg) _Pragma(arg)
|
||||||
#else
|
#else
|
||||||
# define FMT_GCC_VERSION 0
|
# define FMT_GCC_VERSION 0
|
||||||
|
# define FMT_GCC_PRAGMA(arg)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__INTEL_COMPILER)
|
#if defined(__INTEL_COMPILER)
|
||||||
@ -52,10 +51,10 @@
|
|||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# define FMT_MSC_VER _MSC_VER
|
# define FMT_MSC_VER _MSC_VER
|
||||||
# define FMT_SUPPRESS_MSC_WARNING(n) __pragma(warning(suppress : n))
|
# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__))
|
||||||
#else
|
#else
|
||||||
# define FMT_MSC_VER 0
|
# define FMT_MSC_VER 0
|
||||||
# define FMT_SUPPRESS_MSC_WARNING(n)
|
# define FMT_MSC_WARNING(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __has_feature
|
#ifdef __has_feature
|
||||||
@ -95,7 +94,7 @@
|
|||||||
# define FMT_CONSTEXPR constexpr
|
# define FMT_CONSTEXPR constexpr
|
||||||
# define FMT_CONSTEXPR_DECL constexpr
|
# define FMT_CONSTEXPR_DECL constexpr
|
||||||
#else
|
#else
|
||||||
# define FMT_CONSTEXPR inline
|
# define FMT_CONSTEXPR
|
||||||
# define FMT_CONSTEXPR_DECL
|
# define FMT_CONSTEXPR_DECL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -180,7 +179,7 @@
|
|||||||
|
|
||||||
#ifndef FMT_USE_INLINE_NAMESPACES
|
#ifndef FMT_USE_INLINE_NAMESPACES
|
||||||
# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
|
# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
|
||||||
(FMT_MSC_VER >= 1900 && !_MANAGED)
|
(FMT_MSC_VER >= 1900 && (!defined(_MANAGED) || !_MANAGED))
|
||||||
# define FMT_USE_INLINE_NAMESPACES 1
|
# define FMT_USE_INLINE_NAMESPACES 1
|
||||||
# else
|
# else
|
||||||
# define FMT_USE_INLINE_NAMESPACES 0
|
# define FMT_USE_INLINE_NAMESPACES 0
|
||||||
@ -206,7 +205,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
|
#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
|
||||||
# define FMT_CLASS_API FMT_SUPPRESS_MSC_WARNING(4275)
|
# define FMT_CLASS_API FMT_MSC_WARNING(suppress : 4275)
|
||||||
# ifdef FMT_EXPORT
|
# ifdef FMT_EXPORT
|
||||||
# define FMT_API __declspec(dllexport)
|
# define FMT_API __declspec(dllexport)
|
||||||
# define FMT_EXTERN_TEMPLATE_API FMT_API
|
# define FMT_EXTERN_TEMPLATE_API FMT_API
|
||||||
@ -248,8 +247,15 @@
|
|||||||
#ifndef FMT_UNICODE
|
#ifndef FMT_UNICODE
|
||||||
# define FMT_UNICODE !FMT_MSC_VER
|
# define FMT_UNICODE !FMT_MSC_VER
|
||||||
#endif
|
#endif
|
||||||
#if FMT_UNICODE && FMT_MSC_VER
|
|
||||||
# pragma execution_character_set("utf-8")
|
#ifndef FMT_COMPILE_TIME_CHECKS
|
||||||
|
# define FMT_COMPILE_TIME_CHECKS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Enable minimal optimizations for more compact code in debug mode.
|
||||||
|
FMT_GCC_PRAGMA("GCC push_options")
|
||||||
|
#ifndef __OPTIMIZE__
|
||||||
|
FMT_GCC_PRAGMA("GCC optimize(\"Og\")")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
@ -274,10 +280,22 @@ struct monostate {};
|
|||||||
// An enable_if helper to be used in template parameters which results in much
|
// An enable_if helper to be used in template parameters which results in much
|
||||||
// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
|
// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
|
||||||
// to workaround a bug in MSVC 2019 (see #1140 and #1186).
|
// to workaround a bug in MSVC 2019 (see #1140 and #1186).
|
||||||
#define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0
|
#ifdef FMT_DOC
|
||||||
|
# define FMT_ENABLE_IF(...)
|
||||||
|
#else
|
||||||
|
# define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
constexpr bool is_constant_evaluated() FMT_NOEXCEPT {
|
||||||
|
#ifdef __cpp_lib_is_constant_evaluated
|
||||||
|
return std::is_constant_evaluated();
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// A helper function to suppress "conditional expression is constant" warnings.
|
// A helper function to suppress "conditional expression is constant" warnings.
|
||||||
template <typename T> constexpr T const_check(T value) { return value; }
|
template <typename T> constexpr T const_check(T value) { return value; }
|
||||||
|
|
||||||
@ -327,7 +345,7 @@ FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
|
|||||||
return static_cast<typename std::make_unsigned<Int>::type>(value);
|
return static_cast<typename std::make_unsigned<Int>::type>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_SUPPRESS_MSC_WARNING(4566) constexpr unsigned char micro[] = "\u00B5";
|
FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5";
|
||||||
|
|
||||||
template <typename Char> constexpr bool is_unicode() {
|
template <typename Char> constexpr bool is_unicode() {
|
||||||
return FMT_UNICODE || sizeof(Char) != 1 ||
|
return FMT_UNICODE || sizeof(Char) != 1 ||
|
||||||
@ -377,8 +395,12 @@ template <typename Char> class basic_string_view {
|
|||||||
#if __cplusplus >= 201703L // C++17's char_traits::length() is constexpr.
|
#if __cplusplus >= 201703L // C++17's char_traits::length() is constexpr.
|
||||||
FMT_CONSTEXPR
|
FMT_CONSTEXPR
|
||||||
#endif
|
#endif
|
||||||
basic_string_view(const Char* s)
|
FMT_INLINE basic_string_view(const Char* s) : data_(s) {
|
||||||
: data_(s), size_(std::char_traits<Char>::length(s)) {}
|
if (std::is_same<Char, char>::value)
|
||||||
|
size_ = std::strlen(reinterpret_cast<const char*>(s));
|
||||||
|
else
|
||||||
|
size_ = std::char_traits<Char>::length(s);
|
||||||
|
}
|
||||||
|
|
||||||
/** Constructs a string reference from a ``std::basic_string`` object. */
|
/** Constructs a string reference from a ``std::basic_string`` object. */
|
||||||
template <typename Traits, typename Alloc>
|
template <typename Traits, typename Alloc>
|
||||||
@ -465,7 +487,7 @@ template <> struct is_char<char32_t> : std::true_type {};
|
|||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
|
template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
|
||||||
inline basic_string_view<Char> to_string_view(const Char* s) {
|
FMT_INLINE basic_string_view<Char> to_string_view(const Char* s) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,7 +498,7 @@ inline basic_string_view<Char> to_string_view(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
inline basic_string_view<Char> to_string_view(basic_string_view<Char> s) {
|
constexpr basic_string_view<Char> to_string_view(basic_string_view<Char> s) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -670,7 +692,7 @@ template <typename T> class buffer {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Don't initialize ptr_ since it is not accessed to save a few cycles.
|
// Don't initialize ptr_ since it is not accessed to save a few cycles.
|
||||||
FMT_SUPPRESS_MSC_WARNING(26495)
|
FMT_MSC_WARNING(suppress : 26495)
|
||||||
buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {}
|
buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {}
|
||||||
|
|
||||||
buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) FMT_NOEXCEPT
|
buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) FMT_NOEXCEPT
|
||||||
@ -783,9 +805,7 @@ class iterator_buffer final : public Traits, public buffer<T> {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit iterator_buffer(OutputIt out, size_t n = buffer_size)
|
explicit iterator_buffer(OutputIt out, size_t n = buffer_size)
|
||||||
: Traits(n),
|
: Traits(n), buffer<T>(data_, 0, buffer_size), out_(out) {}
|
||||||
buffer<T>(data_, 0, buffer_size),
|
|
||||||
out_(out) {}
|
|
||||||
~iterator_buffer() { flush(); }
|
~iterator_buffer() { flush(); }
|
||||||
|
|
||||||
OutputIt out() {
|
OutputIt out() {
|
||||||
@ -935,9 +955,9 @@ struct arg_data<T, Char, NUM_ARGS, 0> {
|
|||||||
T args_[NUM_ARGS != 0 ? NUM_ARGS : +1];
|
T args_[NUM_ARGS != 0 ? NUM_ARGS : +1];
|
||||||
|
|
||||||
template <typename... U>
|
template <typename... U>
|
||||||
FMT_INLINE arg_data(const U&... init) : args_{init...} {}
|
FMT_CONSTEXPR FMT_INLINE arg_data(const U&... init) : args_{init...} {}
|
||||||
FMT_INLINE const T* args() const { return args_; }
|
FMT_CONSTEXPR FMT_INLINE const T* args() const { return args_; }
|
||||||
FMT_INLINE std::nullptr_t named_args() { return nullptr; }
|
FMT_CONSTEXPR FMT_INLINE std::nullptr_t named_args() { return nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
@ -958,7 +978,8 @@ void init_named_args(named_arg_info<Char>* named_args, int arg_count,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
FMT_INLINE void init_named_args(std::nullptr_t, int, int, const Args&...) {}
|
FMT_CONSTEXPR FMT_INLINE void init_named_args(std::nullptr_t, int, int,
|
||||||
|
const Args&...) {}
|
||||||
|
|
||||||
template <typename T> struct is_named_arg : std::false_type {};
|
template <typename T> struct is_named_arg : std::false_type {};
|
||||||
|
|
||||||
@ -1070,17 +1091,20 @@ template <typename Context> class value {
|
|||||||
|
|
||||||
constexpr FMT_INLINE value(int val = 0) : int_value(val) {}
|
constexpr FMT_INLINE value(int val = 0) : int_value(val) {}
|
||||||
constexpr FMT_INLINE value(unsigned val) : uint_value(val) {}
|
constexpr FMT_INLINE value(unsigned val) : uint_value(val) {}
|
||||||
FMT_INLINE value(long long val) : long_long_value(val) {}
|
constexpr FMT_INLINE value(long long val) : long_long_value(val) {}
|
||||||
FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {}
|
constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {}
|
||||||
FMT_INLINE value(int128_t val) : int128_value(val) {}
|
FMT_INLINE value(int128_t val) : int128_value(val) {}
|
||||||
FMT_INLINE value(uint128_t val) : uint128_value(val) {}
|
FMT_INLINE value(uint128_t val) : uint128_value(val) {}
|
||||||
FMT_INLINE value(float val) : float_value(val) {}
|
FMT_INLINE value(float val) : float_value(val) {}
|
||||||
FMT_INLINE value(double val) : double_value(val) {}
|
FMT_INLINE value(double val) : double_value(val) {}
|
||||||
FMT_INLINE value(long double val) : long_double_value(val) {}
|
FMT_INLINE value(long double val) : long_double_value(val) {}
|
||||||
FMT_INLINE value(bool val) : bool_value(val) {}
|
constexpr FMT_INLINE value(bool val) : bool_value(val) {}
|
||||||
FMT_INLINE value(char_type val) : char_value(val) {}
|
constexpr FMT_INLINE value(char_type val) : char_value(val) {}
|
||||||
FMT_INLINE value(const char_type* val) { string.data = val; }
|
FMT_CONSTEXPR FMT_INLINE value(const char_type* val) {
|
||||||
FMT_INLINE value(basic_string_view<char_type> val) {
|
string.data = val;
|
||||||
|
if (is_constant_evaluated()) string.size = {};
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR FMT_INLINE value(basic_string_view<char_type> val) {
|
||||||
string.data = val.data();
|
string.data = val.data();
|
||||||
string.size = val.size();
|
string.size = val.size();
|
||||||
}
|
}
|
||||||
@ -1126,36 +1150,40 @@ struct unformattable {};
|
|||||||
template <typename Context> struct arg_mapper {
|
template <typename Context> struct arg_mapper {
|
||||||
using char_type = typename Context::char_type;
|
using char_type = typename Context::char_type;
|
||||||
|
|
||||||
FMT_CONSTEXPR int map(signed char val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE int map(signed char val) { return val; }
|
||||||
FMT_CONSTEXPR unsigned map(unsigned char val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE unsigned map(unsigned char val) { return val; }
|
||||||
FMT_CONSTEXPR int map(short val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE int map(short val) { return val; }
|
||||||
FMT_CONSTEXPR unsigned map(unsigned short val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE unsigned map(unsigned short val) { return val; }
|
||||||
FMT_CONSTEXPR int map(int val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE int map(int val) { return val; }
|
||||||
FMT_CONSTEXPR unsigned map(unsigned val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE unsigned map(unsigned val) { return val; }
|
||||||
FMT_CONSTEXPR long_type map(long val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE long_type map(long val) { return val; }
|
||||||
FMT_CONSTEXPR ulong_type map(unsigned long val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE ulong_type map(unsigned long val) { return val; }
|
||||||
FMT_CONSTEXPR long long map(long long val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE long long map(long long val) { return val; }
|
||||||
FMT_CONSTEXPR unsigned long long map(unsigned long long val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE unsigned long long map(unsigned long long val) {
|
||||||
FMT_CONSTEXPR int128_t map(int128_t val) { return val; }
|
return val;
|
||||||
FMT_CONSTEXPR uint128_t map(uint128_t val) { return val; }
|
}
|
||||||
FMT_CONSTEXPR bool map(bool val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE int128_t map(int128_t val) { return val; }
|
||||||
|
FMT_CONSTEXPR FMT_INLINE uint128_t map(uint128_t val) { return val; }
|
||||||
|
FMT_CONSTEXPR FMT_INLINE bool map(bool val) { return val; }
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
|
template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
|
||||||
FMT_CONSTEXPR char_type map(T val) {
|
FMT_CONSTEXPR FMT_INLINE char_type map(T val) {
|
||||||
static_assert(
|
static_assert(
|
||||||
std::is_same<T, char>::value || std::is_same<T, char_type>::value,
|
std::is_same<T, char>::value || std::is_same<T, char_type>::value,
|
||||||
"mixing character types is disallowed");
|
"mixing character types is disallowed");
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR float map(float val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE float map(float val) { return val; }
|
||||||
FMT_CONSTEXPR double map(double val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE double map(double val) { return val; }
|
||||||
FMT_CONSTEXPR long double map(long double val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE long double map(long double val) { return val; }
|
||||||
|
|
||||||
FMT_CONSTEXPR const char_type* map(char_type* val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE const char_type* map(char_type* val) { return val; }
|
||||||
FMT_CONSTEXPR const char_type* map(const char_type* val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE const char_type* map(const char_type* val) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
template <typename T, FMT_ENABLE_IF(is_string<T>::value)>
|
template <typename T, FMT_ENABLE_IF(is_string<T>::value)>
|
||||||
FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
|
FMT_CONSTEXPR FMT_INLINE basic_string_view<char_type> map(const T& val) {
|
||||||
static_assert(std::is_same<char_type, char_t<T>>::value,
|
static_assert(std::is_same<char_type, char_t<T>>::value,
|
||||||
"mixing character types is disallowed");
|
"mixing character types is disallowed");
|
||||||
return to_string_view(val);
|
return to_string_view(val);
|
||||||
@ -1165,7 +1193,7 @@ template <typename Context> struct arg_mapper {
|
|||||||
std::is_constructible<basic_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)>
|
!has_fallback_formatter<T, Context>::value)>
|
||||||
FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
|
FMT_CONSTEXPR FMT_INLINE basic_string_view<char_type> map(const T& val) {
|
||||||
return basic_string_view<char_type>(val);
|
return basic_string_view<char_type>(val);
|
||||||
}
|
}
|
||||||
template <
|
template <
|
||||||
@ -1175,30 +1203,34 @@ template <typename Context> struct arg_mapper {
|
|||||||
!std::is_constructible<basic_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)>
|
!has_fallback_formatter<T, Context>::value)>
|
||||||
FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
|
FMT_CONSTEXPR FMT_INLINE basic_string_view<char_type> map(const T& val) {
|
||||||
return std_string_view<char_type>(val);
|
return std_string_view<char_type>(val);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR const char* map(const signed char* val) {
|
FMT_CONSTEXPR FMT_INLINE const char* map(const signed char* val) {
|
||||||
static_assert(std::is_same<char_type, char>::value, "invalid string type");
|
static_assert(std::is_same<char_type, char>::value, "invalid string type");
|
||||||
return reinterpret_cast<const char*>(val);
|
return reinterpret_cast<const char*>(val);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR const char* map(const unsigned char* val) {
|
FMT_CONSTEXPR FMT_INLINE const char* map(const unsigned char* val) {
|
||||||
static_assert(std::is_same<char_type, char>::value, "invalid string type");
|
static_assert(std::is_same<char_type, char>::value, "invalid string type");
|
||||||
return reinterpret_cast<const char*>(val);
|
return reinterpret_cast<const char*>(val);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR const char* map(signed char* val) {
|
FMT_CONSTEXPR FMT_INLINE const char* map(signed char* val) {
|
||||||
const auto* const_val = val;
|
const auto* const_val = val;
|
||||||
return map(const_val);
|
return map(const_val);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR const char* map(unsigned char* val) {
|
FMT_CONSTEXPR FMT_INLINE const char* map(unsigned char* val) {
|
||||||
const auto* const_val = val;
|
const auto* const_val = val;
|
||||||
return map(const_val);
|
return map(const_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR const void* map(void* val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE const void* map(void* val) { return val; }
|
||||||
FMT_CONSTEXPR const void* map(const void* val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE const void* map(const void* val) { return val; }
|
||||||
FMT_CONSTEXPR const void* map(std::nullptr_t val) { return val; }
|
FMT_CONSTEXPR FMT_INLINE const void* map(std::nullptr_t val) { return val; }
|
||||||
template <typename T> FMT_CONSTEXPR int map(const T*) {
|
|
||||||
|
// We use SFINAE instead of a const T* parameter to avoid conflicting with
|
||||||
|
// the C array overload.
|
||||||
|
template <typename T>
|
||||||
|
FMT_CONSTEXPR auto map(T) -> enable_if_t<std::is_pointer<T>::value, int> {
|
||||||
// Formatting of arbitrary pointers is disallowed. If you want to output
|
// Formatting of arbitrary pointers is disallowed. If you want to output
|
||||||
// a pointer cast it to "void *" or "const void *". In particular, this
|
// a pointer cast it to "void *" or "const void *". In particular, this
|
||||||
// forbids formatting of "[const] volatile char *" which is printed as bool
|
// forbids formatting of "[const] volatile char *" which is printed as bool
|
||||||
@ -1207,11 +1239,16 @@ template <typename Context> struct arg_mapper {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, std::size_t N>
|
||||||
|
FMT_CONSTEXPR FMT_INLINE auto map(const T (&values)[N]) -> const T (&)[N] {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T,
|
template <typename T,
|
||||||
FMT_ENABLE_IF(std::is_enum<T>::value &&
|
FMT_ENABLE_IF(std::is_enum<T>::value &&
|
||||||
!has_formatter<T, Context>::value &&
|
!has_formatter<T, Context>::value &&
|
||||||
!has_fallback_formatter<T, Context>::value)>
|
!has_fallback_formatter<T, Context>::value)>
|
||||||
FMT_CONSTEXPR auto map(const T& val)
|
FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
|
||||||
-> decltype(std::declval<arg_mapper>().map(
|
-> decltype(std::declval<arg_mapper>().map(
|
||||||
static_cast<typename std::underlying_type<T>::type>(val))) {
|
static_cast<typename std::underlying_type<T>::type>(val))) {
|
||||||
return map(static_cast<typename std::underlying_type<T>::type>(val));
|
return map(static_cast<typename std::underlying_type<T>::type>(val));
|
||||||
@ -1220,12 +1257,12 @@ template <typename Context> struct arg_mapper {
|
|||||||
FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value &&
|
FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value &&
|
||||||
(has_formatter<T, Context>::value ||
|
(has_formatter<T, Context>::value ||
|
||||||
has_fallback_formatter<T, Context>::value))>
|
has_fallback_formatter<T, Context>::value))>
|
||||||
FMT_CONSTEXPR const T& map(const T& val) {
|
FMT_CONSTEXPR FMT_INLINE const T& map(const T& val) {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FMT_CONSTEXPR auto map(const named_arg<char_type, T>& val)
|
FMT_CONSTEXPR FMT_INLINE auto map(const named_arg<char_type, T>& val)
|
||||||
-> decltype(std::declval<arg_mapper>().map(val.value)) {
|
-> decltype(std::declval<arg_mapper>().map(val.value)) {
|
||||||
return map(val.value);
|
return map(val.value);
|
||||||
}
|
}
|
||||||
@ -1354,14 +1391,16 @@ FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg(
|
|||||||
return vis(monostate());
|
return vis(monostate());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> struct formattable : std::false_type {};
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
|
||||||
// A workaround for gcc 4.8 to make void_t work in a SFINAE context.
|
// 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; };
|
template <typename... Ts> struct void_t_impl { using type = void; };
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
using void_t = typename detail::void_t_impl<Ts...>::type;
|
using void_t = typename detail::void_t_impl<Ts...>::type;
|
||||||
|
#else
|
||||||
|
template <typename...> using void_t = void;
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename It, typename T, typename Enable = void>
|
template <typename It, typename T, typename Enable = void>
|
||||||
struct is_output_iterator : std::false_type {};
|
struct is_output_iterator : std::false_type {};
|
||||||
@ -1394,7 +1433,7 @@ class locale_ref {
|
|||||||
const void* locale_; // A type-erased pointer to std::locale.
|
const void* locale_; // A type-erased pointer to std::locale.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
locale_ref() : locale_(nullptr) {}
|
constexpr locale_ref() : locale_(nullptr) {}
|
||||||
template <typename Locale> explicit locale_ref(const Locale& loc);
|
template <typename Locale> explicit locale_ref(const Locale& loc);
|
||||||
|
|
||||||
explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; }
|
explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; }
|
||||||
@ -1418,24 +1457,18 @@ FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value) {
|
|||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> int check(unformattable) {
|
|
||||||
static_assert(
|
|
||||||
formattable<T>(),
|
|
||||||
"Cannot format an argument. To make type T formattable provide a "
|
|
||||||
"formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
template <typename T, typename U> inline const U& check(const U& val) {
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The type template parameter is there to avoid an ODR violation when using
|
// The type template parameter is there to avoid an ODR violation when using
|
||||||
// a fallback formatter in one translation unit and an implicit conversion in
|
// a fallback formatter in one translation unit and an implicit conversion in
|
||||||
// another (not recommended).
|
// another (not recommended).
|
||||||
template <bool IS_PACKED, typename Context, type, typename T,
|
template <bool IS_PACKED, typename Context, type, typename T,
|
||||||
FMT_ENABLE_IF(IS_PACKED)>
|
FMT_ENABLE_IF(IS_PACKED)>
|
||||||
inline value<Context> make_arg(const T& val) {
|
FMT_CONSTEXPR FMT_INLINE value<Context> make_arg(const T& val) {
|
||||||
return check<T>(arg_mapper<Context>().map(val));
|
const auto& arg = arg_mapper<Context>().map(val);
|
||||||
|
static_assert(
|
||||||
|
!std::is_same<decltype(arg), const unformattable&>::value,
|
||||||
|
"Cannot format an argument. To make type T formattable provide a "
|
||||||
|
"formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
|
||||||
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool IS_PACKED, typename Context, type, typename T,
|
template <bool IS_PACKED, typename Context, type, typename T,
|
||||||
@ -1443,47 +1476,6 @@ template <bool IS_PACKED, typename Context, type, typename T,
|
|||||||
inline basic_format_arg<Context> make_arg(const T& value) {
|
inline basic_format_arg<Context> make_arg(const T& value) {
|
||||||
return make_arg<Context>(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 {};
|
|
||||||
|
|
||||||
template <typename T> const T& unwrap(const T& v) { return v; }
|
|
||||||
template <typename T> const T& unwrap(const std::reference_wrapper<T>& v) {
|
|
||||||
return static_cast<const T&>(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
|
|
||||||
auto& value = new_node->value;
|
|
||||||
new_node->next = std::move(head_);
|
|
||||||
head_ = std::move(new_node);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
// Formatting context.
|
// Formatting context.
|
||||||
@ -1509,28 +1501,30 @@ template <typename OutputIt, typename Char> class basic_format_context {
|
|||||||
Constructs a ``basic_format_context`` object. References to the arguments are
|
Constructs a ``basic_format_context`` object. References to the arguments are
|
||||||
stored in the object so make sure they have appropriate lifetimes.
|
stored in the object so make sure they have appropriate lifetimes.
|
||||||
*/
|
*/
|
||||||
basic_format_context(OutputIt out,
|
constexpr basic_format_context(
|
||||||
basic_format_args<basic_format_context> ctx_args,
|
OutputIt out, basic_format_args<basic_format_context> ctx_args,
|
||||||
detail::locale_ref loc = detail::locale_ref())
|
detail::locale_ref loc = detail::locale_ref())
|
||||||
: out_(out), args_(ctx_args), loc_(loc) {}
|
: out_(out), args_(ctx_args), loc_(loc) {}
|
||||||
|
|
||||||
format_arg arg(int id) const { return args_.get(id); }
|
constexpr format_arg arg(int id) const { return args_.get(id); }
|
||||||
format_arg arg(basic_string_view<char_type> name) { return args_.get(name); }
|
FMT_CONSTEXPR format_arg arg(basic_string_view<char_type> name) {
|
||||||
|
return args_.get(name);
|
||||||
|
}
|
||||||
int arg_id(basic_string_view<char_type> name) { return args_.get_id(name); }
|
int arg_id(basic_string_view<char_type> name) { return args_.get_id(name); }
|
||||||
const basic_format_args<basic_format_context>& args() const { return args_; }
|
const basic_format_args<basic_format_context>& args() const { return args_; }
|
||||||
|
|
||||||
detail::error_handler error_handler() { return {}; }
|
FMT_CONSTEXPR detail::error_handler error_handler() { return {}; }
|
||||||
void on_error(const char* message) { error_handler().on_error(message); }
|
void on_error(const char* message) { error_handler().on_error(message); }
|
||||||
|
|
||||||
// Returns an iterator to the beginning of the output range.
|
// Returns an iterator to the beginning of the output range.
|
||||||
iterator out() { return out_; }
|
FMT_CONSTEXPR iterator out() { return out_; }
|
||||||
|
|
||||||
// Advances the begin iterator to ``it``.
|
// Advances the begin iterator to ``it``.
|
||||||
void advance_to(iterator it) {
|
void advance_to(iterator it) {
|
||||||
if (!detail::is_back_insert_iterator<iterator>()) out_ = it;
|
if (!detail::is_back_insert_iterator<iterator>()) out_ = it;
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::locale_ref locale() { return loc_; }
|
FMT_CONSTEXPR detail::locale_ref locale() { return loc_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
@ -1543,6 +1537,11 @@ using wformat_context = buffer_context<wchar_t>;
|
|||||||
#define FMT_BUFFER_CONTEXT(Char) \
|
#define FMT_BUFFER_CONTEXT(Char) \
|
||||||
basic_format_context<detail::buffer_appender<Char>, Char>
|
basic_format_context<detail::buffer_appender<Char>, Char>
|
||||||
|
|
||||||
|
template <typename T, typename Char = char>
|
||||||
|
using is_formattable = bool_constant<!std::is_same<
|
||||||
|
decltype(detail::arg_mapper<buffer_context<Char>>().map(std::declval<T>())),
|
||||||
|
detail::unformattable>::value>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
An array of references to arguments. It can be implicitly converted into
|
An array of references to arguments. It can be implicitly converted into
|
||||||
@ -1579,7 +1578,7 @@ class format_arg_store
|
|||||||
: 0);
|
: 0);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
format_arg_store(const Args&... args)
|
FMT_CONSTEXPR FMT_INLINE format_arg_store(const Args&... args)
|
||||||
:
|
:
|
||||||
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
|
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
|
||||||
basic_format_args<Context>(*this),
|
basic_format_args<Context>(*this),
|
||||||
@ -1600,7 +1599,7 @@ class format_arg_store
|
|||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename Context = format_context, typename... Args>
|
template <typename Context = format_context, typename... Args>
|
||||||
inline format_arg_store<Context, Args...> make_format_args(
|
constexpr format_arg_store<Context, Args...> make_format_args(
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
return {args...};
|
return {args...};
|
||||||
}
|
}
|
||||||
@ -1614,7 +1613,7 @@ inline format_arg_store<Context, Args...> make_format_args(
|
|||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args, typename S, typename Char = char_t<S>>
|
template <typename... Args, typename S, typename Char = char_t<S>>
|
||||||
inline auto make_args_checked(const S& format_str,
|
FMT_INLINE auto make_args_checked(const S& format_str,
|
||||||
const remove_reference_t<Args>&... args)
|
const remove_reference_t<Args>&... args)
|
||||||
-> format_arg_store<buffer_context<Char>, remove_reference_t<Args>...> {
|
-> format_arg_store<buffer_context<Char>, remove_reference_t<Args>...> {
|
||||||
static_assert(
|
static_assert(
|
||||||
@ -1628,8 +1627,9 @@ inline auto make_args_checked(const S& format_str,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Returns a named argument to be used in a formatting function. It should only
|
Returns a named argument to be used in a formatting function.
|
||||||
be used in a call to a formatting function.
|
It should only be used in a call to a formatting function or
|
||||||
|
`dynamic_format_arg_store::push_back`.
|
||||||
|
|
||||||
**Example**::
|
**Example**::
|
||||||
|
|
||||||
@ -1642,179 +1642,6 @@ inline detail::named_arg<Char, T> arg(const Char* name, const T& arg) {
|
|||||||
return {name, arg};
|
return {name, arg};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
\rst
|
|
||||||
A dynamic version of `fmt::format_arg_store`.
|
|
||||||
It's equipped with a storage to potentially temporary objects which lifetimes
|
|
||||||
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 detail::type mapped_type =
|
|
||||||
detail::mapped_type_constant<T, Context>::value;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
value = !(detail::is_reference_wrapper<T>::value ||
|
|
||||||
std::is_same<T, basic_string_view<char_type>>::value ||
|
|
||||||
std::is_same<T, detail::std_string_view<char_type>>::value ||
|
|
||||||
(mapped_type != detail::type::cstring_type &&
|
|
||||||
mapped_type != detail::type::string_type &&
|
|
||||||
mapped_type != detail::type::custom_type))
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
using stored_type = conditional_t<detail::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_;
|
|
||||||
std::vector<detail::named_arg_info<char_type>> named_info_;
|
|
||||||
|
|
||||||
// Storage of arguments not fitting into basic_format_arg must grow
|
|
||||||
// without relocation because items in data_ refer to it.
|
|
||||||
detail::dynamic_arg_list dynamic_args_;
|
|
||||||
|
|
||||||
friend class basic_format_args<Context>;
|
|
||||||
|
|
||||||
unsigned long long get_types() const {
|
|
||||||
return detail::is_unpacked_bit | data_.size() |
|
|
||||||
(named_info_.empty()
|
|
||||||
? 0ULL
|
|
||||||
: static_cast<unsigned long long>(detail::has_named_args_bit));
|
|
||||||
}
|
|
||||||
|
|
||||||
const basic_format_arg<Context>* data() const {
|
|
||||||
return named_info_.empty() ? data_.data() : data_.data() + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> void emplace_arg(const T& arg) {
|
|
||||||
data_.emplace_back(detail::make_arg<Context>(arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void emplace_arg(const detail::named_arg<char_type, T>& arg) {
|
|
||||||
if (named_info_.empty()) {
|
|
||||||
constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr};
|
|
||||||
data_.insert(data_.begin(), {zero_ptr, 0});
|
|
||||||
}
|
|
||||||
data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value)));
|
|
||||||
auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
|
|
||||||
data->pop_back();
|
|
||||||
};
|
|
||||||
std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
|
|
||||||
guard{&data_, pop_one};
|
|
||||||
named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
|
|
||||||
data_[0].value_.named_args = {named_info_.data(), named_info_.size()};
|
|
||||||
guard.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
\rst
|
|
||||||
Adds an argument into the dynamic store for later passing to a formatting
|
|
||||||
function.
|
|
||||||
|
|
||||||
Note that custom types and string types (but not string views) are copied
|
|
||||||
into the store dynamically allocating memory if necessary.
|
|
||||||
|
|
||||||
**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) {
|
|
||||||
if (detail::const_check(need_copy<T>::value))
|
|
||||||
emplace_arg(dynamic_args_.push<stored_type<T>>(arg));
|
|
||||||
else
|
|
||||||
emplace_arg(detail::unwrap(arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
\rst
|
|
||||||
Adds a reference to the argument into the dynamic store for later passing to
|
|
||||||
a formatting function. Supports named arguments wrapped in
|
|
||||||
``std::reference_wrapper`` via ``std::ref()``/``std::cref()``.
|
|
||||||
|
|
||||||
**Example**::
|
|
||||||
|
|
||||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
|
||||||
char str[] = "1234567890";
|
|
||||||
store.push_back(std::cref(str));
|
|
||||||
int a1_val{42};
|
|
||||||
auto a1 = fmt::arg("a1_", a1_val);
|
|
||||||
store.push_back(std::cref(a1));
|
|
||||||
|
|
||||||
// Changing str affects the output but only for string and custom types.
|
|
||||||
str[0] = 'X';
|
|
||||||
|
|
||||||
std::string result = fmt::vformat("{} and {a1_}");
|
|
||||||
assert(result == "X234567890 and 42");
|
|
||||||
\endrst
|
|
||||||
*/
|
|
||||||
template <typename T> void push_back(std::reference_wrapper<T> arg) {
|
|
||||||
static_assert(
|
|
||||||
detail::is_named_arg<typename std::remove_cv<T>::type>::value ||
|
|
||||||
need_copy<T>::value,
|
|
||||||
"objects of built-in types and string views are always copied");
|
|
||||||
emplace_arg(arg.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Adds named argument into the dynamic store for later passing to a formatting
|
|
||||||
function. ``std::reference_wrapper`` is supported to avoid copying of the
|
|
||||||
argument.
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
void push_back(const detail::named_arg<char_type, T>& arg) {
|
|
||||||
const char_type* arg_name =
|
|
||||||
dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str();
|
|
||||||
if (detail::const_check(need_copy<T>::value)) {
|
|
||||||
emplace_arg(
|
|
||||||
fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value)));
|
|
||||||
} else {
|
|
||||||
emplace_arg(fmt::arg(arg_name, arg.value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Erase all elements from the store */
|
|
||||||
void clear() {
|
|
||||||
data_.clear();
|
|
||||||
named_info_.clear();
|
|
||||||
dynamic_args_ = detail::dynamic_arg_list();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
\rst
|
|
||||||
Reserves space to store at least *new_cap* arguments including
|
|
||||||
*new_cap_named* named arguments.
|
|
||||||
\endrst
|
|
||||||
*/
|
|
||||||
void reserve(size_t new_cap, size_t new_cap_named) {
|
|
||||||
FMT_ASSERT(new_cap >= new_cap_named,
|
|
||||||
"Set of arguments includes set of named arguments");
|
|
||||||
data_.reserve(new_cap);
|
|
||||||
named_info_.reserve(new_cap_named);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
A view of a collection of formatting arguments. To avoid lifetime issues it
|
A view of a collection of formatting arguments. To avoid lifetime issues it
|
||||||
@ -1846,25 +1673,27 @@ template <typename Context> class basic_format_args {
|
|||||||
const format_arg* args_;
|
const format_arg* args_;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_packed() const { return (desc_ & detail::is_unpacked_bit) == 0; }
|
constexpr bool is_packed() const {
|
||||||
|
return (desc_ & detail::is_unpacked_bit) == 0;
|
||||||
|
}
|
||||||
bool has_named_args() const {
|
bool has_named_args() const {
|
||||||
return (desc_ & detail::has_named_args_bit) != 0;
|
return (desc_ & detail::has_named_args_bit) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::type type(int index) const {
|
FMT_CONSTEXPR detail::type type(int index) const {
|
||||||
int shift = index * detail::packed_arg_bits;
|
int shift = index * detail::packed_arg_bits;
|
||||||
unsigned int mask = (1 << detail::packed_arg_bits) - 1;
|
unsigned int mask = (1 << detail::packed_arg_bits) - 1;
|
||||||
return static_cast<detail::type>((desc_ >> shift) & mask);
|
return static_cast<detail::type>((desc_ >> shift) & mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
basic_format_args(unsigned long long desc,
|
constexpr FMT_INLINE basic_format_args(unsigned long long desc,
|
||||||
const detail::value<Context>* values)
|
const detail::value<Context>* values)
|
||||||
: desc_(desc), values_(values) {}
|
: desc_(desc), values_(values) {}
|
||||||
basic_format_args(unsigned long long desc, const format_arg* args)
|
constexpr basic_format_args(unsigned long long desc, const format_arg* args)
|
||||||
: desc_(desc), args_(args) {}
|
: desc_(desc), args_(args) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
basic_format_args() : desc_(0) {}
|
constexpr basic_format_args() : desc_(0), args_(nullptr) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
@ -1872,8 +1701,10 @@ template <typename Context> class basic_format_args {
|
|||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
FMT_INLINE basic_format_args(const format_arg_store<Context, Args...>& store)
|
constexpr FMT_INLINE basic_format_args(
|
||||||
: basic_format_args(store.desc, store.data_.args()) {}
|
const format_arg_store<Context, Args...>& store)
|
||||||
|
: basic_format_args(format_arg_store<Context, Args...>::desc,
|
||||||
|
store.data_.args()) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
@ -1881,7 +1712,8 @@ template <typename Context> class basic_format_args {
|
|||||||
`~fmt::dynamic_format_arg_store`.
|
`~fmt::dynamic_format_arg_store`.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
FMT_INLINE basic_format_args(const dynamic_format_arg_store<Context>& store)
|
constexpr FMT_INLINE basic_format_args(
|
||||||
|
const dynamic_format_arg_store<Context>& store)
|
||||||
: basic_format_args(store.get_types(), store.data()) {}
|
: basic_format_args(store.get_types(), store.data()) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1889,12 +1721,12 @@ template <typename Context> class basic_format_args {
|
|||||||
Constructs a `basic_format_args` object from a dynamic set of arguments.
|
Constructs a `basic_format_args` object from a dynamic set of arguments.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
basic_format_args(const format_arg* args, int count)
|
constexpr basic_format_args(const format_arg* args, int count)
|
||||||
: basic_format_args(detail::is_unpacked_bit | detail::to_unsigned(count),
|
: basic_format_args(detail::is_unpacked_bit | detail::to_unsigned(count),
|
||||||
args) {}
|
args) {}
|
||||||
|
|
||||||
/** Returns the argument with the specified id. */
|
/** Returns the argument with the specified id. */
|
||||||
format_arg get(int id) const {
|
FMT_CONSTEXPR format_arg get(int id) const {
|
||||||
format_arg arg;
|
format_arg arg;
|
||||||
if (!is_packed()) {
|
if (!is_packed()) {
|
||||||
if (id < max_size()) arg = args_[id];
|
if (id < max_size()) arg = args_[id];
|
||||||
@ -2043,11 +1875,11 @@ inline auto format_to_n(OutputIt out, size_t n, const S& format_str,
|
|||||||
Returns the number of characters in the output of
|
Returns the number of characters in the output of
|
||||||
``format(format_str, args...)``.
|
``format(format_str, args...)``.
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||||
inline size_t formatted_size(string_view format_str, Args&&... args) {
|
inline size_t formatted_size(const S& format_str, Args&&... args) {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||||
detail::counting_buffer<> buf;
|
detail::counting_buffer<> buf;
|
||||||
detail::vformat_to(buf, format_str, vargs);
|
detail::vformat_to(buf, to_string_view(format_str), vargs);
|
||||||
return buf.count();
|
return buf.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2070,7 +1902,9 @@ FMT_INLINE std::basic_string<Char> vformat(
|
|||||||
*/
|
*/
|
||||||
// Pass char_t as a default template parameter instead of using
|
// Pass char_t as a default template parameter instead of using
|
||||||
// std::basic_string<char_t<S>> to reduce the symbol size.
|
// std::basic_string<char_t<S>> to reduce the symbol size.
|
||||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
template <typename S, typename... Args, typename Char = char_t<S>,
|
||||||
|
FMT_ENABLE_IF(!FMT_COMPILE_TIME_CHECKS ||
|
||||||
|
!std::is_same<Char, char>::value)>
|
||||||
FMT_INLINE std::basic_string<Char> format(const S& format_str, Args&&... args) {
|
FMT_INLINE std::basic_string<Char> format(const S& format_str, Args&&... args) {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||||
return detail::vformat(to_string_view(format_str), vargs);
|
return detail::vformat(to_string_view(format_str), vargs);
|
||||||
@ -2117,6 +1951,13 @@ inline void print(const S& format_str, Args&&... args) {
|
|||||||
: detail::vprint_mojibake(stdout, to_string_view(format_str),
|
: detail::vprint_mojibake(stdout, to_string_view(format_str),
|
||||||
vargs);
|
vargs);
|
||||||
}
|
}
|
||||||
|
FMT_GCC_PRAGMA("GCC pop_options")
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_CORE_H_
|
#endif // FMT_CORE_H_
|
||||||
|
|
||||||
|
// Define FMT_DYNAMIC_ARGS to make core.h provide dynamic_format_arg_store
|
||||||
|
// DEPRECATED! Include fmt/args.h directly instead.
|
||||||
|
#ifdef FMT_DYNAMIC_ARGS
|
||||||
|
#include "args.h"
|
||||||
|
#endif
|
||||||
|
156
vendor/Fmt/include/fmt/format-inl.h
vendored
156
vendor/Fmt/include/fmt/format-inl.h
vendored
@ -8,7 +8,7 @@
|
|||||||
#ifndef FMT_FORMAT_INL_H_
|
#ifndef FMT_FORMAT_INL_H_
|
||||||
#define FMT_FORMAT_INL_H_
|
#define FMT_FORMAT_INL_H_
|
||||||
|
|
||||||
#include <cassert>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@ -145,9 +145,9 @@ FMT_FUNC void format_error_code(detail::buffer<char>& out, int error_code,
|
|||||||
error_code_size += detail::to_unsigned(detail::count_digits(abs_value));
|
error_code_size += detail::to_unsigned(detail::count_digits(abs_value));
|
||||||
auto it = buffer_appender<char>(out);
|
auto it = buffer_appender<char>(out);
|
||||||
if (message.size() <= inline_buffer_size - error_code_size)
|
if (message.size() <= inline_buffer_size - error_code_size)
|
||||||
format_to(it, "{}{}", message, SEP);
|
format_to(it, FMT_STRING("{}{}"), message, SEP);
|
||||||
format_to(it, "{}{}", ERROR_STR, error_code);
|
format_to(it, FMT_STRING("{}{}"), ERROR_STR, error_code);
|
||||||
assert(out.size() <= inline_buffer_size);
|
FMT_ASSERT(out.size() <= inline_buffer_size, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_FUNC void report_error(format_func func, int error_code,
|
FMT_FUNC void report_error(format_func func, int error_code,
|
||||||
@ -165,11 +165,8 @@ inline void fwrite_fully(const void* ptr, size_t size, size_t count,
|
|||||||
size_t written = std::fwrite(ptr, size, count, stream);
|
size_t written = std::fwrite(ptr, size, count, stream);
|
||||||
if (written < count) FMT_THROW(system_error(errno, "cannot write to file"));
|
if (written < count) FMT_THROW(system_error(errno, "cannot write to file"));
|
||||||
}
|
}
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
|
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
template <typename Locale>
|
template <typename Locale>
|
||||||
locale_ref::locale_ref(const Locale& loc) : locale_(&loc) {
|
locale_ref::locale_ref(const Locale& loc) : locale_(&loc) {
|
||||||
static_assert(std::is_same<Locale, std::locale>::value, "");
|
static_assert(std::is_same<Locale, std::locale>::value, "");
|
||||||
@ -191,19 +188,18 @@ template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref loc) {
|
|||||||
return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>())
|
return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>())
|
||||||
.decimal_point();
|
.decimal_point();
|
||||||
}
|
}
|
||||||
} // namespace detail
|
|
||||||
#else
|
#else
|
||||||
template <typename Char>
|
template <typename Char> FMT_FUNC std::string grouping_impl(locale_ref) {
|
||||||
FMT_FUNC std::string detail::grouping_impl(locale_ref) {
|
|
||||||
return "\03";
|
return "\03";
|
||||||
}
|
}
|
||||||
template <typename Char> FMT_FUNC Char detail::thousands_sep_impl(locale_ref) {
|
template <typename Char> FMT_FUNC Char thousands_sep_impl(locale_ref) {
|
||||||
return FMT_STATIC_THOUSANDS_SEPARATOR;
|
return FMT_STATIC_THOUSANDS_SEPARATOR;
|
||||||
}
|
}
|
||||||
template <typename Char> FMT_FUNC Char detail::decimal_point_impl(locale_ref) {
|
template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref) {
|
||||||
return '.';
|
return '.';
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
FMT_API FMT_FUNC format_error::~format_error() FMT_NOEXCEPT = default;
|
FMT_API FMT_FUNC format_error::~format_error() FMT_NOEXCEPT = default;
|
||||||
FMT_API FMT_FUNC system_error::~system_error() FMT_NOEXCEPT = default;
|
FMT_API FMT_FUNC system_error::~system_error() FMT_NOEXCEPT = default;
|
||||||
@ -247,9 +243,6 @@ const typename basic_data<T>::digit_pair basic_data<T>::digits[] = {
|
|||||||
{'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'},
|
{'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'},
|
||||||
{'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}};
|
{'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
const char basic_data<T>::hex_digits[] = "0123456789abcdef";
|
|
||||||
|
|
||||||
#define FMT_POWERS_OF_10(factor) \
|
#define FMT_POWERS_OF_10(factor) \
|
||||||
factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \
|
factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \
|
||||||
(factor)*1000000, (factor)*10000000, (factor)*100000000, \
|
(factor)*1000000, (factor)*10000000, (factor)*100000000, \
|
||||||
@ -1070,10 +1063,14 @@ const char basic_data<T>::background_color[] = "\x1b[48;2;";
|
|||||||
template <typename T> const char basic_data<T>::reset_color[] = "\x1b[0m";
|
template <typename T> const char basic_data<T>::reset_color[] = "\x1b[0m";
|
||||||
template <typename T> const wchar_t basic_data<T>::wreset_color[] = L"\x1b[0m";
|
template <typename T> const wchar_t basic_data<T>::wreset_color[] = L"\x1b[0m";
|
||||||
template <typename T> const char basic_data<T>::signs[] = {0, '-', '+', ' '};
|
template <typename T> const char basic_data<T>::signs[] = {0, '-', '+', ' '};
|
||||||
|
|
||||||
|
#if __cplusplus < 201703L
|
||||||
|
template <typename T> constexpr const char basic_data<T>::hex_digits[];
|
||||||
|
template <typename T> constexpr const unsigned basic_data<T>::prefixes[];
|
||||||
|
template <typename T> constexpr const char basic_data<T>::left_padding_shifts[];
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const char basic_data<T>::left_padding_shifts[] = {31, 31, 0, 1, 0};
|
constexpr const char basic_data<T>::right_padding_shifts[];
|
||||||
template <typename T>
|
#endif
|
||||||
const char basic_data<T>::right_padding_shifts[] = {0, 31, 0, 1, 0};
|
|
||||||
|
|
||||||
template <typename T> struct bits {
|
template <typename T> struct bits {
|
||||||
static FMT_CONSTEXPR_DECL const int value =
|
static FMT_CONSTEXPR_DECL const int value =
|
||||||
@ -1228,7 +1225,7 @@ struct accumulator {
|
|||||||
if (lower < n) ++upper;
|
if (lower < n) ++upper;
|
||||||
}
|
}
|
||||||
void operator>>=(int shift) {
|
void operator>>=(int shift) {
|
||||||
assert(shift == 32);
|
FMT_ASSERT(shift == 32, "");
|
||||||
(void)shift;
|
(void)shift;
|
||||||
lower = (upper << 32) | (lower >> 32);
|
lower = (upper << 32) | (lower >> 32);
|
||||||
upper >>= 32;
|
upper >>= 32;
|
||||||
@ -1307,7 +1304,7 @@ class bigint {
|
|||||||
public:
|
public:
|
||||||
bigint() : exp_(0) {}
|
bigint() : exp_(0) {}
|
||||||
explicit bigint(uint64_t n) { assign(n); }
|
explicit bigint(uint64_t n) { assign(n); }
|
||||||
~bigint() { assert(bigits_.capacity() <= bigits_capacity); }
|
~bigint() { FMT_ASSERT(bigits_.capacity() <= bigits_capacity, ""); }
|
||||||
|
|
||||||
bigint(const bigint&) = delete;
|
bigint(const bigint&) = delete;
|
||||||
void operator=(const bigint&) = delete;
|
void operator=(const bigint&) = delete;
|
||||||
@ -1333,7 +1330,7 @@ class bigint {
|
|||||||
int num_bigits() const { return static_cast<int>(bigits_.size()) + exp_; }
|
int num_bigits() const { return static_cast<int>(bigits_.size()) + exp_; }
|
||||||
|
|
||||||
FMT_NOINLINE bigint& operator<<=(int shift) {
|
FMT_NOINLINE bigint& operator<<=(int shift) {
|
||||||
assert(shift >= 0);
|
FMT_ASSERT(shift >= 0, "");
|
||||||
exp_ += shift / bigit_bits;
|
exp_ += shift / bigit_bits;
|
||||||
shift %= bigit_bits;
|
shift %= bigit_bits;
|
||||||
if (shift == 0) return *this;
|
if (shift == 0) return *this;
|
||||||
@ -1395,7 +1392,7 @@ class bigint {
|
|||||||
|
|
||||||
// Assigns pow(10, exp) to this bigint.
|
// Assigns pow(10, exp) to this bigint.
|
||||||
void assign_pow10(int exp) {
|
void assign_pow10(int exp) {
|
||||||
assert(exp >= 0);
|
FMT_ASSERT(exp >= 0, "");
|
||||||
if (exp == 0) return assign(1);
|
if (exp == 0) return assign(1);
|
||||||
// Find the top bit.
|
// Find the top bit.
|
||||||
int bitmask = 1;
|
int bitmask = 1;
|
||||||
@ -1646,8 +1643,7 @@ struct fixed_handler {
|
|||||||
// Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox.
|
// Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox.
|
||||||
namespace dragonbox {
|
namespace dragonbox {
|
||||||
// Computes 128-bit result of multiplication of two 64-bit unsigned integers.
|
// Computes 128-bit result of multiplication of two 64-bit unsigned integers.
|
||||||
FMT_SAFEBUFFERS inline uint128_wrapper umul128(uint64_t x,
|
inline uint128_wrapper umul128(uint64_t x, uint64_t y) FMT_NOEXCEPT {
|
||||||
uint64_t y) FMT_NOEXCEPT {
|
|
||||||
#if FMT_USE_INT128
|
#if FMT_USE_INT128
|
||||||
return static_cast<uint128_t>(x) * static_cast<uint128_t>(y);
|
return static_cast<uint128_t>(x) * static_cast<uint128_t>(y);
|
||||||
#elif defined(_MSC_VER) && defined(_M_X64)
|
#elif defined(_MSC_VER) && defined(_M_X64)
|
||||||
@ -1675,8 +1671,7 @@ FMT_SAFEBUFFERS inline uint128_wrapper umul128(uint64_t x,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Computes upper 64 bits of multiplication of two 64-bit unsigned integers.
|
// Computes upper 64 bits of multiplication of two 64-bit unsigned integers.
|
||||||
FMT_SAFEBUFFERS inline uint64_t umul128_upper64(uint64_t x,
|
inline uint64_t umul128_upper64(uint64_t x, uint64_t y) FMT_NOEXCEPT {
|
||||||
uint64_t y) FMT_NOEXCEPT {
|
|
||||||
#if FMT_USE_INT128
|
#if FMT_USE_INT128
|
||||||
auto p = static_cast<uint128_t>(x) * static_cast<uint128_t>(y);
|
auto p = static_cast<uint128_t>(x) * static_cast<uint128_t>(y);
|
||||||
return static_cast<uint64_t>(p >> 64);
|
return static_cast<uint64_t>(p >> 64);
|
||||||
@ -1689,8 +1684,7 @@ FMT_SAFEBUFFERS inline uint64_t umul128_upper64(uint64_t x,
|
|||||||
|
|
||||||
// Computes upper 64 bits of multiplication of a 64-bit unsigned integer and a
|
// Computes upper 64 bits of multiplication of a 64-bit unsigned integer and a
|
||||||
// 128-bit unsigned integer.
|
// 128-bit unsigned integer.
|
||||||
FMT_SAFEBUFFERS inline uint64_t umul192_upper64(uint64_t x, uint128_wrapper y)
|
inline uint64_t umul192_upper64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT {
|
||||||
FMT_NOEXCEPT {
|
|
||||||
uint128_wrapper g0 = umul128(x, y.high());
|
uint128_wrapper g0 = umul128(x, y.high());
|
||||||
g0 += umul128_upper64(x, y.low());
|
g0 += umul128_upper64(x, y.low());
|
||||||
return g0.high();
|
return g0.high();
|
||||||
@ -1704,8 +1698,7 @@ inline uint32_t umul96_upper32(uint32_t x, uint64_t y) FMT_NOEXCEPT {
|
|||||||
|
|
||||||
// Computes middle 64 bits of multiplication of a 64-bit unsigned integer and a
|
// Computes middle 64 bits of multiplication of a 64-bit unsigned integer and a
|
||||||
// 128-bit unsigned integer.
|
// 128-bit unsigned integer.
|
||||||
FMT_SAFEBUFFERS inline uint64_t umul192_middle64(uint64_t x, uint128_wrapper y)
|
inline uint64_t umul192_middle64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT {
|
||||||
FMT_NOEXCEPT {
|
|
||||||
uint64_t g01 = x * y.high();
|
uint64_t g01 = x * y.high();
|
||||||
uint64_t g10 = umul128_upper64(x, y.low());
|
uint64_t g10 = umul128_upper64(x, y.low());
|
||||||
return g01 + g10;
|
return g01 + g10;
|
||||||
@ -2124,8 +2117,8 @@ FMT_ALWAYS_INLINE int remove_trailing_zeros(uint64_t& n) FMT_NOEXCEPT {
|
|||||||
|
|
||||||
// The main algorithm for shorter interval case
|
// The main algorithm for shorter interval case
|
||||||
template <class T>
|
template <class T>
|
||||||
FMT_ALWAYS_INLINE FMT_SAFEBUFFERS decimal_fp<T> shorter_interval_case(
|
FMT_ALWAYS_INLINE decimal_fp<T> shorter_interval_case(int exponent)
|
||||||
int exponent) FMT_NOEXCEPT {
|
FMT_NOEXCEPT {
|
||||||
decimal_fp<T> ret_value;
|
decimal_fp<T> ret_value;
|
||||||
// Compute k and beta
|
// Compute k and beta
|
||||||
const int minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent);
|
const int minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent);
|
||||||
@ -2171,8 +2164,7 @@ FMT_ALWAYS_INLINE FMT_SAFEBUFFERS decimal_fp<T> shorter_interval_case(
|
|||||||
return ret_value;
|
return ret_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T> decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT {
|
||||||
FMT_SAFEBUFFERS decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT {
|
|
||||||
// Step 1: integer promotion & Schubfach multiplier calculation.
|
// Step 1: integer promotion & Schubfach multiplier calculation.
|
||||||
|
|
||||||
using carrier_uint = typename float_info<T>::carrier_uint;
|
using carrier_uint = typename float_info<T>::carrier_uint;
|
||||||
@ -2571,11 +2563,11 @@ int snprintf_float(T value, int precision, float_specs specs,
|
|||||||
--exp_pos;
|
--exp_pos;
|
||||||
} while (*exp_pos != 'e');
|
} while (*exp_pos != 'e');
|
||||||
char sign = exp_pos[1];
|
char sign = exp_pos[1];
|
||||||
assert(sign == '+' || sign == '-');
|
FMT_ASSERT(sign == '+' || sign == '-', "");
|
||||||
int exp = 0;
|
int exp = 0;
|
||||||
auto p = exp_pos + 2; // Skip 'e' and sign.
|
auto p = exp_pos + 2; // Skip 'e' and sign.
|
||||||
do {
|
do {
|
||||||
assert(is_digit(*p));
|
FMT_ASSERT(is_digit(*p), "");
|
||||||
exp = exp * 10 + (*p++ - '0');
|
exp = exp * 10 + (*p++ - '0');
|
||||||
} while (p != end);
|
} while (p != end);
|
||||||
if (sign == '-') exp = -exp;
|
if (sign == '-') exp = -exp;
|
||||||
@ -2593,54 +2585,6 @@ int snprintf_float(T value, int precision, float_specs specs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A public domain branchless UTF-8 decoder by Christopher Wellons:
|
|
||||||
// https://github.com/skeeto/branchless-utf8
|
|
||||||
/* Decode the next character, c, from buf, reporting errors in e.
|
|
||||||
*
|
|
||||||
* Since this is a branchless decoder, four bytes will be read from the
|
|
||||||
* buffer regardless of the actual length of the next character. This
|
|
||||||
* means the buffer _must_ have at least three bytes of zero padding
|
|
||||||
* following the end of the data stream.
|
|
||||||
*
|
|
||||||
* Errors are reported in e, which will be non-zero if the parsed
|
|
||||||
* character was somehow invalid: invalid byte sequence, non-canonical
|
|
||||||
* encoding, or a surrogate half.
|
|
||||||
*
|
|
||||||
* The function returns a pointer to the next character. When an error
|
|
||||||
* occurs, this pointer will be a guess that depends on the particular
|
|
||||||
* error, but it will always advance at least one byte.
|
|
||||||
*/
|
|
||||||
inline const char* utf8_decode(const char* buf, uint32_t* c, int* e) {
|
|
||||||
static const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07};
|
|
||||||
static const uint32_t mins[] = {4194304, 0, 128, 2048, 65536};
|
|
||||||
static const int shiftc[] = {0, 18, 12, 6, 0};
|
|
||||||
static const int shifte[] = {0, 6, 4, 2, 0};
|
|
||||||
|
|
||||||
int len = code_point_length(buf);
|
|
||||||
const char* next = buf + len;
|
|
||||||
|
|
||||||
// Assume a four-byte character and load four bytes. Unused bits are
|
|
||||||
// shifted out.
|
|
||||||
auto s = reinterpret_cast<const unsigned char*>(buf);
|
|
||||||
*c = uint32_t(s[0] & masks[len]) << 18;
|
|
||||||
*c |= uint32_t(s[1] & 0x3f) << 12;
|
|
||||||
*c |= uint32_t(s[2] & 0x3f) << 6;
|
|
||||||
*c |= uint32_t(s[3] & 0x3f) << 0;
|
|
||||||
*c >>= shiftc[len];
|
|
||||||
|
|
||||||
// Accumulate the various error conditions.
|
|
||||||
*e = (*c < mins[len]) << 6; // non-canonical encoding
|
|
||||||
*e |= ((*c >> 11) == 0x1b) << 7; // surrogate half?
|
|
||||||
*e |= (*c > 0x10FFFF) << 8; // out of range?
|
|
||||||
*e |= (s[1] & 0xc0) >> 2;
|
|
||||||
*e |= (s[2] & 0xc0) >> 4;
|
|
||||||
*e |= (s[3]) >> 6;
|
|
||||||
*e ^= 0x2a; // top two bits of each tail byte correct?
|
|
||||||
*e >>= shifte[len];
|
|
||||||
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct stringifier {
|
struct stringifier {
|
||||||
template <typename T> FMT_INLINE std::string operator()(T value) const {
|
template <typename T> FMT_INLINE std::string operator()(T value) const {
|
||||||
return to_string(value);
|
return to_string(value);
|
||||||
@ -2656,7 +2600,8 @@ struct stringifier {
|
|||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <> struct formatter<detail::bigint> {
|
template <> struct formatter<detail::bigint> {
|
||||||
format_parse_context::iterator parse(format_parse_context& ctx) {
|
FMT_CONSTEXPR format_parse_context::iterator parse(
|
||||||
|
format_parse_context& ctx) {
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2667,23 +2612,21 @@ template <> struct formatter<detail::bigint> {
|
|||||||
for (auto i = n.bigits_.size(); i > 0; --i) {
|
for (auto i = n.bigits_.size(); i > 0; --i) {
|
||||||
auto value = n.bigits_[i - 1u];
|
auto value = n.bigits_[i - 1u];
|
||||||
if (first) {
|
if (first) {
|
||||||
out = format_to(out, "{:x}", value);
|
out = format_to(out, FMT_STRING("{:x}"), value);
|
||||||
first = false;
|
first = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out = format_to(out, "{:08x}", value);
|
out = format_to(out, FMT_STRING("{:08x}"), value);
|
||||||
}
|
}
|
||||||
if (n.exp_ > 0)
|
if (n.exp_ > 0)
|
||||||
out = format_to(out, "p{}", n.exp_ * detail::bigint::bigit_bits);
|
out = format_to(out, FMT_STRING("p{}"),
|
||||||
|
n.exp_ * detail::bigint::bigit_bits);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) {
|
FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) {
|
||||||
auto transcode = [this](const char* p) {
|
for_each_codepoint(s, [this](uint32_t cp, int error) {
|
||||||
auto cp = uint32_t();
|
|
||||||
auto error = 0;
|
|
||||||
p = utf8_decode(p, &cp, &error);
|
|
||||||
if (error != 0) FMT_THROW(std::runtime_error("invalid utf8"));
|
if (error != 0) FMT_THROW(std::runtime_error("invalid utf8"));
|
||||||
if (cp <= 0xFFFF) {
|
if (cp <= 0xFFFF) {
|
||||||
buffer_.push_back(static_cast<wchar_t>(cp));
|
buffer_.push_back(static_cast<wchar_t>(cp));
|
||||||
@ -2692,21 +2635,7 @@ FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) {
|
|||||||
buffer_.push_back(static_cast<wchar_t>(0xD800 + (cp >> 10)));
|
buffer_.push_back(static_cast<wchar_t>(0xD800 + (cp >> 10)));
|
||||||
buffer_.push_back(static_cast<wchar_t>(0xDC00 + (cp & 0x3FF)));
|
buffer_.push_back(static_cast<wchar_t>(0xDC00 + (cp & 0x3FF)));
|
||||||
}
|
}
|
||||||
return p;
|
});
|
||||||
};
|
|
||||||
auto p = s.data();
|
|
||||||
const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars.
|
|
||||||
if (s.size() >= block_size) {
|
|
||||||
for (auto end = p + s.size() - block_size + 1; p < end;) p = transcode(p);
|
|
||||||
}
|
|
||||||
if (auto num_chars_left = s.data() + s.size() - p) {
|
|
||||||
char buf[2 * block_size - 1] = {};
|
|
||||||
memcpy(buf, p, to_unsigned(num_chars_left));
|
|
||||||
p = buf;
|
|
||||||
do {
|
|
||||||
p = transcode(p);
|
|
||||||
} while (p - buf < num_chars_left);
|
|
||||||
}
|
|
||||||
buffer_.push_back(0);
|
buffer_.push_back(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2720,8 +2649,8 @@ FMT_FUNC void format_system_error(detail::buffer<char>& out, int error_code,
|
|||||||
int result =
|
int result =
|
||||||
detail::safe_strerror(error_code, system_message, buf.size());
|
detail::safe_strerror(error_code, system_message, buf.size());
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
format_to(detail::buffer_appender<char>(out), "{}: {}", message,
|
format_to(detail::buffer_appender<char>(out), FMT_STRING("{}: {}"),
|
||||||
system_message);
|
message, system_message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (result != ERANGE)
|
if (result != ERANGE)
|
||||||
@ -2770,13 +2699,14 @@ FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) {
|
|||||||
if (_isatty(fd)) {
|
if (_isatty(fd)) {
|
||||||
detail::utf8_to_utf16 u16(string_view(buffer.data(), buffer.size()));
|
detail::utf8_to_utf16 u16(string_view(buffer.data(), buffer.size()));
|
||||||
auto written = detail::dword();
|
auto written = detail::dword();
|
||||||
if (!detail::WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)),
|
if (detail::WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)),
|
||||||
u16.c_str(), static_cast<uint32_t>(u16.size()),
|
u16.c_str(), static_cast<uint32_t>(u16.size()),
|
||||||
&written, nullptr)) {
|
&written, nullptr)) {
|
||||||
FMT_THROW(format_error("failed to write to console"));
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Fallback to fwrite on failure. It can happen if the output has been
|
||||||
|
// redirected to NUL.
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
detail::fwrite_fully(buffer.data(), 1, buffer.size(), f);
|
detail::fwrite_fully(buffer.data(), 1, buffer.size(), f);
|
||||||
}
|
}
|
||||||
|
1248
vendor/Fmt/include/fmt/format.h
vendored
1248
vendor/Fmt/include/fmt/format.h
vendored
File diff suppressed because it is too large
Load Diff
4
vendor/Fmt/include/fmt/locale.h
vendored
4
vendor/Fmt/include/fmt/locale.h
vendored
@ -52,8 +52,8 @@ inline OutputIt vformat_to(
|
|||||||
|
|
||||||
template <typename OutputIt, typename S, typename... Args,
|
template <typename OutputIt, typename S, typename... Args,
|
||||||
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
|
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
|
||||||
inline auto format_to(OutputIt out, const std::locale& loc,
|
inline auto format_to(OutputIt out, const std::locale& loc, const S& format_str,
|
||||||
const S& format_str, Args&&... args) ->
|
Args&&... args) ->
|
||||||
typename std::enable_if<enable, OutputIt>::type {
|
typename std::enable_if<enable, OutputIt>::type {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||||
return vformat_to(out, loc, to_string_view(format_str), vargs);
|
return vformat_to(out, loc, to_string_view(format_str), vargs);
|
||||||
|
40
vendor/Fmt/include/fmt/os.h
vendored
40
vendor/Fmt/include/fmt/os.h
vendored
@ -8,11 +8,6 @@
|
|||||||
#ifndef FMT_OS_H_
|
#ifndef FMT_OS_H_
|
||||||
#define FMT_OS_H_
|
#define FMT_OS_H_
|
||||||
|
|
||||||
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
|
||||||
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
|
|
||||||
# undef __STRICT_ANSI__
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <clocale> // for locale_t
|
#include <clocale> // for locale_t
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
@ -280,7 +275,8 @@ class file {
|
|||||||
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
|
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
|
||||||
RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing.
|
RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing.
|
||||||
CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist.
|
CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist.
|
||||||
APPEND = FMT_POSIX(O_APPEND) // Open in append mode.
|
APPEND = FMT_POSIX(O_APPEND), // Open in append mode.
|
||||||
|
TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constructs a file object which doesn't represent any file.
|
// Constructs a file object which doesn't represent any file.
|
||||||
@ -348,6 +344,7 @@ long getpagesize();
|
|||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
struct buffer_size {
|
struct buffer_size {
|
||||||
|
buffer_size() = default;
|
||||||
size_t value = 0;
|
size_t value = 0;
|
||||||
buffer_size operator=(size_t val) const {
|
buffer_size operator=(size_t val) const {
|
||||||
auto bs = buffer_size();
|
auto bs = buffer_size();
|
||||||
@ -357,14 +354,14 @@ struct buffer_size {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ostream_params {
|
struct ostream_params {
|
||||||
int oflag = file::WRONLY | file::CREATE;
|
int oflag = file::WRONLY | file::CREATE | file::TRUNC;
|
||||||
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;
|
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;
|
||||||
|
|
||||||
ostream_params() {}
|
ostream_params() {}
|
||||||
|
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
ostream_params(T... params, int oflag) : ostream_params(params...) {
|
ostream_params(T... params, int new_oflag) : ostream_params(params...) {
|
||||||
this->oflag = oflag;
|
oflag = new_oflag;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
@ -377,7 +374,7 @@ struct ostream_params {
|
|||||||
|
|
||||||
static constexpr detail::buffer_size buffer_size;
|
static constexpr detail::buffer_size buffer_size;
|
||||||
|
|
||||||
// A fast output stream which is not thread-safe.
|
/** A fast output stream which is not thread-safe. */
|
||||||
class ostream final : private detail::buffer<char> {
|
class ostream final : private detail::buffer<char> {
|
||||||
private:
|
private:
|
||||||
file file_;
|
file file_;
|
||||||
@ -414,16 +411,31 @@ class ostream final : private detail::buffer<char> {
|
|||||||
file_.close();
|
file_.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Formats ``args`` according to specifications in ``format_str`` and writes
|
||||||
|
the output to the file.
|
||||||
|
*/
|
||||||
template <typename S, typename... Args>
|
template <typename S, typename... Args>
|
||||||
void print(const S& format_str, const Args&... args) {
|
void print(const S& format_str, Args&&... args) {
|
||||||
format_to(detail::buffer_appender<char>(*this), format_str, args...);
|
format_to(detail::buffer_appender<char>(*this), format_str,
|
||||||
|
std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Opens a file for writing. Supported parameters passed in `params`:
|
\rst
|
||||||
* ``<integer>``: Output flags (``file::WRONLY | file::CREATE`` by default)
|
Opens a file for writing. Supported parameters passed in *params*:
|
||||||
|
|
||||||
|
* ``<integer>``: Flags passed to `open
|
||||||
|
<https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
|
||||||
|
(``file::WRONLY | file::CREATE`` by default)
|
||||||
* ``buffer_size=<integer>``: Output buffer size
|
* ``buffer_size=<integer>``: Output buffer size
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
auto out = fmt::output_file("guide.txt");
|
||||||
|
out.print("Don't {}", "Panic");
|
||||||
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
inline ostream output_file(cstring_view path, T... params) {
|
inline ostream output_file(cstring_view path, T... params) {
|
||||||
|
2
vendor/Fmt/include/fmt/ostream.h
vendored
2
vendor/Fmt/include/fmt/ostream.h
vendored
@ -85,6 +85,8 @@ template <typename T, typename Char> class is_streamable {
|
|||||||
using result = decltype(test<T>(0));
|
using result = decltype(test<T>(0));
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
is_streamable() = default;
|
||||||
|
|
||||||
static const bool value = result::value;
|
static const bool value = result::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
103
vendor/Fmt/include/fmt/printf.h
vendored
103
vendor/Fmt/include/fmt/printf.h
vendored
@ -207,50 +207,32 @@ template <typename OutputIt, typename Char> class basic_printf_context;
|
|||||||
*/
|
*/
|
||||||
template <typename OutputIt, typename Char>
|
template <typename OutputIt, typename Char>
|
||||||
class printf_arg_formatter : public detail::arg_formatter_base<OutputIt, Char> {
|
class printf_arg_formatter : public detail::arg_formatter_base<OutputIt, Char> {
|
||||||
public:
|
|
||||||
using iterator = OutputIt;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using char_type = Char;
|
|
||||||
using base = detail::arg_formatter_base<OutputIt, Char>;
|
using base = detail::arg_formatter_base<OutputIt, Char>;
|
||||||
using context_type = basic_printf_context<OutputIt, Char>;
|
using context_type = basic_printf_context<OutputIt, Char>;
|
||||||
|
using format_specs = typename base::format_specs;
|
||||||
|
|
||||||
context_type& context_;
|
context_type& context_;
|
||||||
|
|
||||||
void write_null_pointer(char) {
|
OutputIt write_null_pointer(bool is_string = false) {
|
||||||
this->specs()->type = 0;
|
auto s = this->specs();
|
||||||
this->write("(nil)");
|
s.type = 0;
|
||||||
}
|
return detail::write(this->out(),
|
||||||
|
string_view(is_string ? "(null)" : "(nil)"), s);
|
||||||
void write_null_pointer(wchar_t) {
|
|
||||||
this->specs()->type = 0;
|
|
||||||
this->write(L"(nil)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using format_specs = typename base::format_specs;
|
printf_arg_formatter(OutputIt iter, format_specs& specs, context_type& ctx)
|
||||||
|
: base(iter, specs, detail::locale_ref()), context_(ctx) {}
|
||||||
|
|
||||||
/**
|
OutputIt operator()(monostate value) { return base::operator()(value); }
|
||||||
\rst
|
|
||||||
Constructs an argument formatter object.
|
|
||||||
*buffer* is a reference to the output buffer and *specs* contains format
|
|
||||||
specifier information for standard argument types.
|
|
||||||
\endrst
|
|
||||||
*/
|
|
||||||
printf_arg_formatter(iterator iter, format_specs& specs, context_type& ctx)
|
|
||||||
: base(iter, &specs, detail::locale_ref()), context_(ctx) {}
|
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(fmt::detail::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(fmt::detail::is_integral<T>::value)>
|
||||||
iterator operator()(T value) {
|
OutputIt operator()(T value) {
|
||||||
// MSVC2013 fails to compile separate overloads for bool and char_type so
|
// MSVC2013 fails to compile separate overloads for bool and Char so use
|
||||||
// use std::is_same instead.
|
// std::is_same instead.
|
||||||
if (std::is_same<T, bool>::value) {
|
if (std::is_same<T, Char>::value) {
|
||||||
format_specs& fmt_specs = *this->specs();
|
format_specs fmt_specs = this->specs();
|
||||||
if (fmt_specs.type != 's') return base::operator()(value ? 1 : 0);
|
|
||||||
fmt_specs.type = 0;
|
|
||||||
this->write(value != 0);
|
|
||||||
} else if (std::is_same<T, char_type>::value) {
|
|
||||||
format_specs& fmt_specs = *this->specs();
|
|
||||||
if (fmt_specs.type && fmt_specs.type != 'c')
|
if (fmt_specs.type && fmt_specs.type != 'c')
|
||||||
return (*this)(static_cast<int>(value));
|
return (*this)(static_cast<int>(value));
|
||||||
fmt_specs.sign = sign::none;
|
fmt_specs.sign = sign::none;
|
||||||
@ -260,56 +242,39 @@ class printf_arg_formatter : public detail::arg_formatter_base<OutputIt, Char> {
|
|||||||
// ignored for non-numeric types
|
// ignored for non-numeric types
|
||||||
if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
|
if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
|
||||||
fmt_specs.align = align::right;
|
fmt_specs.align = align::right;
|
||||||
return base::operator()(value);
|
return write_char(this->out(), static_cast<Char>(value), fmt_specs);
|
||||||
} else {
|
|
||||||
return base::operator()(value);
|
|
||||||
}
|
}
|
||||||
return this->out();
|
return base::operator()(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
|
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
|
||||||
iterator operator()(T value) {
|
OutputIt operator()(T value) {
|
||||||
return base::operator()(value);
|
return base::operator()(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Formats a null-terminated C string. */
|
/** Formats a null-terminated C string. */
|
||||||
iterator operator()(const char* value) {
|
OutputIt operator()(const char* value) {
|
||||||
if (value)
|
if (value) return base::operator()(value);
|
||||||
base::operator()(value);
|
return write_null_pointer(this->specs().type != 'p');
|
||||||
else if (this->specs()->type == 'p')
|
|
||||||
write_null_pointer(char_type());
|
|
||||||
else
|
|
||||||
this->write("(null)");
|
|
||||||
return this->out();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Formats a null-terminated wide C string. */
|
/** Formats a null-terminated wide C string. */
|
||||||
iterator operator()(const wchar_t* value) {
|
OutputIt operator()(const wchar_t* value) {
|
||||||
if (value)
|
if (value) return base::operator()(value);
|
||||||
base::operator()(value);
|
return write_null_pointer(this->specs().type != 'p');
|
||||||
else if (this->specs()->type == 'p')
|
|
||||||
write_null_pointer(char_type());
|
|
||||||
else
|
|
||||||
this->write(L"(null)");
|
|
||||||
return this->out();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator operator()(basic_string_view<char_type> value) {
|
OutputIt operator()(basic_string_view<Char> value) {
|
||||||
return base::operator()(value);
|
return base::operator()(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator operator()(monostate value) { return base::operator()(value); }
|
|
||||||
|
|
||||||
/** Formats a pointer. */
|
/** Formats a pointer. */
|
||||||
iterator operator()(const void* value) {
|
OutputIt operator()(const void* value) {
|
||||||
if (value) return base::operator()(value);
|
return value ? base::operator()(value) : write_null_pointer();
|
||||||
this->specs()->type = 0;
|
|
||||||
write_null_pointer(char_type());
|
|
||||||
return this->out();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Formats an argument of a custom (user-defined) type. */
|
/** Formats an argument of a custom (user-defined) type. */
|
||||||
iterator operator()(typename basic_format_arg<context_type>::handle handle) {
|
OutputIt operator()(typename basic_format_arg<context_type>::handle handle) {
|
||||||
handle.format(context_.parse_context(), context_);
|
handle.format(context_.parse_context(), context_);
|
||||||
return this->out();
|
return this->out();
|
||||||
}
|
}
|
||||||
@ -474,14 +439,19 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
|
|||||||
const Char* end = parse_ctx_.end();
|
const Char* end = parse_ctx_.end();
|
||||||
auto it = start;
|
auto it = start;
|
||||||
while (it != end) {
|
while (it != end) {
|
||||||
|
if (!detail::find<false, Char>(it, end, '%', it)) {
|
||||||
|
it = end; // detail::find leaves it == nullptr if it doesn't find '%'
|
||||||
|
break;
|
||||||
|
}
|
||||||
char_type c = *it++;
|
char_type c = *it++;
|
||||||
if (c != '%') continue;
|
|
||||||
if (it != end && *it == c) {
|
if (it != end && *it == c) {
|
||||||
out = std::copy(start, it, out);
|
out = detail::write(
|
||||||
|
out, basic_string_view<Char>(start, detail::to_unsigned(it - start)));
|
||||||
start = ++it;
|
start = ++it;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out = std::copy(start, it - 1, out);
|
out = detail::write(out, basic_string_view<Char>(
|
||||||
|
start, detail::to_unsigned(it - 1 - start)));
|
||||||
|
|
||||||
format_specs specs;
|
format_specs specs;
|
||||||
specs.align = align::right;
|
specs.align = align::right;
|
||||||
@ -593,7 +563,8 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
|
|||||||
// Format argument.
|
// Format argument.
|
||||||
out = visit_format_arg(ArgFormatter(out, specs, *this), arg);
|
out = visit_format_arg(ArgFormatter(out, specs, *this), arg);
|
||||||
}
|
}
|
||||||
return std::copy(start, it, out);
|
return detail::write(
|
||||||
|
out, basic_string_view<Char>(start, detail::to_unsigned(it - start)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
|
199
vendor/Fmt/include/fmt/ranges.h
vendored
199
vendor/Fmt/include/fmt/ranges.h
vendored
@ -36,22 +36,14 @@ struct formatting_range : formatting_base<Char> {
|
|||||||
static FMT_CONSTEXPR_DECL const size_t range_length_limit =
|
static FMT_CONSTEXPR_DECL const size_t range_length_limit =
|
||||||
FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the
|
FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the
|
||||||
// range.
|
// range.
|
||||||
Char prefix;
|
Char prefix = '{';
|
||||||
Char delimiter;
|
Char postfix = '}';
|
||||||
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>
|
template <typename Char, typename Enable = void>
|
||||||
struct formatting_tuple : formatting_base<Char> {
|
struct formatting_tuple : formatting_base<Char> {
|
||||||
Char prefix;
|
Char prefix = '(';
|
||||||
Char delimiter;
|
Char postfix = ')';
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -95,12 +87,100 @@ template <typename... Ts> struct conditional_helper {};
|
|||||||
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
||||||
|
|
||||||
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
|
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
|
||||||
|
|
||||||
|
# define FMT_DECLTYPE_RETURN(val) \
|
||||||
|
->decltype(val) { return val; } \
|
||||||
|
static_assert( \
|
||||||
|
true, "") // This makes it so that a semicolon is required after the
|
||||||
|
// macro, which helps clang-format handle the formatting.
|
||||||
|
|
||||||
|
// C array overload
|
||||||
|
template <typename T, std::size_t N>
|
||||||
|
auto range_begin(const T (&arr)[N]) -> const T* {
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
template <typename T, std::size_t N>
|
||||||
|
auto range_end(const T (&arr)[N]) -> const T* {
|
||||||
|
return arr + N;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename Enable = void>
|
||||||
|
struct has_member_fn_begin_end_t : std::false_type {};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_range_<
|
struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()),
|
||||||
T, conditional_t<false,
|
decltype(std::declval<T>().end())>>
|
||||||
conditional_helper<decltype(std::declval<T>().begin()),
|
: std::true_type {};
|
||||||
decltype(std::declval<T>().end())>,
|
|
||||||
void>> : std::true_type {};
|
// Member function overload
|
||||||
|
template <typename T>
|
||||||
|
auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin());
|
||||||
|
template <typename T>
|
||||||
|
auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end());
|
||||||
|
|
||||||
|
// ADL overload. Only participates in overload resolution if member functions
|
||||||
|
// are not found.
|
||||||
|
template <typename T>
|
||||||
|
auto range_begin(T&& rng)
|
||||||
|
-> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
|
||||||
|
decltype(begin(static_cast<T&&>(rng)))> {
|
||||||
|
return begin(static_cast<T&&>(rng));
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
|
||||||
|
decltype(end(static_cast<T&&>(rng)))> {
|
||||||
|
return end(static_cast<T&&>(rng));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename Enable = void>
|
||||||
|
struct has_const_begin_end : std::false_type {};
|
||||||
|
template <typename T, typename Enable = void>
|
||||||
|
struct has_mutable_begin_end : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct has_const_begin_end<
|
||||||
|
T, void_t<decltype(detail::range_begin(
|
||||||
|
std::declval<const remove_cvref_t<T>&>())),
|
||||||
|
decltype(detail::range_begin(
|
||||||
|
std::declval<const remove_cvref_t<T>&>()))>>
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct has_mutable_begin_end<
|
||||||
|
T, void_t<decltype(detail::range_begin(std::declval<T>())),
|
||||||
|
decltype(detail::range_begin(std::declval<T>())),
|
||||||
|
enable_if_t<std::is_copy_constructible<T>::value>>>
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_range_<T, void>
|
||||||
|
: std::integral_constant<bool, (has_const_begin_end<T>::value ||
|
||||||
|
has_mutable_begin_end<T>::value)> {};
|
||||||
|
|
||||||
|
template <typename T, typename Enable = void> struct range_to_view;
|
||||||
|
template <typename T>
|
||||||
|
struct range_to_view<T, enable_if_t<has_const_begin_end<T>::value>> {
|
||||||
|
struct view_t {
|
||||||
|
const T* m_range_ptr;
|
||||||
|
|
||||||
|
auto begin() const FMT_DECLTYPE_RETURN(detail::range_begin(*m_range_ptr));
|
||||||
|
auto end() const FMT_DECLTYPE_RETURN(detail::range_end(*m_range_ptr));
|
||||||
|
};
|
||||||
|
static auto view(const T& range) -> view_t { return {&range}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct range_to_view<T, enable_if_t<!has_const_begin_end<T>::value &&
|
||||||
|
has_mutable_begin_end<T>::value>> {
|
||||||
|
struct view_t {
|
||||||
|
T m_range_copy;
|
||||||
|
|
||||||
|
auto begin() FMT_DECLTYPE_RETURN(detail::range_begin(m_range_copy));
|
||||||
|
auto end() FMT_DECLTYPE_RETURN(detail::range_end(m_range_copy));
|
||||||
|
};
|
||||||
|
static auto view(const T& range) -> view_t { return {range}; }
|
||||||
|
};
|
||||||
|
# undef FMT_DECLTYPE_RETURN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// tuple_size and tuple_element check.
|
/// tuple_size and tuple_element check.
|
||||||
@ -158,33 +238,42 @@ template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
using value_type = remove_cvref_t<decltype(*std::declval<Range>().begin())>;
|
using value_type =
|
||||||
|
remove_cvref_t<decltype(*detail::range_begin(std::declval<Range>()))>;
|
||||||
|
|
||||||
template <typename Arg, FMT_ENABLE_IF(!is_like_std_string<
|
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
||||||
typename std::decay<Arg>::type>::value)>
|
*out++ = ',';
|
||||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
|
*out++ = ' ';
|
||||||
return add_space ? " {}" : "{}";
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Arg, FMT_ENABLE_IF(is_like_std_string<
|
template <
|
||||||
typename std::decay<Arg>::type>::value)>
|
typename Char, typename OutputIt, typename Arg,
|
||||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
|
FMT_ENABLE_IF(is_like_std_string<typename std::decay<Arg>::type>::value)>
|
||||||
return add_space ? " \"{}\"" : "\"{}\"";
|
OutputIt write_range_entry(OutputIt out, const Arg& v) {
|
||||||
|
*out++ = '"';
|
||||||
|
out = write<Char>(out, v);
|
||||||
|
*out++ = '"';
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) {
|
template <typename Char, typename OutputIt, typename Arg,
|
||||||
return add_space ? " \"{}\"" : "\"{}\"";
|
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
|
||||||
}
|
OutputIt write_range_entry(OutputIt out, const Arg v) {
|
||||||
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) {
|
*out++ = '\'';
|
||||||
return add_space ? L" \"{}\"" : L"\"{}\"";
|
*out++ = v;
|
||||||
|
*out++ = '\'';
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
|
template <
|
||||||
return add_space ? " '{}'" : "'{}'";
|
typename Char, typename OutputIt, typename Arg,
|
||||||
}
|
FMT_ENABLE_IF(!is_like_std_string<typename std::decay<Arg>::type>::value &&
|
||||||
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
|
!std::is_same<Arg, Char>::value)>
|
||||||
return add_space ? L" '{}'" : L"'{}'";
|
OutputIt write_range_entry(OutputIt out, const Arg& v) {
|
||||||
|
return write<Char>(out, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <typename T> struct is_tuple_like {
|
template <typename T> struct is_tuple_like {
|
||||||
@ -198,19 +287,10 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
|
|||||||
// C++11 generic lambda for format()
|
// C++11 generic lambda for format()
|
||||||
template <typename FormatContext> struct format_each {
|
template <typename FormatContext> struct format_each {
|
||||||
template <typename T> void operator()(const T& v) {
|
template <typename T> void operator()(const T& v) {
|
||||||
if (i > 0) {
|
if (i > 0) out = detail::write_delimiter(out);
|
||||||
if (formatting.add_prepostfix_space) {
|
out = detail::write_range_entry<Char>(out, v);
|
||||||
*out++ = ' ';
|
|
||||||
}
|
|
||||||
out = detail::copy(formatting.delimiter, out);
|
|
||||||
}
|
|
||||||
out = format_to(out,
|
|
||||||
detail::format_str_quoted(
|
|
||||||
(formatting.add_delimiter_spaces && i > 0), v),
|
|
||||||
v);
|
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
formatting_tuple<Char>& formatting;
|
formatting_tuple<Char>& formatting;
|
||||||
size_t& i;
|
size_t& i;
|
||||||
typename std::add_lvalue_reference<decltype(
|
typename std::add_lvalue_reference<decltype(
|
||||||
@ -229,12 +309,9 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
|
|||||||
auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) {
|
auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||||
auto out = ctx.out();
|
auto out = ctx.out();
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
detail::copy(formatting.prefix, out);
|
|
||||||
|
|
||||||
|
detail::copy(formatting.prefix, out);
|
||||||
detail::for_each(values, format_each<FormatContext>{formatting, i, out});
|
detail::for_each(values, format_each<FormatContext>{formatting, i, out});
|
||||||
if (formatting.add_prepostfix_space) {
|
|
||||||
*out++ = ' ';
|
|
||||||
}
|
|
||||||
detail::copy(formatting.postfix, out);
|
detail::copy(formatting.postfix, out);
|
||||||
|
|
||||||
return ctx.out();
|
return ctx.out();
|
||||||
@ -271,23 +348,17 @@ struct formatter<
|
|||||||
typename FormatContext::iterator format(const T& values, FormatContext& ctx) {
|
typename FormatContext::iterator format(const T& values, FormatContext& ctx) {
|
||||||
auto out = detail::copy(formatting.prefix, ctx.out());
|
auto out = detail::copy(formatting.prefix, ctx.out());
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
auto it = values.begin();
|
auto view = detail::range_to_view<T>::view(values);
|
||||||
auto end = values.end();
|
auto it = view.begin();
|
||||||
|
auto end = view.end();
|
||||||
for (; it != end; ++it) {
|
for (; it != end; ++it) {
|
||||||
if (i > 0) {
|
if (i > 0) out = detail::write_delimiter(out);
|
||||||
if (formatting.add_prepostfix_space) *out++ = ' ';
|
out = detail::write_range_entry<Char>(out, *it);
|
||||||
out = detail::copy(formatting.delimiter, out);
|
|
||||||
}
|
|
||||||
out = format_to(out,
|
|
||||||
detail::format_str_quoted(
|
|
||||||
(formatting.add_delimiter_spaces && i > 0), *it),
|
|
||||||
*it);
|
|
||||||
if (++i > formatting.range_length_limit) {
|
if (++i > formatting.range_length_limit) {
|
||||||
out = format_to(out, " ... <other elements>");
|
out = format_to(out, FMT_STRING("{}"), " ... <other elements>");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (formatting.add_prepostfix_space) *out++ = ' ';
|
|
||||||
return detail::copy(formatting.postfix, out);
|
return detail::copy(formatting.postfix, out);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -297,7 +368,7 @@ template <typename Char, typename... T> struct tuple_arg_join : detail::view {
|
|||||||
basic_string_view<Char> sep;
|
basic_string_view<Char> sep;
|
||||||
|
|
||||||
tuple_arg_join(const std::tuple<T...>& t, basic_string_view<Char> s)
|
tuple_arg_join(const std::tuple<T...>& t, basic_string_view<Char> s)
|
||||||
: tuple{t}, sep{s} {}
|
: tuple(t), sep{s} {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char, typename... T>
|
template <typename Char, typename... T>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user