mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 00:37:15 +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_
|
||||
#define FMT_CHRONO_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <locale>
|
||||
@ -288,7 +289,11 @@ inline null<> gmtime_r(...) { return null<>(); }
|
||||
inline null<> gmtime_s(...) { return null<>(); }
|
||||
} // 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) {
|
||||
struct dispatcher {
|
||||
std::time_t time_;
|
||||
@ -330,7 +335,11 @@ inline std::tm localtime(
|
||||
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) {
|
||||
struct dispatcher {
|
||||
std::time_t time_;
|
||||
@ -374,12 +383,21 @@ inline std::tm gmtime(
|
||||
namespace detail {
|
||||
inline size_t strftime(char* str, size_t count, const char* format,
|
||||
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,
|
||||
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
|
||||
|
||||
@ -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 ParseContext>
|
||||
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
auto it = ctx.begin();
|
||||
if (it != ctx.end() && *it == ':') ++it;
|
||||
auto end = it;
|
||||
while (end != ctx.end() && *end != '}') ++end;
|
||||
tm_format.reserve(detail::to_unsigned(end - it + 1));
|
||||
tm_format.append(it, end);
|
||||
tm_format.push_back('\0');
|
||||
specs = {it, detail::to_unsigned(end - it)};
|
||||
return end;
|
||||
}
|
||||
|
||||
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;
|
||||
size_t start = buf.size();
|
||||
for (;;) {
|
||||
@ -431,34 +451,68 @@ template <typename Char> struct formatter<std::tm, Char> {
|
||||
return std::copy(buf.begin(), buf.end(), ctx.out());
|
||||
}
|
||||
|
||||
basic_memory_buffer<Char> tm_format;
|
||||
basic_string_view<Char> specs;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <typename Period> FMT_CONSTEXPR const char* get_units() {
|
||||
return nullptr;
|
||||
}
|
||||
template <> FMT_CONSTEXPR const char* get_units<std::atto>() { return "as"; }
|
||||
template <> FMT_CONSTEXPR const char* get_units<std::femto>() { return "fs"; }
|
||||
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 const char* get_units<std::micro>() { return "µs"; }
|
||||
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 const char* get_units<std::deci>() { return "ds"; }
|
||||
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 const char* get_units<std::hecto>() { return "hs"; }
|
||||
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 const char* get_units<std::giga>() { return "Gs"; }
|
||||
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 const char* get_units<std::exa>() { return "Es"; }
|
||||
template <> FMT_CONSTEXPR const char* get_units<std::ratio<60>>() {
|
||||
template <> FMT_CONSTEXPR inline const char* get_units<std::atto>() {
|
||||
return "as";
|
||||
}
|
||||
template <> FMT_CONSTEXPR inline const char* get_units<std::femto>() {
|
||||
return "fs";
|
||||
}
|
||||
template <> FMT_CONSTEXPR inline const char* get_units<std::pico>() {
|
||||
return "ps";
|
||||
}
|
||||
template <> FMT_CONSTEXPR inline const char* get_units<std::nano>() {
|
||||
return "ns";
|
||||
}
|
||||
template <> FMT_CONSTEXPR inline const char* get_units<std::micro>() {
|
||||
return "µs";
|
||||
}
|
||||
template <> FMT_CONSTEXPR inline const char* get_units<std::milli>() {
|
||||
return "ms";
|
||||
}
|
||||
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";
|
||||
}
|
||||
template <> FMT_CONSTEXPR const char* get_units<std::ratio<3600>>() {
|
||||
template <> FMT_CONSTEXPR inline const char* get_units<std::ratio<3600>>() {
|
||||
return "h";
|
||||
}
|
||||
|
||||
@ -629,28 +683,29 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
|
||||
struct chrono_format_checker {
|
||||
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_full_weekday() { 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_abbr_month() { report_no_date(); }
|
||||
FMT_NORETURN void on_full_month() { report_no_date(); }
|
||||
void on_24_hour(numeric_system) {}
|
||||
void on_12_hour(numeric_system) {}
|
||||
void on_minute(numeric_system) {}
|
||||
void on_second(numeric_system) {}
|
||||
FMT_CONSTEXPR void on_24_hour(numeric_system) {}
|
||||
FMT_CONSTEXPR void on_12_hour(numeric_system) {}
|
||||
FMT_CONSTEXPR void on_minute(numeric_system) {}
|
||||
FMT_CONSTEXPR void on_second(numeric_system) {}
|
||||
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_time(numeric_system) { report_no_date(); }
|
||||
FMT_NORETURN void on_us_date() { report_no_date(); }
|
||||
FMT_NORETURN void on_iso_date() { report_no_date(); }
|
||||
void on_12_hour_time() {}
|
||||
void on_24_hour_time() {}
|
||||
void on_iso_time() {}
|
||||
void on_am_pm() {}
|
||||
void on_duration_value() {}
|
||||
void on_duration_unit() {}
|
||||
FMT_CONSTEXPR void on_12_hour_time() {}
|
||||
FMT_CONSTEXPR void on_24_hour_time() {}
|
||||
FMT_CONSTEXPR void on_iso_time() {}
|
||||
FMT_CONSTEXPR void on_am_pm() {}
|
||||
FMT_CONSTEXPR void on_duration_value() {}
|
||||
FMT_CONSTEXPR void on_duration_unit() {}
|
||||
FMT_NORETURN void on_utc_offset() { 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).
|
||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||
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;
|
||||
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));
|
||||
}
|
||||
|
||||
template <typename Char, typename Rep, typename OutputIt>
|
||||
OutputIt format_duration_value(OutputIt out, Rep val, int precision) {
|
||||
const Char pr_f[] = {'{', ':', '.', '{', '}', 'f', '}', 0};
|
||||
if (precision >= 0) return format_to(out, pr_f, val, precision);
|
||||
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_integral<Rep>::value)>
|
||||
OutputIt format_duration_value(OutputIt out, Rep val, int) {
|
||||
return write<Char>(out, 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>
|
||||
OutputIt copy_unit(string_view unit, OutputIt out, Char) {
|
||||
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) {
|
||||
if (const char* unit = get_units<Period>())
|
||||
return copy_unit(string_view(unit), out, Char());
|
||||
const Char num_f[] = {'[', '{', '}', ']', 's', 0};
|
||||
if (const_check(Period::den == 1)) return format_to(out, num_f, Period::num);
|
||||
const Char num_def_f[] = {'[', '{', '}', '/', '{', '}', ']', 's', 0};
|
||||
return format_to(out, num_def_f, Period::num, Period::den);
|
||||
*out++ = '[';
|
||||
out = write<Char>(out, Period::num);
|
||||
if (const_check(Period::den != 1)) {
|
||||
*out++ = '/';
|
||||
out = write<Char>(out, Period::den);
|
||||
}
|
||||
*out++ = ']';
|
||||
*out++ = 's';
|
||||
return out;
|
||||
}
|
||||
|
||||
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> {
|
||||
private:
|
||||
basic_format_specs<Char> specs;
|
||||
int precision;
|
||||
int precision = -1;
|
||||
using arg_ref_type = detail::arg_ref<Char>;
|
||||
arg_ref_type width_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>;
|
||||
|
||||
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_fill(basic_string_view<Char> fill) { f.specs.fill = fill; }
|
||||
void on_align(align_t align) { f.specs.align = align; }
|
||||
void on_width(int width) { f.specs.width = width; }
|
||||
void on_precision(int _precision) { f.precision = _precision; }
|
||||
void end_precision() {}
|
||||
FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) {
|
||||
f.specs.fill = fill;
|
||||
}
|
||||
FMT_CONSTEXPR void on_align(align_t align) { f.specs.align = align; }
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
@ -1078,8 +1149,6 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||
}
|
||||
|
||||
public:
|
||||
formatter() : precision(-1) {}
|
||||
|
||||
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
|
||||
-> decltype(ctx.begin()) {
|
||||
auto range = do_parse(ctx);
|
||||
@ -1089,27 +1158,30 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||
}
|
||||
|
||||
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();
|
||||
// As a possible future optimization, we could avoid extra copying if width
|
||||
// is not specified.
|
||||
basic_memory_buffer<Char> buf;
|
||||
auto out = std::back_inserter(buf);
|
||||
detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref,
|
||||
ctx);
|
||||
detail::handle_dynamic_spec<detail::precision_checker>(precision,
|
||||
detail::handle_dynamic_spec<detail::width_checker>(specs_copy.width,
|
||||
width_ref, ctx);
|
||||
detail::handle_dynamic_spec<detail::precision_checker>(precision_copy,
|
||||
precision_ref, ctx);
|
||||
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);
|
||||
} else {
|
||||
detail::chrono_formatter<FormatContext, decltype(out), Rep, Period> f(
|
||||
ctx, out, d);
|
||||
f.precision = precision;
|
||||
f.precision = precision_copy;
|
||||
parse_chrono_format(begin, end, f);
|
||||
}
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
85
vendor/Fmt/include/fmt/color.h
vendored
85
vendor/Fmt/include/fmt/color.h
vendored
@ -10,6 +10,13 @@
|
||||
|
||||
#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
|
||||
|
||||
enum class color : uint32_t {
|
||||
@ -223,7 +230,7 @@ struct color_type {
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
// Experimental text formatting support.
|
||||
/** A text style consisting of foreground and background colors and emphasis. */
|
||||
class text_style {
|
||||
public:
|
||||
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
|
||||
@ -260,33 +267,14 @@ class text_style {
|
||||
return lhs |= rhs;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR text_style& operator&=(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;
|
||||
FMT_DEPRECATED_NONMSVC FMT_CONSTEXPR text_style& operator&=(
|
||||
const text_style& rhs) {
|
||||
return and_assign(rhs);
|
||||
}
|
||||
|
||||
friend FMT_CONSTEXPR text_style operator&(text_style lhs,
|
||||
const text_style& rhs) {
|
||||
return lhs &= 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 {
|
||||
@ -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)
|
||||
FMT_NOEXCEPT;
|
||||
|
||||
friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background)
|
||||
FMT_NOEXCEPT;
|
||||
|
||||
@ -338,15 +352,18 @@ class text_style {
|
||||
emphasis ems;
|
||||
};
|
||||
|
||||
FMT_CONSTEXPR text_style fg(detail::color_type foreground) FMT_NOEXCEPT {
|
||||
return text_style(/*is_foreground=*/true, foreground);
|
||||
/** Creates a text style from the foreground (text) color. */
|
||||
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 {
|
||||
return text_style(/*is_foreground=*/false, background);
|
||||
/** Creates a text style from the background color. */
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
specify text formatting.
|
||||
Example:
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_string<S>::value)>
|
||||
|
363
vendor/Fmt/include/fmt/compile.h
vendored
363
vendor/Fmt/include/fmt/compile.h
vendored
@ -8,13 +8,102 @@
|
||||
#ifndef FMT_COMPILE_H_
|
||||
#define FMT_COMPILE_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#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
|
||||
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.
|
||||
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)
|
||||
|
||||
#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>
|
||||
const T& first(const T& value, const Tail&...) {
|
||||
return value;
|
||||
@ -175,9 +282,9 @@ class format_string_compiler : public error_handler {
|
||||
repl.arg_id = part_.part_kind == part::kind::arg_index
|
||||
? arg_ref<Char>(part_.val.arg_index)
|
||||
: arg_ref<Char>(part_.val.str);
|
||||
auto part = part::make_replacement(repl);
|
||||
part.arg_id_end = begin;
|
||||
handler_(part);
|
||||
auto replacement_part = part::make_replacement(repl);
|
||||
replacement_part.arg_id_end = begin;
|
||||
handler_(replacement_part);
|
||||
return it;
|
||||
}
|
||||
};
|
||||
@ -195,9 +302,15 @@ template <typename OutputIt, typename Context, typename Id>
|
||||
void format_arg(
|
||||
basic_format_parse_context<typename Context::char_type>& parse_ctx,
|
||||
Context& ctx, Id arg_id) {
|
||||
ctx.advance_to(visit_format_arg(
|
||||
arg_formatter<OutputIt, typename Context::char_type>(ctx, &parse_ctx),
|
||||
ctx.arg(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(
|
||||
default_arg_formatter<OutputIt, typename Context::char_type>{
|
||||
ctx.out(), ctx.args(), ctx.locale()},
|
||||
arg));
|
||||
}
|
||||
}
|
||||
|
||||
// vformat_to is defined in a subnamespace to prevent ADL.
|
||||
@ -257,10 +370,9 @@ auto vformat_to(OutputIt out, CompiledFormat& cf,
|
||||
if (specs.precision >= 0) checker.check_precision();
|
||||
|
||||
advance_to(parse_ctx, part.arg_id_end);
|
||||
ctx.advance_to(
|
||||
visit_format_arg(arg_formatter<OutputIt, typename Context::char_type>(
|
||||
ctx, nullptr, &specs),
|
||||
arg));
|
||||
ctx.advance_to(visit_format_arg(
|
||||
arg_formatter<OutputIt, typename Context::char_type>(ctx, specs),
|
||||
arg));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -393,7 +505,7 @@ template <typename Char> struct text {
|
||||
using char_type = Char;
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
@ -412,7 +524,7 @@ template <typename Char> struct code_unit {
|
||||
using char_type = Char;
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
@ -425,23 +537,60 @@ template <typename Char, typename T, int N> struct field {
|
||||
using char_type = Char;
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
OutputIt format(OutputIt out, const Args&... args) const {
|
||||
// This ensures that the argument type is convertile to `const T&`.
|
||||
const T& arg = get<N>(args...);
|
||||
return write<Char>(out, arg);
|
||||
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&`.
|
||||
const T& arg = get<N>(args...);
|
||||
return write<Char>(out, arg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename T, int N>
|
||||
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.
|
||||
template <typename Char, typename T, int N> struct spec_field {
|
||||
using char_type = Char;
|
||||
mutable formatter<T, Char> fmt;
|
||||
formatter<T, Char> fmt;
|
||||
|
||||
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&`.
|
||||
const T& arg = get<N>(args...);
|
||||
const auto& vargs =
|
||||
@ -460,7 +609,7 @@ template <typename L, typename R> struct concat {
|
||||
using char_type = typename L::char_type;
|
||||
|
||||
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...);
|
||||
return rhs.format(out, args...);
|
||||
}
|
||||
@ -508,14 +657,51 @@ template <typename T, typename Char> struct parse_specs_result {
|
||||
int next_arg_id;
|
||||
};
|
||||
|
||||
constexpr int manual_indexing_id = -1;
|
||||
|
||||
template <typename T, typename Char>
|
||||
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);
|
||||
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 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
|
||||
@ -525,24 +711,59 @@ constexpr auto compile_format_string(S format_str) {
|
||||
using char_type = typename S::char_type;
|
||||
constexpr basic_string_view<char_type> str = format_str;
|
||||
if constexpr (str[POS] == '{') {
|
||||
if (POS + 1 == str.size())
|
||||
if constexpr (POS + 1 == str.size())
|
||||
throw format_error("unmatched '{' in format string");
|
||||
if constexpr (str[POS + 1] == '{') {
|
||||
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
||||
} else if constexpr (str[POS + 1] == '}') {
|
||||
using type = get_type<ID, Args>;
|
||||
return parse_tail<Args, POS + 2, ID + 1>(field<char_type, type, ID>(),
|
||||
format_str);
|
||||
} else if constexpr (str[POS + 1] == ':') {
|
||||
using type = get_type<ID, Args>;
|
||||
constexpr auto result = parse_specs<type>(str, POS + 2, ID);
|
||||
return parse_tail<Args, result.end, result.next_arg_id>(
|
||||
spec_field<char_type, type, ID>{result.fmt}, format_str);
|
||||
} else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') {
|
||||
static_assert(ID != manual_indexing_id,
|
||||
"cannot switch from manual to automatic argument indexing");
|
||||
using id_type = get_type<ID, Args>;
|
||||
if constexpr (str[POS + 1] == '}') {
|
||||
constexpr auto next_id =
|
||||
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
|
||||
return parse_tail<Args, POS + 2, next_id>(
|
||||
field<char_type, id_type, ID>(), format_str);
|
||||
} else {
|
||||
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 {
|
||||
return unknown_format();
|
||||
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] == '}') {
|
||||
if (POS + 1 == str.size())
|
||||
if constexpr (POS + 1 == str.size())
|
||||
throw format_error("unmatched '}' in format string");
|
||||
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
||||
} else {
|
||||
@ -568,12 +789,7 @@ constexpr auto compile(S format_str) {
|
||||
constexpr auto result =
|
||||
detail::compile_format_string<detail::type_list<Args...>, 0, 0>(
|
||||
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
|
||||
@ -615,8 +831,8 @@ FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
|
||||
|
||||
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
|
||||
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||
const Args&... args) {
|
||||
constexpr OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||
const Args&... args) {
|
||||
return cf.format(out, args...);
|
||||
}
|
||||
# endif // __cpp_if_constexpr
|
||||
@ -641,19 +857,36 @@ FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
|
||||
#ifdef __cpp_if_constexpr
|
||||
if constexpr (std::is_same<typename S::char_type, char>::value) {
|
||||
constexpr basic_string_view<typename S::char_type> str = S();
|
||||
if (str.size() == 2 && str[0] == '{' && str[1] == '}')
|
||||
return fmt::to_string(detail::first(args...));
|
||||
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {
|
||||
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
|
||||
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)...);
|
||||
}
|
||||
#else
|
||||
return format(compiled, std::forward<Args>(args)...);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||
FMT_ENABLE_IF(std::is_base_of<detail::basic_compiled_format,
|
||||
CompiledFormat>::value)>
|
||||
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||
const Args&... args) {
|
||||
constexpr OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||
const Args&... args) {
|
||||
using char_type = typename CompiledFormat::char_type;
|
||||
using context = format_context_t<OutputIt, char_type>;
|
||||
return detail::cf::vformat_to<context>(out, cf,
|
||||
@ -662,9 +895,20 @@ OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
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());
|
||||
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>
|
||||
@ -684,18 +928,31 @@ auto format_to_n(OutputIt out, size_t n, const CompiledFormat& cf,
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n, const S&,
|
||||
const Args&... args) {
|
||||
constexpr auto compiled = detail::compile<Args...>(S());
|
||||
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), compiled,
|
||||
args...);
|
||||
Args&&... args) {
|
||||
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), S(),
|
||||
std::forward<Args>(args)...);
|
||||
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) {
|
||||
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
|
||||
|
||||
#endif // FMT_COMPILE_H_
|
||||
|
485
vendor/Fmt/include/fmt/core.h
vendored
485
vendor/Fmt/include/fmt/core.h
vendored
@ -10,12 +10,9 @@
|
||||
|
||||
#include <cstdio> // std::FILE
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
// The fmt library version in the form major * 10000 + minor * 100 + patch.
|
||||
#define FMT_VERSION 70103
|
||||
@ -28,8 +25,10 @@
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||
# define FMT_GCC_PRAGMA(arg) _Pragma(arg)
|
||||
#else
|
||||
# define FMT_GCC_VERSION 0
|
||||
# define FMT_GCC_PRAGMA(arg)
|
||||
#endif
|
||||
|
||||
#if defined(__INTEL_COMPILER)
|
||||
@ -52,10 +51,10 @@
|
||||
|
||||
#ifdef _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
|
||||
# define FMT_MSC_VER 0
|
||||
# define FMT_SUPPRESS_MSC_WARNING(n)
|
||||
# define FMT_MSC_WARNING(...)
|
||||
#endif
|
||||
|
||||
#ifdef __has_feature
|
||||
@ -95,7 +94,7 @@
|
||||
# define FMT_CONSTEXPR constexpr
|
||||
# define FMT_CONSTEXPR_DECL constexpr
|
||||
#else
|
||||
# define FMT_CONSTEXPR inline
|
||||
# define FMT_CONSTEXPR
|
||||
# define FMT_CONSTEXPR_DECL
|
||||
#endif
|
||||
|
||||
@ -180,7 +179,7 @@
|
||||
|
||||
#ifndef FMT_USE_INLINE_NAMESPACES
|
||||
# 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
|
||||
# else
|
||||
# define FMT_USE_INLINE_NAMESPACES 0
|
||||
@ -206,7 +205,7 @@
|
||||
#endif
|
||||
|
||||
#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
|
||||
# define FMT_API __declspec(dllexport)
|
||||
# define FMT_EXTERN_TEMPLATE_API FMT_API
|
||||
@ -248,8 +247,15 @@
|
||||
#ifndef FMT_UNICODE
|
||||
# define FMT_UNICODE !FMT_MSC_VER
|
||||
#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
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
@ -274,10 +280,22 @@ struct monostate {};
|
||||
// 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
|
||||
// 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 {
|
||||
|
||||
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.
|
||||
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);
|
||||
}
|
||||
|
||||
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() {
|
||||
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.
|
||||
FMT_CONSTEXPR
|
||||
#endif
|
||||
basic_string_view(const Char* s)
|
||||
: data_(s), size_(std::char_traits<Char>::length(s)) {}
|
||||
FMT_INLINE basic_string_view(const Char* s) : data_(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. */
|
||||
template <typename Traits, typename Alloc>
|
||||
@ -465,7 +487,7 @@ template <> struct is_char<char32_t> : std::true_type {};
|
||||
\endrst
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
@ -476,7 +498,7 @@ inline basic_string_view<Char> to_string_view(
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -670,7 +692,7 @@ template <typename T> class buffer {
|
||||
|
||||
protected:
|
||||
// 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(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:
|
||||
explicit iterator_buffer(OutputIt out, size_t n = buffer_size)
|
||||
: Traits(n),
|
||||
buffer<T>(data_, 0, buffer_size),
|
||||
out_(out) {}
|
||||
: Traits(n), buffer<T>(data_, 0, buffer_size), out_(out) {}
|
||||
~iterator_buffer() { flush(); }
|
||||
|
||||
OutputIt out() {
|
||||
@ -935,9 +955,9 @@ struct arg_data<T, Char, NUM_ARGS, 0> {
|
||||
T args_[NUM_ARGS != 0 ? NUM_ARGS : +1];
|
||||
|
||||
template <typename... U>
|
||||
FMT_INLINE arg_data(const U&... init) : args_{init...} {}
|
||||
FMT_INLINE const T* args() const { return args_; }
|
||||
FMT_INLINE std::nullptr_t named_args() { return nullptr; }
|
||||
FMT_CONSTEXPR FMT_INLINE arg_data(const U&... init) : args_{init...} {}
|
||||
FMT_CONSTEXPR FMT_INLINE const T* args() const { return args_; }
|
||||
FMT_CONSTEXPR FMT_INLINE std::nullptr_t named_args() { return nullptr; }
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
@ -958,7 +978,8 @@ void init_named_args(named_arg_info<Char>* named_args, int arg_count,
|
||||
}
|
||||
|
||||
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 {};
|
||||
|
||||
@ -1070,17 +1091,20 @@ template <typename Context> class value {
|
||||
|
||||
constexpr FMT_INLINE value(int val = 0) : int_value(val) {}
|
||||
constexpr FMT_INLINE value(unsigned val) : uint_value(val) {}
|
||||
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(long long val) : long_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(uint128_t val) : uint128_value(val) {}
|
||||
FMT_INLINE value(float val) : float_value(val) {}
|
||||
FMT_INLINE value(double val) : double_value(val) {}
|
||||
FMT_INLINE value(long double val) : long_double_value(val) {}
|
||||
FMT_INLINE value(bool val) : bool_value(val) {}
|
||||
FMT_INLINE value(char_type val) : char_value(val) {}
|
||||
FMT_INLINE value(const char_type* val) { string.data = val; }
|
||||
FMT_INLINE value(basic_string_view<char_type> val) {
|
||||
constexpr FMT_INLINE value(bool val) : bool_value(val) {}
|
||||
constexpr FMT_INLINE value(char_type val) : char_value(val) {}
|
||||
FMT_CONSTEXPR FMT_INLINE value(const 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.size = val.size();
|
||||
}
|
||||
@ -1126,36 +1150,40 @@ struct unformattable {};
|
||||
template <typename Context> struct arg_mapper {
|
||||
using char_type = typename Context::char_type;
|
||||
|
||||
FMT_CONSTEXPR int map(signed char val) { return val; }
|
||||
FMT_CONSTEXPR unsigned map(unsigned char val) { return val; }
|
||||
FMT_CONSTEXPR int map(short val) { return val; }
|
||||
FMT_CONSTEXPR unsigned map(unsigned short val) { return val; }
|
||||
FMT_CONSTEXPR int map(int val) { return val; }
|
||||
FMT_CONSTEXPR unsigned map(unsigned val) { return val; }
|
||||
FMT_CONSTEXPR long_type map(long val) { return val; }
|
||||
FMT_CONSTEXPR ulong_type map(unsigned long val) { return val; }
|
||||
FMT_CONSTEXPR long long map(long long val) { return val; }
|
||||
FMT_CONSTEXPR unsigned long long map(unsigned long long val) { return val; }
|
||||
FMT_CONSTEXPR int128_t map(int128_t 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 int map(signed char val) { return val; }
|
||||
FMT_CONSTEXPR FMT_INLINE unsigned map(unsigned char val) { return val; }
|
||||
FMT_CONSTEXPR FMT_INLINE int map(short val) { return val; }
|
||||
FMT_CONSTEXPR FMT_INLINE unsigned map(unsigned short val) { return val; }
|
||||
FMT_CONSTEXPR FMT_INLINE int map(int val) { return val; }
|
||||
FMT_CONSTEXPR FMT_INLINE unsigned map(unsigned val) { return val; }
|
||||
FMT_CONSTEXPR FMT_INLINE long_type map(long val) { return val; }
|
||||
FMT_CONSTEXPR FMT_INLINE ulong_type map(unsigned long val) { return val; }
|
||||
FMT_CONSTEXPR FMT_INLINE long long map(long long val) { return val; }
|
||||
FMT_CONSTEXPR FMT_INLINE unsigned long long map(unsigned long long 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)>
|
||||
FMT_CONSTEXPR char_type map(T val) {
|
||||
FMT_CONSTEXPR FMT_INLINE char_type map(T val) {
|
||||
static_assert(
|
||||
std::is_same<T, char>::value || std::is_same<T, char_type>::value,
|
||||
"mixing character types is disallowed");
|
||||
return val;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR float map(float val) { return val; }
|
||||
FMT_CONSTEXPR double map(double val) { return val; }
|
||||
FMT_CONSTEXPR long double map(long double val) { return val; }
|
||||
FMT_CONSTEXPR FMT_INLINE float map(float val) { return val; }
|
||||
FMT_CONSTEXPR FMT_INLINE double map(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 const char_type* map(const char_type* val) { return val; }
|
||||
FMT_CONSTEXPR FMT_INLINE const char_type* map(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)>
|
||||
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,
|
||||
"mixing character types is disallowed");
|
||||
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 &&
|
||||
!is_string<T>::value && !has_formatter<T, Context>::value &&
|
||||
!has_fallback_formatter<T, Context>::value)>
|
||||
FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
|
||||
FMT_CONSTEXPR FMT_INLINE basic_string_view<char_type> map(const T& val) {
|
||||
return basic_string_view<char_type>(val);
|
||||
}
|
||||
template <
|
||||
@ -1175,30 +1203,34 @@ template <typename Context> struct arg_mapper {
|
||||
!std::is_constructible<basic_string_view<char_type>, T>::value &&
|
||||
!is_string<T>::value && !has_formatter<T, Context>::value &&
|
||||
!has_fallback_formatter<T, Context>::value)>
|
||||
FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
|
||||
FMT_CONSTEXPR FMT_INLINE basic_string_view<char_type> map(const T& 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");
|
||||
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");
|
||||
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;
|
||||
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;
|
||||
return map(const_val);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR const void* map(void* val) { return val; }
|
||||
FMT_CONSTEXPR const void* map(const void* val) { return val; }
|
||||
FMT_CONSTEXPR const void* map(std::nullptr_t val) { return val; }
|
||||
template <typename T> FMT_CONSTEXPR int map(const T*) {
|
||||
FMT_CONSTEXPR FMT_INLINE const void* map(void* val) { return val; }
|
||||
FMT_CONSTEXPR FMT_INLINE const void* map(const void* val) { return val; }
|
||||
FMT_CONSTEXPR FMT_INLINE const void* map(std::nullptr_t val) { return val; }
|
||||
|
||||
// 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
|
||||
// a pointer cast it to "void *" or "const void *". In particular, this
|
||||
// forbids formatting of "[const] volatile char *" which is printed as bool
|
||||
@ -1207,11 +1239,16 @@ template <typename Context> struct arg_mapper {
|
||||
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,
|
||||
FMT_ENABLE_IF(std::is_enum<T>::value &&
|
||||
!has_formatter<T, Context>::value &&
|
||||
!has_fallback_formatter<T, Context>::value)>
|
||||
FMT_CONSTEXPR auto map(const T& val)
|
||||
FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
|
||||
-> decltype(std::declval<arg_mapper>().map(
|
||||
static_cast<typename std::underlying_type<T>::type>(val))) {
|
||||
return map(static_cast<typename std::underlying_type<T>::type>(val));
|
||||
@ -1220,12 +1257,12 @@ template <typename Context> struct arg_mapper {
|
||||
FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value &&
|
||||
(has_formatter<T, Context>::value ||
|
||||
has_fallback_formatter<T, Context>::value))>
|
||||
FMT_CONSTEXPR const T& map(const T& val) {
|
||||
FMT_CONSTEXPR FMT_INLINE const T& map(const T& val) {
|
||||
return val;
|
||||
}
|
||||
|
||||
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)) {
|
||||
return map(val.value);
|
||||
}
|
||||
@ -1354,14 +1391,16 @@ FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg(
|
||||
return vis(monostate());
|
||||
}
|
||||
|
||||
template <typename T> struct formattable : std::false_type {};
|
||||
|
||||
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.
|
||||
template <typename... Ts> struct void_t_impl { using type = void; };
|
||||
template <typename... Ts>
|
||||
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>
|
||||
struct is_output_iterator : std::false_type {};
|
||||
@ -1394,7 +1433,7 @@ class locale_ref {
|
||||
const void* locale_; // A type-erased pointer to std::locale.
|
||||
|
||||
public:
|
||||
locale_ref() : locale_(nullptr) {}
|
||||
constexpr locale_ref() : locale_(nullptr) {}
|
||||
template <typename Locale> explicit locale_ref(const Locale& loc);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
// a fallback formatter in one translation unit and an implicit conversion in
|
||||
// another (not recommended).
|
||||
template <bool IS_PACKED, typename Context, type, typename T,
|
||||
FMT_ENABLE_IF(IS_PACKED)>
|
||||
inline value<Context> make_arg(const T& val) {
|
||||
return check<T>(arg_mapper<Context>().map(val));
|
||||
FMT_CONSTEXPR FMT_INLINE value<Context> make_arg(const T& 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,
|
||||
@ -1443,47 +1476,6 @@ template <bool IS_PACKED, typename Context, type, typename T,
|
||||
inline basic_format_arg<Context> make_arg(const T& value) {
|
||||
return make_arg<Context>(value);
|
||||
}
|
||||
|
||||
template <typename T> struct is_reference_wrapper : std::false_type {};
|
||||
template <typename T>
|
||||
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
|
||||
|
||||
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
|
||||
|
||||
// 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
|
||||
stored in the object so make sure they have appropriate lifetimes.
|
||||
*/
|
||||
basic_format_context(OutputIt out,
|
||||
basic_format_args<basic_format_context> ctx_args,
|
||||
detail::locale_ref loc = detail::locale_ref())
|
||||
constexpr basic_format_context(
|
||||
OutputIt out, basic_format_args<basic_format_context> ctx_args,
|
||||
detail::locale_ref loc = detail::locale_ref())
|
||||
: out_(out), args_(ctx_args), loc_(loc) {}
|
||||
|
||||
format_arg arg(int id) const { return args_.get(id); }
|
||||
format_arg arg(basic_string_view<char_type> name) { return args_.get(name); }
|
||||
constexpr format_arg arg(int id) const { return args_.get(id); }
|
||||
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); }
|
||||
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); }
|
||||
|
||||
// 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``.
|
||||
void advance_to(iterator 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>
|
||||
@ -1543,6 +1537,11 @@ using wformat_context = buffer_context<wchar_t>;
|
||||
#define FMT_BUFFER_CONTEXT(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
|
||||
An array of references to arguments. It can be implicitly converted into
|
||||
@ -1579,7 +1578,7 @@ class format_arg_store
|
||||
: 0);
|
||||
|
||||
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
|
||||
basic_format_args<Context>(*this),
|
||||
@ -1600,7 +1599,7 @@ class format_arg_store
|
||||
\endrst
|
||||
*/
|
||||
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) {
|
||||
return {args...};
|
||||
}
|
||||
@ -1614,8 +1613,8 @@ inline format_arg_store<Context, Args...> make_format_args(
|
||||
\endrst
|
||||
*/
|
||||
template <typename... Args, typename S, typename Char = char_t<S>>
|
||||
inline auto make_args_checked(const S& format_str,
|
||||
const remove_reference_t<Args>&... args)
|
||||
FMT_INLINE auto make_args_checked(const S& format_str,
|
||||
const remove_reference_t<Args>&... args)
|
||||
-> format_arg_store<buffer_context<Char>, remove_reference_t<Args>...> {
|
||||
static_assert(
|
||||
detail::count<(
|
||||
@ -1628,8 +1627,9 @@ inline auto make_args_checked(const S& format_str,
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns a named argument to be used in a formatting function. It should only
|
||||
be used in a call to a formatting function.
|
||||
Returns a named argument to be used in a formatting function.
|
||||
It should only be used in a call to a formatting function or
|
||||
`dynamic_format_arg_store::push_back`.
|
||||
|
||||
**Example**::
|
||||
|
||||
@ -1642,179 +1642,6 @@ inline detail::named_arg<Char, T> arg(const Char* name, const T& 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
|
||||
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_;
|
||||
};
|
||||
|
||||
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 {
|
||||
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;
|
||||
unsigned int mask = (1 << detail::packed_arg_bits) - 1;
|
||||
return static_cast<detail::type>((desc_ >> shift) & mask);
|
||||
}
|
||||
|
||||
basic_format_args(unsigned long long desc,
|
||||
const detail::value<Context>* values)
|
||||
constexpr FMT_INLINE basic_format_args(unsigned long long desc,
|
||||
const detail::value<Context>* 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) {}
|
||||
|
||||
public:
|
||||
basic_format_args() : desc_(0) {}
|
||||
constexpr basic_format_args() : desc_(0), args_(nullptr) {}
|
||||
|
||||
/**
|
||||
\rst
|
||||
@ -1872,8 +1701,10 @@ template <typename Context> class basic_format_args {
|
||||
\endrst
|
||||
*/
|
||||
template <typename... Args>
|
||||
FMT_INLINE basic_format_args(const format_arg_store<Context, Args...>& store)
|
||||
: basic_format_args(store.desc, store.data_.args()) {}
|
||||
constexpr FMT_INLINE basic_format_args(
|
||||
const format_arg_store<Context, Args...>& store)
|
||||
: basic_format_args(format_arg_store<Context, Args...>::desc,
|
||||
store.data_.args()) {}
|
||||
|
||||
/**
|
||||
\rst
|
||||
@ -1881,7 +1712,8 @@ template <typename Context> class basic_format_args {
|
||||
`~fmt::dynamic_format_arg_store`.
|
||||
\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()) {}
|
||||
|
||||
/**
|
||||
@ -1889,12 +1721,12 @@ template <typename Context> class basic_format_args {
|
||||
Constructs a `basic_format_args` object from a dynamic set of arguments.
|
||||
\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),
|
||||
args) {}
|
||||
|
||||
/** Returns the argument with the specified id. */
|
||||
format_arg get(int id) const {
|
||||
FMT_CONSTEXPR format_arg get(int id) const {
|
||||
format_arg arg;
|
||||
if (!is_packed()) {
|
||||
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
|
||||
``format(format_str, args...)``.
|
||||
*/
|
||||
template <typename... Args>
|
||||
inline size_t formatted_size(string_view format_str, Args&&... args) {
|
||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||
inline size_t formatted_size(const S& format_str, Args&&... args) {
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||
detail::counting_buffer<> buf;
|
||||
detail::vformat_to(buf, format_str, vargs);
|
||||
detail::vformat_to(buf, to_string_view(format_str), vargs);
|
||||
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
|
||||
// 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) {
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||
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),
|
||||
vargs);
|
||||
}
|
||||
FMT_GCC_PRAGMA("GCC pop_options")
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#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
|
||||
|
160
vendor/Fmt/include/fmt/format-inl.h
vendored
160
vendor/Fmt/include/fmt/format-inl.h
vendored
@ -8,7 +8,7 @@
|
||||
#ifndef FMT_FORMAT_INL_H_
|
||||
#define FMT_FORMAT_INL_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <climits>
|
||||
#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));
|
||||
auto it = buffer_appender<char>(out);
|
||||
if (message.size() <= inline_buffer_size - error_code_size)
|
||||
format_to(it, "{}{}", message, SEP);
|
||||
format_to(it, "{}{}", ERROR_STR, error_code);
|
||||
assert(out.size() <= inline_buffer_size);
|
||||
format_to(it, FMT_STRING("{}{}"), message, SEP);
|
||||
format_to(it, FMT_STRING("{}{}"), ERROR_STR, error_code);
|
||||
FMT_ASSERT(out.size() <= inline_buffer_size, "");
|
||||
}
|
||||
|
||||
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);
|
||||
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>
|
||||
locale_ref::locale_ref(const Locale& loc) : locale_(&loc) {
|
||||
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>())
|
||||
.decimal_point();
|
||||
}
|
||||
} // namespace detail
|
||||
#else
|
||||
template <typename Char>
|
||||
FMT_FUNC std::string detail::grouping_impl(locale_ref) {
|
||||
template <typename Char> FMT_FUNC std::string grouping_impl(locale_ref) {
|
||||
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;
|
||||
}
|
||||
template <typename Char> FMT_FUNC Char detail::decimal_point_impl(locale_ref) {
|
||||
template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref) {
|
||||
return '.';
|
||||
}
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
FMT_API FMT_FUNC format_error::~format_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', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}};
|
||||
|
||||
template <typename T>
|
||||
const char basic_data<T>::hex_digits[] = "0123456789abcdef";
|
||||
|
||||
#define FMT_POWERS_OF_10(factor) \
|
||||
factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \
|
||||
(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 wchar_t basic_data<T>::wreset_color[] = L"\x1b[0m";
|
||||
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>
|
||||
const char basic_data<T>::left_padding_shifts[] = {31, 31, 0, 1, 0};
|
||||
template <typename T>
|
||||
const char basic_data<T>::right_padding_shifts[] = {0, 31, 0, 1, 0};
|
||||
constexpr const char basic_data<T>::right_padding_shifts[];
|
||||
#endif
|
||||
|
||||
template <typename T> struct bits {
|
||||
static FMT_CONSTEXPR_DECL const int value =
|
||||
@ -1228,7 +1225,7 @@ struct accumulator {
|
||||
if (lower < n) ++upper;
|
||||
}
|
||||
void operator>>=(int shift) {
|
||||
assert(shift == 32);
|
||||
FMT_ASSERT(shift == 32, "");
|
||||
(void)shift;
|
||||
lower = (upper << 32) | (lower >> 32);
|
||||
upper >>= 32;
|
||||
@ -1307,7 +1304,7 @@ class bigint {
|
||||
public:
|
||||
bigint() : exp_(0) {}
|
||||
explicit bigint(uint64_t n) { assign(n); }
|
||||
~bigint() { assert(bigits_.capacity() <= bigits_capacity); }
|
||||
~bigint() { FMT_ASSERT(bigits_.capacity() <= bigits_capacity, ""); }
|
||||
|
||||
bigint(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_; }
|
||||
|
||||
FMT_NOINLINE bigint& operator<<=(int shift) {
|
||||
assert(shift >= 0);
|
||||
FMT_ASSERT(shift >= 0, "");
|
||||
exp_ += shift / bigit_bits;
|
||||
shift %= bigit_bits;
|
||||
if (shift == 0) return *this;
|
||||
@ -1395,7 +1392,7 @@ class bigint {
|
||||
|
||||
// Assigns pow(10, exp) to this bigint.
|
||||
void assign_pow10(int exp) {
|
||||
assert(exp >= 0);
|
||||
FMT_ASSERT(exp >= 0, "");
|
||||
if (exp == 0) return assign(1);
|
||||
// Find the top bit.
|
||||
int bitmask = 1;
|
||||
@ -1646,8 +1643,7 @@ struct fixed_handler {
|
||||
// Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox.
|
||||
namespace dragonbox {
|
||||
// Computes 128-bit result of multiplication of two 64-bit unsigned integers.
|
||||
FMT_SAFEBUFFERS inline uint128_wrapper umul128(uint64_t x,
|
||||
uint64_t y) FMT_NOEXCEPT {
|
||||
inline uint128_wrapper umul128(uint64_t x, uint64_t y) FMT_NOEXCEPT {
|
||||
#if FMT_USE_INT128
|
||||
return static_cast<uint128_t>(x) * static_cast<uint128_t>(y);
|
||||
#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.
|
||||
FMT_SAFEBUFFERS inline uint64_t umul128_upper64(uint64_t x,
|
||||
uint64_t y) FMT_NOEXCEPT {
|
||||
inline uint64_t umul128_upper64(uint64_t x, uint64_t y) FMT_NOEXCEPT {
|
||||
#if FMT_USE_INT128
|
||||
auto p = static_cast<uint128_t>(x) * static_cast<uint128_t>(y);
|
||||
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
|
||||
// 128-bit unsigned integer.
|
||||
FMT_SAFEBUFFERS inline uint64_t umul192_upper64(uint64_t x, uint128_wrapper y)
|
||||
FMT_NOEXCEPT {
|
||||
inline uint64_t umul192_upper64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT {
|
||||
uint128_wrapper g0 = umul128(x, y.high());
|
||||
g0 += umul128_upper64(x, y.low());
|
||||
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
|
||||
// 128-bit unsigned integer.
|
||||
FMT_SAFEBUFFERS inline uint64_t umul192_middle64(uint64_t x, uint128_wrapper y)
|
||||
FMT_NOEXCEPT {
|
||||
inline uint64_t umul192_middle64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT {
|
||||
uint64_t g01 = x * y.high();
|
||||
uint64_t g10 = umul128_upper64(x, y.low());
|
||||
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
|
||||
template <class T>
|
||||
FMT_ALWAYS_INLINE FMT_SAFEBUFFERS decimal_fp<T> shorter_interval_case(
|
||||
int exponent) FMT_NOEXCEPT {
|
||||
FMT_ALWAYS_INLINE decimal_fp<T> shorter_interval_case(int exponent)
|
||||
FMT_NOEXCEPT {
|
||||
decimal_fp<T> ret_value;
|
||||
// Compute k and beta
|
||||
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;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FMT_SAFEBUFFERS decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT {
|
||||
template <typename T> decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT {
|
||||
// Step 1: integer promotion & Schubfach multiplier calculation.
|
||||
|
||||
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;
|
||||
} while (*exp_pos != 'e');
|
||||
char sign = exp_pos[1];
|
||||
assert(sign == '+' || sign == '-');
|
||||
FMT_ASSERT(sign == '+' || sign == '-', "");
|
||||
int exp = 0;
|
||||
auto p = exp_pos + 2; // Skip 'e' and sign.
|
||||
do {
|
||||
assert(is_digit(*p));
|
||||
FMT_ASSERT(is_digit(*p), "");
|
||||
exp = exp * 10 + (*p++ - '0');
|
||||
} while (p != end);
|
||||
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 {
|
||||
template <typename T> FMT_INLINE std::string operator()(T value) const {
|
||||
return to_string(value);
|
||||
@ -2656,7 +2600,8 @@ struct stringifier {
|
||||
} // namespace detail
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@ -2667,23 +2612,21 @@ template <> struct formatter<detail::bigint> {
|
||||
for (auto i = n.bigits_.size(); i > 0; --i) {
|
||||
auto value = n.bigits_[i - 1u];
|
||||
if (first) {
|
||||
out = format_to(out, "{:x}", value);
|
||||
out = format_to(out, FMT_STRING("{:x}"), value);
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
out = format_to(out, "{:08x}", value);
|
||||
out = format_to(out, FMT_STRING("{:08x}"), value);
|
||||
}
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) {
|
||||
auto transcode = [this](const char* p) {
|
||||
auto cp = uint32_t();
|
||||
auto error = 0;
|
||||
p = utf8_decode(p, &cp, &error);
|
||||
for_each_codepoint(s, [this](uint32_t cp, int error) {
|
||||
if (error != 0) FMT_THROW(std::runtime_error("invalid utf8"));
|
||||
if (cp <= 0xFFFF) {
|
||||
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>(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);
|
||||
}
|
||||
|
||||
@ -2720,8 +2649,8 @@ FMT_FUNC void format_system_error(detail::buffer<char>& out, int error_code,
|
||||
int result =
|
||||
detail::safe_strerror(error_code, system_message, buf.size());
|
||||
if (result == 0) {
|
||||
format_to(detail::buffer_appender<char>(out), "{}: {}", message,
|
||||
system_message);
|
||||
format_to(detail::buffer_appender<char>(out), FMT_STRING("{}: {}"),
|
||||
message, system_message);
|
||||
return;
|
||||
}
|
||||
if (result != ERANGE)
|
||||
@ -2770,12 +2699,13 @@ FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) {
|
||||
if (_isatty(fd)) {
|
||||
detail::utf8_to_utf16 u16(string_view(buffer.data(), buffer.size()));
|
||||
auto written = detail::dword();
|
||||
if (!detail::WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)),
|
||||
u16.c_str(), static_cast<uint32_t>(u16.size()),
|
||||
&written, nullptr)) {
|
||||
FMT_THROW(format_error("failed to write to console"));
|
||||
if (detail::WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)),
|
||||
u16.c_str(), static_cast<uint32_t>(u16.size()),
|
||||
&written, nullptr)) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
// Fallback to fwrite on failure. It can happen if the output has been
|
||||
// redirected to NUL.
|
||||
}
|
||||
#endif
|
||||
detail::fwrite_fully(buffer.data(), 1, buffer.size(), f);
|
||||
|
1380
vendor/Fmt/include/fmt/format.h
vendored
1380
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,
|
||||
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
|
||||
inline auto format_to(OutputIt out, const std::locale& loc,
|
||||
const S& format_str, Args&&... args) ->
|
||||
inline auto format_to(OutputIt out, const std::locale& loc, const S& format_str,
|
||||
Args&&... args) ->
|
||||
typename std::enable_if<enable, OutputIt>::type {
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||
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_
|
||||
#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 <clocale> // for locale_t
|
||||
#include <cstddef>
|
||||
@ -280,7 +275,8 @@ class file {
|
||||
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
|
||||
RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing.
|
||||
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.
|
||||
@ -348,6 +344,7 @@ long getpagesize();
|
||||
namespace detail {
|
||||
|
||||
struct buffer_size {
|
||||
buffer_size() = default;
|
||||
size_t value = 0;
|
||||
buffer_size operator=(size_t val) const {
|
||||
auto bs = buffer_size();
|
||||
@ -357,14 +354,14 @@ struct buffer_size {
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
ostream_params() {}
|
||||
|
||||
template <typename... T>
|
||||
ostream_params(T... params, int oflag) : ostream_params(params...) {
|
||||
this->oflag = oflag;
|
||||
ostream_params(T... params, int new_oflag) : ostream_params(params...) {
|
||||
oflag = new_oflag;
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
@ -377,7 +374,7 @@ struct ostream_params {
|
||||
|
||||
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> {
|
||||
private:
|
||||
file file_;
|
||||
@ -414,16 +411,31 @@ class ostream final : private detail::buffer<char> {
|
||||
file_.close();
|
||||
}
|
||||
|
||||
/**
|
||||
Formats ``args`` according to specifications in ``format_str`` and writes
|
||||
the output to the file.
|
||||
*/
|
||||
template <typename S, typename... Args>
|
||||
void print(const S& format_str, const Args&... args) {
|
||||
format_to(detail::buffer_appender<char>(*this), format_str, args...);
|
||||
void print(const S& format_str, Args&&... args) {
|
||||
format_to(detail::buffer_appender<char>(*this), format_str,
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Opens a file for writing. Supported parameters passed in `params`:
|
||||
* ``<integer>``: Output flags (``file::WRONLY | file::CREATE`` by default)
|
||||
\rst
|
||||
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
|
||||
|
||||
**Example**::
|
||||
|
||||
auto out = fmt::output_file("guide.txt");
|
||||
out.print("Don't {}", "Panic");
|
||||
\endrst
|
||||
*/
|
||||
template <typename... T>
|
||||
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));
|
||||
|
||||
public:
|
||||
is_streamable() = default;
|
||||
|
||||
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>
|
||||
class printf_arg_formatter : public detail::arg_formatter_base<OutputIt, Char> {
|
||||
public:
|
||||
using iterator = OutputIt;
|
||||
|
||||
private:
|
||||
using char_type = Char;
|
||||
using base = detail::arg_formatter_base<OutputIt, Char>;
|
||||
using context_type = basic_printf_context<OutputIt, Char>;
|
||||
using format_specs = typename base::format_specs;
|
||||
|
||||
context_type& context_;
|
||||
|
||||
void write_null_pointer(char) {
|
||||
this->specs()->type = 0;
|
||||
this->write("(nil)");
|
||||
}
|
||||
|
||||
void write_null_pointer(wchar_t) {
|
||||
this->specs()->type = 0;
|
||||
this->write(L"(nil)");
|
||||
OutputIt write_null_pointer(bool is_string = false) {
|
||||
auto s = this->specs();
|
||||
s.type = 0;
|
||||
return detail::write(this->out(),
|
||||
string_view(is_string ? "(null)" : "(nil)"), s);
|
||||
}
|
||||
|
||||
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) {}
|
||||
|
||||
/**
|
||||
\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) {}
|
||||
OutputIt operator()(monostate value) { return base::operator()(value); }
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(fmt::detail::is_integral<T>::value)>
|
||||
iterator operator()(T value) {
|
||||
// MSVC2013 fails to compile separate overloads for bool and char_type so
|
||||
// use std::is_same instead.
|
||||
if (std::is_same<T, bool>::value) {
|
||||
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();
|
||||
OutputIt operator()(T value) {
|
||||
// MSVC2013 fails to compile separate overloads for bool and Char so use
|
||||
// std::is_same instead.
|
||||
if (std::is_same<T, Char>::value) {
|
||||
format_specs fmt_specs = this->specs();
|
||||
if (fmt_specs.type && fmt_specs.type != 'c')
|
||||
return (*this)(static_cast<int>(value));
|
||||
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
|
||||
if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
|
||||
fmt_specs.align = align::right;
|
||||
return base::operator()(value);
|
||||
} else {
|
||||
return base::operator()(value);
|
||||
return write_char(this->out(), static_cast<Char>(value), fmt_specs);
|
||||
}
|
||||
return this->out();
|
||||
return base::operator()(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);
|
||||
}
|
||||
|
||||
/** Formats a null-terminated C string. */
|
||||
iterator operator()(const char* value) {
|
||||
if (value)
|
||||
base::operator()(value);
|
||||
else if (this->specs()->type == 'p')
|
||||
write_null_pointer(char_type());
|
||||
else
|
||||
this->write("(null)");
|
||||
return this->out();
|
||||
OutputIt operator()(const char* value) {
|
||||
if (value) return base::operator()(value);
|
||||
return write_null_pointer(this->specs().type != 'p');
|
||||
}
|
||||
|
||||
/** Formats a null-terminated wide C string. */
|
||||
iterator operator()(const wchar_t* value) {
|
||||
if (value)
|
||||
base::operator()(value);
|
||||
else if (this->specs()->type == 'p')
|
||||
write_null_pointer(char_type());
|
||||
else
|
||||
this->write(L"(null)");
|
||||
return this->out();
|
||||
OutputIt operator()(const wchar_t* value) {
|
||||
if (value) return base::operator()(value);
|
||||
return write_null_pointer(this->specs().type != 'p');
|
||||
}
|
||||
|
||||
iterator operator()(basic_string_view<char_type> value) {
|
||||
OutputIt operator()(basic_string_view<Char> value) {
|
||||
return base::operator()(value);
|
||||
}
|
||||
|
||||
iterator operator()(monostate value) { return base::operator()(value); }
|
||||
|
||||
/** Formats a pointer. */
|
||||
iterator operator()(const void* value) {
|
||||
if (value) return base::operator()(value);
|
||||
this->specs()->type = 0;
|
||||
write_null_pointer(char_type());
|
||||
return this->out();
|
||||
OutputIt operator()(const void* value) {
|
||||
return value ? base::operator()(value) : write_null_pointer();
|
||||
}
|
||||
|
||||
/** 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_);
|
||||
return this->out();
|
||||
}
|
||||
@ -474,14 +439,19 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
|
||||
const Char* end = parse_ctx_.end();
|
||||
auto it = start;
|
||||
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++;
|
||||
if (c != '%') continue;
|
||||
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;
|
||||
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;
|
||||
specs.align = align::right;
|
||||
@ -593,7 +563,8 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
|
||||
// Format argument.
|
||||
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>
|
||||
|
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 =
|
||||
FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the
|
||||
// range.
|
||||
Char prefix;
|
||||
Char delimiter;
|
||||
Char postfix;
|
||||
formatting_range() : prefix('{'), delimiter(','), postfix('}') {}
|
||||
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
|
||||
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
|
||||
Char prefix = '{';
|
||||
Char postfix = '}';
|
||||
};
|
||||
|
||||
template <typename Char, typename Enable = void>
|
||||
struct formatting_tuple : formatting_base<Char> {
|
||||
Char prefix;
|
||||
Char delimiter;
|
||||
Char postfix;
|
||||
formatting_tuple() : prefix('('), delimiter(','), postfix(')') {}
|
||||
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
|
||||
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
|
||||
Char prefix = '(';
|
||||
Char postfix = ')';
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
@ -95,12 +87,100 @@ template <typename... Ts> struct conditional_helper {};
|
||||
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
||||
|
||||
#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>
|
||||
struct is_range_<
|
||||
T, conditional_t<false,
|
||||
conditional_helper<decltype(std::declval<T>().begin()),
|
||||
decltype(std::declval<T>().end())>,
|
||||
void>> : std::true_type {};
|
||||
struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()),
|
||||
decltype(std::declval<T>().end())>>
|
||||
: 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
|
||||
|
||||
/// 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>
|
||||
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<
|
||||
typename std::decay<Arg>::type>::value)>
|
||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
|
||||
return add_space ? " {}" : "{}";
|
||||
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
||||
*out++ = ',';
|
||||
*out++ = ' ';
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename Arg, FMT_ENABLE_IF(is_like_std_string<
|
||||
typename std::decay<Arg>::type>::value)>
|
||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
|
||||
return add_space ? " \"{}\"" : "\"{}\"";
|
||||
template <
|
||||
typename Char, typename OutputIt, typename Arg,
|
||||
FMT_ENABLE_IF(is_like_std_string<typename std::decay<Arg>::type>::value)>
|
||||
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*) {
|
||||
return add_space ? " \"{}\"" : "\"{}\"";
|
||||
}
|
||||
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) {
|
||||
return add_space ? L" \"{}\"" : L"\"{}\"";
|
||||
template <typename Char, typename OutputIt, typename Arg,
|
||||
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
|
||||
OutputIt write_range_entry(OutputIt out, const Arg v) {
|
||||
*out++ = '\'';
|
||||
*out++ = v;
|
||||
*out++ = '\'';
|
||||
return out;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
|
||||
return add_space ? " '{}'" : "'{}'";
|
||||
}
|
||||
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
|
||||
return add_space ? L" '{}'" : L"'{}'";
|
||||
template <
|
||||
typename Char, typename OutputIt, typename Arg,
|
||||
FMT_ENABLE_IF(!is_like_std_string<typename std::decay<Arg>::type>::value &&
|
||||
!std::is_same<Arg, Char>::value)>
|
||||
OutputIt write_range_entry(OutputIt out, const Arg& v) {
|
||||
return write<Char>(out, v);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
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()
|
||||
template <typename FormatContext> struct format_each {
|
||||
template <typename T> void operator()(const T& v) {
|
||||
if (i > 0) {
|
||||
if (formatting.add_prepostfix_space) {
|
||||
*out++ = ' ';
|
||||
}
|
||||
out = detail::copy(formatting.delimiter, out);
|
||||
}
|
||||
out = format_to(out,
|
||||
detail::format_str_quoted(
|
||||
(formatting.add_delimiter_spaces && i > 0), v),
|
||||
v);
|
||||
if (i > 0) out = detail::write_delimiter(out);
|
||||
out = detail::write_range_entry<Char>(out, v);
|
||||
++i;
|
||||
}
|
||||
|
||||
formatting_tuple<Char>& formatting;
|
||||
size_t& i;
|
||||
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 out = ctx.out();
|
||||
size_t i = 0;
|
||||
detail::copy(formatting.prefix, out);
|
||||
|
||||
detail::copy(formatting.prefix, out);
|
||||
detail::for_each(values, format_each<FormatContext>{formatting, i, out});
|
||||
if (formatting.add_prepostfix_space) {
|
||||
*out++ = ' ';
|
||||
}
|
||||
detail::copy(formatting.postfix, out);
|
||||
|
||||
return ctx.out();
|
||||
@ -271,23 +348,17 @@ struct formatter<
|
||||
typename FormatContext::iterator format(const T& values, FormatContext& ctx) {
|
||||
auto out = detail::copy(formatting.prefix, ctx.out());
|
||||
size_t i = 0;
|
||||
auto it = values.begin();
|
||||
auto end = values.end();
|
||||
auto view = detail::range_to_view<T>::view(values);
|
||||
auto it = view.begin();
|
||||
auto end = view.end();
|
||||
for (; it != end; ++it) {
|
||||
if (i > 0) {
|
||||
if (formatting.add_prepostfix_space) *out++ = ' ';
|
||||
out = detail::copy(formatting.delimiter, out);
|
||||
}
|
||||
out = format_to(out,
|
||||
detail::format_str_quoted(
|
||||
(formatting.add_delimiter_spaces && i > 0), *it),
|
||||
*it);
|
||||
if (i > 0) out = detail::write_delimiter(out);
|
||||
out = detail::write_range_entry<Char>(out, *it);
|
||||
if (++i > formatting.range_length_limit) {
|
||||
out = format_to(out, " ... <other elements>");
|
||||
out = format_to(out, FMT_STRING("{}"), " ... <other elements>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (formatting.add_prepostfix_space) *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;
|
||||
|
||||
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>
|
||||
|
Loading…
Reference in New Issue
Block a user