merge branch master
This commit is contained in:
1 parent
b7e467ff42
commit
561fbf7c93
68 files changed
+1426
-812
No files matched your search
@@ -29,6 +29,8 @@ add_units_module(core-fmt DEPENDENCIES mp-units::core HEADERS include/mp-units/f
|
||||
target_compile_definitions(mp-units-core-fmt INTERFACE ${projectPrefix}USE_LIBFMT=$<BOOL:${${projectPrefix}USE_LIBFMT}>)
|
||||
|
||||
if(${projectPrefix}USE_LIBFMT)
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
if(NOT TARGET fmt::fmt)
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
endif()
|
||||
target_link_libraries(mp-units-core-fmt INTERFACE fmt::fmt)
|
||||
endif()
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
constexpr fill_t& operator=(std::basic_string_view<Char> str)
|
||||
{
|
||||
auto size = str.size();
|
||||
if (size > max_size) throw STD_FMT::format_error("invalid fill");
|
||||
if (size > max_size) UNITS_THROW(UNITS_STD_FMT::format_error("invalid fill"));
|
||||
for (size_t i = 0; i < size; ++i) data_[i] = str[i];
|
||||
size_ = static_cast<unsigned char>(size);
|
||||
return *this;
|
||||
@@ -98,11 +98,11 @@ struct width_checker {
|
||||
{
|
||||
if constexpr (is_integer<T>) {
|
||||
if constexpr (std::numeric_limits<T>::is_signed) {
|
||||
if (value < 0) throw STD_FMT::format_error("negative width");
|
||||
if (value < 0) UNITS_THROW(UNITS_STD_FMT::format_error("negative width"));
|
||||
}
|
||||
return static_cast<unsigned long long>(value);
|
||||
} else {
|
||||
throw STD_FMT::format_error("width is not integer");
|
||||
UNITS_THROW(UNITS_STD_FMT::format_error("width is not integer"));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -113,11 +113,11 @@ struct precision_checker {
|
||||
{
|
||||
if constexpr (is_integer<T>) {
|
||||
if constexpr (std::numeric_limits<T>::is_signed) {
|
||||
if (value < 0) throw STD_FMT::format_error("negative precision");
|
||||
if (value < 0) UNITS_THROW(UNITS_STD_FMT::format_error("negative precision"));
|
||||
}
|
||||
return static_cast<unsigned long long>(value);
|
||||
} else {
|
||||
throw STD_FMT::format_error("precision is not integer");
|
||||
UNITS_THROW(UNITS_STD_FMT::format_error("precision is not integer"));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -147,31 +147,31 @@ struct dynamic_format_specs : basic_format_specs<Char> {
|
||||
[[nodiscard]] constexpr int verify_dynamic_arg_index_in_range(size_t idx)
|
||||
{
|
||||
if (idx > static_cast<size_t>(std::numeric_limits<int>::max())) {
|
||||
throw STD_FMT::format_error("Dynamic width or precision index too large.");
|
||||
UNITS_THROW(UNITS_STD_FMT::format_error("Dynamic width or precision index too large."));
|
||||
}
|
||||
return static_cast<int>(idx);
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
[[nodiscard]] constexpr int on_dynamic_arg(size_t arg_id, STD_FMT::basic_format_parse_context<CharT>& context)
|
||||
[[nodiscard]] constexpr int on_dynamic_arg(size_t arg_id, UNITS_STD_FMT::basic_format_parse_context<CharT>& context)
|
||||
{
|
||||
context.check_arg_id(FMT_TO_ARG_ID(arg_id));
|
||||
context.check_arg_id(UNITS_FMT_TO_ARG_ID(arg_id));
|
||||
return verify_dynamic_arg_index_in_range(arg_id);
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
[[nodiscard]] constexpr int on_dynamic_arg(auto_id, STD_FMT::basic_format_parse_context<CharT>& context)
|
||||
[[nodiscard]] constexpr int on_dynamic_arg(auto_id, UNITS_STD_FMT::basic_format_parse_context<CharT>& context)
|
||||
{
|
||||
return verify_dynamic_arg_index_in_range(FMT_FROM_ARG_ID(context.next_arg_id()));
|
||||
return verify_dynamic_arg_index_in_range(UNITS_FMT_FROM_ARG_ID(context.next_arg_id()));
|
||||
}
|
||||
|
||||
template<class Handler, typename FormatContext>
|
||||
[[nodiscard]] constexpr int get_dynamic_spec(int index, FormatContext& ctx)
|
||||
{
|
||||
const unsigned long long value =
|
||||
STD_FMT::visit_format_arg(Handler{}, ctx.arg(FMT_TO_ARG_ID(static_cast<size_t>(index))));
|
||||
UNITS_STD_FMT::visit_format_arg(Handler{}, ctx.arg(UNITS_FMT_TO_ARG_ID(static_cast<size_t>(index))));
|
||||
if (value > static_cast<unsigned long long>(std::numeric_limits<int>::max())) {
|
||||
throw STD_FMT::format_error("number is too big");
|
||||
UNITS_THROW(UNITS_STD_FMT::format_error("number is too big"));
|
||||
}
|
||||
return static_cast<int>(value);
|
||||
}
|
||||
@@ -195,7 +195,7 @@ template<std::input_iterator It, std::sentinel_for<It> S>
|
||||
++begin;
|
||||
} while (begin != end && '0' <= *begin && *begin <= '9');
|
||||
|
||||
if (value > max_int) throw STD_FMT::format_error("Number is too big");
|
||||
if (value > max_int) UNITS_THROW(UNITS_STD_FMT::format_error("Number is too big"));
|
||||
|
||||
return begin;
|
||||
}
|
||||
@@ -222,12 +222,12 @@ template<std::input_iterator It, std::sentinel_for<It> S, typename IDHandler>
|
||||
else
|
||||
++begin;
|
||||
if (begin == end || (*begin != '}' && *begin != ':'))
|
||||
throw STD_FMT::format_error("invalid format string");
|
||||
UNITS_THROW(UNITS_STD_FMT::format_error("invalid format string"));
|
||||
else
|
||||
handler(index);
|
||||
return begin;
|
||||
}
|
||||
throw STD_FMT::format_error("invalid format string");
|
||||
UNITS_THROW(UNITS_STD_FMT::format_error("invalid format string"));
|
||||
}
|
||||
|
||||
template<std::input_iterator It, std::sentinel_for<It> S, typename IDHandler>
|
||||
@@ -278,11 +278,11 @@ template<std::input_iterator It, std::sentinel_for<It> S, typename Handler>
|
||||
if (width != -1)
|
||||
handler.on_width(width);
|
||||
else
|
||||
throw STD_FMT::format_error("number is too big");
|
||||
UNITS_THROW(UNITS_STD_FMT::format_error("number is too big"));
|
||||
} else if (*begin == '{') {
|
||||
++begin;
|
||||
if (begin != end) begin = parse_arg_id(begin, end, width_adapter{handler});
|
||||
if (begin == end || *begin != '}') throw STD_FMT::format_error("invalid format string");
|
||||
if (begin == end || *begin != '}') UNITS_THROW(UNITS_STD_FMT::format_error("invalid format string"));
|
||||
++begin;
|
||||
}
|
||||
return begin;
|
||||
@@ -305,13 +305,13 @@ template<std::input_iterator It, std::sentinel_for<It> S, typename Handler>
|
||||
if (precision != -1)
|
||||
handler.on_precision(precision);
|
||||
else
|
||||
throw STD_FMT::format_error("number is too big");
|
||||
UNITS_THROW(UNITS_STD_FMT::format_error("number is too big"));
|
||||
} else if (c == '{') {
|
||||
++begin;
|
||||
if (begin != end) begin = parse_arg_id(begin, end, precision_adapter{handler});
|
||||
if (begin == end || *begin++ != '}') throw STD_FMT::format_error("invalid format string");
|
||||
if (begin == end || *begin++ != '}') UNITS_THROW(UNITS_STD_FMT::format_error("invalid format string"));
|
||||
} else {
|
||||
throw STD_FMT::format_error("missing precision specifier");
|
||||
UNITS_THROW(UNITS_STD_FMT::format_error("missing precision specifier"));
|
||||
}
|
||||
return begin;
|
||||
}
|
||||
@@ -355,7 +355,7 @@ template<std::input_iterator It, std::sentinel_for<It> S, typename Handler>
|
||||
if (align != fmt_align::none) {
|
||||
if (p != begin) {
|
||||
auto c = *begin;
|
||||
if (c == '{') throw STD_FMT::format_error("invalid fill character '{'");
|
||||
if (c == '{') UNITS_THROW(UNITS_STD_FMT::format_error("invalid fill character '{'"));
|
||||
handler.on_fill(std::basic_string_view<std::iter_value_t<It>>(&*begin, static_cast<size_t>(p - begin)));
|
||||
begin = p + 1;
|
||||
} else
|
||||
|
||||
@@ -41,10 +41,24 @@ UNITS_DIAGNOSTIC_IGNORE_SHADOW
|
||||
#include <fmt/format.h>
|
||||
UNITS_DIAGNOSTIC_POP
|
||||
|
||||
#define STD_FMT fmt
|
||||
#define FMT_LOCALE(loc) (loc).template get<std::locale>()
|
||||
#define FMT_TO_ARG_ID(arg) static_cast<int>(arg)
|
||||
#define FMT_FROM_ARG_ID(arg) static_cast<size_t>(arg)
|
||||
#define UNITS_STD_FMT fmt
|
||||
#define UNITS_FMT_LOCALE(loc) (loc).template get<std::locale>()
|
||||
#define UNITS_FMT_TO_ARG_ID(arg) static_cast<int>(arg)
|
||||
#define UNITS_FMT_FROM_ARG_ID(arg) static_cast<size_t>(arg)
|
||||
|
||||
// This re-uses code from fmt;
|
||||
#if FMT_EXCEPTIONS
|
||||
#if FMT_MSC_VERSION || defined(__NVCC__)
|
||||
#define UNITS_THROW(x) ::fmt::detail::do_throw(x)
|
||||
#else
|
||||
#define UNITS_THROW(x) throw x
|
||||
#endif
|
||||
#else
|
||||
#define UNITS_THROW(x) \
|
||||
do { \
|
||||
FMT_ASSERT(false, (x).what()); \
|
||||
} while (false)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
@@ -54,9 +68,10 @@ UNITS_DIAGNOSTIC_POP
|
||||
|
||||
#include <format>
|
||||
|
||||
#define STD_FMT std
|
||||
#define FMT_LOCALE(loc) loc
|
||||
#define FMT_TO_ARG_ID(arg) arg
|
||||
#define FMT_FROM_ARG_ID(arg) arg
|
||||
#define UNITS_STD_FMT std
|
||||
#define UNITS_FMT_LOCALE(loc) loc
|
||||
#define UNITS_FMT_TO_ARG_ID(arg) arg
|
||||
#define UNITS_FMT_FROM_ARG_ID(arg) arg
|
||||
#define UNITS_THROW(arg) throw arg
|
||||
|
||||
#endif
|
||||
@@ -96,7 +96,7 @@ constexpr It parse_units_rep(It begin, S end, Handler&& handler, bool treat_as_f
|
||||
if (treat_as_floating_point) {
|
||||
begin = parse_precision(begin, end, handler);
|
||||
} else
|
||||
throw STD_FMT::format_error("precision not allowed for integral quantity representation");
|
||||
throw UNITS_STD_FMT::format_error("precision not allowed for integral quantity representation");
|
||||
if (begin == end) return begin;
|
||||
}
|
||||
|
||||
@@ -126,12 +126,12 @@ constexpr It parse_units_format(It begin, S end, Handler&& handler)
|
||||
}
|
||||
if (begin != ptr) handler.on_text(begin, ptr);
|
||||
begin = ++ptr; // consume '%'
|
||||
if (ptr == end) throw STD_FMT::format_error("invalid format");
|
||||
if (ptr == end) throw UNITS_STD_FMT::format_error("invalid format");
|
||||
c = *ptr++;
|
||||
|
||||
constexpr auto units_types = std::string_view{"Qq"};
|
||||
const auto new_end = find_first_of(begin, end, units_types.begin(), units_types.end());
|
||||
if (new_end == end) throw STD_FMT::format_error("invalid format");
|
||||
if (new_end == end) throw UNITS_STD_FMT::format_error("invalid format");
|
||||
if (*new_end == 'Q') {
|
||||
handler.on_quantity_value(begin, new_end); // Edit `on_quantity_value` to add rep modifiers
|
||||
} else {
|
||||
@@ -152,43 +152,43 @@ template<typename CharT, typename Rep, typename OutputIt, typename Locale>
|
||||
std::basic_string<CharT> buffer;
|
||||
auto to_buffer = std::back_inserter(buffer);
|
||||
|
||||
STD_FMT::format_to(to_buffer, "{{:");
|
||||
UNITS_STD_FMT::format_to(to_buffer, "{{:");
|
||||
switch (rep_specs.sign) {
|
||||
case fmt_sign::none:
|
||||
break;
|
||||
case fmt_sign::plus:
|
||||
STD_FMT::format_to(to_buffer, "+");
|
||||
UNITS_STD_FMT::format_to(to_buffer, "+");
|
||||
break;
|
||||
case fmt_sign::minus:
|
||||
STD_FMT::format_to(to_buffer, "-");
|
||||
UNITS_STD_FMT::format_to(to_buffer, "-");
|
||||
break;
|
||||
case fmt_sign::space:
|
||||
STD_FMT::format_to(to_buffer, " ");
|
||||
UNITS_STD_FMT::format_to(to_buffer, " ");
|
||||
break;
|
||||
}
|
||||
|
||||
if (rep_specs.alt) {
|
||||
STD_FMT::format_to(to_buffer, "#");
|
||||
UNITS_STD_FMT::format_to(to_buffer, "#");
|
||||
}
|
||||
auto type = rep_specs.type;
|
||||
if (auto precision = rep_specs.precision; precision >= 0) {
|
||||
STD_FMT::format_to(to_buffer, ".{}{}", precision, type == '\0' ? 'f' : type);
|
||||
UNITS_STD_FMT::format_to(to_buffer, ".{}{}", precision, type == '\0' ? 'f' : type);
|
||||
} else if constexpr (treat_as_floating_point<Rep>) {
|
||||
STD_FMT::format_to(to_buffer, "{}", type == '\0' ? 'g' : type);
|
||||
UNITS_STD_FMT::format_to(to_buffer, "{}", type == '\0' ? 'g' : type);
|
||||
} else {
|
||||
if (type != '\0') {
|
||||
STD_FMT::format_to(to_buffer, "{}", type);
|
||||
UNITS_STD_FMT::format_to(to_buffer, "{}", type);
|
||||
}
|
||||
}
|
||||
if (rep_specs.localized) {
|
||||
STD_FMT::format_to(to_buffer, "L");
|
||||
UNITS_STD_FMT::format_to(to_buffer, "L");
|
||||
}
|
||||
|
||||
STD_FMT::format_to(to_buffer, "}}");
|
||||
UNITS_STD_FMT::format_to(to_buffer, "}}");
|
||||
if (rep_specs.localized) {
|
||||
return STD_FMT::vformat_to(out, FMT_LOCALE(loc), buffer, STD_FMT::make_format_args(val));
|
||||
return UNITS_STD_FMT::vformat_to(out, UNITS_FMT_LOCALE(loc), buffer, UNITS_STD_FMT::make_format_args(val));
|
||||
}
|
||||
return STD_FMT::vformat_to(out, buffer, STD_FMT::make_format_args(val));
|
||||
return UNITS_STD_FMT::vformat_to(out, buffer, UNITS_STD_FMT::make_format_args(val));
|
||||
}
|
||||
|
||||
// Creates a global format string
|
||||
@@ -196,25 +196,25 @@ template<typename CharT, typename Rep, typename OutputIt, typename Locale>
|
||||
template<typename CharT, typename OutputIt>
|
||||
OutputIt format_global_buffer(OutputIt out, const quantity_global_format_specs<CharT>& specs)
|
||||
{
|
||||
STD_FMT::format_to(out, "{{:");
|
||||
UNITS_STD_FMT::format_to(out, "{{:");
|
||||
if (specs.fill.size() != 1 || specs.fill[0] != ' ') {
|
||||
STD_FMT::format_to(out, "{}", specs.fill.data());
|
||||
UNITS_STD_FMT::format_to(out, "{}", specs.fill.data());
|
||||
}
|
||||
switch (specs.align) {
|
||||
case fmt_align::left:
|
||||
STD_FMT::format_to(out, "<");
|
||||
UNITS_STD_FMT::format_to(out, "<");
|
||||
break;
|
||||
case fmt_align::right:
|
||||
STD_FMT::format_to(out, ">");
|
||||
UNITS_STD_FMT::format_to(out, ">");
|
||||
break;
|
||||
case fmt_align::center:
|
||||
STD_FMT::format_to(out, "^");
|
||||
UNITS_STD_FMT::format_to(out, "^");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (specs.width >= 1) STD_FMT::format_to(out, "{}", specs.width);
|
||||
return STD_FMT::format_to(out, "}}");
|
||||
if (specs.width >= 1) UNITS_STD_FMT::format_to(out, "{}", specs.width);
|
||||
return UNITS_STD_FMT::format_to(out, "}}");
|
||||
}
|
||||
|
||||
template<auto Reference, typename Rep, typename Locale, typename CharT, typename OutputIt>
|
||||
@@ -254,18 +254,18 @@ template<std::input_iterator It, std::sentinel_for<It> S>
|
||||
{
|
||||
auto it = find_first_of(begin, end, modifiers.begin(), modifiers.end());
|
||||
if (it != end && find_first_of(it + 1, end, modifiers.begin(), modifiers.end()) != end)
|
||||
throw STD_FMT::format_error("only one of '" + std::string(modifiers) +
|
||||
"' unit modifiers may be used in the format spec");
|
||||
throw UNITS_STD_FMT::format_error("only one of '" + std::string(modifiers) +
|
||||
"' unit modifiers may be used in the format spec");
|
||||
return it;
|
||||
}
|
||||
|
||||
} // namespace mp_units::detail
|
||||
|
||||
template<auto Reference, typename Rep, typename CharT>
|
||||
struct STD_FMT::formatter<mp_units::quantity<Reference, Rep>, CharT> {
|
||||
struct UNITS_STD_FMT::formatter<mp_units::quantity<Reference, Rep>, CharT> {
|
||||
private:
|
||||
using quantity = mp_units::quantity<Reference, Rep>;
|
||||
using iterator = TYPENAME STD_FMT::basic_format_parse_context<CharT>::iterator;
|
||||
using iterator = TYPENAME UNITS_STD_FMT::basic_format_parse_context<CharT>::iterator;
|
||||
|
||||
bool quantity_value = false;
|
||||
bool quantity_unit = false;
|
||||
@@ -274,7 +274,7 @@ private:
|
||||
|
||||
struct spec_handler {
|
||||
formatter& f;
|
||||
STD_FMT::basic_format_parse_context<CharT>& context;
|
||||
UNITS_STD_FMT::basic_format_parse_context<CharT>& context;
|
||||
|
||||
constexpr void on_fill(std::basic_string_view<CharT> fill) { f.specs.global.fill = fill; }
|
||||
constexpr void on_align(mp_units::detail::fmt_align align) { f.specs.global.align = align; }
|
||||
@@ -290,7 +290,7 @@ private:
|
||||
if (valid_rep_types.find(type) != std::string_view::npos) {
|
||||
f.specs.rep.type = type;
|
||||
} else {
|
||||
throw STD_FMT::format_error("invalid quantity type specifier");
|
||||
throw UNITS_STD_FMT::format_error("invalid quantity type specifier");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ private:
|
||||
constexpr auto valid_modifiers = std::string_view{"UAoansd"};
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
if (valid_modifiers.find(*it) == std::string_view::npos)
|
||||
throw STD_FMT::format_error("invalid unit modifier specified");
|
||||
throw UNITS_STD_FMT::format_error("invalid unit modifier specified");
|
||||
}
|
||||
|
||||
if (auto it = mp_units::detail::at_most_one_of(begin, end, "UA"); it != end) {
|
||||
@@ -350,7 +350,7 @@ private:
|
||||
f.specs.unit.separator = mp_units::unit_symbol_separator::space;
|
||||
else {
|
||||
if (f.specs.unit.encoding == mp_units::text_encoding::ascii)
|
||||
throw STD_FMT::format_error("dot unit separator allowed only for Unicode encoding");
|
||||
throw UNITS_STD_FMT::format_error("dot unit separator allowed only for Unicode encoding");
|
||||
f.specs.unit.separator = mp_units::unit_symbol_separator::dot;
|
||||
}
|
||||
}
|
||||
@@ -359,7 +359,7 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr std::pair<iterator, iterator> do_parse(STD_FMT::basic_format_parse_context<CharT>& ctx)
|
||||
[[nodiscard]] constexpr std::pair<iterator, iterator> do_parse(UNITS_STD_FMT::basic_format_parse_context<CharT>& ctx)
|
||||
{
|
||||
auto begin = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
@@ -409,7 +409,7 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
[[nodiscard]] constexpr auto parse(STD_FMT::basic_format_parse_context<CharT>& ctx)
|
||||
[[nodiscard]] constexpr auto parse(UNITS_STD_FMT::basic_format_parse_context<CharT>& ctx)
|
||||
{
|
||||
auto range = do_parse(ctx);
|
||||
if (range.first != range.second)
|
||||
@@ -446,8 +446,9 @@ public:
|
||||
mp_units::detail::format_global_buffer<CharT>(std::back_inserter(global_format_buffer), specs.global);
|
||||
|
||||
// Format the `quantity buffer` using specs from `global_format_buffer`
|
||||
// In the example, equivalent to STD_FMT::format("{:*^10}", "1.2_m")
|
||||
return STD_FMT::vformat_to(ctx.out(), global_format_buffer, STD_FMT::make_format_args(quantity_buffer));
|
||||
// In the example, equivalent to UNITS_STD_FMT::format("{:*^10}", "1.2_m")
|
||||
return UNITS_STD_FMT::vformat_to(ctx.out(), global_format_buffer,
|
||||
UNITS_STD_FMT::make_format_args(quantity_buffer));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -49,12 +49,12 @@ std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>&
|
||||
{
|
||||
if (os.width()) {
|
||||
// std::setw() applies to the whole quantity output so it has to be first put into std::string
|
||||
std::basic_ostringstream<CharT, Traits> s;
|
||||
s.flags(os.flags());
|
||||
s.imbue(os.getloc());
|
||||
s.precision(os.precision());
|
||||
detail::to_stream(s, q);
|
||||
return os << s.str();
|
||||
std::basic_ostringstream<CharT, Traits> oss;
|
||||
oss.flags(os.flags());
|
||||
oss.imbue(os.getloc());
|
||||
oss.precision(os.precision());
|
||||
detail::to_stream(oss, q);
|
||||
return os << std::move(oss).str();
|
||||
}
|
||||
|
||||
detail::to_stream(os, q);
|
||||
|
||||
@@ -23,7 +23,9 @@
|
||||
cmake_minimum_required(VERSION 3.19)
|
||||
|
||||
# find dependencies
|
||||
find_package(gsl-lite CONFIG REQUIRED)
|
||||
if(NOT TARGET gsl::gsl-lite)
|
||||
find_package(gsl-lite CONFIG REQUIRED)
|
||||
endif()
|
||||
|
||||
# check if libc++ is being used
|
||||
include(CheckLibcxxInUse)
|
||||
@@ -81,7 +83,9 @@ target_include_directories(
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
if(${projectPrefix}LIBCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "14")
|
||||
find_package(range-v3 CONFIG REQUIRED)
|
||||
if(NOT TARGET range-v3::range-v3)
|
||||
find_package(range-v3 CONFIG REQUIRED)
|
||||
endif()
|
||||
target_link_libraries(mp-units-core INTERFACE range-v3::range-v3)
|
||||
endif()
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
|
||||
+13
-3
@@ -96,7 +96,7 @@
|
||||
#include <compare>
|
||||
#include <concepts>
|
||||
|
||||
#if UNITS_COMP_MSVC || UNITS_COMP_CLANG
|
||||
#if UNITS_COMP_MSVC || (UNITS_COMP_CLANG && UNITS_COMP_CLANG < 16)
|
||||
|
||||
#define TYPENAME typename
|
||||
|
||||
@@ -108,11 +108,21 @@
|
||||
|
||||
#if UNITS_COMP_MSVC
|
||||
|
||||
#define UNITS_MSVC_WORKAROUND(X)
|
||||
#define UNITS_CONSTRAINED_AUTO_WORKAROUND(X)
|
||||
|
||||
#else
|
||||
|
||||
#define UNITS_MSVC_WORKAROUND(X) X
|
||||
#define UNITS_CONSTRAINED_AUTO_WORKAROUND(X) X
|
||||
|
||||
#endif
|
||||
|
||||
#if UNITS_COMP_MSVC || (UNITS_COMP_GCC && UNITS_COMP_GCC < 11)
|
||||
|
||||
#define UNITS_CONSTRAINED_NTTP_WORKAROUND(X)
|
||||
|
||||
#else
|
||||
|
||||
#define UNITS_CONSTRAINED_NTTP_WORKAROUND(X) X
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
#include <cstdint>
|
||||
#include <numbers>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace mp_units {
|
||||
|
||||
@@ -243,10 +242,10 @@ using widen_t = conditional<std::is_arithmetic_v<T>,
|
||||
template<typename T>
|
||||
[[nodiscard]] consteval T int_power(T base, std::integral auto exp)
|
||||
{
|
||||
// As this function should only be called at compile time, the exceptions herein function as
|
||||
// "parameter-compatible static_asserts", and should not result in exceptions at runtime.
|
||||
// As this function should only be called at compile time, the terminations herein function as
|
||||
// "parameter-compatible static_asserts", and should not result in terminations at runtime.
|
||||
if (exp < 0) {
|
||||
throw std::invalid_argument{"int_power only supports positive integer powers"};
|
||||
std::terminate(); // int_power only supports positive integer powers
|
||||
}
|
||||
|
||||
constexpr auto checked_multiply = [](auto a, auto b) {
|
||||
@@ -254,7 +253,7 @@ template<typename T>
|
||||
UNITS_DIAGNOSTIC_PUSH
|
||||
UNITS_DIAGNOSTIC_IGNORE_FLOAT_EQUAL
|
||||
if (result / a != b) {
|
||||
throw std::overflow_error{"Wraparound detected"};
|
||||
std::terminate(); // Wraparound detected
|
||||
}
|
||||
UNITS_DIAGNOSTIC_POP
|
||||
return result;
|
||||
@@ -284,15 +283,15 @@ template<typename T>
|
||||
// need to write a custom function.
|
||||
//
|
||||
// Note that since this function should only be called at compile time, the point of these
|
||||
// exceptions is to act as "static_assert substitutes", not to throw actual exceptions at runtime.
|
||||
// terminations is to act as "static_assert substitutes", not to actually terminate at runtime.
|
||||
const auto exp = get_exponent(el);
|
||||
if (exp.den != 1) {
|
||||
throw std::invalid_argument{"Rational powers not yet supported"};
|
||||
std::terminate(); // Rational powers not yet supported
|
||||
}
|
||||
|
||||
if (exp.num < 0) {
|
||||
if constexpr (std::is_integral_v<T>) {
|
||||
throw std::invalid_argument{"Cannot represent reciprocal as integer"};
|
||||
std::terminate(); // Cannot represent reciprocal as integer
|
||||
} else {
|
||||
return T{1} / compute_base_power<T>(inverse(el));
|
||||
}
|
||||
@@ -311,11 +310,11 @@ template<typename To, typename From>
|
||||
requires(!std::is_integral_v<To> || std::is_integral_v<From>)
|
||||
[[nodiscard]] consteval To checked_static_cast(From x)
|
||||
{
|
||||
// This function should only ever be called at compile time. The purpose of these exceptions is
|
||||
// This function should only ever be called at compile time. The purpose of these terminations is
|
||||
// to produce compiler errors, because we cannot `static_assert` on function arguments.
|
||||
if constexpr (std::is_integral_v<To>) {
|
||||
if (!std::in_range<To>(x)) {
|
||||
throw std::invalid_argument{"Cannot represent magnitude in this type"};
|
||||
std::terminate(); // Cannot represent magnitude in this type
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,7 +472,7 @@ void to_base_specialization_of_magnitude(const volatile magnitude<Ms...>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_specialization_of_magnitude =
|
||||
requires(T * t) { to_base_specialization_of_magnitude(t); };
|
||||
requires(T* t) { to_base_specialization_of_magnitude(t); };
|
||||
|
||||
template<typename T>
|
||||
requires is_derived_from_specialization_of_magnitude<T>
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace mp_units {
|
||||
*/
|
||||
template<Magnitude auto M, Unit U>
|
||||
struct scaled_unit {
|
||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = M;
|
||||
static constexpr UNITS_CONSTRAINED_AUTO_WORKAROUND(Magnitude) auto mag = M;
|
||||
static constexpr U reference_unit{};
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user