mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-04 20:54:28 +02:00
@@ -116,8 +116,8 @@ MP_UNITS_DIAGNOSTIC_POP
|
|||||||
|
|
||||||
#define MP_UNITS_STD_FMT fmt
|
#define MP_UNITS_STD_FMT fmt
|
||||||
#define MP_UNITS_FMT_LOCALE(loc) (loc).template get<std::locale>()
|
#define MP_UNITS_FMT_LOCALE(loc) (loc).template get<std::locale>()
|
||||||
#define MP_UNITS_FMT_TO_ARG_ID(arg) static_cast<int>(arg)
|
#define MP_UNITS_FMT_TO_ARG_ID(arg) (arg)
|
||||||
#define MP_UNITS_FMT_FROM_ARG_ID(arg) static_cast<size_t>(arg)
|
#define MP_UNITS_FMT_FROM_ARG_ID(arg) (arg)
|
||||||
|
|
||||||
// This re-uses code from fmt;
|
// This re-uses code from fmt;
|
||||||
#if FMT_EXCEPTIONS
|
#if FMT_EXCEPTIONS
|
||||||
@@ -143,8 +143,8 @@ MP_UNITS_DIAGNOSTIC_POP
|
|||||||
|
|
||||||
#define MP_UNITS_STD_FMT std
|
#define MP_UNITS_STD_FMT std
|
||||||
#define MP_UNITS_FMT_LOCALE(loc) loc
|
#define MP_UNITS_FMT_LOCALE(loc) loc
|
||||||
#define MP_UNITS_FMT_TO_ARG_ID(arg) arg
|
#define MP_UNITS_FMT_TO_ARG_ID(arg) static_cast<std::size_t>(arg)
|
||||||
#define MP_UNITS_FMT_FROM_ARG_ID(arg) arg
|
#define MP_UNITS_FMT_FROM_ARG_ID(arg) static_cast<int>(arg)
|
||||||
#define MP_UNITS_THROW(arg) throw arg
|
#define MP_UNITS_THROW(arg) throw arg
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -40,23 +40,35 @@
|
|||||||
namespace mp_units::detail {
|
namespace mp_units::detail {
|
||||||
|
|
||||||
enum class fmt_align { none, left, right, center, numeric };
|
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<typename Char>
|
template<typename Char>
|
||||||
struct fmt_arg_ref {
|
struct fmt_arg_ref {
|
||||||
fmt_arg_id_kind kind = fmt_arg_id_kind::none;
|
fmt_arg_id_kind kind = fmt_arg_id_kind::none;
|
||||||
union value {
|
union value {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
#if MP_UNITS_USE_FMTLIB
|
||||||
std::basic_string_view<Char> name;
|
std::basic_string_view<Char> name;
|
||||||
|
#endif
|
||||||
|
|
||||||
value() = default;
|
constexpr value() {}
|
||||||
constexpr value(int idx) : index(idx) {}
|
constexpr value(int idx) : index(idx) {}
|
||||||
|
#if MP_UNITS_USE_FMTLIB
|
||||||
constexpr value(std::basic_string_view<Char> n) : name(n) {}
|
constexpr value(std::basic_string_view<Char> n) : name(n) {}
|
||||||
|
#endif
|
||||||
} val{};
|
} val{};
|
||||||
|
|
||||||
fmt_arg_ref() = default;
|
fmt_arg_ref() = default;
|
||||||
constexpr explicit fmt_arg_ref(int index) : kind(fmt_arg_id_kind::index), val(index) {}
|
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<Char> name) : kind(fmt_arg_id_kind::name), val(name) {}
|
constexpr explicit fmt_arg_ref(std::basic_string_view<Char> name) : kind(fmt_arg_id_kind::name), val(name) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
[[nodiscard]] constexpr fmt_arg_ref& operator=(int idx)
|
[[nodiscard]] constexpr fmt_arg_ref& operator=(int idx)
|
||||||
{
|
{
|
||||||
@@ -79,7 +91,7 @@ public:
|
|||||||
{
|
{
|
||||||
auto size = str.size();
|
auto size = str.size();
|
||||||
if (size > max_size) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("invalid fill"));
|
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<unsigned char>(size);
|
size_ = static_cast<unsigned char>(size);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -144,8 +156,8 @@ template<class Handler, typename FormatArg>
|
|||||||
template<typename Context, typename ID>
|
template<typename Context, typename ID>
|
||||||
[[nodiscard]] constexpr auto get_arg(Context& ctx, ID id) -> decltype(ctx.arg(id))
|
[[nodiscard]] constexpr auto get_arg(Context& ctx, ID id) -> decltype(ctx.arg(id))
|
||||||
{
|
{
|
||||||
auto arg = ctx.arg(id);
|
auto arg = ctx.arg(MP_UNITS_FMT_TO_ARG_ID(id));
|
||||||
if (!arg) ctx.on_error("argument not found");
|
if (!arg) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("argument not found"));
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,9 +170,11 @@ constexpr void handle_dynamic_spec(int& value, fmt_arg_ref<typename Context::cha
|
|||||||
case fmt_arg_id_kind::index:
|
case fmt_arg_id_kind::index:
|
||||||
value = ::mp_units::detail::get_dynamic_spec<Handler>(get_arg(ctx, ref.val.index));
|
value = ::mp_units::detail::get_dynamic_spec<Handler>(get_arg(ctx, ref.val.index));
|
||||||
break;
|
break;
|
||||||
|
#if MP_UNITS_USE_FMTLIB
|
||||||
case fmt_arg_id_kind::name:
|
case fmt_arg_id_kind::name:
|
||||||
value = ::mp_units::detail::get_dynamic_spec<Handler>(get_arg(ctx, ref.val.name));
|
value = ::mp_units::detail::get_dynamic_spec<Handler>(get_arg(ctx, ref.val.name));
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +233,12 @@ template<typename Char, typename Handler>
|
|||||||
do {
|
do {
|
||||||
++it;
|
++it;
|
||||||
} while (it != end && (::mp_units::detail::is_name_start(*it) || ('0' <= *it && *it <= '9')));
|
} 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)});
|
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;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,21 +279,27 @@ struct dynamic_spec_id_handler {
|
|||||||
|
|
||||||
constexpr void on_auto()
|
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<Char>(id);
|
ref = fmt_arg_ref<Char>(id);
|
||||||
|
#if MP_UNITS_USE_FMTLIB || __cpp_lib_format >= 202305L
|
||||||
ctx.check_dynamic_spec(id);
|
ctx.check_dynamic_spec(id);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
constexpr void on_index(int id)
|
constexpr void on_index(int id)
|
||||||
{
|
{
|
||||||
ref = fmt_arg_ref<Char>(id);
|
ref = fmt_arg_ref<Char>(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);
|
ctx.check_dynamic_spec(id);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
constexpr void on_name(std::basic_string_view<Char> id)
|
#if MP_UNITS_USE_FMTLIB
|
||||||
|
constexpr void on_name([[maybe_unused]] std::basic_string_view<Char> id)
|
||||||
{
|
{
|
||||||
ref = fmt_arg_ref<Char>(id);
|
ref = fmt_arg_ref<Char>(id);
|
||||||
ctx.check_arg_id(id);
|
ctx.check_arg_id(id);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Char>
|
template<typename Char>
|
||||||
|
@@ -293,6 +293,8 @@ class MP_UNITS_STD_FMT::formatter<mp_units::quantity<Reference, Rep>, Char> {
|
|||||||
return begin + *format_str_lengths_it++;
|
return begin + *format_str_lengths_it++;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
template<typename OutputIt, typename... Args>
|
||||||
|
quantity_formatter(OutputIt, Args...) -> quantity_formatter<OutputIt>;
|
||||||
|
|
||||||
template<typename Handler>
|
template<typename Handler>
|
||||||
constexpr const Char* parse_quantity_specs(const Char* begin, const Char* end, Handler&& handler) const
|
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<mp_units::quantity<Reference, Rep>, Char> {
|
|||||||
template<typename OutputIt, typename FormatContext>
|
template<typename OutputIt, typename FormatContext>
|
||||||
OutputIt format_quantity(OutputIt out, const quantity_t& q, FormatContext& ctx) const
|
OutputIt format_quantity(OutputIt out, const quantity_t& q, FormatContext& ctx) const
|
||||||
{
|
{
|
||||||
std::locale locale = ctx.locale().template get<std::locale>();
|
std::locale locale = MP_UNITS_FMT_LOCALE(ctx.locale());
|
||||||
if (modifiers_format_str_.empty()) {
|
if (modifiers_format_str_.empty()) {
|
||||||
// default format should print value followed by the unit separated with 1 space
|
// default format should print value followed by the unit separated with 1 space
|
||||||
out = MP_UNITS_STD_FMT::vformat_to(out, locale, "{}",
|
out = MP_UNITS_STD_FMT::vformat_to(out, locale, "{}",
|
||||||
|
Reference in New Issue
Block a user