mirror of
https://github.com/mpusz/mp-units.git
synced 2025-06-24 16:51:33 +02:00
refactor: code refactored to comply with clang-tidy
This commit is contained in:
47
.clang-tidy
47
.clang-tidy
@ -1,23 +1,48 @@
|
||||
---
|
||||
Checks: '
|
||||
*,
|
||||
-abseil-*,
|
||||
-altera-*,
|
||||
-cert-dcl37-c,
|
||||
-cert-dcl50-cpp,
|
||||
-cert-dcl51-cpp,
|
||||
-cert-dcl58-cpp,
|
||||
-cppcoreguidelines-avoid-const-or-ref-data-members,
|
||||
-cppcoreguidelines-avoid-do-while,
|
||||
-cppcoreguidelines-pro-bounds-constant-array-index,
|
||||
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
|
||||
-cppcoreguidelines-pro-type-vararg,
|
||||
-llvm-header-guard,
|
||||
-llvm-include-order,
|
||||
-bugprone-branch-clone,
|
||||
-bugprone-reserved-identifier,
|
||||
-modernize-use-trailing-return-type,
|
||||
-llvm-namespace-comment,
|
||||
-llvmlibc-*,
|
||||
-fuchsia-default-arguments-calls,
|
||||
-fuchsia-default-arguments-declarations,
|
||||
-fuchsia-multiple-inheritance,
|
||||
-fuchsia-overloaded-operator,
|
||||
-fuchsia-statically-constructed-objects,
|
||||
-fuchsia-trailing-return,
|
||||
-*-special-member-functions,
|
||||
-cppcoreguidelines-owning-memory,
|
||||
-cert-err58-cpp,
|
||||
-cert-dcl37-c,
|
||||
-cert-dcl51-cpp
|
||||
-google-readability-namespace-comments,
|
||||
-google-readability-todo,
|
||||
-google-runtime-int,
|
||||
-hicpp-signed-bitwise,
|
||||
-hicpp-vararg,
|
||||
-misc-include-cleaner,
|
||||
-modernize-use-trailing-return-type,
|
||||
-modernize-use-designated-initializers,
|
||||
-readability-identifier-length,
|
||||
-readability-isolate-declaration,
|
||||
-readability-magic-numbers,
|
||||
-readability-static-accessed-through-instance,
|
||||
-*-braces-around-statements,
|
||||
-*-named-parameter,
|
||||
-*-uppercase-literal-suffix,
|
||||
-misc-no-recursion
|
||||
'
|
||||
CheckOptions:
|
||||
- key: hicpp-signed-bitwise.IgnorePositiveIntegerLiterals
|
||||
value: true
|
||||
- key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
|
||||
value: true
|
||||
WarningsAsErrors: '*'
|
||||
HeaderFilterRegex: '.*'
|
||||
AnalyzeTemporaryDtors: false
|
||||
FormatStyle: file
|
||||
...
|
||||
|
@ -28,7 +28,12 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
||||
set(projectPrefix MP_UNITS_)
|
||||
|
||||
option(${projectPrefix}DEV_BUILD_LA "Build code depending on the linear algebra library" ON)
|
||||
option(${projectPrefix}DEV_IWYU "Enables include-what-you-use" OFF)
|
||||
option(${projectPrefix}DEV_CLANG_TIDY "Enables clang-tidy" OFF)
|
||||
|
||||
message(STATUS "${projectPrefix}DEV_BUILD_LA: ${${projectPrefix}DEV_BUILD_LA}")
|
||||
message(STATUS "${projectPrefix}DEV_IWYU: ${${projectPrefix}DEV_IWYU}")
|
||||
message(STATUS "${projectPrefix}DEV_CLANG_TIDY: ${${projectPrefix}DEV_CLANG_TIDY}")
|
||||
|
||||
# make sure that the file is being used as an entry point
|
||||
include(modern_project_structure)
|
||||
@ -38,9 +43,6 @@ ensure_entry_point()
|
||||
include(ccache)
|
||||
enable_ccache(BASE_DIR ${PROJECT_SOURCE_DIR})
|
||||
|
||||
# enable include-what-you-use
|
||||
option(${projectPrefix}DEV_IWYU "Enables include-what-you-use" OFF)
|
||||
|
||||
if(${projectPrefix}DEV_IWYU)
|
||||
set(${projectPrefix}BUILD_AS_SYSTEM_HEADERS ON)
|
||||
|
||||
@ -51,6 +53,9 @@ if(${projectPrefix}DEV_IWYU)
|
||||
MAX_LINE_LENGTH 120
|
||||
NO_COMMENTS
|
||||
)
|
||||
elseif(${projectPrefix}DEV_CLANG_TIDY)
|
||||
include(static_analysis)
|
||||
enable_clang_tidy()
|
||||
else()
|
||||
# set restrictive compilation warnings
|
||||
# (some gcc warnings are not recognized by IWYU which is based on clang)
|
||||
@ -58,8 +63,6 @@ else()
|
||||
set_warnings()
|
||||
endif()
|
||||
|
||||
# enable_clang_tidy()
|
||||
|
||||
# add project code
|
||||
add_subdirectory(src)
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
cmake_minimum_required(VERSION 3.3)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
macro(enable_clang_tidy)
|
||||
find_program(clang_tidy_cmd NAMES "clang-tidy")
|
||||
|
6
example/.clang-tidy
Normal file
6
example/.clang-tidy
Normal file
@ -0,0 +1,6 @@
|
||||
Checks: '
|
||||
-bugprone-exception-escape,
|
||||
-cppcoreguidelines-avoid-magic-numbers,
|
||||
-google-build-using-namespace
|
||||
'
|
||||
InheritParentConfig: true
|
@ -35,7 +35,7 @@ namespace {
|
||||
|
||||
template<mp_units::Quantity Target, mp_units::Quantity Source>
|
||||
requires std::constructible_from<Target, Source>
|
||||
inline constexpr double conversion_factor(Target, Source)
|
||||
constexpr double conversion_factor(Target, Source)
|
||||
{
|
||||
return (1. * Source::reference).force_numerical_value_in(Target::unit);
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ inline constexpr auto JPY = japanese_jen;
|
||||
static_assert(!std::equality_comparable_with<quantity<euro, int>, quantity<us_dollar, int>>);
|
||||
|
||||
|
||||
#if 0
|
||||
#if 0 // NOLINT(readability-avoid-unconditional-preprocessor-if)
|
||||
|
||||
// if you have only a few currencies to handle
|
||||
template<Unit auto From, Unit auto To>
|
||||
@ -76,12 +76,12 @@ template<Unit auto From, Unit auto To>
|
||||
template<Unit auto From, Unit auto To>
|
||||
[[nodiscard]] double exchange_rate()
|
||||
{
|
||||
static std::map<std::pair<std::string_view, std::string_view>, double> rates = {
|
||||
static const std::map<std::pair<std::string_view, std::string_view>, double> rates = {
|
||||
{{"USD", "EUR"}, 0.9215}, {{"EUR", "USD"}, 1.0848},
|
||||
// ...
|
||||
};
|
||||
|
||||
return rates[std::make_pair(to_string_view(From), to_string_view(To))];
|
||||
return rates.at(std::make_pair(to_string_view(From), to_string_view(To)));
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -103,8 +103,8 @@ int main()
|
||||
{
|
||||
using namespace unit_symbols;
|
||||
|
||||
quantity_point price_usd{100 * USD};
|
||||
quantity_point price_euro = exchange_to<euro>(price_usd);
|
||||
const quantity_point price_usd{100 * USD};
|
||||
const quantity_point price_euro = exchange_to<euro>(price_usd);
|
||||
|
||||
std::cout << price_usd.quantity_from_zero() << " -> " << price_euro.quantity_from_zero() << "\n";
|
||||
// std::cout << price_usd.quantity_from_zero() + price_euro.quantity_from_zero() << "\n"; // does
|
||||
|
@ -181,7 +181,7 @@ void example()
|
||||
|
||||
for (const auto& g : gliders) {
|
||||
for (const auto& c : weather_conditions) {
|
||||
std::string txt = "Scenario: Glider = " + g.name + ", Weather = " + c.first;
|
||||
const std::string txt = "Scenario: Glider = " + g.name + ", Weather = " + c.first;
|
||||
std::cout << txt << "\n";
|
||||
std::cout << MP_UNITS_STD_FMT::format("{0:=^{1}}\n\n", "", txt.size());
|
||||
|
||||
|
@ -111,10 +111,11 @@ public:
|
||||
const waypoint* end_;
|
||||
distance length_ = geographic::spherical_distance(begin().pos, end().pos);
|
||||
public:
|
||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||
leg(const waypoint& b, const waypoint& e) noexcept : begin_(&b), end_(&e) {}
|
||||
constexpr const waypoint& begin() const { return *begin_; };
|
||||
constexpr const waypoint& end() const { return *end_; }
|
||||
constexpr distance get_distance() const { return length_; }
|
||||
[[nodiscard]] constexpr const waypoint& begin() const { return *begin_; };
|
||||
[[nodiscard]] constexpr const waypoint& end() const { return *end_; }
|
||||
[[nodiscard]] constexpr distance get_distance() const { return length_; }
|
||||
};
|
||||
using legs = std::vector<leg>;
|
||||
|
||||
@ -126,19 +127,19 @@ public:
|
||||
|
||||
task(std::initializer_list<waypoint> wpts) : waypoints_(wpts) {}
|
||||
|
||||
const waypoints& get_waypoints() const { return waypoints_; }
|
||||
const legs& get_legs() const { return legs_; }
|
||||
[[nodiscard]] const waypoints& get_waypoints() const { return waypoints_; }
|
||||
[[nodiscard]] const legs& get_legs() const { return legs_; }
|
||||
|
||||
const waypoint& get_start() const { return waypoints_.front(); }
|
||||
const waypoint& get_finish() const { return waypoints_.back(); }
|
||||
[[nodiscard]] const waypoint& get_start() const { return waypoints_.front(); }
|
||||
[[nodiscard]] const waypoint& get_finish() const { return waypoints_.back(); }
|
||||
|
||||
distance get_distance() const { return length_; }
|
||||
[[nodiscard]] distance get_distance() const { return length_; }
|
||||
|
||||
distance get_leg_dist_offset(std::size_t leg_index) const
|
||||
[[nodiscard]] distance get_leg_dist_offset(std::size_t leg_index) const
|
||||
{
|
||||
return leg_index == 0 ? distance{} : leg_total_distances_[leg_index - 1];
|
||||
}
|
||||
std::size_t get_leg_index(distance dist) const
|
||||
[[nodiscard]] std::size_t get_leg_index(distance dist) const
|
||||
{
|
||||
return static_cast<std::size_t>(
|
||||
std::ranges::distance(leg_total_distances_.cbegin(), std::ranges::lower_bound(leg_total_distances_, dist)));
|
||||
|
@ -84,20 +84,14 @@ template<class CharT, class Traits, typename T>
|
||||
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const latitude<T>& lat)
|
||||
{
|
||||
const auto& q = lat.quantity_ref_from(geographic::equator);
|
||||
if (is_gteq_zero(q))
|
||||
return os << q << " N";
|
||||
else
|
||||
return os << -q << " S";
|
||||
return (is_gteq_zero(q)) ? (os << q << " N") : (os << -q << " S");
|
||||
}
|
||||
|
||||
template<class CharT, class Traits, typename T>
|
||||
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const longitude<T>& lon)
|
||||
{
|
||||
const auto& q = lon.quantity_ref_from(geographic::prime_meridian);
|
||||
if (is_gteq_zero(q))
|
||||
return os << q << " E";
|
||||
else
|
||||
return os << -q << " W";
|
||||
return (is_gteq_zero(q)) ? (os << q << " E") : (os << -q << " W");
|
||||
}
|
||||
|
||||
inline namespace literals {
|
||||
@ -174,6 +168,7 @@ struct position {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||
distance spherical_distance(position<T> from, position<T> to)
|
||||
{
|
||||
using namespace mp_units;
|
||||
|
@ -32,7 +32,6 @@
|
||||
import mp_units.core;
|
||||
#else
|
||||
#include <mp-units/bits/fmt.h>
|
||||
#include <mp-units/bits/hacks.h>
|
||||
#include <mp-units/framework/customization_points.h>
|
||||
#endif
|
||||
|
||||
@ -82,12 +81,14 @@ public:
|
||||
|
||||
#else
|
||||
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
constexpr explicit(false) operator T() const& noexcept(std::is_nothrow_copy_constructible_v<T>)
|
||||
requires std::copyable<T>
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
constexpr explicit(false) operator T() && noexcept(std::is_nothrow_move_constructible_v<T>)
|
||||
{
|
||||
return std::move(value_);
|
||||
@ -96,14 +97,14 @@ public:
|
||||
#endif
|
||||
|
||||
constexpr T& value() & noexcept = delete;
|
||||
constexpr const T& value() const& noexcept { return value_; }
|
||||
constexpr T&& value() && noexcept { return std::move(value_); }
|
||||
constexpr const T&& value() const&& noexcept { return std::move(value_); }
|
||||
[[nodiscard]] constexpr const T& value() const& noexcept { return value_; }
|
||||
[[nodiscard]] constexpr T&& value() && noexcept { return std::move(value_); }
|
||||
[[nodiscard]] constexpr const T&& value() const&& noexcept { return std::move(value_); }
|
||||
|
||||
bool operator==(const validated_type&) const
|
||||
[[nodiscard]] bool operator==(const validated_type&) const
|
||||
requires std::equality_comparable<T>
|
||||
= default;
|
||||
auto operator<=>(const validated_type&) const
|
||||
[[nodiscard]] auto operator<=>(const validated_type&) const
|
||||
requires std::three_way_comparable<T>
|
||||
= default;
|
||||
};
|
||||
|
@ -45,11 +45,13 @@ public:
|
||||
|
||||
measurement() = default;
|
||||
|
||||
constexpr explicit measurement(value_type val, const value_type& err = {}) : value_(std::move(val))
|
||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||
constexpr explicit measurement(value_type val, const value_type& err = {}) :
|
||||
value_(std::move(val)), uncertainty_([&] {
|
||||
using namespace std;
|
||||
return abs(err);
|
||||
}())
|
||||
{
|
||||
// it sucks that using declaration cannot be provided for a constructor initializer list
|
||||
using namespace std;
|
||||
uncertainty_ = abs(err);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const value_type& value() const { return value_; }
|
||||
|
@ -40,8 +40,6 @@ using namespace mp_units;
|
||||
using mp_units::si::unit_symbols::cm;
|
||||
using mp_units::si::unit_symbols::eV;
|
||||
using mp_units::si::unit_symbols::K;
|
||||
using mp_units::si::unit_symbols::kJ;
|
||||
using mp_units::si::unit_symbols::mol;
|
||||
using mp_units::si::unit_symbols::THz;
|
||||
using mp_units::si::unit_symbols::um;
|
||||
|
||||
|
@ -52,7 +52,7 @@ void si_example()
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
constexpr Unit auto GeV = si::giga<si::electronvolt>;
|
||||
constexpr quantity c = 1. * si::si2019::speed_of_light_in_vacuum;
|
||||
quantity c2 = pow<2>(c);
|
||||
const quantity c2 = pow<2>(c);
|
||||
|
||||
const quantity p1 = isq::momentum(4. * GeV / c);
|
||||
const QuantityOf<isq::mass> auto m1 = 3. * GeV / c2;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "ranged_representation.h"
|
||||
#include <mp-units/compat_macros.h>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#ifdef MP_UNITS_MODULES
|
||||
@ -39,14 +40,14 @@ using namespace geographic;
|
||||
|
||||
// **** HAE ****
|
||||
|
||||
enum class earth_gravity_model { egm84_15, egm95_5, egm2008_1 };
|
||||
enum class earth_gravity_model : std::int8_t { egm84_15, egm95_5, egm2008_1 };
|
||||
|
||||
template<earth_gravity_model M>
|
||||
struct height_above_ellipsoid_t : absolute_point_origin<height_above_ellipsoid_t<M>, isq::altitude> {
|
||||
static constexpr earth_gravity_model egm = M;
|
||||
};
|
||||
template<earth_gravity_model M>
|
||||
inline constexpr height_above_ellipsoid_t<M> height_above_ellipsoid;
|
||||
inline constexpr height_above_ellipsoid_t<M> height_above_ellipsoid; // NOLINT(google-readability-casting)
|
||||
|
||||
template<earth_gravity_model M>
|
||||
using hae_altitude = quantity_point<isq::altitude[si::metre], height_above_ellipsoid<M>>;
|
||||
@ -141,12 +142,12 @@ class unmanned_aerial_vehicle {
|
||||
msl_altitude launch_ = current_;
|
||||
public:
|
||||
void take_off(msl_altitude alt) { launch_ = alt; }
|
||||
msl_altitude take_off() const { return launch_; }
|
||||
[[nodiscard]] msl_altitude take_off() const { return launch_; }
|
||||
|
||||
void current(msl_altitude alt) { current_ = alt; }
|
||||
msl_altitude current() const { return current_; }
|
||||
[[nodiscard]] msl_altitude current() const { return current_; }
|
||||
|
||||
hal_altitude hal() const { return height_above_launch + (current_ - launch_); }
|
||||
[[nodiscard]] hal_altitude hal() const { return height_above_launch + (current_ - launch_); }
|
||||
};
|
||||
|
||||
|
||||
@ -160,7 +161,7 @@ int main()
|
||||
uav.current(mean_sea_level + 10'000 * ft);
|
||||
std::cout << MP_UNITS_STD_FMT::format("hal = {::N[.2f]}\n", uav.hal());
|
||||
|
||||
msl_altitude ground_level = mean_sea_level + 123 * m;
|
||||
const msl_altitude ground_level = mean_sea_level + 123 * m;
|
||||
std::cout << MP_UNITS_STD_FMT::format("agl = {::N[.2f]}\n", uav.current() - ground_level);
|
||||
|
||||
struct waypoint {
|
||||
@ -169,7 +170,7 @@ int main()
|
||||
msl_altitude msl_alt;
|
||||
};
|
||||
|
||||
waypoint wpt = {"EPPR", {54.24772_N, 18.6745_E}, mean_sea_level + 16. * ft};
|
||||
const waypoint wpt = {"EPPR", {54.24772_N, 18.6745_E}, mean_sea_level + 16. * ft};
|
||||
std::cout << MP_UNITS_STD_FMT::format("{}: {} {}, {::N[.2f]}, {::N[.2f]}\n", wpt.name, wpt.pos.lat, wpt.pos.lon,
|
||||
wpt.msl_alt, to_hae<earth_gravity_model::egm2008_1>(wpt.msl_alt, wpt.pos));
|
||||
}
|
||||
|
@ -27,13 +27,16 @@
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-type-union-access)
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/compat_macros.h>
|
||||
#include <mp-units/ext/algorithm.h>
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <string_view>
|
||||
#endif
|
||||
@ -42,8 +45,8 @@
|
||||
|
||||
namespace mp_units::detail {
|
||||
|
||||
enum class fmt_align { none, left, right, center, numeric };
|
||||
enum class fmt_arg_id_kind {
|
||||
enum class fmt_align : std::int8_t { none, left, right, center, numeric };
|
||||
enum class fmt_arg_id_kind : std::int8_t {
|
||||
none,
|
||||
#if MP_UNITS_USE_FMTLIB
|
||||
name,
|
||||
@ -61,7 +64,7 @@ struct fmt_arg_ref {
|
||||
#endif
|
||||
|
||||
constexpr value() {}
|
||||
constexpr value(int idx) : index(idx) {}
|
||||
constexpr explicit value(int idx) : index(idx) {}
|
||||
#if MP_UNITS_USE_FMTLIB
|
||||
constexpr value(std::basic_string_view<Char> n) : name(n) {}
|
||||
#endif
|
||||
@ -86,7 +89,7 @@ struct fill_t {
|
||||
private:
|
||||
static constexpr size_t max_size = 4 / sizeof(Char);
|
||||
// At most one codepoint (so one char32_t or four utf-8 char8_t)
|
||||
Char data_[max_size] = {Char{' '}};
|
||||
std::array<Char, max_size> data_ = {Char{' '}};
|
||||
unsigned char size_ = 1;
|
||||
|
||||
public:
|
||||
@ -100,15 +103,15 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr size_t size() const { return size_; }
|
||||
[[nodiscard]] constexpr const Char* data() const { return data_; }
|
||||
[[nodiscard]] constexpr const Char* data() const { return data_.data(); }
|
||||
|
||||
[[nodiscard]] constexpr Char& operator[](size_t index) { return data_[index]; }
|
||||
[[nodiscard]] constexpr const Char& operator[](size_t index) const { return data_[index]; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_integer = std::is_integral<T>::value && !std::is_same<T, bool>::value &&
|
||||
!std::is_same<T, char>::value && !std::is_same<T, wchar_t>::value;
|
||||
inline constexpr bool is_integer =
|
||||
std::is_integral_v<T> && !std::is_same_v<T, bool> && !std::is_same_v<T, char> && !std::is_same_v<T, wchar_t>;
|
||||
|
||||
// Converts a character to ASCII. Returns a number > 127 on conversion failure.
|
||||
template<std::integral Char>
|
||||
@ -211,7 +214,7 @@ template<typename Char>
|
||||
}
|
||||
|
||||
template<typename Char, typename Handler>
|
||||
[[nodiscard]] constexpr const Char* do_parse_arg_id(const Char* begin, const Char* end, Handler&& handler)
|
||||
[[nodiscard]] constexpr const Char* do_parse_arg_id(const Char* begin, const Char* end, Handler& handler)
|
||||
{
|
||||
Char c = *begin;
|
||||
if (c >= '0' && c <= '9') {
|
||||
@ -223,8 +226,7 @@ template<typename Char, typename Handler>
|
||||
++begin;
|
||||
if (begin == end || (*begin != '}' && *begin != ':'))
|
||||
MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("invalid format string"));
|
||||
else
|
||||
handler.on_index(index);
|
||||
handler.on_index(index);
|
||||
return begin;
|
||||
}
|
||||
if (c == '%') return begin; // mp-units extension
|
||||
@ -246,7 +248,7 @@ template<typename Char, typename Handler>
|
||||
}
|
||||
|
||||
template<typename Char, typename Handler>
|
||||
[[nodiscard]] constexpr const Char* parse_arg_id(const Char* begin, const Char* end, Handler&& handler)
|
||||
[[nodiscard]] constexpr const Char* parse_arg_id(const Char* begin, const Char* end, Handler& handler)
|
||||
{
|
||||
gsl_Expects(begin != end);
|
||||
Char c = *begin;
|
||||
@ -262,7 +264,7 @@ struct dynamic_spec_id_handler {
|
||||
|
||||
constexpr void on_auto()
|
||||
{
|
||||
int id = MP_UNITS_FMT_FROM_ARG_ID(ctx.next_arg_id());
|
||||
const int id = MP_UNITS_FMT_FROM_ARG_ID(ctx.next_arg_id());
|
||||
ref = fmt_arg_ref<Char>(id);
|
||||
#if MP_UNITS_USE_FMTLIB || __cpp_lib_format >= 202305L
|
||||
ctx.check_dynamic_spec(id);
|
||||
@ -292,7 +294,7 @@ template<typename Char>
|
||||
{
|
||||
gsl_Expects(begin != end);
|
||||
if ('0' <= *begin && *begin <= '9') {
|
||||
int val = ::mp_units::detail::parse_nonnegative_int(begin, end, -1);
|
||||
const int val = ::mp_units::detail::parse_nonnegative_int(begin, end, -1);
|
||||
if (val != -1)
|
||||
value = val;
|
||||
else
|
||||
@ -312,9 +314,9 @@ template<std::input_iterator It>
|
||||
constexpr int code_point_length(It begin)
|
||||
{
|
||||
if constexpr (sizeof(std::iter_value_t<It>) != 1) return 1;
|
||||
constexpr char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0};
|
||||
int len = lengths[static_cast<unsigned char>(*begin) >> 3];
|
||||
constexpr std::array lengths = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0};
|
||||
const int len = lengths[static_cast<unsigned char>(*begin) >> 3];
|
||||
|
||||
// Compute the pointer to the next character early so that the next
|
||||
// iteration can start working on the next character. Neither Clang
|
||||
@ -357,9 +359,8 @@ template<typename Char, typename Specs>
|
||||
++begin;
|
||||
}
|
||||
break;
|
||||
} else if (p == begin) {
|
||||
break;
|
||||
}
|
||||
if (p == begin) break;
|
||||
p = begin;
|
||||
}
|
||||
if (align == fmt_align::none) align = default_align; // mp-units extension
|
||||
@ -368,3 +369,4 @@ template<typename Char, typename Specs>
|
||||
}
|
||||
|
||||
} // namespace mp_units::detail
|
||||
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-type-union-access)
|
||||
|
@ -20,6 +20,7 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
// NOLINTBEGIN(bugprone-reserved-identifier, cppcoreguidelines-macro-usage)
|
||||
#pragma once
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
@ -122,3 +123,4 @@
|
||||
#define MP_UNITS_API_NO_CRTP 1
|
||||
|
||||
#endif
|
||||
// NOLINTEND(bugprone-reserved-identifier, cppcoreguidelines-macro-usage)
|
||||
|
@ -42,17 +42,18 @@ template<typename T>
|
||||
|
||||
[[nodiscard]] consteval std::intmax_t safe_multiply(std::intmax_t lhs, std::intmax_t rhs)
|
||||
{
|
||||
constexpr std::intmax_t c = std::uintmax_t(1) << (sizeof(std::intmax_t) * 4);
|
||||
constexpr std::intmax_t c = std::uintmax_t{1} << (sizeof(std::intmax_t) * 4);
|
||||
|
||||
const std::intmax_t a0 = abs(lhs) % c;
|
||||
const std::intmax_t a1 = abs(lhs) / c;
|
||||
const std::intmax_t b0 = abs(rhs) % c;
|
||||
const std::intmax_t b1 = abs(rhs) / c;
|
||||
|
||||
gsl_Assert(a1 == 0 || b1 == 0); // overflow in multiplication
|
||||
gsl_Assert(a0 * b1 + b0 * a1 < (c >> 1)); // overflow in multiplication
|
||||
gsl_Assert(b0 * a0 <= INTMAX_MAX); // overflow in multiplication
|
||||
gsl_Assert((a0 * b1 + b0 * a1) * c <= INTMAX_MAX - b0 * a0); // overflow in multiplication
|
||||
// overflow in multiplication
|
||||
gsl_Assert(a1 == 0 || b1 == 0);
|
||||
gsl_Assert(a0 * b1 + b0 * a1 < (c >> 1)); // NOLINT(hicpp-signed-bitwise)
|
||||
gsl_Assert(b0 * a0 <= INTMAX_MAX);
|
||||
gsl_Assert((a0 * b1 + b0 * a1) * c <= INTMAX_MAX - b0 * a0);
|
||||
|
||||
return lhs * rhs;
|
||||
}
|
||||
@ -68,13 +69,14 @@ MP_UNITS_EXPORT struct ratio {
|
||||
std::intmax_t num;
|
||||
std::intmax_t den;
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||
MP_UNITS_CONSTEVAL explicit(false) ratio(std::intmax_t n, std::intmax_t d = 1) : num{n}, den{d}
|
||||
{
|
||||
gsl_Expects(den != 0);
|
||||
if (num == 0)
|
||||
den = 1;
|
||||
else {
|
||||
std::intmax_t gcd = std::gcd(num, den);
|
||||
const std::intmax_t gcd = std::gcd(num, den);
|
||||
num = num * (den < 0 ? -1 : 1) / gcd;
|
||||
den = detail::abs(den) / gcd;
|
||||
}
|
||||
@ -114,9 +116,9 @@ MP_UNITS_EXPORT struct ratio {
|
||||
gsl_Assert(std::numeric_limits<std::intmax_t>::max() / r2.num > r1.den);
|
||||
gsl_Assert(std::numeric_limits<std::intmax_t>::max() / r1.den > r2.den);
|
||||
|
||||
std::intmax_t num = std::gcd(r1.num * r2.den, r2.num * r1.den);
|
||||
std::intmax_t den = r1.den * r2.den;
|
||||
std::intmax_t gcd = std::gcd(num, den);
|
||||
const std::intmax_t num = std::gcd(r1.num * r2.den, r2.num * r1.den);
|
||||
const std::intmax_t den = r1.den * r2.den;
|
||||
const std::intmax_t gcd = std::gcd(num, den);
|
||||
return ratio{num / gcd, den / gcd};
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ constexpr Out copy(const symbol_text<N, M>& txt, text_encoding encoding, Out out
|
||||
if constexpr (is_same_v<CharT, char8_t>)
|
||||
return copy(txt.unicode(), out).out;
|
||||
else if constexpr (is_same_v<CharT, char>) {
|
||||
for (char8_t ch : txt.unicode()) *out++ = static_cast<char>(ch);
|
||||
for (const char8_t ch : txt.unicode()) *out++ = static_cast<char>(ch);
|
||||
return out;
|
||||
} else
|
||||
throw std::invalid_argument("Unicode text can't be copied to CharT output");
|
||||
@ -130,20 +130,17 @@ constexpr Out copy_symbol_exponent(text_encoding encoding, bool negative_power,
|
||||
constexpr auto txt =
|
||||
symbol_text("^-(") + regular<r.num>() + symbol_text("/") + regular<r.den>() + symbol_text(")");
|
||||
return copy<CharT>(txt, encoding, out);
|
||||
} else {
|
||||
constexpr auto txt =
|
||||
symbol_text("^(") + regular<r.num>() + symbol_text("/") + regular<r.den>() + symbol_text(")");
|
||||
return copy<CharT>(txt, encoding, out);
|
||||
}
|
||||
constexpr auto txt = symbol_text("^(") + regular<r.num>() + symbol_text("/") + regular<r.den>() + symbol_text(")");
|
||||
return copy<CharT>(txt, encoding, out);
|
||||
} else if constexpr (r.num != 1) {
|
||||
// add exponent part
|
||||
if (negative_power) {
|
||||
constexpr auto txt = superscript<-r.num>();
|
||||
return copy<CharT>(txt, encoding, out);
|
||||
} else {
|
||||
constexpr auto txt = superscript<r.num>();
|
||||
return copy<CharT>(txt, encoding, out);
|
||||
}
|
||||
constexpr auto txt = superscript<r.num>();
|
||||
return copy<CharT>(txt, encoding, out);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
// SOFTWARE.
|
||||
|
||||
// IWYU pragma: always_keep
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/bits/hacks.h>
|
||||
@ -103,3 +103,4 @@ MP_UNITS_DIAGNOSTIC_POP
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#endif
|
||||
// NOLINTEND(cppcoreguidelines-macro-usage)
|
||||
|
@ -36,6 +36,24 @@
|
||||
|
||||
namespace mp_units::detail {
|
||||
|
||||
template<class InputIt, class UnaryPred>
|
||||
constexpr InputIt find_if(InputIt first, InputIt last, UnaryPred p)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
if (p(*first)) return first;
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
template<class InputIt, class UnaryPred>
|
||||
constexpr InputIt find_if_not(InputIt first, InputIt last, UnaryPred q)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
if (!q(*first)) return first;
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
template<class InputIt, class ForwardIt>
|
||||
constexpr InputIt find_first_of(InputIt first, InputIt last, ForwardIt s_first, ForwardIt s_last)
|
||||
{
|
||||
@ -49,6 +67,12 @@ constexpr InputIt find_first_of(InputIt first, InputIt last, ForwardIt s_first,
|
||||
return last;
|
||||
}
|
||||
|
||||
template<class InputIt, class UnaryPred>
|
||||
constexpr bool all_of(InputIt first, InputIt last, UnaryPred p)
|
||||
{
|
||||
return find_if_not(first, last, p) == last;
|
||||
}
|
||||
|
||||
template<class InputIt1, class InputIt2>
|
||||
constexpr bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2)
|
||||
{
|
||||
@ -61,30 +85,31 @@ constexpr bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2)
|
||||
}
|
||||
|
||||
template<class I1, class I2, class Cmp>
|
||||
constexpr auto lexicographical_compare_three_way(I1 f1, I1 l1, I2 f2, I2 l2, Cmp comp) -> decltype(comp(*f1, *f2))
|
||||
constexpr auto lexicographical_compare_three_way(I1 first1, I1 last1, I2 first2, I2 last2, Cmp comp)
|
||||
-> decltype(comp(*first1, *first2))
|
||||
{
|
||||
using ret_t = decltype(comp(*f1, *f2));
|
||||
using ret_t = decltype(comp(*first1, *first2));
|
||||
static_assert(std::disjunction_v<std::is_same<ret_t, std::strong_ordering>, std::is_same<ret_t, std::weak_ordering>,
|
||||
std::is_same<ret_t, std::partial_ordering>>,
|
||||
"The return type must be a comparison category type.");
|
||||
|
||||
bool exhaust1 = (f1 == l1);
|
||||
bool exhaust2 = (f2 == l2);
|
||||
bool exhaust1 = (first1 == last1);
|
||||
bool exhaust2 = (first2 == last2);
|
||||
MP_UNITS_DIAGNOSTIC_PUSH
|
||||
MP_UNITS_DIAGNOSTIC_IGNORE_ZERO_AS_NULLPOINTER_CONSTANT
|
||||
for (; !exhaust1 && !exhaust2; exhaust1 = (++f1 == l1), exhaust2 = (++f2 == l2))
|
||||
if (auto c = comp(*f1, *f2); c != 0) return c;
|
||||
for (; !exhaust1 && !exhaust2; exhaust1 = (++first1 == last1), exhaust2 = (++first2 == last2))
|
||||
if (auto c = comp(*first1, *first2); c != 0) return c;
|
||||
MP_UNITS_DIAGNOSTIC_POP
|
||||
|
||||
return !exhaust1 ? std::strong_ordering::greater
|
||||
: !exhaust2 ? std::strong_ordering::less
|
||||
: std::strong_ordering::equal;
|
||||
if (!exhaust1) return std::strong_ordering::greater;
|
||||
if (!exhaust2) return std::strong_ordering::less;
|
||||
return std::strong_ordering::equal;
|
||||
}
|
||||
|
||||
template<class I1, class I2>
|
||||
constexpr auto lexicographical_compare_three_way(I1 f1, I1 l1, I2 f2, I2 l2)
|
||||
constexpr auto lexicographical_compare_three_way(I1 first1, I1 last1, I2 first2, I2 last2)
|
||||
{
|
||||
return ::mp_units::detail::lexicographical_compare_three_way(f1, l1, f2, l2, std::compare_three_way());
|
||||
return ::mp_units::detail::lexicographical_compare_three_way(first1, last1, first2, last2, std::compare_three_way());
|
||||
}
|
||||
|
||||
template<class ForwardIt>
|
||||
|
@ -23,6 +23,7 @@
|
||||
// To be replaced with:
|
||||
// P3094: std::basic_fixed_string
|
||||
|
||||
// NOLINTBEGIN(*-avoid-c-arrays)
|
||||
#pragma once
|
||||
|
||||
// TODO use <algorithm> when moved to C++20 modules (parsing takes too long for each translation unit)
|
||||
@ -84,7 +85,7 @@ struct basic_fixed_string {
|
||||
|
||||
[[nodiscard]] constexpr bool empty() const noexcept { return N == 0; }
|
||||
[[nodiscard]] constexpr size_type size() const noexcept { return N; }
|
||||
[[nodiscard]] constexpr const_pointer data() const noexcept { return data_; }
|
||||
[[nodiscard]] constexpr const_pointer data() const noexcept { return static_cast<const_pointer>(data_); }
|
||||
[[nodiscard]] constexpr const CharT* c_str() const noexcept { return data(); }
|
||||
[[nodiscard]] constexpr value_type operator[](size_type index) const noexcept
|
||||
{
|
||||
@ -97,7 +98,8 @@ struct basic_fixed_string {
|
||||
[[nodiscard]] constexpr const_iterator end() const noexcept { return data() + size(); }
|
||||
[[nodiscard]] constexpr const_iterator cend() const noexcept { return data() + size(); }
|
||||
|
||||
[[nodiscard]] constexpr operator std::basic_string_view<CharT>() const noexcept
|
||||
// NOLINTNEXTLINE(*-explicit-conversions, google-explicit-constructor)
|
||||
[[nodiscard]] constexpr explicit(false) operator std::basic_string_view<CharT>() const noexcept
|
||||
{
|
||||
return std::basic_string_view<CharT>(cbegin(), cend());
|
||||
}
|
||||
@ -169,3 +171,4 @@ struct MP_UNITS_STD_FMT::formatter<mp_units::basic_fixed_string<CharT, N>> : for
|
||||
return formatter<std::basic_string_view<CharT>>::format(std::basic_string_view<CharT>(str), ctx);
|
||||
}
|
||||
};
|
||||
// NOLINTEND(*-avoid-c-arrays)
|
||||
|
@ -65,7 +65,7 @@ namespace mp_units::detail {
|
||||
template<std::size_t N>
|
||||
[[nodiscard]] consteval std::array<std::uintmax_t, N> first_n_primes()
|
||||
{
|
||||
std::array<std::uintmax_t, N> primes;
|
||||
std::array<std::uintmax_t, N> primes{};
|
||||
primes[0] = 2;
|
||||
for (std::size_t i = 1; i < N; ++i) {
|
||||
primes[i] = primes[i - 1] + 1;
|
||||
@ -77,7 +77,7 @@ template<std::size_t N>
|
||||
}
|
||||
|
||||
template<std::size_t N, typename Callable>
|
||||
consteval void call_for_coprimes_up_to(std::uintmax_t n, const std::array<std::uintmax_t, N>& basis, Callable&& call)
|
||||
consteval void call_for_coprimes_up_to(std::uintmax_t n, const std::array<std::uintmax_t, N>& basis, Callable call)
|
||||
{
|
||||
for (std::uintmax_t i = 0u; i < n; ++i) {
|
||||
if (std::apply([&i](auto... primes) { return ((i % primes != 0) && ...); }, basis)) {
|
||||
@ -97,7 +97,7 @@ template<std::size_t N>
|
||||
template<std::size_t ResultSize, std::size_t N>
|
||||
[[nodiscard]] consteval auto coprimes_up_to(std::size_t n, const std::array<std::uintmax_t, N>& basis)
|
||||
{
|
||||
std::array<std::uintmax_t, ResultSize> coprimes;
|
||||
std::array<std::uintmax_t, ResultSize> coprimes{};
|
||||
std::size_t i = 0u;
|
||||
|
||||
call_for_coprimes_up_to(n, basis, [&coprimes, &i](std::uintmax_t cp) { coprimes[i++] = cp; });
|
||||
@ -120,7 +120,7 @@ constexpr std::invoke_result_t<UnaryFunction, std::iter_value_t<InputIt>> get_fi
|
||||
UnaryFunction f)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
if (auto opt = f(*first)) return *opt;
|
||||
if (auto opt = f(*first)) return opt;
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ template<typename T>
|
||||
template<typename T1, typename T2>
|
||||
[[nodiscard]] consteval auto better_type_name(T1 v1, T2 v2)
|
||||
{
|
||||
// NOLINTBEGIN(bugprone-branch-clone)
|
||||
if constexpr (type_name<T1>().size() < type_name<T2>().size())
|
||||
return v1;
|
||||
else if constexpr (type_name<T2>().size() < type_name<T1>().size())
|
||||
@ -44,6 +45,7 @@ template<typename T1, typename T2>
|
||||
return v1;
|
||||
else
|
||||
return v2;
|
||||
// NOLINTEND(bugprone-branch-clone)
|
||||
}
|
||||
|
||||
} // namespace mp_units::detail
|
||||
|
@ -44,7 +44,7 @@ struct fill_align_width_format_specs {
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr const Char* at_most_one_of(const Char* begin, const Char* end, std::string_view modifiers)
|
||||
{
|
||||
auto it = find_first_of(begin, end, modifiers.begin(), modifiers.end());
|
||||
const Char* const 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 MP_UNITS_STD_FMT::format_error("only one of '" + std::string(modifiers) +
|
||||
"' unit modifiers may be used in the format spec");
|
||||
@ -141,17 +141,16 @@ public:
|
||||
auto specs = specs_;
|
||||
mp_units::detail::handle_dynamic_spec<mp_units::detail::width_checker>(specs.width, specs.width_ref, ctx);
|
||||
|
||||
if (specs.width == 0) {
|
||||
if (specs.width == 0)
|
||||
// Avoid extra copying if width is not specified
|
||||
return mp_units::dimension_symbol_to<Char>(ctx.out(), d, specs);
|
||||
} else {
|
||||
std::basic_string<Char> unit_buffer;
|
||||
mp_units::dimension_symbol_to<Char>(std::back_inserter(unit_buffer), d, specs);
|
||||
std::basic_string<Char> unit_buffer;
|
||||
mp_units::dimension_symbol_to<Char>(std::back_inserter(unit_buffer), d, specs);
|
||||
|
||||
std::basic_string<Char> global_format_buffer = "{:" + std::basic_string<Char>{fill_align_width_format_str_} + "}";
|
||||
return MP_UNITS_STD_FMT::vformat_to(ctx.out(), global_format_buffer,
|
||||
MP_UNITS_STD_FMT::make_format_args(unit_buffer));
|
||||
}
|
||||
const std::basic_string<Char> global_format_buffer =
|
||||
"{:" + std::basic_string<Char>{fill_align_width_format_str_} + "}";
|
||||
return MP_UNITS_STD_FMT::vformat_to(ctx.out(), global_format_buffer,
|
||||
MP_UNITS_STD_FMT::make_format_args(unit_buffer));
|
||||
}
|
||||
};
|
||||
|
||||
@ -231,17 +230,16 @@ public:
|
||||
auto specs = specs_;
|
||||
mp_units::detail::handle_dynamic_spec<mp_units::detail::width_checker>(specs.width, specs.width_ref, ctx);
|
||||
|
||||
if (specs.width == 0) {
|
||||
if (specs.width == 0)
|
||||
// Avoid extra copying if width is not specified
|
||||
return mp_units::unit_symbol_to<Char>(ctx.out(), u, specs);
|
||||
} else {
|
||||
std::basic_string<Char> unit_buffer;
|
||||
mp_units::unit_symbol_to<Char>(std::back_inserter(unit_buffer), u, specs);
|
||||
std::basic_string<Char> unit_buffer;
|
||||
mp_units::unit_symbol_to<Char>(std::back_inserter(unit_buffer), u, specs);
|
||||
|
||||
std::basic_string<Char> global_format_buffer = "{:" + std::basic_string<Char>{fill_align_width_format_str_} + "}";
|
||||
return MP_UNITS_STD_FMT::vformat_to(ctx.out(), global_format_buffer,
|
||||
MP_UNITS_STD_FMT::make_format_args(unit_buffer));
|
||||
}
|
||||
const std::basic_string<Char> global_format_buffer =
|
||||
"{:" + std::basic_string<Char>{fill_align_width_format_str_} + "}";
|
||||
return MP_UNITS_STD_FMT::vformat_to(ctx.out(), global_format_buffer,
|
||||
MP_UNITS_STD_FMT::make_format_args(unit_buffer));
|
||||
}
|
||||
};
|
||||
|
||||
@ -327,7 +325,7 @@ class MP_UNITS_STD_FMT::formatter<mp_units::quantity<Reference, Rep>, Char> {
|
||||
quantity_formatter(const formatter&, OutputIt, Args...) -> quantity_formatter<OutputIt>;
|
||||
|
||||
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
|
||||
{
|
||||
if (begin == end || *begin == ':' || *begin == '}') return begin;
|
||||
if (*begin != '%')
|
||||
@ -342,9 +340,9 @@ class MP_UNITS_STD_FMT::formatter<mp_units::quantity<Reference, Rep>, Char> {
|
||||
handler.on_text(begin, ++ptr); // account for ':'
|
||||
++ptr; // consume the second ':'
|
||||
continue;
|
||||
} else
|
||||
// default specs started
|
||||
break;
|
||||
}
|
||||
// default specs started
|
||||
break;
|
||||
}
|
||||
if (c != '%') {
|
||||
++ptr;
|
||||
@ -383,9 +381,9 @@ class MP_UNITS_STD_FMT::formatter<mp_units::quantity<Reference, Rep>, Char> {
|
||||
template<typename Formatter>
|
||||
constexpr const Char* parse_default_spec(const Char* begin, const Char* end, Formatter& f, std::string& format_str)
|
||||
{
|
||||
if (begin == end || *begin++ != '[')
|
||||
if (begin == end || *begin != '[')
|
||||
throw MP_UNITS_STD_FMT::format_error("`default-spec` should contain a `[` character");
|
||||
auto it = begin;
|
||||
auto it = ++begin;
|
||||
for (int nested_brackets = 0; it != end && !(*it == ']' && nested_brackets == 0); it++) {
|
||||
if (*it == '[') ++nested_brackets;
|
||||
if (*it == ']') {
|
||||
@ -428,19 +426,18 @@ class MP_UNITS_STD_FMT::formatter<mp_units::quantity<Reference, Rep>, Char> {
|
||||
template<typename OutputIt, typename FormatContext>
|
||||
OutputIt format_quantity(OutputIt out, const quantity_t& q, FormatContext& ctx) const
|
||||
{
|
||||
std::locale locale = MP_UNITS_FMT_LOCALE(ctx.locale());
|
||||
const std::locale locale = MP_UNITS_FMT_LOCALE(ctx.locale());
|
||||
if (modifiers_format_str_.empty()) {
|
||||
// default
|
||||
out = MP_UNITS_STD_FMT::vformat_to(out, locale, rep_format_str_,
|
||||
MP_UNITS_STD_FMT::make_format_args(q.numerical_value_ref_in(q.unit)));
|
||||
if constexpr (mp_units::space_before_unit_symbol<unit>) *out++ = ' ';
|
||||
return MP_UNITS_STD_FMT::vformat_to(out, locale, unit_format_str_, MP_UNITS_STD_FMT::make_format_args(q.unit));
|
||||
} else {
|
||||
// user provided format
|
||||
quantity_formatter f{*this, out, q, locale};
|
||||
parse_quantity_specs(modifiers_format_str_.begin(), modifiers_format_str_.end(), f);
|
||||
return f.out;
|
||||
}
|
||||
// user provided format
|
||||
quantity_formatter f{*this, out, q, locale};
|
||||
parse_quantity_specs(modifiers_format_str_.begin(), modifiers_format_str_.end(), f);
|
||||
return f.out;
|
||||
}
|
||||
|
||||
public:
|
||||
@ -451,15 +448,15 @@ public:
|
||||
begin = parse_fill_align_width(ctx, begin, end, specs_, mp_units::detail::fmt_align::right);
|
||||
if (begin == end) return begin;
|
||||
|
||||
format_checker checker{};
|
||||
const format_checker checker{};
|
||||
auto it = parse_quantity_specs(begin, end, checker);
|
||||
modifiers_format_str_ = {begin, it};
|
||||
|
||||
return parse_defaults_specs(it, end);
|
||||
}
|
||||
|
||||
template<typename FormatContext>
|
||||
auto format(const quantity_t& q, FormatContext& ctx) const -> decltype(ctx.out())
|
||||
template<typename OutIt>
|
||||
OutIt format(const quantity_t& q, MP_UNITS_STD_FMT::basic_format_context<OutIt, Char>& ctx) const
|
||||
{
|
||||
auto specs = specs_;
|
||||
mp_units::detail::handle_dynamic_spec<mp_units::detail::width_checker>(specs.width, specs.width_ref, ctx);
|
||||
@ -468,14 +465,13 @@ public:
|
||||
// Avoid extra copying if width is not specified
|
||||
format_quantity(ctx.out(), q, ctx);
|
||||
return ctx.out();
|
||||
} else {
|
||||
std::basic_string<Char> quantity_buffer;
|
||||
format_quantity(std::back_inserter(quantity_buffer), q, ctx);
|
||||
|
||||
std::basic_string<Char> fill_align_width_format_str;
|
||||
mp_units::detail::format_global_buffer(std::back_inserter(fill_align_width_format_str), specs);
|
||||
return MP_UNITS_STD_FMT::vformat_to(ctx.out(), fill_align_width_format_str,
|
||||
MP_UNITS_STD_FMT::make_format_args(quantity_buffer));
|
||||
}
|
||||
std::basic_string<Char> quantity_buffer;
|
||||
format_quantity(std::back_inserter(quantity_buffer), q, ctx);
|
||||
|
||||
std::basic_string<Char> fill_align_width_format_str;
|
||||
mp_units::detail::format_global_buffer(std::back_inserter(fill_align_width_format_str), specs);
|
||||
return MP_UNITS_STD_FMT::vformat_to(ctx.out(), fill_align_width_format_str,
|
||||
MP_UNITS_STD_FMT::make_format_args(quantity_buffer));
|
||||
}
|
||||
};
|
||||
|
@ -239,13 +239,13 @@ namespace detail {
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, Dimension D>
|
||||
requires requires { D::symbol; }
|
||||
constexpr Out dimension_symbol_impl(Out out, D, dimension_symbol_formatting fmt, bool negative_power)
|
||||
constexpr Out dimension_symbol_impl(Out out, D, const dimension_symbol_formatting& fmt, bool negative_power)
|
||||
{
|
||||
return copy_symbol<CharT>(D::symbol, fmt.encoding, negative_power, out);
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, typename F, int Num, int... Den>
|
||||
constexpr auto dimension_symbol_impl(Out out, const power<F, Num, Den...>&, dimension_symbol_formatting fmt,
|
||||
constexpr auto dimension_symbol_impl(Out out, const power<F, Num, Den...>&, const dimension_symbol_formatting& fmt,
|
||||
bool negative_power)
|
||||
{
|
||||
out = dimension_symbol_impl<CharT>(out, F{}, fmt, false); // negative power component will be added below if needed
|
||||
@ -253,7 +253,7 @@ constexpr auto dimension_symbol_impl(Out out, const power<F, Num, Den...>&, dime
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, DerivedDimensionExpr... Ms>
|
||||
constexpr Out dimension_symbol_impl(Out out, const type_list<Ms...>&, dimension_symbol_formatting fmt,
|
||||
constexpr Out dimension_symbol_impl(Out out, const type_list<Ms...>&, const dimension_symbol_formatting& fmt,
|
||||
bool negative_power)
|
||||
{
|
||||
return (..., (out = dimension_symbol_impl<CharT>(out, Ms{}, fmt, negative_power)));
|
||||
@ -261,7 +261,7 @@ constexpr Out dimension_symbol_impl(Out out, const type_list<Ms...>&, dimension_
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, DerivedDimensionExpr... Nums, DerivedDimensionExpr... Dens>
|
||||
constexpr Out dimension_symbol_impl(Out out, const type_list<Nums...>& nums, const type_list<Dens...>& dens,
|
||||
dimension_symbol_formatting fmt)
|
||||
const dimension_symbol_formatting& fmt)
|
||||
{
|
||||
if constexpr (sizeof...(Nums) == 0 && sizeof...(Dens) == 0) {
|
||||
// dimensionless quantity
|
||||
@ -277,7 +277,7 @@ constexpr Out dimension_symbol_impl(Out out, const type_list<Nums...>& nums, con
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, typename... Expr>
|
||||
constexpr Out dimension_symbol_impl(Out out, const derived_dimension<Expr...>&, dimension_symbol_formatting fmt,
|
||||
constexpr Out dimension_symbol_impl(Out out, const derived_dimension<Expr...>&, const dimension_symbol_formatting& fmt,
|
||||
bool negative_power)
|
||||
{
|
||||
gsl_Expects(negative_power == false);
|
||||
@ -289,7 +289,7 @@ constexpr Out dimension_symbol_impl(Out out, const derived_dimension<Expr...>&,
|
||||
} // namespace detail
|
||||
|
||||
MP_UNITS_EXPORT template<typename CharT = char, std::output_iterator<CharT> Out, Dimension D>
|
||||
constexpr Out dimension_symbol_to(Out out, D d, dimension_symbol_formatting fmt = dimension_symbol_formatting{})
|
||||
constexpr Out dimension_symbol_to(Out out, D d, const dimension_symbol_formatting& fmt = dimension_symbol_formatting{})
|
||||
{
|
||||
return detail::dimension_symbol_impl<CharT>(out, d, fmt, false);
|
||||
}
|
||||
|
@ -374,6 +374,7 @@ namespace detail {
|
||||
// Divide a number by a given base raised to some power.
|
||||
//
|
||||
// Undefined unless base > 1, pow >= 0, and (base ^ pow) evenly divides n.
|
||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||
[[nodiscard]] consteval std::intmax_t remove_power(std::intmax_t base, std::intmax_t pow, std::intmax_t n)
|
||||
{
|
||||
while (pow-- > 0) {
|
||||
@ -795,8 +796,9 @@ template<std::intmax_t N>
|
||||
struct prime_factorization {
|
||||
[[nodiscard]] static consteval std::intmax_t get_or_compute_first_factor()
|
||||
{
|
||||
if constexpr (known_first_factor<N>.has_value()) {
|
||||
return known_first_factor<N>.value();
|
||||
constexpr auto opt = known_first_factor<N>;
|
||||
if constexpr (opt.has_value()) {
|
||||
return opt.value(); // NOLINT(bugprone-unchecked-optional-access)
|
||||
} else {
|
||||
return static_cast<std::intmax_t>(factorizer::find_first_factor(N));
|
||||
}
|
||||
|
@ -136,6 +136,7 @@ public:
|
||||
quantity() = default;
|
||||
quantity(const quantity&) = default;
|
||||
quantity(quantity&&) = default;
|
||||
~quantity() = default;
|
||||
|
||||
template<typename Value>
|
||||
requires std::same_as<std::remove_cvref_t<Value>, Rep>
|
||||
@ -227,6 +228,7 @@ public:
|
||||
numerical_value_is_an_implementation_detail_)),
|
||||
convert_explicitly> ||
|
||||
!std::convertible_to<Rep, typename quantity_like_traits<Q>::rep>) constexpr
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
operator Q_() const& noexcept(
|
||||
noexcept(quantity_like_traits<Q>::from_numerical_value(numerical_value_is_an_implementation_detail_)) &&
|
||||
std::is_nothrow_copy_constructible_v<rep>)
|
||||
@ -241,6 +243,7 @@ public:
|
||||
numerical_value_is_an_implementation_detail_)),
|
||||
convert_explicitly> ||
|
||||
!std::convertible_to<Rep, typename quantity_like_traits<Q>::rep>) constexpr
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
operator Q_() && noexcept(
|
||||
noexcept(quantity_like_traits<Q>::from_numerical_value(numerical_value_is_an_implementation_detail_)) &&
|
||||
std::is_nothrow_move_constructible_v<rep>)
|
||||
@ -529,19 +532,15 @@ MP_UNITS_EXPORT_END
|
||||
|
||||
} // namespace mp_units
|
||||
|
||||
namespace std {
|
||||
|
||||
template<mp_units::Quantity Q1, mp_units::Quantity Q2>
|
||||
requires requires {
|
||||
{
|
||||
mp_units::common_reference(Q1::reference, Q2::reference)
|
||||
} -> mp_units::Reference;
|
||||
typename common_type_t<typename Q1::rep, typename Q2::rep>;
|
||||
typename std::common_type_t<typename Q1::rep, typename Q2::rep>;
|
||||
}
|
||||
struct common_type<Q1, Q2> {
|
||||
struct std::common_type<Q1, Q2> {
|
||||
public:
|
||||
using type = mp_units::quantity<mp_units::common_reference(Q1::reference, Q2::reference),
|
||||
common_type_t<typename Q1::rep, typename Q2::rep>>;
|
||||
std::common_type_t<typename Q1::rep, typename Q2::rep>>;
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
@ -36,6 +36,7 @@
|
||||
namespace mp_units {
|
||||
|
||||
MP_UNITS_EXPORT template<typename Derived, QuantitySpec auto QS>
|
||||
// NOLINTNEXTLINE(bugprone-crtp-constructor-accessibility)
|
||||
struct absolute_point_origin {
|
||||
static constexpr QuantitySpec auto quantity_spec = QS;
|
||||
using _type_ = absolute_point_origin;
|
||||
@ -157,6 +158,7 @@ public:
|
||||
quantity_point() = default;
|
||||
quantity_point(const quantity_point&) = default;
|
||||
quantity_point(quantity_point&&) = default;
|
||||
~quantity_point() = default;
|
||||
|
||||
template<typename Q>
|
||||
requires QuantityOf<std::remove_cvref_t<Q>, get_quantity_spec(R)> && std::constructible_from<quantity_type, Q> &&
|
||||
@ -290,6 +292,7 @@ public:
|
||||
convert_explicitly> ||
|
||||
!std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
||||
typename quantity_point_like_traits<QP>::rep>>) constexpr
|
||||
// NOLINTNEXTLINE(*-explicit-conversions, google-explicit-constructor)
|
||||
operator QP_() const& noexcept(
|
||||
noexcept(quantity_point_like_traits<QP>::from_quantity(quantity_from_origin_is_an_implementation_detail_)) &&
|
||||
std::is_nothrow_copy_constructible_v<rep>)
|
||||
@ -307,6 +310,7 @@ public:
|
||||
convert_explicitly> ||
|
||||
!std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
||||
typename quantity_point_like_traits<QP>::rep>>) constexpr
|
||||
// NOLINTNEXTLINE(*-explicit-conversions, google-explicit-constructor)
|
||||
operator QP_() && noexcept(
|
||||
noexcept(quantity_point_like_traits<QP>::from_quantity(quantity_from_origin_is_an_implementation_detail_)) &&
|
||||
std::is_nothrow_move_constructible_v<rep>)
|
||||
|
@ -595,7 +595,7 @@ MP_UNITS_EXPORT_END
|
||||
|
||||
namespace detail {
|
||||
|
||||
enum class specs_convertible_result { no, cast, explicit_conversion, yes };
|
||||
enum class specs_convertible_result : std::int8_t { no, cast, explicit_conversion, yes };
|
||||
|
||||
template<QuantitySpec Q>
|
||||
[[nodiscard]] consteval int get_complexity(Q);
|
||||
@ -634,9 +634,7 @@ template<QuantitySpec Q>
|
||||
template<Dimension D1, Dimension D2>
|
||||
[[nodiscard]] consteval bool ingredients_dimension_less(D1 lhs, D2 rhs)
|
||||
{
|
||||
if constexpr (lhs == rhs)
|
||||
return false;
|
||||
else if constexpr (lhs == dimension_one)
|
||||
if constexpr (lhs == rhs || lhs == dimension_one)
|
||||
return false;
|
||||
else if constexpr (rhs == dimension_one)
|
||||
return true;
|
||||
@ -775,7 +773,7 @@ template<int Complexity, QuantitySpec Q, typename Den, typename... Dens>
|
||||
template<int Complexity, QuantitySpec Q>
|
||||
[[nodiscard]] consteval auto explode(Q, type_list<>, type_list<>)
|
||||
{
|
||||
return explode_result{dimensionless};
|
||||
return explode_result{.quantity = dimensionless};
|
||||
}
|
||||
|
||||
template<int Complexity, IntermediateDerivedQuantitySpec Q>
|
||||
@ -868,11 +866,11 @@ template<typename... DensFrom>
|
||||
[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<>, type_list<>, type_list<>,
|
||||
type_list<>);
|
||||
|
||||
enum class prepend_rest { no, first, second };
|
||||
enum class prepend_rest : std::int8_t { no, first, second };
|
||||
|
||||
template<QuantitySpec From = struct dimensionless, QuantitySpec To = struct dimensionless, typename Elem = int>
|
||||
struct extract_results {
|
||||
bool same_dimension;
|
||||
bool same_dimension{};
|
||||
From from{};
|
||||
To to{};
|
||||
prepend_rest prepend{};
|
||||
@ -914,7 +912,7 @@ template<typename From, typename To>
|
||||
constexpr auto to_factor = std::get<0>(to_norm);
|
||||
constexpr auto to_exp = std::get<1>(to_norm);
|
||||
if constexpr (from_factor.dimension != to_factor.dimension)
|
||||
return extract_results{false};
|
||||
return extract_results{.same_dimension = false};
|
||||
else if constexpr (from_exp > to_exp)
|
||||
return extract_results{true, pow<to_exp.num, to_exp.den>(from_factor), pow<to_exp.num, to_exp.den>(to_factor),
|
||||
prepend_rest::first,
|
||||
@ -926,30 +924,37 @@ template<typename From, typename To>
|
||||
}
|
||||
}
|
||||
|
||||
enum class process_entities { numerators, denominators, from, to };
|
||||
enum class process_entities : std::int8_t { numerators, denominators, from, to };
|
||||
|
||||
template<process_entities Entities, auto Ext, TypeList NumFrom, TypeList DenFrom, TypeList NumTo, TypeList DenTo>
|
||||
[[nodiscard]] consteval specs_convertible_result process_num_den(NumFrom num_from, DenFrom den_from, NumTo num_to,
|
||||
DenTo den_to)
|
||||
{
|
||||
constexpr auto res = convertible_impl(Ext.from, Ext.to);
|
||||
if constexpr (Ext.prepend == prepend_rest::no)
|
||||
return min(res, are_ingredients_convertible(num_from, den_from, num_to, den_to));
|
||||
else {
|
||||
using elem = std::remove_cvref_t<decltype(Ext.elem)>;
|
||||
if constexpr (Entities == process_entities::numerators) {
|
||||
if constexpr (Ext.prepend == prepend_rest::first)
|
||||
return min(res, are_ingredients_convertible(type_list_push_front<NumFrom, elem>{}, den_from, num_to, den_to));
|
||||
else
|
||||
return min(res, are_ingredients_convertible(num_from, den_from, type_list_push_front<NumTo, elem>{}, den_to));
|
||||
} else {
|
||||
if constexpr (Ext.prepend == prepend_rest::first)
|
||||
return min(res, are_ingredients_convertible(num_from, type_list_push_front<DenFrom, elem>{}, num_to, den_to));
|
||||
else
|
||||
return min(res, are_ingredients_convertible(num_from, den_from, num_to, type_list_push_front<DenTo, elem>{}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<process_entities Entities, auto Ext, TypeList NumFrom, TypeList DenFrom, TypeList NumTo, TypeList DenTo>
|
||||
[[nodiscard]] consteval specs_convertible_result process_extracted(NumFrom num_from, DenFrom den_from, NumTo num_to,
|
||||
DenTo den_to)
|
||||
{
|
||||
if constexpr (Entities == process_entities::numerators || Entities == process_entities::denominators) {
|
||||
constexpr auto res = convertible_impl(Ext.from, Ext.to);
|
||||
if constexpr (Ext.prepend == prepend_rest::no)
|
||||
return min(res, are_ingredients_convertible(num_from, den_from, num_to, den_to));
|
||||
else {
|
||||
using elem = std::remove_cvref_t<decltype(Ext.elem)>;
|
||||
if constexpr (Entities == process_entities::numerators) {
|
||||
if constexpr (Ext.prepend == prepend_rest::first)
|
||||
return min(res, are_ingredients_convertible(type_list_push_front<NumFrom, elem>{}, den_from, num_to, den_to));
|
||||
else
|
||||
return min(res, are_ingredients_convertible(num_from, den_from, type_list_push_front<NumTo, elem>{}, den_to));
|
||||
} else {
|
||||
if constexpr (Ext.prepend == prepend_rest::first)
|
||||
return min(res, are_ingredients_convertible(num_from, type_list_push_front<DenFrom, elem>{}, num_to, den_to));
|
||||
else
|
||||
return min(res, are_ingredients_convertible(num_from, den_from, num_to, type_list_push_front<DenTo, elem>{}));
|
||||
}
|
||||
}
|
||||
return process_num_den<Entities, Ext>(num_from, den_from, num_to, den_to);
|
||||
} else {
|
||||
if constexpr (Ext.prepend == prepend_rest::no)
|
||||
return are_ingredients_convertible(num_from, den_from, num_to, den_to);
|
||||
@ -1330,50 +1335,63 @@ template<NamedQuantitySpec From, IntermediateDerivedQuantitySpec To>
|
||||
type_list_sort<typename To::_den_, type_list_of_ingredients_less>{});
|
||||
}
|
||||
|
||||
template<QuantitySpec From, QuantitySpec To>
|
||||
[[nodiscard]] consteval specs_convertible_result convertible_kinds(From from_kind, To to_kind)
|
||||
{
|
||||
constexpr auto exploded_kind_result = [](specs_convertible_result res) {
|
||||
using enum specs_convertible_result;
|
||||
return res == no ? no : yes;
|
||||
};
|
||||
if constexpr ((NamedQuantitySpec<std::remove_cvref_t<decltype(from_kind)>> &&
|
||||
NamedQuantitySpec<std::remove_cvref_t<decltype(to_kind)>>) ||
|
||||
get_complexity(from_kind) == get_complexity(to_kind))
|
||||
return convertible_impl(from_kind, to_kind);
|
||||
else if constexpr (get_complexity(from_kind) > get_complexity(to_kind))
|
||||
return exploded_kind_result(
|
||||
convertible_impl(get_kind_tree_root(explode<get_complexity(to_kind)>(from_kind).quantity), to_kind));
|
||||
else
|
||||
return exploded_kind_result(
|
||||
convertible_impl(from_kind, get_kind_tree_root(explode<get_complexity(from_kind)>(to_kind).quantity)));
|
||||
}
|
||||
|
||||
template<NamedQuantitySpec From, NamedQuantitySpec To>
|
||||
[[nodiscard]] consteval specs_convertible_result convertible_named(From from, To to)
|
||||
{
|
||||
using enum specs_convertible_result;
|
||||
|
||||
if constexpr (have_common_base(From{}, To{})) {
|
||||
if constexpr (std::derived_from<From, To>) return yes;
|
||||
if constexpr (std::derived_from<To, From>) return explicit_conversion;
|
||||
if constexpr (get_kind(From{}) == get_kind(To{})) return cast;
|
||||
return no;
|
||||
} else if constexpr (get_kind(From{}) != get_kind(To{}))
|
||||
return no;
|
||||
else if constexpr (get_complexity(From{}) != get_complexity(To{})) {
|
||||
if constexpr (get_complexity(From{}) > get_complexity(To{}))
|
||||
return convertible_impl(explode<get_complexity(to)>(from).quantity, to);
|
||||
else {
|
||||
auto res = explode<get_complexity(from)>(to);
|
||||
return min(res.result, convertible_impl(from, res.quantity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<QuantitySpec From, QuantitySpec To>
|
||||
[[nodiscard]] consteval specs_convertible_result convertible_impl(From from, To to)
|
||||
{
|
||||
using enum specs_convertible_result;
|
||||
|
||||
// NOLINTBEGIN(bugprone-branch-clone)
|
||||
if constexpr (From::dimension != To::dimension)
|
||||
return no;
|
||||
else if constexpr (From{} == To{})
|
||||
return yes;
|
||||
else if constexpr (QuantityKindSpec<From> || QuantityKindSpec<To>) {
|
||||
constexpr auto from_kind = get_kind_tree_root(From{});
|
||||
constexpr auto to_kind = get_kind_tree_root(To{});
|
||||
constexpr auto exploded_kind_result = [](specs_convertible_result res) {
|
||||
using enum specs_convertible_result;
|
||||
return res == no ? no : yes;
|
||||
};
|
||||
if constexpr ((NamedQuantitySpec<std::remove_cvref_t<decltype(from_kind)>> &&
|
||||
NamedQuantitySpec<std::remove_cvref_t<decltype(to_kind)>>) ||
|
||||
get_complexity(from_kind) == get_complexity(to_kind))
|
||||
return convertible_impl(from_kind, to_kind);
|
||||
else if constexpr (get_complexity(from_kind) > get_complexity(to_kind))
|
||||
return exploded_kind_result(
|
||||
convertible_impl(get_kind_tree_root(explode<get_complexity(to_kind)>(from_kind).quantity), to_kind));
|
||||
else
|
||||
return exploded_kind_result(
|
||||
convertible_impl(from_kind, get_kind_tree_root(explode<get_complexity(from_kind)>(to_kind).quantity)));
|
||||
return convertible_kinds(get_kind_tree_root(from), get_kind_tree_root(to));
|
||||
} else if constexpr (NestedQuantityKindSpecOf<get_kind_tree_root(To{}), from> && get_kind_tree_root(To{}) == To{})
|
||||
return yes;
|
||||
else if constexpr (NamedQuantitySpec<From> && NamedQuantitySpec<To>) {
|
||||
if constexpr (have_common_base(From{}, To{})) {
|
||||
if (std::derived_from<From, To>)
|
||||
return yes;
|
||||
else
|
||||
return std::derived_from<To, From> ? explicit_conversion : (get_kind(from) == get_kind(to) ? cast : no);
|
||||
} else if constexpr (get_kind(From{}) != get_kind(To{}))
|
||||
return no;
|
||||
else if constexpr (get_complexity(From{}) != get_complexity(To{})) {
|
||||
if constexpr (get_complexity(From{}) > get_complexity(To{}))
|
||||
return convertible_impl(explode<get_complexity(to)>(from).quantity, to);
|
||||
else {
|
||||
auto res = explode<get_complexity(from)>(to);
|
||||
return min(res.result, convertible_impl(from, res.quantity));
|
||||
}
|
||||
}
|
||||
return convertible_named(from, to);
|
||||
} else if constexpr (IntermediateDerivedQuantitySpec<From> && IntermediateDerivedQuantitySpec<To>) {
|
||||
return are_ingredients_convertible(from, to);
|
||||
} else if constexpr (IntermediateDerivedQuantitySpec<From>) {
|
||||
@ -1394,6 +1412,7 @@ template<QuantitySpec From, QuantitySpec To>
|
||||
else
|
||||
return min(res.result, are_ingredients_convertible(from, to));
|
||||
}
|
||||
// NOLINTEND(bugprone-branch-clone)
|
||||
return no;
|
||||
}
|
||||
|
||||
@ -1454,6 +1473,7 @@ template<QuantitySpec Q>
|
||||
return false;
|
||||
};
|
||||
|
||||
// NOLINTBEGIN(bugprone-branch-clone)
|
||||
if constexpr (detail::QuantityKindSpec<Q>) {
|
||||
return remove_kind(q);
|
||||
} else if constexpr (defined_as_kind(Q{})) {
|
||||
@ -1467,6 +1487,7 @@ template<QuantitySpec Q>
|
||||
// root quantity
|
||||
return q;
|
||||
}
|
||||
// NOLINTEND(bugprone-branch-clone)
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
@ -1488,6 +1509,8 @@ template<QuantitySpec Q1, QuantitySpec Q2>
|
||||
{
|
||||
using QQ1 = std::remove_const_t<decltype(detail::remove_kind(q1))>;
|
||||
using QQ2 = std::remove_const_t<decltype(detail::remove_kind(q2))>;
|
||||
|
||||
// NOLINTBEGIN(bugprone-branch-clone)
|
||||
if constexpr (is_same_v<Q1, Q2>)
|
||||
return q1;
|
||||
else if constexpr (detail::NestedQuantityKindSpecOf<Q1{}, Q2{}>)
|
||||
@ -1512,6 +1535,7 @@ template<QuantitySpec Q1, QuantitySpec Q2>
|
||||
return get_kind_tree_root(q2);
|
||||
else
|
||||
return get_kind_tree_root(q1);
|
||||
// NOLINTEND(bugprone-branch-clone)
|
||||
}
|
||||
|
||||
[[nodiscard]] consteval QuantitySpec auto common_quantity_spec(QuantitySpec auto q1, QuantitySpec auto q2,
|
||||
|
@ -53,7 +53,7 @@ namespace mp_units {
|
||||
* For example, the Cauchy stress tensor possess magnitude, direction,
|
||||
* and orientation qualities.
|
||||
*/
|
||||
MP_UNITS_EXPORT enum class quantity_character { scalar, vector, tensor };
|
||||
MP_UNITS_EXPORT enum class quantity_character : std::int8_t { scalar, vector, tensor };
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
// NOLINTBEGIN(*-avoid-c-arrays)
|
||||
#pragma once
|
||||
|
||||
// IWYU pragma: private, include <mp-units/framework.h>
|
||||
@ -43,6 +44,7 @@ static_assert(std::text_encoding::literal().mib() == std::text_encoding::id::UTF
|
||||
|
||||
namespace mp_units {
|
||||
|
||||
// NOLINTNEXTLINE(readability-enum-initial-value)
|
||||
MP_UNITS_EXPORT enum class text_encoding : std::int8_t {
|
||||
unicode, // µs; m³; L²MT⁻³
|
||||
ascii, // us; m^3; L^2MT^-3
|
||||
@ -60,9 +62,7 @@ constexpr bool is_basic_literal_character_set_char(char ch)
|
||||
template<std::size_t N>
|
||||
constexpr bool is_basic_literal_character_set(const char (&txt)[N]) noexcept
|
||||
{
|
||||
for (auto ch : txt)
|
||||
if (!is_basic_literal_character_set_char(ch)) return false;
|
||||
return true;
|
||||
return detail::all_of(std::begin(txt), std::end(txt), is_basic_literal_character_set_char);
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
@ -94,6 +94,7 @@ struct symbol_text {
|
||||
gsl_Expects(detail::is_basic_literal_character_set_char(ch));
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(*-avoid-c-arrays)
|
||||
constexpr explicit(false) symbol_text(const char (&txt)[N + 1]) :
|
||||
unicode_(detail::to_u8string(basic_fixed_string{txt})), ascii_(txt)
|
||||
{
|
||||
@ -106,6 +107,7 @@ struct symbol_text {
|
||||
gsl_Expects(detail::is_basic_literal_character_set(txt.data_));
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(*-avoid-c-arrays)
|
||||
constexpr symbol_text(const char8_t (&u)[N + 1], const char (&a)[M + 1]) : unicode_(u), ascii_(a)
|
||||
{
|
||||
gsl_Expects(u[N] == char8_t{});
|
||||
@ -166,3 +168,4 @@ template<std::size_t N, std::size_t M>
|
||||
symbol_text(const fixed_u8string<N>&, const fixed_string<M>&) -> symbol_text<N, M>;
|
||||
|
||||
} // namespace mp_units
|
||||
// NOLINTEND(*-avoid-c-arrays)
|
||||
|
@ -688,6 +688,7 @@ inline constexpr bool space_before_unit_symbol<per_mille> = false;
|
||||
|
||||
// get_unit_symbol
|
||||
|
||||
// NOLINTNEXTLINE(readability-enum-initial-value)
|
||||
enum class unit_symbol_solidus : std::int8_t {
|
||||
one_denominator, // m/s; kg m⁻¹ s⁻¹
|
||||
always, // m/s; kg/(m s)
|
||||
@ -695,6 +696,7 @@ enum class unit_symbol_solidus : std::int8_t {
|
||||
default_denominator = one_denominator
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(readability-enum-initial-value)
|
||||
enum class unit_symbol_separator : std::int8_t {
|
||||
space, // kg m²/s²
|
||||
half_high_dot, // kg⋅m²/s² (valid only for unicode encoding)
|
||||
@ -712,7 +714,7 @@ MP_UNITS_EXPORT_END
|
||||
namespace detail {
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out>
|
||||
constexpr Out print_separator(Out out, unit_symbol_formatting fmt)
|
||||
constexpr Out print_separator(Out out, const unit_symbol_formatting& fmt)
|
||||
{
|
||||
if (fmt.separator == unit_symbol_separator::half_high_dot) {
|
||||
if (fmt.encoding != text_encoding::unicode)
|
||||
@ -727,13 +729,14 @@ constexpr Out print_separator(Out out, unit_symbol_formatting fmt)
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, Unit U>
|
||||
requires requires { U::symbol; }
|
||||
constexpr Out unit_symbol_impl(Out out, U, unit_symbol_formatting fmt, bool negative_power)
|
||||
constexpr Out unit_symbol_impl(Out out, U, const unit_symbol_formatting& fmt, bool negative_power)
|
||||
{
|
||||
return copy_symbol<CharT>(U::symbol, fmt.encoding, negative_power, out);
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, auto M, typename U>
|
||||
constexpr Out unit_symbol_impl(Out out, const scaled_unit<M, U>& u, unit_symbol_formatting fmt, bool negative_power)
|
||||
constexpr Out unit_symbol_impl(Out out, const scaled_unit<M, U>& u, const unit_symbol_formatting& fmt,
|
||||
bool negative_power)
|
||||
{
|
||||
if constexpr (M == mag<1>) {
|
||||
// no ratio/prefix
|
||||
@ -748,14 +751,15 @@ constexpr Out unit_symbol_impl(Out out, const scaled_unit<M, U>& u, unit_symbol_
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, typename F, int Num, int... Den>
|
||||
constexpr auto unit_symbol_impl(Out out, const power<F, Num, Den...>&, unit_symbol_formatting fmt, bool negative_power)
|
||||
constexpr auto unit_symbol_impl(Out out, const power<F, Num, Den...>&, const unit_symbol_formatting& fmt,
|
||||
bool negative_power)
|
||||
{
|
||||
out = unit_symbol_impl<CharT>(out, F{}, fmt, false); // negative power component will be added below if needed
|
||||
return copy_symbol_exponent<CharT, Num, Den...>(fmt.encoding, negative_power, out);
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, DerivedUnitExpr M>
|
||||
constexpr Out unit_symbol_impl(Out out, M m, std::size_t Idx, unit_symbol_formatting fmt, bool negative_power)
|
||||
constexpr Out unit_symbol_impl(Out out, M m, std::size_t Idx, const unit_symbol_formatting& fmt, bool negative_power)
|
||||
{
|
||||
if (Idx > 0) out = print_separator<CharT>(out, fmt);
|
||||
return unit_symbol_impl<CharT>(out, m, fmt, negative_power);
|
||||
@ -763,14 +767,14 @@ constexpr Out unit_symbol_impl(Out out, M m, std::size_t Idx, unit_symbol_format
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, DerivedUnitExpr... Ms, std::size_t... Idxs>
|
||||
constexpr Out unit_symbol_impl(Out out, const type_list<Ms...>&, std::index_sequence<Idxs...>,
|
||||
unit_symbol_formatting fmt, bool negative_power)
|
||||
const unit_symbol_formatting& fmt, bool negative_power)
|
||||
{
|
||||
return (..., (out = unit_symbol_impl<CharT>(out, Ms{}, Idxs, fmt, negative_power)));
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, DerivedUnitExpr... Nums, DerivedUnitExpr... Dens>
|
||||
constexpr Out unit_symbol_impl(Out out, const type_list<Nums...>& nums, const type_list<Dens...>& dens,
|
||||
unit_symbol_formatting fmt)
|
||||
const unit_symbol_formatting& fmt)
|
||||
{
|
||||
if constexpr (sizeof...(Nums) == 0 && sizeof...(Dens) == 0) {
|
||||
// dimensionless quantity
|
||||
@ -792,7 +796,7 @@ constexpr Out unit_symbol_impl(Out out, const type_list<Nums...>& nums, const ty
|
||||
}
|
||||
|
||||
if (fmt.solidus == always && sizeof...(Dens) > 1) *out++ = '(';
|
||||
bool negative_power = fmt.solidus == never || (fmt.solidus == one_denominator && sizeof...(Dens) > 1);
|
||||
const bool negative_power = fmt.solidus == never || (fmt.solidus == one_denominator && sizeof...(Dens) > 1);
|
||||
out = unit_symbol_impl<CharT>(out, dens, std::index_sequence_for<Dens...>(), fmt, negative_power);
|
||||
if (fmt.solidus == always && sizeof...(Dens) > 1) *out++ = ')';
|
||||
return out;
|
||||
@ -800,7 +804,8 @@ constexpr Out unit_symbol_impl(Out out, const type_list<Nums...>& nums, const ty
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, typename... Expr>
|
||||
constexpr Out unit_symbol_impl(Out out, const derived_unit<Expr...>&, unit_symbol_formatting fmt, bool negative_power)
|
||||
constexpr Out unit_symbol_impl(Out out, const derived_unit<Expr...>&, const unit_symbol_formatting& fmt,
|
||||
bool negative_power)
|
||||
{
|
||||
gsl_Expects(negative_power == false);
|
||||
return unit_symbol_impl<CharT>(out, typename derived_unit<Expr...>::_num_{}, typename derived_unit<Expr...>::_den_{},
|
||||
@ -810,7 +815,7 @@ constexpr Out unit_symbol_impl(Out out, const derived_unit<Expr...>&, unit_symbo
|
||||
} // namespace detail
|
||||
|
||||
MP_UNITS_EXPORT template<typename CharT = char, std::output_iterator<CharT> Out, Unit U>
|
||||
constexpr Out unit_symbol_to(Out out, U u, unit_symbol_formatting fmt = unit_symbol_formatting{})
|
||||
constexpr Out unit_symbol_to(Out out, U u, const unit_symbol_formatting& fmt = unit_symbol_formatting{})
|
||||
{
|
||||
return detail::unit_symbol_impl<CharT>(out, u, fmt, false);
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ std::vector<typename Q::rep> i_qty_to_rep(InputIt first, InputIt last)
|
||||
{
|
||||
std::vector<typename Q::rep> intervals_rep;
|
||||
intervals_rep.reserve(static_cast<size_t>(std::distance(first, last)));
|
||||
for (auto itr = first; itr != last; ++itr) {
|
||||
for (InputIt itr = first; itr != last; ++itr) {
|
||||
intervals_rep.push_back(itr->numerical_value_ref_in(Q::unit));
|
||||
}
|
||||
return intervals_rep;
|
||||
@ -106,11 +106,11 @@ struct uniform_int_distribution : public std::uniform_int_distribution<typename
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
Q a() const { return base::a() * Q::reference; }
|
||||
Q b() const { return base::b() * Q::reference; }
|
||||
[[nodiscard]] Q a() const { return base::a() * Q::reference; }
|
||||
[[nodiscard]] Q b() const { return base::b() * Q::reference; }
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -131,11 +131,11 @@ struct uniform_real_distribution : public std::uniform_real_distribution<typenam
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
Q a() const { return base::a() * Q::reference; }
|
||||
Q b() const { return base::b() * Q::reference; }
|
||||
[[nodiscard]] Q a() const { return base::a() * Q::reference; }
|
||||
[[nodiscard]] Q b() const { return base::b() * Q::reference; }
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -153,10 +153,10 @@ struct binomial_distribution : public std::binomial_distribution<typename Q::rep
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
Q t() const { return base::t() * Q::reference; }
|
||||
[[nodiscard]] Q t() const { return base::t() * Q::reference; }
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -174,10 +174,10 @@ struct negative_binomial_distribution : public std::negative_binomial_distributi
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
Q k() const { return base::k() * Q::reference; }
|
||||
[[nodiscard]] Q k() const { return base::k() * Q::reference; }
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -187,7 +187,7 @@ struct geometric_distribution : public std::geometric_distribution<typename Q::r
|
||||
using base = MP_UNITS_TYPENAME std::geometric_distribution<rep>;
|
||||
|
||||
geometric_distribution() : base() {}
|
||||
geometric_distribution(double p) : base(p) {}
|
||||
explicit geometric_distribution(double p) : base(p) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
@ -195,8 +195,8 @@ struct geometric_distribution : public std::geometric_distribution<typename Q::r
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -214,8 +214,8 @@ struct poisson_distribution : public std::poisson_distribution<typename Q::rep>
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -233,8 +233,8 @@ struct exponential_distribution : public std::exponential_distribution<typename
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -252,8 +252,8 @@ struct gamma_distribution : public std::gamma_distribution<typename Q::rep> {
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -271,8 +271,8 @@ struct weibull_distribution : public std::weibull_distribution<typename Q::rep>
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -290,10 +290,10 @@ struct extreme_value_distribution : public std::extreme_value_distribution<typen
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q a() const { return base::a() * Q::reference; }
|
||||
[[nodiscard]] Q a() const { return base::a() * Q::reference; }
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -314,11 +314,11 @@ struct normal_distribution : public std::normal_distribution<typename Q::rep> {
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q mean() const { return base::mean() * Q::reference; }
|
||||
Q stddev() const { return base::stddev() * Q::reference; }
|
||||
[[nodiscard]] Q mean() const { return base::mean() * Q::reference; }
|
||||
[[nodiscard]] Q stddev() const { return base::stddev() * Q::reference; }
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -339,11 +339,11 @@ struct lognormal_distribution : public std::lognormal_distribution<typename Q::r
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
Q m() const { return base::m() * Q::reference; }
|
||||
Q s() const { return base::s() * Q::reference; }
|
||||
[[nodiscard]] Q m() const { return base::m() * Q::reference; }
|
||||
[[nodiscard]] Q s() const { return base::s() * Q::reference; }
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -361,8 +361,8 @@ struct chi_squared_distribution : public std::chi_squared_distribution<typename
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -383,11 +383,11 @@ struct cauchy_distribution : public std::cauchy_distribution<typename Q::rep> {
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
Q a() const { return base::a() * Q::reference; }
|
||||
Q b() const { return base::b() * Q::reference; }
|
||||
[[nodiscard]] Q a() const { return base::a() * Q::reference; }
|
||||
[[nodiscard]] Q b() const { return base::b() * Q::reference; }
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -405,8 +405,8 @@ struct fisher_f_distribution : public std::fisher_f_distribution<typename Q::rep
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -424,8 +424,8 @@ struct student_t_distribution : public std::student_t_distribution<typename Q::r
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -455,8 +455,8 @@ struct discrete_distribution : public std::discrete_distribution<typename Q::rep
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -503,9 +503,9 @@ public:
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
std::vector<Q> intervals() const
|
||||
[[nodiscard]] std::vector<Q> intervals() const
|
||||
{
|
||||
std::vector<rep> intervals_rep = base::intervals();
|
||||
const std::vector<rep> intervals_rep = base::intervals();
|
||||
std::vector<Q> intervals_qty;
|
||||
intervals_qty.reserve(intervals_rep.size());
|
||||
for (const rep& val : intervals_rep) {
|
||||
@ -514,8 +514,8 @@ public:
|
||||
return intervals_qty;
|
||||
}
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
@ -562,9 +562,9 @@ public:
|
||||
return base::operator()(g) * Q::reference;
|
||||
}
|
||||
|
||||
std::vector<Q> intervals() const
|
||||
[[nodiscard]] std::vector<Q> intervals() const
|
||||
{
|
||||
std::vector<rep> intervals_rep = base::intervals();
|
||||
const std::vector<rep> intervals_rep = base::intervals();
|
||||
std::vector<Q> intervals_qty;
|
||||
intervals_qty.reserve(intervals_rep.size());
|
||||
for (const rep& val : intervals_rep) {
|
||||
@ -573,8 +573,8 @@ public:
|
||||
return intervals_qty;
|
||||
}
|
||||
|
||||
Q min() const { return base::min() * Q::reference; }
|
||||
Q max() const { return base::max() * Q::reference; }
|
||||
[[nodiscard]] Q min() const { return base::min() * Q::reference; }
|
||||
[[nodiscard]] Q max() const { return base::max() * Q::reference; }
|
||||
};
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
@ -59,7 +59,7 @@ inline constexpr struct lunar_distance : named_unit<"LD", mag<384'399> * si::kil
|
||||
inline constexpr struct light_year : named_unit<"ly", mag<9'460'730'472'580'800> * si::metre> {} light_year;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Parsec
|
||||
inline constexpr struct parsec : named_unit<"pc", astronomical_unit / (mag_ratio<1, 60 * 60> * si::degree)> {} parsec;
|
||||
inline constexpr struct parsec : named_unit<"pc", astronomical_unit / (mag_ratio<1, 3600> * si::degree)> {} parsec;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Angstrom
|
||||
inline constexpr struct angstrom : named_unit<symbol_text{u8"Å", "A"}, mag_power<10, -10> * si::metre> {} angstrom;
|
||||
|
@ -38,7 +38,7 @@ namespace mp_units {
|
||||
namespace detail {
|
||||
|
||||
template<typename Period>
|
||||
[[nodiscard]] inline consteval auto time_unit_from_chrono_period()
|
||||
[[nodiscard]] consteval auto time_unit_from_chrono_period()
|
||||
{
|
||||
using namespace si;
|
||||
|
||||
|
@ -769,7 +769,7 @@ inline constexpr auto d = day;
|
||||
|
||||
namespace si::unit_symbols {
|
||||
|
||||
using namespace non_si::unit_symbols;
|
||||
using namespace non_si::unit_symbols; // NOLINT(google-build-using-namespace)
|
||||
|
||||
} // namespace si::unit_symbols
|
||||
|
||||
|
7
test/.clang-tidy
Normal file
7
test/.clang-tidy
Normal file
@ -0,0 +1,7 @@
|
||||
Checks: '
|
||||
-bugprone-chained-comparison,
|
||||
-cppcoreguidelines-avoid-magic-numbers,
|
||||
-google-build-using-namespace,
|
||||
-readability-function-cognitive-complexity
|
||||
'
|
||||
InheritParentConfig: true
|
@ -34,7 +34,7 @@ namespace mp_units {
|
||||
|
||||
template<Quantity T>
|
||||
struct AlmostEqualsMatcher : Catch::Matchers::MatcherGenericBase {
|
||||
AlmostEqualsMatcher(const T& target) : target_{target} {}
|
||||
explicit AlmostEqualsMatcher(const T& target) : target_{target} {}
|
||||
|
||||
template<std::convertible_to<T> U>
|
||||
requires std::same_as<typename T::rep, typename U::rep> && treat_as_floating_point<typename T::rep>
|
||||
@ -57,7 +57,7 @@ private:
|
||||
template<Quantity T>
|
||||
AlmostEqualsMatcher<T> AlmostEquals(const T& target)
|
||||
{
|
||||
return {target};
|
||||
return AlmostEqualsMatcher<T>{target};
|
||||
}
|
||||
|
||||
} // namespace mp_units
|
||||
|
@ -35,7 +35,7 @@ using namespace mp_units::si::unit_symbols;
|
||||
|
||||
TEST_CASE("std::atomic works with dimensioned types", "[atomic][assignment]")
|
||||
{
|
||||
std::atomic<quantity<isq::area[m2]>> a1 = 3.0 * isq::area[m2];
|
||||
std::atomic<quantity<isq::area[m2]>> a2 = 3.0 * isq::area[m2];
|
||||
const std::atomic<quantity<isq::area[m2]>> a1 = 3.0 * isq::area[m2];
|
||||
const std::atomic<quantity<isq::area[m2]>> a2 = 3.0 * isq::area[m2];
|
||||
REQUIRE(a1.load() == a2.load());
|
||||
}
|
||||
|
@ -499,7 +499,7 @@ TEST_CASE("discrete_distribution")
|
||||
|
||||
SECTION("parametrized_initializer_list")
|
||||
{
|
||||
std::initializer_list<double> weights = {1.0, 2.0, 3.0};
|
||||
const std::initializer_list<double> weights = {1.0, 2.0, 3.0};
|
||||
|
||||
auto stl_dist = std::discrete_distribution<rep>(weights);
|
||||
auto units_dist = mp_units::discrete_distribution<q>(weights);
|
||||
@ -560,8 +560,8 @@ TEST_CASE("piecewise_constant_distribution")
|
||||
|
||||
SECTION("parametrized_initializer_list")
|
||||
{
|
||||
std::initializer_list<rep> intervals_rep = {1.0, 2.0, 3.0};
|
||||
std::initializer_list<q> intervals_qty = {1.0 * isq::length[si::metre], 2.0 * isq::length[si::metre],
|
||||
const std::initializer_list<rep> intervals_rep = {1.0, 2.0, 3.0};
|
||||
const std::initializer_list<q> intervals_qty = {1.0 * isq::length[si::metre], 2.0 * isq::length[si::metre],
|
||||
3.0 * isq::length[si::metre]};
|
||||
|
||||
auto stl_dist = std::piecewise_constant_distribution<rep>(intervals_rep, [](rep val) { return val; });
|
||||
@ -628,8 +628,8 @@ TEST_CASE("piecewise_linear_distribution")
|
||||
|
||||
SECTION("parametrized_initializer_list")
|
||||
{
|
||||
std::initializer_list<rep> intervals_rep = {1.0, 2.0, 3.0};
|
||||
std::initializer_list<q> intervals_qty = {1.0 * isq::length[si::metre], 2.0 * isq::length[si::metre],
|
||||
const std::initializer_list<rep> intervals_rep = {1.0, 2.0, 3.0};
|
||||
const std::initializer_list<q> intervals_qty = {1.0 * isq::length[si::metre], 2.0 * isq::length[si::metre],
|
||||
3.0 * isq::length[si::metre]};
|
||||
|
||||
auto stl_dist = std::piecewise_linear_distribution<rep>(intervals_rep, [](rep val) { return val; });
|
||||
|
@ -999,17 +999,17 @@ TEST_CASE("different base types with the # specifier", "[text][fmt]")
|
||||
TEST_CASE("localization with the 'L' specifier", "[text][fmt][localization]")
|
||||
{
|
||||
struct group2 : std::numpunct<char> {
|
||||
char do_thousands_sep() const override { return '_'; }
|
||||
std::string do_grouping() const override { return "\2"; }
|
||||
[[nodiscard]] char do_thousands_sep() const override { return '_'; }
|
||||
[[nodiscard]] std::string do_grouping() const override { return "\2"; }
|
||||
};
|
||||
|
||||
struct group3 : std::numpunct<char> {
|
||||
char do_thousands_sep() const override { return '\''; }
|
||||
std::string do_grouping() const override { return "\3"; }
|
||||
[[nodiscard]] char do_thousands_sep() const override { return '\''; }
|
||||
[[nodiscard]] std::string do_grouping() const override { return "\3"; }
|
||||
};
|
||||
|
||||
std::locale grp2{std::locale::classic(), new group2};
|
||||
std::locale grp3{std::locale::classic(), new group3};
|
||||
const std::locale grp2{std::locale::classic(), new group2};
|
||||
const std::locale grp3{std::locale::classic(), new group3};
|
||||
|
||||
SECTION("full format on a quantity")
|
||||
{
|
||||
|
@ -48,6 +48,7 @@ public:
|
||||
constexpr explicit(false) min_impl(min_impl<U> i) noexcept : value_(static_cast<T>(static_cast<U>(i)))
|
||||
{
|
||||
}
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
constexpr explicit(false) operator T() const noexcept { return value_; }
|
||||
};
|
||||
|
||||
@ -140,9 +141,9 @@ static_assert(min_impl<int>{1} * si::metre + min_impl<double>{1.5} * si::metre =
|
||||
static_assert(1 * si::metre + min_impl<int>{1} * si::metre == min_impl<int>{2} * si::metre);
|
||||
static_assert(1 * si::metre + min_impl<double>{1.5} * si::metre == min_impl<double>{2.5} * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::metre + 1 * si::metre == min_impl<int>{2} * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::metre + double{1.5} * si::metre == min_impl<double>{2.5} * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::metre + 1.5 * si::metre == min_impl<double>{2.5} * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::metre + min_impl<int>{1} * si::metre == 2 * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::metre + min_impl<double>{1.5} * si::metre == double{2.5} * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::metre + min_impl<double>{1.5} * si::metre == 2.5 * si::metre);
|
||||
|
||||
static_assert(min_impl<int>{1} * si::kilo<si::metre> + min_impl<int>{1} * si::metre ==
|
||||
min_impl<int>{1'001} * si::metre);
|
||||
@ -151,9 +152,9 @@ static_assert(min_impl<int>{1} * si::kilo<si::metre> + min_impl<double>{1.5} * s
|
||||
static_assert(1 * si::kilo<si::metre> + min_impl<int>{1} * si::metre == min_impl<int>{1'001} * si::metre);
|
||||
static_assert(1 * si::kilo<si::metre> + min_impl<double>{1.5} * si::metre == min_impl<double>{1001.5} * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::kilo<si::metre> + 1 * si::metre == min_impl<int>{1'001} * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::kilo<si::metre> + double{1.5} * si::metre == min_impl<double>{1001.5} * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::kilo<si::metre> + 1.5 * si::metre == min_impl<double>{1001.5} * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::kilo<si::metre> + min_impl<int>{1} * si::metre == 1'001 * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::kilo<si::metre> + min_impl<double>{1.5} * si::metre == double{1001.5} * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::kilo<si::metre> + min_impl<double>{1.5} * si::metre == 1001.5 * si::metre);
|
||||
|
||||
static_assert(min_impl<int>{1} * si::metre + min_impl<int>{1} * si::kilo<si::metre> ==
|
||||
min_impl<int>{1'001} * si::metre);
|
||||
@ -162,7 +163,7 @@ static_assert(min_impl<int>{1} * si::metre + min_impl<double>{1.5} * si::kilo<si
|
||||
static_assert(1 * si::metre + min_impl<int>{1} * si::kilo<si::metre> == min_impl<int>{1'001} * si::metre);
|
||||
static_assert(1 * si::metre + min_impl<double>{1.5} * si::kilo<si::metre> == min_impl<double>{1'501} * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::metre + 1 * si::kilo<si::metre> == min_impl<int>{1'001} * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::metre + double{1.5} * si::kilo<si::metre> == min_impl<double>{1'501} * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::metre + 1.5 * si::kilo<si::metre> == min_impl<double>{1'501} * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::metre + min_impl<int>{1} * si::kilo<si::metre> == 1'001 * si::metre);
|
||||
static_assert(min_impl<int>{1} * si::metre + min_impl<double>{1.5} * si::kilo<si::metre> == double{1'501} * si::metre);
|
||||
|
||||
@ -171,9 +172,9 @@ static_assert(min_impl<int>{2} * si::metre - min_impl<double>{1.5} * si::metre =
|
||||
static_assert(2 * si::metre - min_impl<int>{1} * si::metre == min_impl<int>{1} * si::metre);
|
||||
static_assert(2 * si::metre - min_impl<double>{1.5} * si::metre == min_impl<double>{0.5} * si::metre);
|
||||
static_assert(min_impl<int>{2} * si::metre - 1 * si::metre == min_impl<int>{1} * si::metre);
|
||||
static_assert(min_impl<int>{2} * si::metre - double{1.5} * si::metre == min_impl<double>{0.5} * si::metre);
|
||||
static_assert(min_impl<int>{2} * si::metre - 1.5 * si::metre == min_impl<double>{0.5} * si::metre);
|
||||
static_assert(min_impl<int>{2} * si::metre - min_impl<int>{1} * si::metre == 1 * si::metre);
|
||||
static_assert(min_impl<int>{2} * si::metre - min_impl<double>{1.5} * si::metre == double{0.5} * si::metre);
|
||||
static_assert(min_impl<int>{2} * si::metre - min_impl<double>{1.5} * si::metre == 0.5 * si::metre);
|
||||
|
||||
static_assert(min_impl<int>{2} * si::kilo<si::metre> - min_impl<int>{1} * si::metre ==
|
||||
min_impl<int>{1'999} * si::metre);
|
||||
@ -182,9 +183,9 @@ static_assert(min_impl<int>{2} * si::kilo<si::metre> - min_impl<double>{1.5} * s
|
||||
static_assert(2 * si::kilo<si::metre> - min_impl<int>{1} * si::metre == min_impl<int>{1'999} * si::metre);
|
||||
static_assert(2 * si::kilo<si::metre> - min_impl<double>{1.5} * si::metre == min_impl<double>{1998.5} * si::metre);
|
||||
static_assert(min_impl<int>{2} * si::kilo<si::metre> - 1 * si::metre == min_impl<int>{1'999} * si::metre);
|
||||
static_assert(min_impl<int>{2} * si::kilo<si::metre> - double{1.5} * si::metre == min_impl<double>{1998.5} * si::metre);
|
||||
static_assert(min_impl<int>{2} * si::kilo<si::metre> - 1.5 * si::metre == min_impl<double>{1998.5} * si::metre);
|
||||
static_assert(min_impl<int>{2} * si::kilo<si::metre> - min_impl<int>{1} * si::metre == 1'999 * si::metre);
|
||||
static_assert(min_impl<int>{2} * si::kilo<si::metre> - min_impl<double>{1.5} * si::metre == double{1998.5} * si::metre);
|
||||
static_assert(min_impl<int>{2} * si::kilo<si::metre> - min_impl<double>{1.5} * si::metre == 1998.5 * si::metre);
|
||||
|
||||
static_assert(min_impl<int>{2'000} * si::metre - min_impl<int>{1} * si::kilo<si::metre> ==
|
||||
min_impl<int>{1'000} * si::metre);
|
||||
@ -193,8 +194,7 @@ static_assert(min_impl<int>{2'000} * si::metre - min_impl<double>{1.5} * si::kil
|
||||
static_assert(2'000 * si::metre - min_impl<int>{1} * si::kilo<si::metre> == min_impl<int>{1'000} * si::metre);
|
||||
static_assert(2'000 * si::metre - min_impl<double>{1.5} * si::kilo<si::metre> == min_impl<double>{500} * si::metre);
|
||||
static_assert(min_impl<int>{2'000} * si::metre - 1 * si::kilo<si::metre> == min_impl<int>{1'000} * si::metre);
|
||||
static_assert(min_impl<int>{2'000} * si::metre - double{1.5} * si::kilo<si::metre> ==
|
||||
min_impl<double>{500} * si::metre);
|
||||
static_assert(min_impl<int>{2'000} * si::metre - 1.5 * si::kilo<si::metre> == min_impl<double>{500} * si::metre);
|
||||
static_assert(min_impl<int>{2'000} * si::metre - min_impl<int>{1} * si::kilo<si::metre> == 1'000 * si::metre);
|
||||
static_assert(min_impl<int>{2'000} * si::metre - min_impl<double>{1.5} * si::kilo<si::metre> ==
|
||||
double{500} * si::metre);
|
||||
@ -225,7 +225,7 @@ static_assert(min_impl<int>{123} * si::metre / (2. * one) == min_impl<double>{61
|
||||
static_assert(123 * si::metre / (min_impl<double>(2.) * one) == min_impl<double>{61.5} * si::metre);
|
||||
|
||||
static_assert(min_impl<int>{123} * si::metre / (min_impl<double>{2.} * si::metre) == 61.5 * one);
|
||||
static_assert(min_impl<int>{123} * si::metre / (double{2.} * si::metre) == 61.5 * one);
|
||||
static_assert(min_impl<int>{123} * si::metre / (2. * si::metre) == 61.5 * one);
|
||||
static_assert(123 * si::metre / (min_impl<double>{2.} * si::metre) == 61.5 * one);
|
||||
#endif
|
||||
|
||||
|
@ -835,7 +835,7 @@ static_assert((tower_peak + 42 * m).point_for(tower_peak).quantity_from(tower_pe
|
||||
static_assert((mean_sea_level + 42 * m).point_for(tower_peak).quantity_from(tower_peak) == -42 * m);
|
||||
static_assert((ground_level + 84 * m).point_for(tower_peak).quantity_from(tower_peak) == 42 * m);
|
||||
|
||||
static_assert(is_of_type<(ground_level + isq::height(short(42) * m)).point_for(mean_sea_level),
|
||||
static_assert(is_of_type<(ground_level + isq::height(short{42} * m)).point_for(mean_sea_level),
|
||||
quantity_point<isq::height[m], mean_sea_level, int>>);
|
||||
|
||||
|
||||
@ -938,7 +938,8 @@ static_assert(same_ground_level2_qp.quantity_ref_from(same_ground_level2) == 1 *
|
||||
////////////////////////
|
||||
|
||||
static_assert(([]() {
|
||||
quantity_point l1{mean_sea_level + 1 * m}, l2{mean_sea_level + 2 * m};
|
||||
const quantity_point l1{mean_sea_level + 1 * m};
|
||||
quantity_point l2{mean_sea_level + 2 * m};
|
||||
return l2 = l1;
|
||||
}())
|
||||
.quantity_from(mean_sea_level) == 1 * m);
|
||||
@ -950,7 +951,7 @@ static_assert(([]() {
|
||||
.quantity_from(mean_sea_level) == 1 * m);
|
||||
static_assert(([]() {
|
||||
quantity_point l1{mean_sea_level + 1 * m}, l2{mean_sea_level + 2 * m};
|
||||
return l2 = std::move(l1);
|
||||
return l2 = std::move(l1); // NOLINT(*-move-const-arg)
|
||||
}())
|
||||
.quantity_from(mean_sea_level) == 1 * m);
|
||||
|
||||
@ -960,19 +961,19 @@ static_assert(([]() {
|
||||
////////////////////
|
||||
|
||||
static_assert([](auto v) {
|
||||
auto vv = v++;
|
||||
auto vv = v++; // NOLINT(bugprone-inc-dec-in-conditions)
|
||||
return std::pair(v, vv);
|
||||
}(mean_sea_level + 123 * m) == std::pair(mean_sea_level + 124 * m, quantity_point(mean_sea_level + 123 * m)));
|
||||
static_assert([](auto v) {
|
||||
auto vv = ++v;
|
||||
auto vv = ++v; // NOLINT(bugprone-inc-dec-in-conditions)
|
||||
return std::pair(v, vv);
|
||||
}(mean_sea_level + 123 * m) == std::pair(mean_sea_level + 124 * m, mean_sea_level + 124 * m));
|
||||
static_assert([](auto v) {
|
||||
auto vv = v--;
|
||||
auto vv = v--; // NOLINT(bugprone-inc-dec-in-conditions)
|
||||
return std::pair(v, vv);
|
||||
}(mean_sea_level + 123 * m) == std::pair(mean_sea_level + 122 * m, mean_sea_level + 123 * m));
|
||||
static_assert([](auto v) {
|
||||
auto vv = --v;
|
||||
auto vv = --v; // NOLINT(bugprone-inc-dec-in-conditions)
|
||||
return std::pair(v, vv);
|
||||
}(mean_sea_level + 123 * m) == std::pair(mean_sea_level + 122 * m, mean_sea_level + 122 * m));
|
||||
|
||||
@ -1302,32 +1303,32 @@ static_assert(is_of_type<(1 * m + tower_peak) - (1 * m + other_ground_level), qu
|
||||
|
||||
|
||||
// check for integral types promotion
|
||||
static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t(0) * m) + std::uint8_t(0) * m)
|
||||
static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t{0} * m) + std::uint8_t{0} * m)
|
||||
.quantity_from(mean_sea_level)
|
||||
.numerical_value_in(m)),
|
||||
int>);
|
||||
static_assert(is_same_v<decltype((std::uint8_t(0) * m + (mean_sea_level + std::uint8_t(0) * m))
|
||||
static_assert(is_same_v<decltype((std::uint8_t{0} * m + (mean_sea_level + std::uint8_t{0} * m))
|
||||
.quantity_from(mean_sea_level)
|
||||
.numerical_value_in(m)),
|
||||
int>);
|
||||
static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(0) * m)
|
||||
static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t{0} * m) - std::uint8_t{0} * m)
|
||||
.quantity_from(mean_sea_level)
|
||||
.numerical_value_in(m)),
|
||||
int>);
|
||||
static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(0) * m))
|
||||
static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t{0} * m) - (mean_sea_level + std::uint8_t{0} * m))
|
||||
.numerical_value_in(m)),
|
||||
int>);
|
||||
static_assert(((mean_sea_level + std::uint8_t(128) * m) + std::uint8_t(128) * m)
|
||||
static_assert(((mean_sea_level + std::uint8_t{128} * m) + std::uint8_t{128} * m)
|
||||
.quantity_from(mean_sea_level)
|
||||
.numerical_value_in(m) == std::uint8_t(128) + std::uint8_t(128));
|
||||
static_assert((std::uint8_t(128) * m + (mean_sea_level + std::uint8_t(128) * m))
|
||||
.numerical_value_in(m) == std::uint8_t{128} + std::uint8_t{128});
|
||||
static_assert((std::uint8_t{128} * m + (mean_sea_level + std::uint8_t{128} * m))
|
||||
.quantity_from(mean_sea_level)
|
||||
.numerical_value_in(m) == std::uint8_t(128) + std::uint8_t(128));
|
||||
.numerical_value_in(m) == std::uint8_t{128} + std::uint8_t{128});
|
||||
static_assert(
|
||||
((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(1) * m).quantity_from(mean_sea_level).numerical_value_in(m) ==
|
||||
std::uint8_t(0) - std::uint8_t(1));
|
||||
static_assert(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(1) * m)).numerical_value_in(m) ==
|
||||
std::uint8_t(0) - std::uint8_t(1));
|
||||
((mean_sea_level + std::uint8_t{0} * m) - std::uint8_t{1} * m).quantity_from(mean_sea_level).numerical_value_in(m) ==
|
||||
std::uint8_t{0} - std::uint8_t{1});
|
||||
static_assert(((mean_sea_level + std::uint8_t{0} * m) - (mean_sea_level + std::uint8_t{1} * m)).numerical_value_in(m) ==
|
||||
std::uint8_t{0} - std::uint8_t{1});
|
||||
|
||||
// different representation types
|
||||
static_assert(is_of_type<(mean_sea_level + 1. * m) + 1 * m, quantity_point<si::metre, mean_sea_level, double>>);
|
||||
@ -1676,5 +1677,4 @@ static_assert(invalid_addition(5 * isq::activity[Bq], 10 / (2 * isq::time[s]), q
|
||||
static_assert(invalid_subtraction(quantity_point{5 * isq::activity[Bq]}, 10 / (2 * isq::time[s]),
|
||||
5 * isq::frequency[Hz]));
|
||||
|
||||
|
||||
} // namespace
|
||||
|
@ -277,11 +277,12 @@ struct derived_quantity : quantity<Q::reference, Rep> {
|
||||
R::operator=(std::move(t));
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr operator R&() & noexcept { return *this; }
|
||||
constexpr operator const R&() const& noexcept { return *this; }
|
||||
constexpr operator R&&() && noexcept { return *this; }
|
||||
constexpr operator const R&&() const&& noexcept { return *this; }
|
||||
// NOLINTBEGIN(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
constexpr explicit(false) operator R&() & noexcept { return *this; }
|
||||
constexpr explicit(false) operator const R&() const& noexcept { return *this; }
|
||||
constexpr explicit(false) operator R&&() && noexcept { return *this; }
|
||||
constexpr explicit(false) operator const R&&() const&& noexcept { return *this; }
|
||||
// NOLINTEND(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
};
|
||||
|
||||
static_assert(Quantity<derived_quantity<double, quantity<isq::length[m]>, "NTTP type description">>);
|
||||
@ -320,19 +321,19 @@ static_assert(quantity{24h}.quantity_spec == kind_of<isq::time>);
|
||||
////////////////////////
|
||||
|
||||
static_assert([] {
|
||||
auto l1(1 * m), l2(2 * m);
|
||||
auto l1 = 1 * m, l2 = 2 * m;
|
||||
return l2 = l1;
|
||||
}()
|
||||
.numerical_value_in(m) == 1);
|
||||
static_assert([] {
|
||||
const auto l1(1 * m);
|
||||
auto l2(2 * m);
|
||||
const auto l1 = 1 * m;
|
||||
auto l2 = 2 * m;
|
||||
return l2 = l1;
|
||||
}()
|
||||
.numerical_value_in(m) == 1);
|
||||
static_assert([]() {
|
||||
auto l1(1 * m), l2(2 * m);
|
||||
return l2 = std::move(l1);
|
||||
auto l1 = 1 * m, l2 = 2 * m;
|
||||
return l2 = std::move(l1); // NOLINT(*-move-const-arg)
|
||||
}()
|
||||
.numerical_value_in(m) == 1);
|
||||
|
||||
@ -347,19 +348,19 @@ static_assert((+(-123 * m)).numerical_value_in(m) == -123);
|
||||
static_assert((-(-123 * m)).numerical_value_in(m) == 123);
|
||||
|
||||
static_assert([](auto v) {
|
||||
auto vv = v++;
|
||||
const auto vv = v++; // NOLINT(bugprone-inc-dec-in-conditions)
|
||||
return std::pair(v, vv);
|
||||
}(123 * m) == std::pair(124 * m, 123 * m));
|
||||
static_assert([](auto v) {
|
||||
auto vv = ++v;
|
||||
const auto vv = ++v; // NOLINT(bugprone-inc-dec-in-conditions)
|
||||
return std::pair(v, vv);
|
||||
}(123 * m) == std::pair(124 * m, 124 * m));
|
||||
static_assert([](auto v) {
|
||||
auto vv = v--;
|
||||
const auto vv = v--; // NOLINT(bugprone-inc-dec-in-conditions)
|
||||
return std::pair(v, vv);
|
||||
}(123 * m) == std::pair(122 * m, 123 * m));
|
||||
static_assert([](auto v) {
|
||||
auto vv = --v;
|
||||
const auto vv = --v; // NOLINT(bugprone-inc-dec-in-conditions)
|
||||
return std::pair(v, vv);
|
||||
}(123 * m) == std::pair(122 * m, 122 * m));
|
||||
|
||||
@ -390,12 +391,12 @@ static_assert((2.5 * m *= 3 * one).numerical_value_in(m) == 7.5);
|
||||
static_assert((7.5 * m /= 3 * one).numerical_value_in(m) == 2.5);
|
||||
static_assert((3500 * m %= 1 * km).numerical_value_in(m) == 500);
|
||||
|
||||
// static_assert((std::uint8_t(255) * m %= 256 * m).numerical_value_in(m) == [] {
|
||||
// static_assert((std::uint8_t{255} * m %= 256 * m).numerical_value_in(m) == [] {
|
||||
// std::uint8_t ui(255);
|
||||
// return ui %= 256;
|
||||
// }()); // UB
|
||||
// TODO: Fix
|
||||
static_assert((std::uint8_t(255) * m %= 257 * m).numerical_value_in(m) != [] {
|
||||
static_assert((std::uint8_t{255}* m %= 257 * m).numerical_value_in(m) != [] {
|
||||
std::uint8_t ui(255);
|
||||
return ui %= 257;
|
||||
}());
|
||||
@ -538,14 +539,14 @@ static_assert(is_of_type<1 * km % (300 * m), quantity<si::metre, int>>);
|
||||
static_assert(is_of_type<4 * one % (2 * one), quantity<one, int>>);
|
||||
|
||||
// check for integral types promotion
|
||||
static_assert(is_same_v<decltype(std::uint8_t(0) * m + std::uint8_t(0) * m)::rep, int>);
|
||||
static_assert(is_same_v<decltype(std::uint8_t(0) * m - std::uint8_t(0) * m)::rep, int>);
|
||||
static_assert((std::uint8_t(128) * m + std::uint8_t(128) * m).numerical_value_in(m) ==
|
||||
std::uint8_t(128) + std::uint8_t(128));
|
||||
static_assert((std::uint8_t(0) * m - std::uint8_t(1) * m).numerical_value_in(m) == std::uint8_t(0) - std::uint8_t(1));
|
||||
static_assert(is_same_v<decltype(std::uint8_t{0} * m + std::uint8_t{0} * m)::rep, int>);
|
||||
static_assert(is_same_v<decltype(std::uint8_t{0} * m - std::uint8_t{0} * m)::rep, int>);
|
||||
static_assert((std::uint8_t{128} * m + std::uint8_t{128} * m).numerical_value_in(m) ==
|
||||
std::uint8_t{128} + std::uint8_t{128});
|
||||
static_assert((std::uint8_t{0} * m - std::uint8_t{1} * m).numerical_value_in(m) == std::uint8_t{0} - std::uint8_t{1});
|
||||
|
||||
static_assert(
|
||||
is_same_v<decltype((std::uint8_t(0) * m) % (std::uint8_t(0) * m))::rep, decltype(std::uint8_t(0) % std::uint8_t(0))>);
|
||||
is_same_v<decltype((std::uint8_t{0} * m) % (std::uint8_t{0} * m))::rep, decltype(std::uint8_t{0} % std::uint8_t{0})>);
|
||||
|
||||
// different representation types
|
||||
static_assert(is_of_type<1. * m + 1 * m, quantity<si::metre, double>>);
|
||||
@ -767,14 +768,14 @@ static_assert(is_same_v<decltype(0.0 * one - 0 * one), decltype(0.0 * one)>);
|
||||
static_assert(1 * one - 30 * percent == (100 - 30) * percent);
|
||||
static_assert(1 * one + 30 * percent == (100 + 30) * percent);
|
||||
|
||||
static_assert(is_same_v<decltype(std::uint8_t(0) * one + std::uint8_t(0) * one)::rep, int>);
|
||||
static_assert(is_same_v<decltype(std::uint8_t(0) * one - std::uint8_t(0) * one)::rep, int>);
|
||||
static_assert((std::uint8_t(128) * one + std::uint8_t(128) * one).numerical_value_in(one) ==
|
||||
std::uint8_t(128) + std::uint8_t(128));
|
||||
static_assert((std::uint8_t(0) * one - std::uint8_t(1) * one).numerical_value_in(one) ==
|
||||
std::uint8_t(0) - std::uint8_t(1));
|
||||
static_assert(is_same_v<decltype(std::uint8_t(0) * one % (std::uint8_t(0) * one))::rep,
|
||||
decltype(std::uint8_t(0) % std::uint8_t(0))>);
|
||||
static_assert(is_same_v<decltype(std::uint8_t{0} * one + std::uint8_t{0} * one)::rep, int>);
|
||||
static_assert(is_same_v<decltype(std::uint8_t{0} * one - std::uint8_t{0} * one)::rep, int>);
|
||||
static_assert((std::uint8_t{128} * one + std::uint8_t{128} * one).numerical_value_in(one) ==
|
||||
std::uint8_t{128} + std::uint8_t{128});
|
||||
static_assert((std::uint8_t{0} * one - std::uint8_t{1} * one).numerical_value_in(one) ==
|
||||
std::uint8_t{0} - std::uint8_t{1});
|
||||
static_assert(is_same_v<decltype(std::uint8_t{0} * one % (std::uint8_t{0} * one))::rep,
|
||||
decltype(std::uint8_t{0} % std::uint8_t{0})>);
|
||||
|
||||
static_assert(2 * one * (1 * m) == 2 * m);
|
||||
static_assert(2 * one / (1 * m) == 2 / (1 * m));
|
||||
|
@ -29,6 +29,7 @@
|
||||
template<auto V, typename T>
|
||||
inline constexpr bool is_of_type = std::is_same_v<std::remove_cvref_t<decltype(V)>, T>;
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
|
||||
#ifdef MP_UNITS_API_NO_CRTP
|
||||
|
||||
#define QUANTITY_SPEC_(name, ...) \
|
||||
@ -42,3 +43,4 @@ inline constexpr bool is_of_type = std::is_same_v<std::remove_cvref_t<decltype(V
|
||||
} name
|
||||
|
||||
#endif
|
||||
// NOLINTEND(cppcoreguidelines-macro-usage)
|
||||
|
@ -111,7 +111,7 @@ static_assert(unit_symbol<unit_symbol_formatting{.encoding = ascii}>(mag<60> * s
|
||||
static_assert(unit_symbol(mag_ratio<1, 18> * metre / second) == "[1/18] m/s");
|
||||
|
||||
// derived units
|
||||
static_assert(unit_symbol(one) == "");
|
||||
static_assert(unit_symbol(one) == ""); // NOLINT(readability-container-size-empty)
|
||||
static_assert(unit_symbol(percent) == "%");
|
||||
static_assert(unit_symbol(per_mille) == "‰");
|
||||
static_assert(unit_symbol<unit_symbol_formatting{.encoding = ascii}>(per_mille) == "%o");
|
||||
@ -122,7 +122,7 @@ static_assert(unit_symbol(cubic(metre)) == "m³");
|
||||
static_assert(unit_symbol<unit_symbol_formatting{.encoding = ascii}>(cubic(metre)) == "m^3");
|
||||
static_assert(unit_symbol(kilo<metre> * metre) == "km m");
|
||||
static_assert(unit_symbol<unit_symbol_formatting{.separator = half_high_dot}>(kilo<metre> * metre) == "km⋅m");
|
||||
static_assert(unit_symbol(metre / metre) == "");
|
||||
static_assert(unit_symbol(metre / metre) == ""); // NOLINT(readability-container-size-empty)
|
||||
static_assert(unit_symbol(kilo<metre> / metre) == "km/m");
|
||||
static_assert(unit_symbol<unit_symbol_formatting{.solidus = never}>(kilo<metre> / metre) == "km m⁻¹");
|
||||
static_assert(unit_symbol<unit_symbol_formatting{.encoding = ascii, .solidus = never}>(kilo<metre> / metre) ==
|
||||
|
Reference in New Issue
Block a user