merge branch master

This commit is contained in:
Mateusz Pusz committed 2023-05-26 13:53:52 +02:00
1 parent b7e467ff42
commit 561fbf7c93
68 files changed
+1426 -812

No files matched your search

+3 -1
View File
@@ -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()
+21 -21
View File
@@ -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
+23 -8
View File
@@ -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
+35 -34
View File
@@ -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));
}
}
};
+6 -6
View File
@@ -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);
+6 -2
View File
@@ -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
View File
@@ -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
+10 -11
View File
@@ -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>
+1 -1
View File
@@ -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{};
};