Stax
Programming language
Loading...
Searching...
No Matches
format.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <fmt/format.h>
4#include <fmt/std.h>
5
6#include <boost/describe.hpp>
7#include <boost/system/error_code.hpp>
8
9#include "utils/reflect.hpp"
10
11template <typename T>
12concept IsFormattable = requires(T& v, fmt::format_context ctx) {
13 fmt::formatter<std::remove_cvref_t<T>>().format(v, ctx);
14};
15
16template <>
17struct fmt::formatter<boost::system::error_code> : fmt::formatter<std::string> {
18 template <typename Ctx>
19 auto format(const boost::system::error_code& ec, Ctx& ctx) const {
20 return formatter<std::string>::format(
21 fmt::format("{}: {}", ec.category().name(), ec.message()), ctx);
22 }
23};
24
25template <>
26struct fmt::formatter<std::error_code> : fmt::formatter<std::string> {
27 template <typename Ctx>
28 auto format(const std::error_code& ec, Ctx& ctx) const {
29 return formatter<std::string>::format(
30 fmt::format("{}: {}", ec.category().name(), ec.message()), ctx);
31 }
32};
33
34// ========== Struct formatter ============== //
35
36template <typename T>
38 boost::describe::has_describe_bases<T>::value &&
39 boost::describe::has_describe_members<T>::value && !std::is_union_v<T>;
40
41template <formattable_struct T>
42struct fmt::formatter<T, char> {
43 // NOLINTNEXTLINE
44 constexpr auto parse(format_parse_context& ctx) {
45 const auto* it = ctx.begin();
46 const auto* end = ctx.end();
47
48 if (it != end && *it != '}') {
49 fmt::throw_format_error("invalid format");
50 }
51
52 return it;
53 }
54
55 // NOLINTNEXTLINE
56 auto format(T const& t, format_context& ctx) const {
57 using Bd =
58 boost::describe::describe_bases<T, boost::describe::mod_any_access>;
59 using Md =
60 boost::describe::describe_members<T, boost::describe::mod_any_access>;
61
62 auto out = ctx.out();
63
64 out = fmt::format_to(out, "{} ", stax::reflect::GetTypeName<T>());
65 *out++ = '{';
66
67 bool first = true;
68
69 boost::mp11::mp_for_each<Bd>([&](auto d) {
70 if (!first) {
71 *out++ = ',';
72 }
73
74 first = false;
75
76 out = fmt::format_to(out, " {}",
77 static_cast<typename decltype(d)::type const&>(t));
78 });
79
80 boost::mp11::mp_for_each<Md>([&](auto d) {
81 if (!first) {
82 *out++ = ',';
83 }
84
85 first = false;
86
87 out = fmt::format_to(out, " .{}: {}", d.name, t.*d.pointer);
88 });
89
90 if (!first) {
91 *out++ = ' ';
92 }
93
94 *out++ = '}';
95
96 return out;
97 }
98};
99
100// ========== Struct formatter ============== //
101
102template <typename T>
103concept formattable_enum = boost::describe::has_describe_enumerators<T>::value;
104
105template <formattable_enum T>
106struct fmt::formatter<T, char> {
107 private:
108 using U = std::underlying_type_t<T>;
109
110 fmt::formatter<std::string_view, char> sf_;
111 fmt::formatter<U, char> nf_;
112
113 public:
114 constexpr auto parse(fmt::format_parse_context& ctx) {
115 auto i1 = sf_.parse(ctx);
116 auto i2 = nf_.parse(ctx);
117
118 if (i1 != i2) {
119 fmt::throw_format_error("invalid format");
120 }
121
122 return i1;
123 }
124
125 auto format(T const& t, fmt::format_context& ctx) const {
126 char const* s = boost::describe::enum_to_string(t, 0);
127
128 if (s) {
129 return sf_.format(s, ctx);
130 } else {
131 return nf_.format(static_cast<U>(t), ctx);
132 }
133 }
134};
Definition format.hpp:12
Definition format.hpp:103
Definition format.hpp:37
constexpr auto GetTypeName() -> std::string
Definition reflect.hpp:15
constexpr auto parse(format_parse_context &ctx)
Definition format.hpp:44
auto format(T const &t, fmt::format_context &ctx) const
Definition format.hpp:125
constexpr auto parse(fmt::format_parse_context &ctx)
Definition format.hpp:114
auto format(T const &t, format_context &ctx) const
Definition format.hpp:56
auto format(const boost::system::error_code &ec, Ctx &ctx) const
Definition format.hpp:19
auto format(const std::error_code &ec, Ctx &ctx) const
Definition format.hpp:28