microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
boost_describe.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 Jarosław Pelczar <jarek@jpelczar.com>
2//
3// SPDX-License-Identifier: BSD-2-Clause
4
5#pragma once
6
9#include "../microfmt.hpp"
10#include <boost/describe.hpp>
11#include <type_traits>
12
13namespace microfmt {
14
15namespace detail {
16
17// Check if T has Boost.Describe members (only takes T)
18template <typename T> using is_described_struct = boost::describe::has_describe_members<T>;
19
20// Check if E is an enum registered with Boost.Describe
21template <typename E>
23 : std::integral_constant<bool, std::is_enum_v<E> && boost::describe::has_describe_enumerators<E>::value> {};
24
25} // namespace detail
26
27// ============================================================================
28// Formatter for Boost.Describe Reflected Enums
29// ============================================================================
30template <typename E> struct formatter<E, std::enable_if_t<detail::is_described_enum<E>::value>> {
31 constexpr void parse(format_parse_context &ctx) noexcept { (void)ctx; }
32
33 void format(E val, const sink &out) const noexcept {
34 using Enumerators = boost::describe::describe_enumerators<E>;
35 bool found = false;
36
37 boost::mp11::mp_for_each<Enumerators>([&](auto D) noexcept {
38 if (!found && D.value == val) {
39 out.write(D.name);
40 found = true;
41 }
42 });
43
44 if (!found) {
45 // Fallback: format raw underlying integer if value is unmapped/invalid
46 using Underlying = std::underlying_type_t<E>;
47 format_to(out, "static_cast<{}>({})",
48 sizeof(Underlying) == 1 ? "uint8_t"
49 : sizeof(Underlying) == 2 ? "uint16_t"
50 : "uint32_t",
51 static_cast<Underlying>(val));
52 }
53 }
54};
55
56// ============================================================================
57// Formatter for Boost.Describe Reflected Structs & Classes
58// ============================================================================
59template <typename T> struct formatter<T, std::enable_if_t<detail::is_described_struct<T>::value>> {
60 constexpr void parse(format_parse_context &ctx) noexcept { (void)ctx; }
61
62 void format(const T &val, const sink &out) const noexcept {
63 using Members = boost::describe::describe_members<T, boost::describe::mod_public>;
64
65 out.put('{');
66 bool first = true;
67
68 boost::mp11::mp_for_each<Members>([&](auto D) noexcept {
69 if (!first) {
70 out.write(", ");
71 }
72 first = false;
73
74 // Output member name
75 out.write(D.name);
76 out.write(": ");
77
78 // Format member value recursively via microfmt
79 format_to(out, "{}", val.*D.pointer);
80 });
81
82 out.put('}');
83 }
84};
85
86} // namespace microfmt
Definition microfmt.hpp:881
boost::describe::has_describe_members< T > is_described_struct
Definition boost_describe.hpp:18
Definition assert.hpp:19
reloco::sink sink
Type-erased, zero-allocation output sink.
Definition microfmt.hpp:46
RELOCO_CONSTEXPR20 void format_to(const sink &out, microfmt::string_view fmt, const Args &...args) noexcept
Definition microfmt.hpp:1766
Definition boost_describe.hpp:23
constexpr void parse(format_parse_context &ctx) noexcept
Definition boost_describe.hpp:31
void format(E val, const sink &out) const noexcept
Definition boost_describe.hpp:33
void format(const T &val, const sink &out) const noexcept
Definition boost_describe.hpp:62
constexpr void parse(format_parse_context &ctx) noexcept
Definition boost_describe.hpp:60
Definition microfmt.hpp:985