WPILibC++ 2025.0.0-alpha-1-14-g3b6f38d
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 template <typename ParseContext>
24 constexpr auto parse(ParseContext& ctx) {
25 return m_underlying.parse(ctx);
26 }
27
28 /**
29 * Writes out a formatted unit.
30 *
31 * @param obj Unit instance.
32 * @param ctx Format string context.
33 */
34 template <typename FmtContext>
35 auto format(const Unit& obj, FmtContext& ctx) const {
36 using Units = typename Unit::unit_type;
37 using BaseUnits =
39 typename units::traits::unit_traits<Units>::base_unit_type>;
40
41 auto out = ctx.out();
42
43 out = m_underlying.format(units::convert<Units, BaseUnits>(obj()), ctx);
44
45 if constexpr (units::traits::unit_traits<
46 Units>::base_unit_type::meter_ratio::num != 0) {
47 out = fmt::format_to(out, " m");
48 }
49 if constexpr (units::traits::unit_traits<
50 Units>::base_unit_type::meter_ratio::num != 0 &&
51 units::traits::unit_traits<
52 Units>::base_unit_type::meter_ratio::num != 1) {
53 out = fmt::format_to(
54 out, "^{}",
55 units::traits::unit_traits<Units>::base_unit_type::meter_ratio::num);
56 }
57 if constexpr (units::traits::unit_traits<
58 Units>::base_unit_type::meter_ratio::den != 1) {
59 out = fmt::format_to(
60 out, "/{}",
61 units::traits::unit_traits<Units>::base_unit_type::meter_ratio::den);
62 }
63
64 if constexpr (units::traits::unit_traits<
65 Units>::base_unit_type::kilogram_ratio::num != 0) {
66 out = fmt::format_to(out, " kg");
67 }
68 if constexpr (units::traits::unit_traits<
69 Units>::base_unit_type::kilogram_ratio::num != 0 &&
70 units::traits::unit_traits<
71 Units>::base_unit_type::kilogram_ratio::num != 1) {
72 out = fmt::format_to(out, "^{}",
73 units::traits::unit_traits<
74 Units>::base_unit_type::kilogram_ratio::num);
75 }
76 if constexpr (units::traits::unit_traits<
77 Units>::base_unit_type::kilogram_ratio::den != 1) {
78 out = fmt::format_to(out, "/{}",
79 units::traits::unit_traits<
80 Units>::base_unit_type::kilogram_ratio::den);
81 }
82
83 if constexpr (units::traits::unit_traits<
84 Units>::base_unit_type::second_ratio::num != 0) {
85 out = fmt::format_to(out, " s");
86 }
87 if constexpr (units::traits::unit_traits<
88 Units>::base_unit_type::second_ratio::num != 0 &&
89 units::traits::unit_traits<
90 Units>::base_unit_type::second_ratio::num != 1) {
91 out = fmt::format_to(
92 out, "^{}",
93 units::traits::unit_traits<Units>::base_unit_type::second_ratio::num);
94 }
95 if constexpr (units::traits::unit_traits<
96 Units>::base_unit_type::second_ratio::den != 1) {
97 out = fmt::format_to(
98 out, "/{}",
99 units::traits::unit_traits<Units>::base_unit_type::second_ratio::den);
100 }
101
102 if constexpr (units::traits::unit_traits<
103 Units>::base_unit_type::ampere_ratio::num != 0) {
104 out = fmt::format_to(out, " A");
105 }
106 if constexpr (units::traits::unit_traits<
107 Units>::base_unit_type::ampere_ratio::num != 0 &&
108 units::traits::unit_traits<
109 Units>::base_unit_type::ampere_ratio::num != 1) {
110 out = fmt::format_to(
111 out, "^{}",
112 units::traits::unit_traits<Units>::base_unit_type::ampere_ratio::num);
113 }
114 if constexpr (units::traits::unit_traits<
115 Units>::base_unit_type::ampere_ratio::den != 1) {
116 out = fmt::format_to(
117 out, "/{}",
118 units::traits::unit_traits<Units>::base_unit_type::ampere_ratio::den);
119 }
120
121 if constexpr (units::traits::unit_traits<
122 Units>::base_unit_type::kelvin_ratio::num != 0) {
123 out = fmt::format_to(out, " K");
124 }
125 if constexpr (units::traits::unit_traits<
126 Units>::base_unit_type::kelvin_ratio::num != 0 &&
127 units::traits::unit_traits<
128 Units>::base_unit_type::kelvin_ratio::num != 1) {
129 out = fmt::format_to(
130 out, "^{}",
131 units::traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num);
132 }
133 if constexpr (units::traits::unit_traits<
134 Units>::base_unit_type::kelvin_ratio::den != 1) {
135 out = fmt::format_to(
136 out, "/{}",
137 units::traits::unit_traits<Units>::base_unit_type::kelvin_ratio::den);
138 }
139
140 if constexpr (units::traits::unit_traits<
141 Units>::base_unit_type::mole_ratio::num != 0) {
142 out = fmt::format_to(out, " mol");
143 }
144 if constexpr (units::traits::unit_traits<
145 Units>::base_unit_type::mole_ratio::num != 0 &&
146 units::traits::unit_traits<
147 Units>::base_unit_type::mole_ratio::num != 1) {
148 out = fmt::format_to(
149 out, "^{}",
150 units::traits::unit_traits<Units>::base_unit_type::mole_ratio::num);
151 }
152 if constexpr (units::traits::unit_traits<
153 Units>::base_unit_type::mole_ratio::den != 1) {
154 out = fmt::format_to(
155 out, "/{}",
156 units::traits::unit_traits<Units>::base_unit_type::mole_ratio::den);
157 }
158
159 if constexpr (units::traits::unit_traits<
160 Units>::base_unit_type::candela_ratio::num != 0) {
161 out = fmt::format_to(out, " cd");
162 }
163 if constexpr (units::traits::unit_traits<
164 Units>::base_unit_type::candela_ratio::num != 0 &&
165 units::traits::unit_traits<
166 Units>::base_unit_type::candela_ratio::num != 1) {
167 out = fmt::format_to(out, "^{}",
168 units::traits::unit_traits<
169 Units>::base_unit_type::candela_ratio::num);
170 }
171 if constexpr (units::traits::unit_traits<
172 Units>::base_unit_type::candela_ratio::den != 1) {
173 out = fmt::format_to(out, "/{}",
174 units::traits::unit_traits<
175 Units>::base_unit_type::candela_ratio::den);
176 }
177
178 if constexpr (units::traits::unit_traits<
179 Units>::base_unit_type::radian_ratio::num != 0) {
180 out = fmt::format_to(out, " rad");
181 }
182 if constexpr (units::traits::unit_traits<
183 Units>::base_unit_type::radian_ratio::num != 0 &&
184 units::traits::unit_traits<
185 Units>::base_unit_type::radian_ratio::num != 1) {
186 out = fmt::format_to(
187 out, "^{}",
188 units::traits::unit_traits<Units>::base_unit_type::radian_ratio::num);
189 }
190 if constexpr (units::traits::unit_traits<
191 Units>::base_unit_type::radian_ratio::den != 1) {
192 out = fmt::format_to(
193 out, "/{}",
194 units::traits::unit_traits<Units>::base_unit_type::radian_ratio::den);
195 }
196
197 if constexpr (units::traits::unit_traits<
198 Units>::base_unit_type::byte_ratio::num != 0) {
199 out = fmt::format_to(out, " b");
200 }
201 if constexpr (units::traits::unit_traits<
202 Units>::base_unit_type::byte_ratio::num != 0 &&
203 units::traits::unit_traits<
204 Units>::base_unit_type::byte_ratio::num != 1) {
205 out = fmt::format_to(
206 out, "^{}",
207 units::traits::unit_traits<Units>::base_unit_type::byte_ratio::num);
208 }
209 if constexpr (units::traits::unit_traits<
210 Units>::base_unit_type::byte_ratio::den != 1) {
211 out = fmt::format_to(
212 out, "/{}",
213 units::traits::unit_traits<Units>::base_unit_type::byte_ratio::den);
214 }
215
216 return out;
217 }
218
219 private:
220 fmt::formatter<typename Unit::underlying_type, CharT> m_underlying;
221};
Implement std::hash so that hash_code can be used in STL containers.
Definition: array.h:89
auto format(const Unit &obj, FmtContext &ctx) const
Writes out a formatted unit.
Definition: formatter.h:35
constexpr auto parse(ParseContext &ctx)
Definition: formatter.h:24
Type representing an arbitrary unit.
Definition: base.h:887
typename std::enable_if< B, T >::type enable_if_t
Definition: base.h:317
auto format_to(OutputIt out, wformat_string< T... > fmt, T &&... args) -> OutputIt
Definition: xchar.h:142