121[[nodiscard]]
inline std::string render_measure_value(
const double v,
125 const FormatStyle style) {
126 int eff_precision = precision;
127 if (eff_precision < 0)
129 if (eff_precision < 0)
131 std::string num = format_numeric<double>(v, eff_precision);
133 case FormatStyle::Json:
134 return std::format(R
"({{"measure":"{}","unit":"{}","value":{}}})", md.id, ud.id, num);
135 case FormatStyle::Full:
136 return std::format(
"{} {} ({})", num, md.
name, ud.
long_name);
137 case FormatStyle::Short: {
142 return std::format(
"{}{}", num, sym);
144 case FormatStyle::Default:
150 return std::format(
"{}{}", num, ud.
symbol);
152 return std::format(
"{} {}", num, ud.
symbol);
157[[nodiscard]]
inline char open_bracket(
const Bound b)
noexcept {
158 return b == Bound::Inclusive ?
'[' :
'(';
161[[nodiscard]]
inline char close_bracket(
const Bound b)
noexcept {
162 return b == Bound::Inclusive ?
']' :
')';
167template <dimval::UnitLike U, dimval::NumericValue T>
168struct std::formatter<dimval::UnitValue<U, T>> {
169 dimval::detail::ValueFormatSpec spec_{};
171 constexpr auto parse(
const std::format_parse_context& ctx) {
172 const auto* it = dimval::detail::parse_value_format_spec(ctx.begin(), ctx.end(), spec_);
173 if (it != ctx.end() && *it !=
'}') {
174 throw std::format_error{
"dimval::UnitValue: invalid format spec"};
179 template <
typename FormatContext>
181 const auto d = U::descriptor();
182 const auto s = dimval::detail::render_unit_value(
183 static_cast<double>(v.v), spec_.precision, d, spec_.style);
184 return std::ranges::copy(s, ctx.out()).out;
188template <dimval::MeasureLike M, dimval::NumericValue T>
189struct std::formatter<dimval::MeasureValue<M, T>> {
190 dimval::detail::ValueFormatSpec spec_{};
192 constexpr auto parse(
const std::format_parse_context& ctx) {
193 const auto* it = dimval::detail::parse_value_format_spec(ctx.begin(), ctx.end(), spec_);
194 if (it != ctx.end() && *it !=
'}') {
195 throw std::format_error{
"dimval::MeasureValue: invalid format spec"};
200 template <
typename FormatContext>
202 const auto md = M::descriptor();
203 using unit_t = M::base_unit_t;
204 const auto ud = unit_t::descriptor();
205 const auto s = dimval::detail::render_measure_value(
206 static_cast<double>(v.v), spec_.precision, md, ud, spec_.style);
207 return std::ranges::copy(s, ctx.out()).out;
211template <dimval::UnitLike U, dimval::NumericValue T>
212struct std::formatter<dimval::UnitRangeValue<U, T>> {
213 dimval::detail::ValueFormatSpec spec_{};
215 constexpr auto parse(
const std::format_parse_context& ctx) {
216 const auto* it = dimval::detail::parse_value_format_spec(ctx.begin(), ctx.end(), spec_);
217 if (it != ctx.end() && *it !=
'}') {
218 throw std::format_error{
"dimval::UnitRangeValue: invalid format spec"};
223 template <
typename FormatContext>
225 const auto d = U::descriptor();
226 if (spec_.style == dimval::detail::FormatStyle::Json) {
227 const auto out = std::format(
228 R
"({{"unit":"{}","min":{},"max":{},"min_inclusive":{},"max_inclusive":{}}})",
230 dimval::detail::format_numeric<double>(static_cast<double>(r.min().v),
232 dimval::detail::format_numeric<double>(
static_cast<double>(r.max().v),
234 r.inclusion().lower == dimval::Bound::Inclusive ?
"true" :
"false",
235 r.inclusion().upper == dimval::
Bound::Inclusive ?
"true" :
"false");
236 return std::ranges::copy(out, ctx.out()).out;
238 const auto lo = dimval::detail::render_unit_value(
239 static_cast<double>(r.min().v), spec_.precision, d, spec_.style);
240 const auto hi = dimval::detail::render_unit_value(
241 static_cast<double>(r.max().v), spec_.precision, d, spec_.style);
242 const auto out = std::format(
"{}{}, {}{}",
243 dimval::detail::open_bracket(r.inclusion().lower),
246 dimval::detail::close_bracket(r.inclusion().upper));
247 return std::ranges::copy(out, ctx.out()).out;
251template <dimval::MeasureLike M, dimval::NumericValue T>
252struct std::formatter<dimval::MeasureRangeValue<M, T>> {
253 dimval::detail::ValueFormatSpec spec_{};
255 constexpr auto parse(
const std::format_parse_context& ctx) {
256 const auto* it = dimval::detail::parse_value_format_spec(ctx.begin(), ctx.end(), spec_);
257 if (it != ctx.end() && *it !=
'}') {
258 throw std::format_error{
"dimval::MeasureRangeValue: invalid format spec"};
263 template <
typename FormatContext>
265 const auto md = M::descriptor();
266 using unit_t = M::base_unit_t;
267 const auto ud = unit_t::descriptor();
268 if (spec_.style == dimval::detail::FormatStyle::Json) {
270 std::format(R
"({{"measure":"{}","unit":"{}","min":{},"max":{},)"
271 R"("min_inclusive":{},"max_inclusive":{}}})",
274 dimval::detail::format_numeric<double>(static_cast<double>(r.min().v),
276 dimval::detail::format_numeric<double>(
static_cast<double>(r.max().v),
278 r.inclusion().lower == dimval::Bound::Inclusive ?
"true" :
"false",
279 r.inclusion().upper == dimval::
Bound::Inclusive ?
"true" :
"false");
280 return std::ranges::copy(out, ctx.out()).out;
282 const auto lo = dimval::detail::render_measure_value(
283 static_cast<double>(r.min().v), spec_.precision, md, ud, spec_.style);
284 const auto hi = dimval::detail::render_measure_value(
285 static_cast<double>(r.max().v), spec_.precision, md, ud, spec_.style);
286 const auto out = std::format(
"{}{}, {}{}",
287 dimval::detail::open_bracket(r.inclusion().lower),
290 dimval::detail::close_bracket(r.inclusion().upper));
291 return std::ranges::copy(out, ctx.out()).out;
296struct std::formatter<dimval::UnitDescriptor> {
297 static constexpr auto parse(
const std::format_parse_context& ctx) {
298 const auto* it = ctx.begin();
299 if (it != ctx.end() && *it !=
'}') {
300 throw std::format_error{
"dimval::UnitDescriptor: invalid format spec"};
304 template <
typename FormatContext>
307 std::format(
"UnitDescriptor{{id={}, symbol={}, kind={}, factor={}, offset={}}}",
313 return std::ranges::copy(out, ctx.out()).out;
318struct std::formatter<dimval::MeasureDescriptor> {
319 static constexpr auto parse(
const std::format_parse_context& ctx) {
320 const auto* it = ctx.begin();
321 if (it != ctx.end() && *it !=
'}') {
322 throw std::format_error{
"dimval::MeasureDescriptor: invalid format spec"};
326 template <
typename FormatContext>
328 const auto out = std::format(
329 "MeasureDescriptor{{id={}, base_unit={}, name={}}}", d.id, d.base_unit_id, d.name);
330 return std::ranges::copy(out, ctx.out()).out;
339template <UnitLike U, NumericValue T>
341 return std::format(
"{}", *
this);
344template <UnitLike U, NumericValue T>
346 return std::format(
"{}", *
this);