8 #ifndef FMTQUILL_STD_H_ 9 #define FMTQUILL_STD_H_ 14 #ifndef FMTQUILL_MODULE 20 # include <functional> 23 # include <type_traits> 29 # if FMTQUILL_CPLUSPLUS >= 201703L 30 # if FMTQUILL_HAS_INCLUDE(<filesystem>) && \ 31 (!defined(FMTQUILL_CPP_LIB_FILESYSTEM) || FMTQUILL_CPP_LIB_FILESYSTEM != 0) 32 # include <filesystem> 34 # if FMTQUILL_HAS_INCLUDE(<variant>) 37 # if FMTQUILL_HAS_INCLUDE(<optional>) 43 # if FMTQUILL_CPLUSPLUS > 201703L && FMTQUILL_HAS_INCLUDE(<source_location>) 44 # include <source_location> 46 # if FMTQUILL_CPLUSPLUS > 202002L && FMTQUILL_HAS_INCLUDE(<expected>) 49 #endif // FMTQUILL_MODULE 51 #if FMTQUILL_HAS_INCLUDE(<version>) 56 #if FMTQUILL_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__) 60 # ifndef __GABIXX_CXXABI_H__ 61 # define FMTQUILL_HAS_ABI_CXA_DEMANGLE 66 #ifndef FMTQUILL_CPP_LIB_FILESYSTEM 67 # ifdef __cpp_lib_filesystem 68 # define FMTQUILL_CPP_LIB_FILESYSTEM __cpp_lib_filesystem 70 # define FMTQUILL_CPP_LIB_FILESYSTEM 0 74 #ifndef FMTQUILL_CPP_LIB_VARIANT 75 # ifdef __cpp_lib_variant 76 # define FMTQUILL_CPP_LIB_VARIANT __cpp_lib_variant 78 # define FMTQUILL_CPP_LIB_VARIANT 0 82 #if FMTQUILL_CPP_LIB_FILESYSTEM 83 FMTQUILL_BEGIN_NAMESPACE
87 template <
typename Char,
typename PathChar>
88 auto get_path_string(
const std::filesystem::path& p,
89 const std::basic_string<PathChar>& native) {
90 if constexpr (std::is_same_v<Char, char> && std::is_same_v<PathChar, wchar_t>)
91 return to_utf8<wchar_t>(native, to_utf8_error_policy::replace);
93 return p.string<Char>();
96 template <
typename Char,
typename PathChar>
98 const std::filesystem::path& p,
99 const std::basic_string<PathChar>& native) {
100 if constexpr (std::is_same_v<Char, char> &&
101 std::is_same_v<PathChar, wchar_t>) {
103 write_escaped_string<wchar_t>(std::back_inserter(buf), native);
104 bool valid = to_utf8<wchar_t>::convert(quoted, {buf.
data(), buf.size()});
105 FMTQUILL_ASSERT(valid,
"invalid utf16");
106 }
else if constexpr (std::is_same_v<Char, PathChar>) {
107 write_escaped_string<std::filesystem::path::value_type>(
108 std::back_inserter(quoted), native);
110 write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
116 template <
typename Char>
struct formatter<
std::filesystem::path, Char> {
124 FMTQUILL_CONSTEXPR
void set_debug_format(
bool set =
true) { debug_ =
set; }
127 auto it = ctx.
begin(), end = ctx.
end();
128 if (it == end)
return it;
130 it = detail::parse_align(it, end, specs_);
131 if (it == end)
return it;
134 if ((c >=
'0' && c <=
'9') || c ==
'{')
135 it = detail::parse_width(it, end, specs_, width_ref_, ctx);
136 if (it != end && *it ==
'?') {
140 if (it != end && (*it ==
'g')) path_type_ = detail::to_ascii(*it++);
144 template <
typename FormatContext>
145 auto format(
const std::filesystem::path& p, FormatContext& ctx)
const {
148 !path_type_ ? p.native()
149 : p.generic_string<std::filesystem::path::value_type>();
151 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
154 auto s = detail::get_path_string<Char>(p, path_string);
158 detail::write_escaped_path(quoted, p, path_string);
159 return detail::write(ctx.out(),
165 class path :
public std::filesystem::path {
167 auto display_string() const ->
std::
string {
168 const std::filesystem::path& base = *
this;
169 return fmtquill::format(FMTQUILL_STRING(
"{}"), base);
171 auto system_string() const ->
std::
string {
return string(); }
173 auto generic_display_string() const ->
std::
string {
174 const std::filesystem::path& base = *
this;
175 return fmtquill::format(FMTQUILL_STRING(
"{:g}"), base);
177 auto generic_system_string() const ->
std::
string {
return generic_string(); }
180 FMTQUILL_END_NAMESPACE
181 #endif // FMTQUILL_CPP_LIB_FILESYSTEM 183 FMTQUILL_BEGIN_NAMESPACE
184 template <std::
size_t N,
typename Char>
190 const std::bitset<N>& bs;
192 template <
typename OutputIt>
193 FMTQUILL_CONSTEXPR
auto operator()(OutputIt out) -> OutputIt {
194 for (
auto pos = N; pos > 0; --pos) {
195 out = detail::write<Char>(out, bs[pos - 1] ? Char(
'1') : Char(
'0'));
203 template <
typename FormatContext>
204 auto format(
const std::bitset<N>& bs, FormatContext& ctx)
const 205 -> decltype(ctx.out()) {
206 return this->write_padded(ctx,
writer{bs});
210 template <
typename Char>
212 FMTQUILL_END_NAMESPACE
214 #ifdef __cpp_lib_optional 215 FMTQUILL_BEGIN_NAMESPACE
216 template <
typename T,
typename Char>
218 std::enable_if_t<is_formattable<T, Char>::value>> {
228 FMTQUILL_CONSTEXPR
static auto maybe_set_debug_format(U& u,
bool set)
229 -> decltype(u.set_debug_format(
set)) {
230 u.set_debug_format(
set);
234 FMTQUILL_CONSTEXPR
static void maybe_set_debug_format(U&, ...) {}
238 maybe_set_debug_format(underlying_,
true);
239 return underlying_.parse(ctx);
242 template <
typename FormatContext>
243 auto format(
const std::optional<T>& opt, FormatContext& ctx)
const 244 -> decltype(ctx.out()) {
245 if (!opt)
return detail::write<Char>(ctx.out(), none);
247 auto out = ctx.out();
248 out = detail::write<Char>(out, optional);
250 out = underlying_.format(*opt, ctx);
251 return detail::write(out,
')');
254 FMTQUILL_END_NAMESPACE
255 #endif // __cpp_lib_optional 257 #if defined(__cpp_lib_expected) || FMTQUILL_CPP_LIB_VARIANT 259 FMTQUILL_BEGIN_NAMESPACE
262 template <
typename Char,
typename OutputIt,
typename T>
263 auto write_escaped_alternative(OutputIt out,
const T& v) -> OutputIt {
264 if constexpr (has_to_string_view<T>::value)
265 return write_escaped_string<Char>(out, detail::to_string_view(v));
266 if constexpr (std::is_same_v<T, Char>)
return write_escaped_char(out, v);
267 return write<Char>(out, v);
272 FMTQUILL_END_NAMESPACE
275 #ifdef __cpp_lib_expected 276 FMTQUILL_BEGIN_NAMESPACE
278 template <
typename T,
typename E,
typename Char>
279 struct formatter<std::expected<T, E>, Char,
280 std::enable_if_t<(std::is_void<T>::value ||
281 is_formattable<T, Char>::value) &&
282 is_formattable<E, Char>::value>> {
287 template <
typename FormatContext>
288 auto format(
const std::expected<T, E>& value, FormatContext& ctx)
const 289 -> decltype(ctx.out()) {
290 auto out = ctx.out();
292 if (value.has_value()) {
293 out = detail::write<Char>(out,
"expected(");
294 if constexpr (!std::is_void<T>::value)
295 out = detail::write_escaped_alternative<Char>(out, *value);
297 out = detail::write<Char>(out,
"unexpected(");
298 out = detail::write_escaped_alternative<Char>(out, value.error());
304 FMTQUILL_END_NAMESPACE
305 #endif // __cpp_lib_expected 307 #ifdef __cpp_lib_source_location 308 FMTQUILL_BEGIN_NAMESPACE
309 template <>
struct formatter<std::source_location> {
312 template <
typename FormatContext>
313 auto format(
const std::source_location& loc, FormatContext& ctx)
const 314 -> decltype(ctx.out()) {
315 auto out = ctx.out();
316 out = detail::write(out, loc.file_name());
317 out = detail::write(out,
':');
318 out = detail::write<char>(out, loc.line());
319 out = detail::write(out,
':');
320 out = detail::write<char>(out, loc.column());
321 out = detail::write(out,
": ");
322 out = detail::write(out, loc.function_name());
326 FMTQUILL_END_NAMESPACE
329 #if FMTQUILL_CPP_LIB_VARIANT 330 FMTQUILL_BEGIN_NAMESPACE
333 template <
typename T>
334 using variant_index_sequence =
335 std::make_index_sequence<std::variant_size<T>::value>;
337 template <
typename>
struct is_variant_like_ : std::false_type {};
338 template <
typename... Types>
339 struct is_variant_like_<std::variant<Types...>> : std::true_type {};
342 template <
typename T,
typename C>
class is_variant_formattable_ {
343 template <std::size_t... Is>
344 static std::conjunction<
345 is_formattable<std::variant_alternative_t<Is, T>, C>...>
346 check(std::index_sequence<Is...>);
349 static constexpr
const bool value =
350 decltype(check(variant_index_sequence<T>{}))::value;
355 template <
typename T>
struct is_variant_like {
356 static constexpr
const bool value = detail::is_variant_like_<T>::value;
359 template <
typename T,
typename C>
struct is_variant_formattable {
360 static constexpr
const bool value =
361 detail::is_variant_formattable_<T, C>::value;
369 template <
typename FormatContext>
370 auto format(
const std::monostate&, FormatContext& ctx)
const 371 -> decltype(ctx.out()) {
372 return detail::write<Char>(ctx.out(),
"monostate");
376 template <
typename Variant,
typename Char>
379 std::enable_if_t<std::conjunction_v<
380 is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
385 template <
typename FormatContext>
386 auto format(
const Variant& value, FormatContext& ctx)
const 387 -> decltype(ctx.out()) {
388 auto out = ctx.out();
390 out = detail::write<Char>(out,
"variant(");
394 out = detail::write_escaped_alternative<Char>(out, v);
398 FMTQUILL_CATCH(
const std::bad_variant_access&) {
399 detail::write<Char>(out,
"valueless by exception");
405 FMTQUILL_END_NAMESPACE
406 #endif // FMTQUILL_CPP_LIB_VARIANT 408 FMTQUILL_BEGIN_NAMESPACE
417 auto it = ctx.
begin(), end = ctx.
end();
418 if (it == end)
return it;
420 it = detail::parse_align(it, end, specs_);
423 if (it != end && ((c >=
'0' && c <=
'9') || c ==
'{'))
424 it = detail::parse_width(it, end, specs_, width_ref_, ctx);
426 if (it != end && *it ==
'?') {
430 if (it != end && *it ==
's') {
431 specs_.set_type(presentation_type::string);
437 template <
typename FormatContext>
438 FMTQUILL_CONSTEXPR20
auto format(
const std::error_code& ec,
439 FormatContext& ctx)
const -> decltype(ctx.out()) {
441 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
444 if (specs_.type() == presentation_type::string) {
445 buf.append(ec.message());
449 detail::write<char>(
appender(buf), ec.value());
454 detail::write_escaped_string<char>(std::back_inserter(quoted), str);
457 return detail::write<char>(ctx.out(), str, specs);
461 #if FMTQUILL_USE_RTTI 464 template <
typename Char,
typename OutputIt>
465 auto write_demangled_name(OutputIt out,
const std::type_info& ti) -> OutputIt {
466 # ifdef FMTQUILL_HAS_ABI_CXA_DEMANGLE 468 std::size_t size = 0;
469 std::unique_ptr<char, void (*)(void*)> demangled_name_ptr(
470 abi::__cxa_demangle(ti.name(),
nullptr, &size, &status), &std::free);
473 if (demangled_name_ptr) {
474 demangled_name_view = demangled_name_ptr.get();
483 if (demangled_name_view.starts_with(
"std::")) {
484 char* begin = demangled_name_ptr.get();
485 char* to = begin + 5;
486 for (
char *from = to, *end = begin + demangled_name_view.
size();
489 if (from[0] ==
'_' && from[1] ==
'_') {
490 char* next = from + 1;
491 while (next < end && *next !=
':') next++;
492 if (next[0] ==
':' && next[1] ==
':') {
499 demangled_name_view = {begin, detail::to_unsigned(to - begin)};
504 return detail::write_bytes<Char>(out, demangled_name_view);
505 # elif FMTQUILL_MSC_VERSION 507 for (std::size_t i = 0; i < demangled_name.size(); ++i) {
508 auto sub = demangled_name;
509 sub.remove_prefix(i);
510 if (sub.starts_with(
"enum ")) {
514 if (sub.starts_with(
"class ") || sub.starts_with(
"union ")) {
518 if (sub.starts_with(
"struct ")) {
522 if (*sub.begin() !=
' ') *out++ = *sub.begin();
526 return detail::write_bytes<Char>(out,
string_view(ti.name()));
532 template <
typename Char>
540 template <
typename Context>
541 auto format(
const std::type_info& ti, Context& ctx)
const 542 -> decltype(ctx.out()) {
543 return detail::write_demangled_name<Char>(ctx.out(), ti);
548 template <
typename T,
typename Char>
551 typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
553 bool with_typename_ =
false;
557 auto it = ctx.
begin();
558 auto end = ctx.
end();
559 if (it == end || *it ==
'}')
return it;
562 with_typename_ = FMTQUILL_USE_RTTI != 0;
567 template <
typename Context>
568 auto format(
const std::exception& ex, Context& ctx)
const 569 -> decltype(ctx.out()) {
570 auto out = ctx.out();
571 #if FMTQUILL_USE_RTTI 572 if (with_typename_) {
573 out = detail::write_demangled_name<Char>(out,
typeid(ex));
578 return detail::write_bytes<Char>(out,
string_view(ex.what()));
584 template <
typename T,
typename Enable =
void>
587 template <
typename T>
588 struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
592 static constexpr
const bool value =
593 std::is_convertible<T, bool>::value &&
597 #ifdef _LIBCPP_VERSION 601 template <
typename C>
603 static constexpr
const bool value =
true;
613 template <
typename BitRef,
typename Char>
615 enable_if_t<
detail::is_bit_reference_like<BitRef>::value>>
617 template <
typename FormatContext>
618 FMTQUILL_CONSTEXPR
auto format(
const BitRef& v, FormatContext& ctx)
const 619 -> decltype(ctx.out()) {
624 template <
typename T,
typename Deleter>
625 auto ptr(
const std::unique_ptr<T, Deleter>& p) ->
const void* {
628 template <
typename T>
auto ptr(
const std::shared_ptr<T>& p) ->
const void* {
632 template <
typename T,
typename Char>
634 enable_if_t<is_formattable<T, Char>::value>>
636 template <
typename FormatContext>
637 auto format(
const std::atomic<T>& v, FormatContext& ctx)
const 638 -> decltype(ctx.out()) {
643 #ifdef __cpp_lib_atomic_flag_test 644 template <
typename Char>
646 template <
typename FormatContext>
647 auto format(
const std::atomic_flag& v, FormatContext& ctx)
const 648 -> decltype(ctx.out()) {
652 #endif // __cpp_lib_atomic_flag_test 654 template <
typename T,
typename Char>
struct formatter<std::complex<T>, Char> {
658 template <
typename FormatContext,
typename OutputIt>
659 FMTQUILL_CONSTEXPR
auto do_format(
const std::complex<T>& c,
661 FormatContext& ctx, OutputIt out)
const 665 out = detail::write<Char>(out, c.real(), specs, ctx.locale());
666 specs.set_sign(sign::plus);
667 out = detail::write<Char>(out, c.imag(), specs, ctx.locale());
668 if (!detail::isfinite(c.imag())) *out++ = Char(
' ');
673 out = detail::write<Char>(out, c.imag(), specs, ctx.locale());
674 if (!detail::isfinite(c.imag())) *out++ = Char(
' ');
682 return parse_format_specs(ctx.
begin(), ctx.
end(), specs_, ctx,
686 template <
typename FormatContext>
687 auto format(
const std::complex<T>& c, FormatContext& ctx)
const 688 -> decltype(ctx.out()) {
690 if (specs.dynamic()) {
691 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
692 specs.width_ref, ctx);
693 detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
694 specs.precision_ref, ctx);
697 if (specs.width == 0)
return do_format(c, specs, ctx, ctx.out());
701 outer_specs.width = specs.width;
702 outer_specs.copy_fill_from(specs);
703 outer_specs.set_align(specs.align());
707 specs.set_align(align::none);
710 return detail::write<Char>(ctx.out(),
716 template <
typename T,
typename Char>
718 enable_if_t<is_formattable<remove_cvref_t<T>, Char>::value>>
720 template <
typename FormatContext>
721 auto format(std::reference_wrapper<T> ref, FormatContext& ctx)
const 722 -> decltype(ctx.out()) {
727 FMTQUILL_END_NAMESPACE
728 #endif // FMTQUILL_STD_H_ A dynamically growing memory buffer for trivially copyable/constructible types with the first SIZE el...
Definition: format.h:790
FMTQUILL_CONSTEXPR auto data() noexcept -> T *
Returns a pointer to the buffer data (not null-terminated).
Definition: base.h:1799
Parsing context consisting of a format string range being parsed and an argument counter for automati...
Definition: base.h:644
constexpr auto size() const noexcept -> size_t
Returns the string size.
Definition: base.h:568
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:24
An implementation of std::basic_string_view for pre-C++17.
Definition: base.h:523
constexpr auto end() const noexcept -> iterator
Returns an iterator past the end of the format string range being parsed.
Definition: base.h:893
constexpr auto size() const noexcept -> size_t
Returns the size of this buffer.
Definition: base.h:1793
constexpr auto begin() const noexcept -> iterator
Returns an iterator to the beginning of the format string range being parsed.
Definition: base.h:890