mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-29 18:27:40 +02:00
Consolidate implementation details
This commit is contained in:
@ -23,7 +23,6 @@
|
|||||||
# include <type_traits>
|
# include <type_traits>
|
||||||
# include <typeinfo>
|
# include <typeinfo>
|
||||||
# include <utility>
|
# include <utility>
|
||||||
# include <vector>
|
|
||||||
|
|
||||||
// Check FMT_CPLUSPLUS to suppress a bogus warning in MSVC.
|
// Check FMT_CPLUSPLUS to suppress a bogus warning in MSVC.
|
||||||
# if FMT_CPLUSPLUS >= 201703L
|
# if FMT_CPLUSPLUS >= 201703L
|
||||||
@ -79,11 +78,11 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FMT_CPP_LIB_FILESYSTEM
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
#if FMT_CPP_LIB_FILESYSTEM
|
||||||
|
|
||||||
template <typename Char, typename PathChar>
|
template <typename Char, typename PathChar>
|
||||||
auto get_path_string(const std::filesystem::path& p,
|
auto get_path_string(const std::filesystem::path& p,
|
||||||
const std::basic_string<PathChar>& native) {
|
const std::basic_string<PathChar>& native) {
|
||||||
@ -111,154 +110,9 @@ void write_escaped_path(basic_memory_buffer<Char>& quoted,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template <typename Char> struct formatter<std::filesystem::path, Char> {
|
|
||||||
private:
|
|
||||||
format_specs specs_;
|
|
||||||
detail::arg_ref<Char> width_ref_;
|
|
||||||
bool debug_ = false;
|
|
||||||
char path_type_ = 0;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; }
|
|
||||||
|
|
||||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) {
|
|
||||||
auto it = ctx.begin(), end = ctx.end();
|
|
||||||
if (it == end) return it;
|
|
||||||
|
|
||||||
it = detail::parse_align(it, end, specs_);
|
|
||||||
if (it == end) return it;
|
|
||||||
|
|
||||||
Char c = *it;
|
|
||||||
if ((c >= '0' && c <= '9') || c == '{')
|
|
||||||
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
|
|
||||||
if (it != end && *it == '?') {
|
|
||||||
debug_ = true;
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
if (it != end && (*it == 'g')) path_type_ = detail::to_ascii(*it++);
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename FormatContext>
|
|
||||||
auto format(const std::filesystem::path& p, FormatContext& ctx) const {
|
|
||||||
auto specs = specs_;
|
|
||||||
auto path_string =
|
|
||||||
!path_type_ ? p.native()
|
|
||||||
: p.generic_string<std::filesystem::path::value_type>();
|
|
||||||
|
|
||||||
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
|
|
||||||
ctx);
|
|
||||||
if (!debug_) {
|
|
||||||
auto s = detail::get_path_string<Char>(p, path_string);
|
|
||||||
return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
|
|
||||||
}
|
|
||||||
auto quoted = basic_memory_buffer<Char>();
|
|
||||||
detail::write_escaped_path(quoted, p, path_string);
|
|
||||||
return detail::write(ctx.out(),
|
|
||||||
basic_string_view<Char>(quoted.data(), quoted.size()),
|
|
||||||
specs);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class path : public std::filesystem::path {
|
|
||||||
public:
|
|
||||||
auto display_string() const -> std::string {
|
|
||||||
const std::filesystem::path& base = *this;
|
|
||||||
return fmt::format(FMT_STRING("{}"), base);
|
|
||||||
}
|
|
||||||
auto system_string() const -> std::string { return string(); }
|
|
||||||
|
|
||||||
auto generic_display_string() const -> std::string {
|
|
||||||
const std::filesystem::path& base = *this;
|
|
||||||
return fmt::format(FMT_STRING("{:g}"), base);
|
|
||||||
}
|
|
||||||
auto generic_system_string() const -> std::string { return generic_string(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
|
||||||
#endif // FMT_CPP_LIB_FILESYSTEM
|
#endif // FMT_CPP_LIB_FILESYSTEM
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
|
||||||
template <std::size_t N, typename Char>
|
|
||||||
struct formatter<std::bitset<N>, Char>
|
|
||||||
: nested_formatter<basic_string_view<Char>, Char> {
|
|
||||||
private:
|
|
||||||
// Functor because C++11 doesn't support generic lambdas.
|
|
||||||
struct writer {
|
|
||||||
const std::bitset<N>& bs;
|
|
||||||
|
|
||||||
template <typename OutputIt>
|
|
||||||
FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt {
|
|
||||||
for (auto pos = N; pos > 0; --pos) {
|
|
||||||
out = detail::write<Char>(out, bs[pos - 1] ? Char('1') : Char('0'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
template <typename FormatContext>
|
|
||||||
auto format(const std::bitset<N>& bs, FormatContext& ctx) const
|
|
||||||
-> decltype(ctx.out()) {
|
|
||||||
return this->write_padded(ctx, writer{bs});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
|
|
||||||
FMT_END_NAMESPACE
|
|
||||||
|
|
||||||
#ifdef __cpp_lib_optional
|
|
||||||
FMT_BEGIN_NAMESPACE
|
|
||||||
template <typename T, typename Char>
|
|
||||||
struct formatter<std::optional<T>, Char,
|
|
||||||
std::enable_if_t<is_formattable<T, Char>::value>> {
|
|
||||||
private:
|
|
||||||
formatter<T, Char> underlying_;
|
|
||||||
static constexpr basic_string_view<Char> optional =
|
|
||||||
detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
|
|
||||||
'('>{};
|
|
||||||
static constexpr basic_string_view<Char> none =
|
|
||||||
detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
|
|
||||||
|
|
||||||
template <class U>
|
|
||||||
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set)
|
|
||||||
-> decltype(u.set_debug_format(set)) {
|
|
||||||
u.set_debug_format(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class U>
|
|
||||||
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) {
|
|
||||||
maybe_set_debug_format(underlying_, true);
|
|
||||||
return underlying_.parse(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename FormatContext>
|
|
||||||
auto format(const std::optional<T>& opt, FormatContext& ctx) const
|
|
||||||
-> decltype(ctx.out()) {
|
|
||||||
if (!opt) return detail::write<Char>(ctx.out(), none);
|
|
||||||
|
|
||||||
auto out = ctx.out();
|
|
||||||
out = detail::write<Char>(out, optional);
|
|
||||||
ctx.advance_to(out);
|
|
||||||
out = underlying_.format(*opt, ctx);
|
|
||||||
return detail::write(out, ')');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
FMT_END_NAMESPACE
|
|
||||||
#endif // __cpp_lib_optional
|
|
||||||
|
|
||||||
#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT
|
#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template <typename Char, typename OutputIt, typename T>
|
template <typename Char, typename OutputIt, typename T>
|
||||||
auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt {
|
auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt {
|
||||||
if constexpr (has_to_string_view<T>::value)
|
if constexpr (has_to_string_view<T>::value)
|
||||||
@ -266,69 +120,9 @@ auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt {
|
|||||||
if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v);
|
if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v);
|
||||||
return write<Char>(out, v);
|
return write<Char>(out, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cpp_lib_expected
|
|
||||||
FMT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
template <typename T, typename E, typename Char>
|
|
||||||
struct formatter<std::expected<T, E>, Char,
|
|
||||||
std::enable_if_t<(std::is_void<T>::value ||
|
|
||||||
is_formattable<T, Char>::value) &&
|
|
||||||
is_formattable<E, Char>::value>> {
|
|
||||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
|
||||||
return ctx.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename FormatContext>
|
|
||||||
auto format(const std::expected<T, E>& value, FormatContext& ctx) const
|
|
||||||
-> decltype(ctx.out()) {
|
|
||||||
auto out = ctx.out();
|
|
||||||
|
|
||||||
if (value.has_value()) {
|
|
||||||
out = detail::write<Char>(out, "expected(");
|
|
||||||
if constexpr (!std::is_void<T>::value)
|
|
||||||
out = detail::write_escaped_alternative<Char>(out, *value);
|
|
||||||
} else {
|
|
||||||
out = detail::write<Char>(out, "unexpected(");
|
|
||||||
out = detail::write_escaped_alternative<Char>(out, value.error());
|
|
||||||
}
|
|
||||||
*out++ = ')';
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
FMT_END_NAMESPACE
|
|
||||||
#endif // __cpp_lib_expected
|
|
||||||
|
|
||||||
#ifdef __cpp_lib_source_location
|
|
||||||
FMT_BEGIN_NAMESPACE
|
|
||||||
template <> struct formatter<std::source_location> {
|
|
||||||
FMT_CONSTEXPR auto parse(parse_context<>& ctx) { return ctx.begin(); }
|
|
||||||
|
|
||||||
template <typename FormatContext>
|
|
||||||
auto format(const std::source_location& loc, FormatContext& ctx) const
|
|
||||||
-> decltype(ctx.out()) {
|
|
||||||
auto out = ctx.out();
|
|
||||||
out = detail::write(out, loc.file_name());
|
|
||||||
out = detail::write(out, ':');
|
|
||||||
out = detail::write<char>(out, loc.line());
|
|
||||||
out = detail::write(out, ':');
|
|
||||||
out = detail::write<char>(out, loc.column());
|
|
||||||
out = detail::write(out, ": ");
|
|
||||||
out = detail::write(out, loc.function_name());
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
FMT_END_NAMESPACE
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FMT_CPP_LIB_VARIANT
|
#if FMT_CPP_LIB_VARIANT
|
||||||
FMT_BEGIN_NAMESPACE
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using variant_index_sequence =
|
using variant_index_sequence =
|
||||||
@ -350,116 +144,9 @@ template <typename T, typename C> class is_variant_formattable_ {
|
|||||||
decltype(check(variant_index_sequence<T>{}))::value;
|
decltype(check(variant_index_sequence<T>{}))::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template <typename T> struct is_variant_like {
|
|
||||||
static constexpr const bool value = detail::is_variant_like_<T>::value;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, typename C> struct is_variant_formattable {
|
|
||||||
static constexpr const bool value =
|
|
||||||
detail::is_variant_formattable_<T, C>::value;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char> struct formatter<std::monostate, Char> {
|
|
||||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
|
||||||
return ctx.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename FormatContext>
|
|
||||||
auto format(const std::monostate&, FormatContext& ctx) const
|
|
||||||
-> decltype(ctx.out()) {
|
|
||||||
return detail::write<Char>(ctx.out(), "monostate");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Variant, typename Char>
|
|
||||||
struct formatter<
|
|
||||||
Variant, Char,
|
|
||||||
std::enable_if_t<std::conjunction_v<
|
|
||||||
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
|
|
||||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
|
||||||
return ctx.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename FormatContext>
|
|
||||||
auto format(const Variant& value, FormatContext& ctx) const
|
|
||||||
-> decltype(ctx.out()) {
|
|
||||||
auto out = ctx.out();
|
|
||||||
|
|
||||||
out = detail::write<Char>(out, "variant(");
|
|
||||||
FMT_TRY {
|
|
||||||
std::visit(
|
|
||||||
[&](const auto& v) {
|
|
||||||
out = detail::write_escaped_alternative<Char>(out, v);
|
|
||||||
},
|
|
||||||
value);
|
|
||||||
}
|
|
||||||
FMT_CATCH(const std::bad_variant_access&) {
|
|
||||||
detail::write<Char>(out, "valueless by exception");
|
|
||||||
}
|
|
||||||
*out++ = ')';
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
FMT_END_NAMESPACE
|
|
||||||
#endif // FMT_CPP_LIB_VARIANT
|
#endif // FMT_CPP_LIB_VARIANT
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
|
||||||
template <> struct formatter<std::error_code> {
|
|
||||||
private:
|
|
||||||
format_specs specs_;
|
|
||||||
detail::arg_ref<char> width_ref_;
|
|
||||||
bool debug_ = false;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* {
|
|
||||||
auto it = ctx.begin(), end = ctx.end();
|
|
||||||
if (it == end) return it;
|
|
||||||
|
|
||||||
it = detail::parse_align(it, end, specs_);
|
|
||||||
|
|
||||||
char c = *it;
|
|
||||||
if (it != end && ((c >= '0' && c <= '9') || c == '{'))
|
|
||||||
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
|
|
||||||
|
|
||||||
if (it != end && *it == '?') {
|
|
||||||
debug_ = true;
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
if (it != end && *it == 's') {
|
|
||||||
specs_.set_type(presentation_type::string);
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename FormatContext>
|
|
||||||
FMT_CONSTEXPR20 auto format(const std::error_code& ec,
|
|
||||||
FormatContext& ctx) const -> decltype(ctx.out()) {
|
|
||||||
auto specs = specs_;
|
|
||||||
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
|
|
||||||
ctx);
|
|
||||||
auto buf = memory_buffer();
|
|
||||||
if (specs_.type() == presentation_type::string) {
|
|
||||||
buf.append(ec.message());
|
|
||||||
} else {
|
|
||||||
buf.append(string_view(ec.category().name()));
|
|
||||||
buf.push_back(':');
|
|
||||||
detail::write<char>(appender(buf), ec.value());
|
|
||||||
}
|
|
||||||
auto quoted = memory_buffer();
|
|
||||||
auto str = string_view(buf.data(), buf.size());
|
|
||||||
if (debug_) {
|
|
||||||
detail::write_escaped_string<char>(std::back_inserter(quoted), str);
|
|
||||||
str = string_view(quoted.data(), quoted.size());
|
|
||||||
}
|
|
||||||
return detail::write<char>(ctx.out(), str, specs);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#if FMT_USE_RTTI
|
#if FMT_USE_RTTI
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template <typename Char, typename OutputIt>
|
template <typename Char, typename OutputIt>
|
||||||
auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt {
|
auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt {
|
||||||
@ -527,8 +214,327 @@ auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt {
|
|||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // FMT_USE_RTTI
|
||||||
|
|
||||||
|
template <typename T, typename Enable = void>
|
||||||
|
struct has_flip : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
|
template <typename T> struct is_bit_reference_like {
|
||||||
|
static constexpr const bool value =
|
||||||
|
std::is_convertible<T, bool>::value &&
|
||||||
|
std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Workaround for libc++ incompatibility with C++ standard.
|
||||||
|
// According to the Standard, `bitset::operator[] const` returns bool.
|
||||||
|
#ifdef _LIBCPP_VERSION
|
||||||
|
template <typename C>
|
||||||
|
struct is_bit_reference_like<std::__bit_const_reference<C>> {
|
||||||
|
static constexpr const bool value = true;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
|
#if FMT_CPP_LIB_FILESYSTEM
|
||||||
|
|
||||||
|
template <typename Char> struct formatter<std::filesystem::path, Char> {
|
||||||
|
private:
|
||||||
|
format_specs specs_;
|
||||||
|
detail::arg_ref<Char> width_ref_;
|
||||||
|
bool debug_ = false;
|
||||||
|
char path_type_ = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; }
|
||||||
|
|
||||||
|
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) {
|
||||||
|
auto it = ctx.begin(), end = ctx.end();
|
||||||
|
if (it == end) return it;
|
||||||
|
|
||||||
|
it = detail::parse_align(it, end, specs_);
|
||||||
|
if (it == end) return it;
|
||||||
|
|
||||||
|
Char c = *it;
|
||||||
|
if ((c >= '0' && c <= '9') || c == '{')
|
||||||
|
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
|
||||||
|
if (it != end && *it == '?') {
|
||||||
|
debug_ = true;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
if (it != end && (*it == 'g')) path_type_ = detail::to_ascii(*it++);
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const std::filesystem::path& p, FormatContext& ctx) const {
|
||||||
|
auto specs = specs_;
|
||||||
|
auto path_string =
|
||||||
|
!path_type_ ? p.native()
|
||||||
|
: p.generic_string<std::filesystem::path::value_type>();
|
||||||
|
|
||||||
|
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
|
||||||
|
ctx);
|
||||||
|
if (!debug_) {
|
||||||
|
auto s = detail::get_path_string<Char>(p, path_string);
|
||||||
|
return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
|
||||||
|
}
|
||||||
|
auto quoted = basic_memory_buffer<Char>();
|
||||||
|
detail::write_escaped_path(quoted, p, path_string);
|
||||||
|
return detail::write(ctx.out(),
|
||||||
|
basic_string_view<Char>(quoted.data(), quoted.size()),
|
||||||
|
specs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class path : public std::filesystem::path {
|
||||||
|
public:
|
||||||
|
auto display_string() const -> std::string {
|
||||||
|
const std::filesystem::path& base = *this;
|
||||||
|
return fmt::format(FMT_STRING("{}"), base);
|
||||||
|
}
|
||||||
|
auto system_string() const -> std::string { return string(); }
|
||||||
|
|
||||||
|
auto generic_display_string() const -> std::string {
|
||||||
|
const std::filesystem::path& base = *this;
|
||||||
|
return fmt::format(FMT_STRING("{:g}"), base);
|
||||||
|
}
|
||||||
|
auto generic_system_string() const -> std::string { return generic_string(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FMT_CPP_LIB_FILESYSTEM
|
||||||
|
|
||||||
|
template <std::size_t N, typename Char>
|
||||||
|
struct formatter<std::bitset<N>, Char>
|
||||||
|
: nested_formatter<basic_string_view<Char>, Char> {
|
||||||
|
private:
|
||||||
|
// Functor because C++11 doesn't support generic lambdas.
|
||||||
|
struct writer {
|
||||||
|
const std::bitset<N>& bs;
|
||||||
|
|
||||||
|
template <typename OutputIt>
|
||||||
|
FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt {
|
||||||
|
for (auto pos = N; pos > 0; --pos) {
|
||||||
|
out = detail::write<Char>(out, bs[pos - 1] ? Char('1') : Char('0'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const std::bitset<N>& bs, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
return this->write_padded(ctx, writer{bs});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_optional
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct formatter<std::optional<T>, Char,
|
||||||
|
std::enable_if_t<is_formattable<T, Char>::value>> {
|
||||||
|
private:
|
||||||
|
formatter<T, Char> underlying_;
|
||||||
|
static constexpr basic_string_view<Char> optional =
|
||||||
|
detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
|
||||||
|
'('>{};
|
||||||
|
static constexpr basic_string_view<Char> none =
|
||||||
|
detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set)
|
||||||
|
-> decltype(u.set_debug_format(set)) {
|
||||||
|
u.set_debug_format(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) {
|
||||||
|
maybe_set_debug_format(underlying_, true);
|
||||||
|
return underlying_.parse(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const std::optional<T>& opt, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
if (!opt) return detail::write<Char>(ctx.out(), none);
|
||||||
|
|
||||||
|
auto out = ctx.out();
|
||||||
|
out = detail::write<Char>(out, optional);
|
||||||
|
ctx.advance_to(out);
|
||||||
|
out = underlying_.format(*opt, ctx);
|
||||||
|
return detail::write(out, ')');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif // __cpp_lib_optional
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_expected
|
||||||
|
template <typename T, typename E, typename Char>
|
||||||
|
struct formatter<std::expected<T, E>, Char,
|
||||||
|
std::enable_if_t<(std::is_void<T>::value ||
|
||||||
|
is_formattable<T, Char>::value) &&
|
||||||
|
is_formattable<E, Char>::value>> {
|
||||||
|
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const std::expected<T, E>& value, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
auto out = ctx.out();
|
||||||
|
|
||||||
|
if (value.has_value()) {
|
||||||
|
out = detail::write<Char>(out, "expected(");
|
||||||
|
if constexpr (!std::is_void<T>::value)
|
||||||
|
out = detail::write_escaped_alternative<Char>(out, *value);
|
||||||
|
} else {
|
||||||
|
out = detail::write<Char>(out, "unexpected(");
|
||||||
|
out = detail::write_escaped_alternative<Char>(out, value.error());
|
||||||
|
}
|
||||||
|
*out++ = ')';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif // __cpp_lib_expected
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_source_location
|
||||||
|
template <> struct formatter<std::source_location> {
|
||||||
|
FMT_CONSTEXPR auto parse(parse_context<>& ctx) { return ctx.begin(); }
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const std::source_location& loc, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
auto out = ctx.out();
|
||||||
|
out = detail::write(out, loc.file_name());
|
||||||
|
out = detail::write(out, ':');
|
||||||
|
out = detail::write<char>(out, loc.line());
|
||||||
|
out = detail::write(out, ':');
|
||||||
|
out = detail::write<char>(out, loc.column());
|
||||||
|
out = detail::write(out, ": ");
|
||||||
|
out = detail::write(out, loc.function_name());
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FMT_CPP_LIB_VARIANT
|
||||||
|
|
||||||
|
template <typename T> struct is_variant_like {
|
||||||
|
static constexpr const bool value = detail::is_variant_like_<T>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename C> struct is_variant_formattable {
|
||||||
|
static constexpr const bool value =
|
||||||
|
detail::is_variant_formattable_<T, C>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char> struct formatter<std::monostate, Char> {
|
||||||
|
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const std::monostate&, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
return detail::write<Char>(ctx.out(), "monostate");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Variant, typename Char>
|
||||||
|
struct formatter<
|
||||||
|
Variant, Char,
|
||||||
|
std::enable_if_t<std::conjunction_v<
|
||||||
|
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
|
||||||
|
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const Variant& value, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
auto out = ctx.out();
|
||||||
|
|
||||||
|
out = detail::write<Char>(out, "variant(");
|
||||||
|
FMT_TRY {
|
||||||
|
std::visit(
|
||||||
|
[&](const auto& v) {
|
||||||
|
out = detail::write_escaped_alternative<Char>(out, v);
|
||||||
|
},
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
FMT_CATCH(const std::bad_variant_access&) {
|
||||||
|
detail::write<Char>(out, "valueless by exception");
|
||||||
|
}
|
||||||
|
*out++ = ')';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FMT_CPP_LIB_VARIANT
|
||||||
|
|
||||||
|
template <> struct formatter<std::error_code> {
|
||||||
|
private:
|
||||||
|
format_specs specs_;
|
||||||
|
detail::arg_ref<char> width_ref_;
|
||||||
|
bool debug_ = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* {
|
||||||
|
auto it = ctx.begin(), end = ctx.end();
|
||||||
|
if (it == end) return it;
|
||||||
|
|
||||||
|
it = detail::parse_align(it, end, specs_);
|
||||||
|
|
||||||
|
char c = *it;
|
||||||
|
if (it != end && ((c >= '0' && c <= '9') || c == '{'))
|
||||||
|
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
|
||||||
|
|
||||||
|
if (it != end && *it == '?') {
|
||||||
|
debug_ = true;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
if (it != end && *it == 's') {
|
||||||
|
specs_.set_type(presentation_type::string);
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
FMT_CONSTEXPR20 auto format(const std::error_code& ec,
|
||||||
|
FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||||
|
auto specs = specs_;
|
||||||
|
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
|
||||||
|
ctx);
|
||||||
|
auto buf = memory_buffer();
|
||||||
|
if (specs_.type() == presentation_type::string) {
|
||||||
|
buf.append(ec.message());
|
||||||
|
} else {
|
||||||
|
buf.append(string_view(ec.category().name()));
|
||||||
|
buf.push_back(':');
|
||||||
|
detail::write<char>(appender(buf), ec.value());
|
||||||
|
}
|
||||||
|
auto quoted = memory_buffer();
|
||||||
|
auto str = string_view(buf.data(), buf.size());
|
||||||
|
if (debug_) {
|
||||||
|
detail::write_escaped_string<char>(std::back_inserter(quoted), str);
|
||||||
|
str = string_view(quoted.data(), quoted.size());
|
||||||
|
}
|
||||||
|
return detail::write<char>(ctx.out(), str, specs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if FMT_USE_RTTI
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
struct formatter<std::type_info, Char // DEPRECATED! Mixing code unit types.
|
struct formatter<std::type_info, Char // DEPRECATED! Mixing code unit types.
|
||||||
> {
|
> {
|
||||||
@ -543,7 +549,7 @@ struct formatter<std::type_info, Char // DEPRECATED! Mixing code unit types.
|
|||||||
return detail::write_demangled_name<Char>(ctx.out(), ti);
|
return detail::write_demangled_name<Char>(ctx.out(), ti);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif
|
#endif // FMT_USE_RTTI
|
||||||
|
|
||||||
template <typename T, typename Char>
|
template <typename T, typename Char>
|
||||||
struct formatter<
|
struct formatter<
|
||||||
@ -579,34 +585,6 @@ struct formatter<
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template <typename T, typename Enable = void>
|
|
||||||
struct has_flip : std::false_type {};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
|
|
||||||
: std::true_type {};
|
|
||||||
|
|
||||||
template <typename T> struct is_bit_reference_like {
|
|
||||||
static constexpr const bool value =
|
|
||||||
std::is_convertible<T, bool>::value &&
|
|
||||||
std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef _LIBCPP_VERSION
|
|
||||||
|
|
||||||
// Workaround for libc++ incompatibility with C++ standard.
|
|
||||||
// According to the Standard, `bitset::operator[] const` returns bool.
|
|
||||||
template <typename C>
|
|
||||||
struct is_bit_reference_like<std::__bit_const_reference<C>> {
|
|
||||||
static constexpr const bool value = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
// We can't use std::vector<bool, Allocator>::reference and
|
// We can't use std::vector<bool, Allocator>::reference and
|
||||||
// std::bitset<N>::reference because the compiler can't deduce Allocator and N
|
// std::bitset<N>::reference because the compiler can't deduce Allocator and N
|
||||||
// in partial specialization.
|
// in partial specialization.
|
||||||
@ -725,4 +703,5 @@ struct formatter<std::reference_wrapper<T>, Char,
|
|||||||
};
|
};
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_STD_H_
|
#endif // FMT_STD_H_
|
||||||
|
Reference in New Issue
Block a user