WPILibC++ 2024.3.2
formatter.h
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <type_traits>
8
9#include <fmt/format.h>
10
11#include "units/base.h"
12
13// FIXME: Replace enable_if with requires clause and remove <type_traits>
14// include once using GCC >= 12. GCC 11 incorrectly emits a struct redefinition
15// error because it doesn't use the requires clause to disambiguate.
16
17/**
18 * Formatter for unit types.
19 */
20template <typename Unit, typename CharT>
21struct fmt::formatter<Unit, CharT,
22 std::enable_if_t<units::traits::is_unit_t_v<Unit>>> {
23 constexpr auto parse(fmt::format_parse_context& ctx) {
24 return m_underlying.parse(ctx);
25 }
26
27 /**
28 * Writes out a formatted unit.
29 *
30 * @param obj Unit instance.
31 * @param ctx Format string context.
32 */
33 auto format(const Unit& obj, fmt::format_context& ctx) const {
34 using Units = typename Unit::unit_type;
35 using BaseUnits =
37 typename units::traits::unit_traits<Units>::base_unit_type>;
38
39 auto out = ctx.out();
40
41 out = m_underlying.format(units::convert<Units, BaseUnits>(obj()), ctx);
42
43 if constexpr (units::traits::unit_traits<
44 Units>::base_unit_type::meter_ratio::num != 0) {
45 out = fmt::format_to(out, " m");
46 }
47 if constexpr (units::traits::unit_traits<
48 Units>::base_unit_type::meter_ratio::num != 0 &&
49 units::traits::unit_traits<
50 Units>::base_unit_type::meter_ratio::num != 1) {
51 out = fmt::format_to(
52 out, "^{}",
53 units::traits::unit_traits<Units>::base_unit_type::meter_ratio::num);
54 }
55 if constexpr (units::traits::unit_traits<
56 Units>::base_unit_type::meter_ratio::den != 1) {
57 out = fmt::format_to(
58 out, "/{}",
59 units::traits::unit_traits<Units>::base_unit_type::meter_ratio::den);
60 }
61
62 if constexpr (units::traits::unit_traits<
63 Units>::base_unit_type::kilogram_ratio::num != 0) {
64 out = fmt::format_to(out, " kg");
65 }
66 if constexpr (units::traits::unit_traits<
67 Units>::base_unit_type::kilogram_ratio::num != 0 &&
68 units::traits::unit_traits<
69 Units>::base_unit_type::kilogram_ratio::num != 1) {
70 out = fmt::format_to(out, "^{}",
71 units::traits::unit_traits<
72 Units>::base_unit_type::kilogram_ratio::num);
73 }
74 if constexpr (units::traits::unit_traits<
75 Units>::base_unit_type::kilogram_ratio::den != 1) {
76 out = fmt::format_to(out, "/{}",
77 units::traits::unit_traits<
78 Units>::base_unit_type::kilogram_ratio::den);
79 }
80
81 if constexpr (units::traits::unit_traits<
82 Units>::base_unit_type::second_ratio::num != 0) {
83 out = fmt::format_to(out, " s");
84 }
85 if constexpr (units::traits::unit_traits<
86 Units>::base_unit_type::second_ratio::num != 0 &&
87 units::traits::unit_traits<
88 Units>::base_unit_type::second_ratio::num != 1) {
89 out = fmt::format_to(
90 out, "^{}",
91 units::traits::unit_traits<Units>::base_unit_type::second_ratio::num);
92 }
93 if constexpr (units::traits::unit_traits<
94 Units>::base_unit_type::second_ratio::den != 1) {
95 out = fmt::format_to(
96 out, "/{}",
97 units::traits::unit_traits<Units>::base_unit_type::second_ratio::den);
98 }
99
100 if constexpr (units::traits::unit_traits<
101 Units>::base_unit_type::ampere_ratio::num != 0) {
102 out = fmt::format_to(out, " A");
103 }
104 if constexpr (units::traits::unit_traits<
105 Units>::base_unit_type::ampere_ratio::num != 0 &&
106 units::traits::unit_traits<
107 Units>::base_unit_type::ampere_ratio::num != 1) {
108 out = fmt::format_to(
109 out, "^{}",
110 units::traits::unit_traits<Units>::base_unit_type::ampere_ratio::num);
111 }
112 if constexpr (units::traits::unit_traits<
113 Units>::base_unit_type::ampere_ratio::den != 1) {
114 out = fmt::format_to(
115 out, "/{}",
116 units::traits::unit_traits<Units>::base_unit_type::ampere_ratio::den);
117 }
118
119 if constexpr (units::traits::unit_traits<
120 Units>::base_unit_type::kelvin_ratio::num != 0) {
121 out = fmt::format_to(out, " K");
122 }
123 if constexpr (units::traits::unit_traits<
124 Units>::base_unit_type::kelvin_ratio::num != 0 &&
125 units::traits::unit_traits<
126 Units>::base_unit_type::kelvin_ratio::num != 1) {
127 out = fmt::format_to(
128 out, "^{}",
129 units::traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num);
130 }
131 if constexpr (units::traits::unit_traits<
132 Units>::base_unit_type::kelvin_ratio::den != 1) {
133 out = fmt::format_to(
134 out, "/{}",
135 units::traits::unit_traits<Units>::base_unit_type::kelvin_ratio::den);
136 }
137
138 if constexpr (units::traits::unit_traits<
139 Units>::base_unit_type::mole_ratio::num != 0) {
140 out = fmt::format_to(out, " mol");
141 }
142 if constexpr (units::traits::unit_traits<
143 Units>::base_unit_type::mole_ratio::num != 0 &&
144 units::traits::unit_traits<
145 Units>::base_unit_type::mole_ratio::num != 1) {
146 out = fmt::format_to(
147 out, "^{}",
148 units::traits::unit_traits<Units>::base_unit_type::mole_ratio::num);
149 }
150 if constexpr (units::traits::unit_traits<
151 Units>::base_unit_type::mole_ratio::den != 1) {
152 out = fmt::format_to(
153 out, "/{}",
154 units::traits::unit_traits<Units>::base_unit_type::mole_ratio::den);
155 }
156
157 if constexpr (units::traits::unit_traits<
158 Units>::base_unit_type::candela_ratio::num != 0) {
159 out = fmt::format_to(out, " cd");
160 }
161 if constexpr (units::traits::unit_traits<
162 Units>::base_unit_type::candela_ratio::num != 0 &&
163 units::traits::unit_traits<
164 Units>::base_unit_type::candela_ratio::num != 1) {
165 out = fmt::format_to(out, "^{}",
166 units::traits::unit_traits<
167 Units>::base_unit_type::candela_ratio::num);
168 }
169 if constexpr (units::traits::unit_traits<
170 Units>::base_unit_type::candela_ratio::den != 1) {
171 out = fmt::format_to(out, "/{}",
172 units::traits::unit_traits<
173 Units>::base_unit_type::candela_ratio::den);
174 }
175
176 if constexpr (units::traits::unit_traits<
177 Units>::base_unit_type::radian_ratio::num != 0) {
178 out = fmt::format_to(out, " rad");
179 }
180 if constexpr (units::traits::unit_traits<
181 Units>::base_unit_type::radian_ratio::num != 0 &&
182 units::traits::unit_traits<
183 Units>::base_unit_type::radian_ratio::num != 1) {
184 out = fmt::format_to(
185 out, "^{}",
186 units::traits::unit_traits<Units>::base_unit_type::radian_ratio::num);
187 }
188 if constexpr (units::traits::unit_traits<
189 Units>::base_unit_type::radian_ratio::den != 1) {
190 out = fmt::format_to(
191 out, "/{}",
192 units::traits::unit_traits<Units>::base_unit_type::radian_ratio::den);
193 }
194
195 if constexpr (units::traits::unit_traits<
196 Units>::base_unit_type::byte_ratio::num != 0) {
197 out = fmt::format_to(out, " b");
198 }
199 if constexpr (units::traits::unit_traits<
200 Units>::base_unit_type::byte_ratio::num != 0 &&
201 units::traits::unit_traits<
202 Units>::base_unit_type::byte_ratio::num != 1) {
203 out = fmt::format_to(
204 out, "^{}",
205 units::traits::unit_traits<Units>::base_unit_type::byte_ratio::num);
206 }
207 if constexpr (units::traits::unit_traits<
208 Units>::base_unit_type::byte_ratio::den != 1) {
209 out = fmt::format_to(
210 out, "/{}",
211 units::traits::unit_traits<Units>::base_unit_type::byte_ratio::den);
212 }
213
214 return out;
215 }
216
217 private:
218 fmt::formatter<typename Unit::underlying_type, CharT> m_underlying;
219};
typename std::enable_if< B, T >::type enable_if_t
Definition: core.h:256
buffer_context< char > format_context
Definition: core.h:1759
basic_format_parse_context< char > format_parse_context
Definition: core.h:722
Definition: array.h:89
constexpr auto parse(fmt::format_parse_context &ctx)
Definition: formatter.h:23
auto format(const Unit &obj, fmt::format_context &ctx) const
Writes out a formatted unit.
Definition: formatter.h:33
Type representing an arbitrary unit.
Definition: base.h:884
auto format_to(OutputIt out, const S &fmt, T &&... args) -> OutputIt
Definition: xchar.h:156