diff --git a/src/core/include/mp-units/bits/external/hacks.h b/src/core/include/mp-units/bits/external/hacks.h index 44c3d452..55ad1d67 100644 --- a/src/core/include/mp-units/bits/external/hacks.h +++ b/src/core/include/mp-units/bits/external/hacks.h @@ -116,8 +116,8 @@ MP_UNITS_DIAGNOSTIC_POP #define MP_UNITS_STD_FMT fmt #define MP_UNITS_FMT_LOCALE(loc) (loc).template get() -#define MP_UNITS_FMT_TO_ARG_ID(arg) static_cast(arg) -#define MP_UNITS_FMT_FROM_ARG_ID(arg) static_cast(arg) +#define MP_UNITS_FMT_TO_ARG_ID(arg) (arg) +#define MP_UNITS_FMT_FROM_ARG_ID(arg) (arg) // This re-uses code from fmt; #if FMT_EXCEPTIONS @@ -143,8 +143,8 @@ MP_UNITS_DIAGNOSTIC_POP #define MP_UNITS_STD_FMT std #define MP_UNITS_FMT_LOCALE(loc) loc -#define MP_UNITS_FMT_TO_ARG_ID(arg) arg -#define MP_UNITS_FMT_FROM_ARG_ID(arg) arg +#define MP_UNITS_FMT_TO_ARG_ID(arg) static_cast(arg) +#define MP_UNITS_FMT_FROM_ARG_ID(arg) static_cast(arg) #define MP_UNITS_THROW(arg) throw arg #endif diff --git a/src/core/include/mp-units/bits/fmt.h b/src/core/include/mp-units/bits/fmt.h index 1ec0ff22..5b7305b4 100644 --- a/src/core/include/mp-units/bits/fmt.h +++ b/src/core/include/mp-units/bits/fmt.h @@ -40,23 +40,35 @@ namespace mp_units::detail { enum class fmt_align { none, left, right, center, numeric }; -enum class fmt_arg_id_kind { none, index, name }; +enum class fmt_arg_id_kind { + none, +#if MP_UNITS_USE_FMTLIB + name, +#endif + index +}; template struct fmt_arg_ref { fmt_arg_id_kind kind = fmt_arg_id_kind::none; union value { int index = 0; +#if MP_UNITS_USE_FMTLIB std::basic_string_view name; +#endif - value() = default; + constexpr value() {} constexpr value(int idx) : index(idx) {} +#if MP_UNITS_USE_FMTLIB constexpr value(std::basic_string_view n) : name(n) {} +#endif } val{}; fmt_arg_ref() = default; constexpr explicit fmt_arg_ref(int index) : kind(fmt_arg_id_kind::index), val(index) {} +#if MP_UNITS_USE_FMTLIB constexpr explicit fmt_arg_ref(std::basic_string_view name) : kind(fmt_arg_id_kind::name), val(name) {} +#endif [[nodiscard]] constexpr fmt_arg_ref& operator=(int idx) { @@ -79,7 +91,7 @@ public: { auto size = str.size(); if (size > max_size) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("invalid fill")); - for (size_t i = 0; i < size; ++i) data_[i] = str[i]; + for (size_t i = 0; i < size && i < max_size; ++i) data_[i] = str[i]; size_ = static_cast(size); return *this; } @@ -144,8 +156,8 @@ template template [[nodiscard]] constexpr auto get_arg(Context& ctx, ID id) -> decltype(ctx.arg(id)) { - auto arg = ctx.arg(id); - if (!arg) ctx.on_error("argument not found"); + auto arg = ctx.arg(MP_UNITS_FMT_TO_ARG_ID(id)); + if (!arg) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("argument not found")); return arg; } @@ -158,9 +170,11 @@ constexpr void handle_dynamic_spec(int& value, fmt_arg_ref(get_arg(ctx, ref.val.index)); break; +#if MP_UNITS_USE_FMTLIB case fmt_arg_id_kind::name: value = ::mp_units::detail::get_dynamic_spec(get_arg(ctx, ref.val.name)); break; +#endif } } @@ -219,7 +233,12 @@ template do { ++it; } while (it != end && (::mp_units::detail::is_name_start(*it) || ('0' <= *it && *it <= '9'))); +#if MP_UNITS_USE_FMTLIB handler.on_name({begin, ::mp_units::detail::to_unsigned(it - begin)}); +#else + MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("named arguments are not supported in the C++ standard facilities")); +#endif + return it; } @@ -260,21 +279,27 @@ struct dynamic_spec_id_handler { constexpr void on_auto() { - int id = ctx.next_arg_id(); + int id = MP_UNITS_FMT_FROM_ARG_ID(ctx.next_arg_id()); ref = fmt_arg_ref(id); +#if MP_UNITS_USE_FMTLIB || __cpp_lib_format >= 202305L ctx.check_dynamic_spec(id); +#endif } constexpr void on_index(int id) { ref = fmt_arg_ref(id); - ctx.check_arg_id(id); + ctx.check_arg_id(MP_UNITS_FMT_TO_ARG_ID(id)); +#if MP_UNITS_USE_FMTLIB || __cpp_lib_format >= 202305L ctx.check_dynamic_spec(id); +#endif } - constexpr void on_name(std::basic_string_view id) +#if MP_UNITS_USE_FMTLIB + constexpr void on_name([[maybe_unused]] std::basic_string_view id) { ref = fmt_arg_ref(id); ctx.check_arg_id(id); } +#endif }; template diff --git a/src/core/include/mp-units/format.h b/src/core/include/mp-units/format.h index 02aaf1f3..21a95e53 100644 --- a/src/core/include/mp-units/format.h +++ b/src/core/include/mp-units/format.h @@ -293,6 +293,8 @@ class MP_UNITS_STD_FMT::formatter, Char> { return begin + *format_str_lengths_it++; } }; + template + quantity_formatter(OutputIt, Args...) -> quantity_formatter; template constexpr const Char* parse_quantity_specs(const Char* begin, const Char* end, Handler&& handler) const @@ -345,7 +347,7 @@ class MP_UNITS_STD_FMT::formatter, Char> { template OutputIt format_quantity(OutputIt out, const quantity_t& q, FormatContext& ctx) const { - std::locale locale = ctx.locale().template get(); + std::locale locale = MP_UNITS_FMT_LOCALE(ctx.locale()); if (modifiers_format_str_.empty()) { // default format should print value followed by the unit separated with 1 space out = MP_UNITS_STD_FMT::vformat_to(out, locale, "{}",