mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-04 12:54:25 +02:00
Merge branch 'master' of github.com:mpusz/mp-units
This commit is contained in:
@@ -20,7 +20,7 @@
|
|||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
|
|
||||||
name: Check CI
|
name: Formatting CI
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
[](https://github.com/mpusz/mp-units/actions?query=workflow%3A%22Conan%20CI%22+branch%3Amaster)
|
[](https://github.com/mpusz/mp-units/actions?query=workflow%3A%22Conan%20CI%22+branch%3Amaster)
|
||||||
[](https://github.com/mpusz/mp-units/actions?query=workflow%3A%22CMake+Test+Package+CI%22+branch%3Amaster)
|
[](https://github.com/mpusz/mp-units/actions?query=workflow%3A%22CMake+Test+Package+CI%22+branch%3Amaster)
|
||||||
[](https://github.com/mpusz/mp-units/actions?query=workflow%3A%22Check%20CI%22+branch%3Amaster)
|
[](https://github.com/mpusz/mp-units/actions?query=workflow%3A%22Formatting%20CI%22+branch%3Amaster)
|
||||||
[](https://github.com/mpusz/mp-units/actions?query=workflow%3ADocumentation+branch%3Amaster)
|
[](https://github.com/mpusz/mp-units/actions?query=workflow%3ADocumentation+branch%3Amaster)
|
||||||
|
|
||||||
[](https://conan.io/center/mp-units)
|
[](https://conan.io/center/mp-units)
|
||||||
|
@@ -25,7 +25,7 @@ specific feature:
|
|||||||
| **Minimum support** | 12 | 16 | 15 | None |
|
| **Minimum support** | 12 | 16 | 15 | None |
|
||||||
| **`std::format`** | None | None | None | None |
|
| **`std::format`** | None | None | None | None |
|
||||||
| **C++ modules** | None | 17 | None | None |
|
| **C++ modules** | None | 17 | None | None |
|
||||||
| **C++23 extensions** | None | None | None | None |
|
| **C++23 extensions** | 14 | 18 | None | None |
|
||||||
|
|
||||||
More requirements for C++ modules support can be found in the
|
More requirements for C++ modules support can be found in the
|
||||||
[CMake's documentation](https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html).
|
[CMake's documentation](https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html).
|
||||||
|
@@ -33,7 +33,7 @@ The library source code is hosted on [GitHub](https://github.com/mpusz/mp-units)
|
|||||||
| **Minimum support** | 12 | 16 | 15 | None |
|
| **Minimum support** | 12 | 16 | 15 | None |
|
||||||
| **`std::format`** | None | None | None | None |
|
| **`std::format`** | None | None | None | None |
|
||||||
| **C++ modules** | None | 17 | None | None |
|
| **C++ modules** | None | 17 | None | None |
|
||||||
| **C++23 extensions** | None | None | None | None |
|
| **C++23 extensions** | 14 | 18 | None | None |
|
||||||
|
|
||||||
More requirements for C++ modules support can be found in the
|
More requirements for C++ modules support can be found in the
|
||||||
[CMake's documentation](https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html).
|
[CMake's documentation](https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html).
|
||||||
|
@@ -165,12 +165,8 @@ A `Reference` can either be:
|
|||||||
|
|
||||||
### `ReferenceOf<T, V>` { #ReferenceOf }
|
### `ReferenceOf<T, V>` { #ReferenceOf }
|
||||||
|
|
||||||
`ReferenceOf` concept is satisfied by references `T` that match the following value `V`:
|
`ReferenceOf` concept is satisfied by references `T` which have a quantity specification that satisfies
|
||||||
|
[`QuantitySpecOf<V>`](#QuantitySpecOf) concept. |
|
||||||
| `V` | Condition |
|
|
||||||
|----------------|-----------------------------------------------------------------------------------------------|
|
|
||||||
| `Dimension` | The dimension of a quantity specification satisfies [`DimensionOf<V>`](#DimensionOf) concept. |
|
|
||||||
| `QuantitySpec` | The quantity specification satisfies [`QuantitySpecOf<V>`](#QuantitySpecOf) concept. |
|
|
||||||
|
|
||||||
|
|
||||||
## `Representation<T>` { #Representation }
|
## `Representation<T>` { #Representation }
|
||||||
@@ -212,7 +208,7 @@ satisfied by all types being or deriving from an instantiation of a `quantity` c
|
|||||||
|
|
||||||
### `QuantityOf<T, V>` { #QuantityOf }
|
### `QuantityOf<T, V>` { #QuantityOf }
|
||||||
|
|
||||||
`QuantityOf` concept is satisfied by all the quantities for which a [`ReferenceOf<V>`](#ReferenceOf)
|
`QuantityOf` concept is satisfied by all the quantities for which a [`QuantitySpecOf<V>`](#QuantitySpecOf)
|
||||||
is `true`.
|
is `true`.
|
||||||
|
|
||||||
|
|
||||||
@@ -259,10 +255,10 @@ class template.
|
|||||||
|
|
||||||
`QuantityPointOf` concept is satisfied by all the quantity points `T` that match the following value `V`:
|
`QuantityPointOf` concept is satisfied by all the quantity points `T` that match the following value `V`:
|
||||||
|
|
||||||
| `V` | Condition |
|
| `V` | Condition |
|
||||||
|---------------|----------------------------------------------------------------------------------|
|
|----------------|-----------------------------------------------------------------------------------------------------|
|
||||||
| `Reference` | The quantity point reference satisfies [`ReferenceOf<V>`](#ReferenceOf) concept. |
|
| `QuantitySpec` | The quantity point quantity specification satisfies [`QuantitySpecOf<V>`](#QuantitySpecOf) concept. |
|
||||||
| `PointOrigin` | The _point_ and `V` have the same absolute point origin. |
|
| `PointOrigin` | The _point_ and `V` have the same absolute point origin. |
|
||||||
|
|
||||||
|
|
||||||
## `QuantityLike<T>` { #QuantityLike }
|
## `QuantityLike<T>` { #QuantityLike }
|
||||||
|
@@ -160,6 +160,8 @@ with dimensionless quantities:
|
|||||||
```cpp
|
```cpp
|
||||||
inline constexpr struct percent : named_unit<"%", mag<ratio{1, 100}> * one> {} percent;
|
inline constexpr struct percent : named_unit<"%", mag<ratio{1, 100}> * one> {} percent;
|
||||||
inline constexpr struct per_mille : named_unit<basic_symbol_text{"‰", "%o"}, mag<ratio(1, 1000)> * one> {} per_mille;
|
inline constexpr struct per_mille : named_unit<basic_symbol_text{"‰", "%o"}, mag<ratio(1, 1000)> * one> {} per_mille;
|
||||||
|
inline constexpr struct parts_per_million : named_unit<"ppm", mag<ratio(1, 1'000'000)> * one> {} parts_per_million;
|
||||||
|
inline constexpr auto ppm = parts_per_million;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@@ -337,13 +337,13 @@ Among others, we can find there the following:
|
|||||||
- `exp()`,
|
- `exp()`,
|
||||||
- `abs()`,
|
- `abs()`,
|
||||||
- `epsilon()`,
|
- `epsilon()`,
|
||||||
- `fma()`,
|
- `fma()`, `fmod()`,
|
||||||
- `isfinite()`, `isinf()`, `isnan()`,
|
- `isfinite()`, `isinf()`, `isnan()`,
|
||||||
- `floor()`, `ceil()`, `round()`,
|
- `floor()`, `ceil()`, `round()`,
|
||||||
- `inverse()`,
|
- `inverse()`,
|
||||||
- `hypot()`,
|
- `hypot()`,
|
||||||
- `sin()`, `cos()`, `tan()`,
|
- `sin()`, `cos()`, `tan()`,
|
||||||
- `asin()`, `acos()`, `atan()`.
|
- `asin()`, `acos()`, `atan()`, `atan2()`.
|
||||||
|
|
||||||
In the library, we can also find _mp-units/random.h_ header file with all the pseudo-random number
|
In the library, we can also find _mp-units/random.h_ header file with all the pseudo-random number
|
||||||
generators working on quantity types.
|
generators working on quantity types.
|
||||||
|
@@ -29,6 +29,7 @@
|
|||||||
// IWYU pragma: begin_exports
|
// IWYU pragma: begin_exports
|
||||||
#include <compare>
|
#include <compare>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <ostream>
|
||||||
// IWYU pragma: end_exports
|
// IWYU pragma: end_exports
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
@@ -56,18 +57,18 @@ struct basic_fixed_string {
|
|||||||
using size_type = std::size_t;
|
using size_type = std::size_t;
|
||||||
using difference_type = std::ptrdiff_t;
|
using difference_type = std::ptrdiff_t;
|
||||||
|
|
||||||
constexpr explicit(false) basic_fixed_string(CharT ch) noexcept
|
|
||||||
requires(N == 1)
|
|
||||||
{
|
|
||||||
data_[0] = ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr explicit(false) basic_fixed_string(const CharT (&txt)[N + 1]) noexcept
|
constexpr explicit(false) basic_fixed_string(const CharT (&txt)[N + 1]) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (N != 0)
|
if constexpr (N != 0)
|
||||||
for (std::size_t i = 0; i < N; ++i) data_[i] = txt[i];
|
for (std::size_t i = 0; i < N; ++i) data_[i] = txt[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<std::convertible_to<CharT>... Rest>
|
||||||
|
requires(1 + sizeof...(Rest) == N)
|
||||||
|
constexpr explicit basic_fixed_string(CharT first, Rest... rest) noexcept : data_{first, rest..., CharT('\0')}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
constexpr basic_fixed_string(const CharT* ptr, std::integral_constant<std::size_t, N>) noexcept
|
constexpr basic_fixed_string(const CharT* ptr, std::integral_constant<std::size_t, N>) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (N != 0)
|
if constexpr (N != 0)
|
||||||
@@ -78,13 +79,18 @@ struct basic_fixed_string {
|
|||||||
[[nodiscard]] constexpr size_type size() const noexcept { return N; }
|
[[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 data_; }
|
||||||
[[nodiscard]] constexpr const CharT* c_str() const noexcept { return data(); }
|
[[nodiscard]] constexpr const CharT* c_str() const noexcept { return data(); }
|
||||||
[[nodiscard]] constexpr const_reference operator[](size_type index) const noexcept { return data()[index]; }
|
[[nodiscard]] constexpr value_type operator[](size_type index) const noexcept { return data()[index]; }
|
||||||
|
|
||||||
[[nodiscard]] constexpr const_iterator begin() const noexcept { return data(); }
|
[[nodiscard]] constexpr const_iterator begin() const noexcept { return data(); }
|
||||||
[[nodiscard]] constexpr const_iterator cbegin() const noexcept { return data(); }
|
[[nodiscard]] constexpr const_iterator cbegin() const noexcept { return data(); }
|
||||||
[[nodiscard]] constexpr const_iterator end() const noexcept { return data() + size(); }
|
[[nodiscard]] constexpr const_iterator end() const noexcept { return data() + size(); }
|
||||||
[[nodiscard]] constexpr const_iterator cend() const noexcept { return data() + size(); }
|
[[nodiscard]] constexpr const_iterator cend() const noexcept { return data() + size(); }
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr std::basic_string_view<CharT> view() const noexcept
|
||||||
|
{
|
||||||
|
return std::basic_string_view<CharT>(cbegin(), cend());
|
||||||
|
}
|
||||||
|
|
||||||
template<std::size_t N2>
|
template<std::size_t N2>
|
||||||
[[nodiscard]] constexpr friend basic_fixed_string<CharT, N + N2> operator+(
|
[[nodiscard]] constexpr friend basic_fixed_string<CharT, N + N2> operator+(
|
||||||
const basic_fixed_string& lhs, const basic_fixed_string<CharT, N2>& rhs) noexcept
|
const basic_fixed_string& lhs, const basic_fixed_string<CharT, N2>& rhs) noexcept
|
||||||
@@ -116,14 +122,21 @@ struct basic_fixed_string {
|
|||||||
// TODO std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
// TODO std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
||||||
return detail::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
return detail::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
template<typename CharT>
|
template<typename Traits>
|
||||||
basic_fixed_string(CharT) -> basic_fixed_string<CharT, 1>;
|
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os,
|
||||||
|
const basic_fixed_string<CharT, N>& str)
|
||||||
|
{
|
||||||
|
return os << str.c_str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename CharT, std::size_t N>
|
template<typename CharT, std::size_t N>
|
||||||
basic_fixed_string(const CharT (&str)[N]) -> basic_fixed_string<CharT, N - 1>;
|
basic_fixed_string(const CharT (&str)[N]) -> basic_fixed_string<CharT, N - 1>;
|
||||||
|
|
||||||
|
template<typename CharT, std::convertible_to<CharT>... Rest>
|
||||||
|
basic_fixed_string(CharT, Rest...) -> basic_fixed_string<CharT, 1 + sizeof...(Rest)>;
|
||||||
|
|
||||||
template<typename CharT, std::size_t N>
|
template<typename CharT, std::size_t N>
|
||||||
basic_fixed_string(const CharT* ptr, std::integral_constant<std::size_t, N>) -> basic_fixed_string<CharT, N>;
|
basic_fixed_string(const CharT* ptr, std::integral_constant<std::size_t, N>) -> basic_fixed_string<CharT, N>;
|
||||||
|
|
||||||
@@ -131,3 +144,12 @@ template<std::size_t N>
|
|||||||
using fixed_string = basic_fixed_string<char, N>;
|
using fixed_string = basic_fixed_string<char, N>;
|
||||||
|
|
||||||
} // namespace mp_units
|
} // namespace mp_units
|
||||||
|
|
||||||
|
template<typename CharT, std::size_t N>
|
||||||
|
struct MP_UNITS_STD_FMT::formatter<mp_units::basic_fixed_string<CharT, N>> : formatter<std::basic_string_view<CharT>> {
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(const mp_units::basic_fixed_string<CharT, N>& str, FormatContext& ctx)
|
||||||
|
{
|
||||||
|
return formatter<std::basic_string_view<CharT>>::format(str.view(), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@@ -83,6 +83,36 @@ template<typename T, template<typename...> typename Type>
|
|||||||
// inline constexpr bool // TODO: Replace with concept when it works with MSVC
|
// inline constexpr bool // TODO: Replace with concept when it works with MSVC
|
||||||
concept is_derived_from_specialization_of = requires(T* t) { detail::to_base_specialization_of<Type>(t); };
|
concept is_derived_from_specialization_of = requires(T* t) { detail::to_base_specialization_of<Type>(t); };
|
||||||
|
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct get_value_type {
|
||||||
|
using type = MP_UNITS_TYPENAME T::value_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct get_element_type {
|
||||||
|
using type = std::remove_reference_t<typename T::element_type>;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct underlying_type {
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
requires requires { typename T::value_type; } || requires { typename T::element_type; }
|
||||||
|
struct underlying_type<T> {
|
||||||
|
using type = MP_UNITS_TYPENAME
|
||||||
|
conditional<requires { typename T::value_type; }, detail::get_value_type<T>, detail::get_element_type<T>>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using underlying_type_t = MP_UNITS_TYPENAME underlying_type<T>::type;
|
||||||
|
|
||||||
template<typename T, typename... Ts>
|
template<typename T, typename... Ts>
|
||||||
concept one_of = (false || ... || std::same_as<T, Ts>);
|
concept one_of = (false || ... || std::same_as<T, Ts>);
|
||||||
|
|
||||||
|
@@ -52,13 +52,13 @@ template<typename T>
|
|||||||
concept Quantity = detail::is_derived_from_specialization_of_quantity<T>;
|
concept Quantity = detail::is_derived_from_specialization_of_quantity<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A concept matching all quantities with provided dimension or quantity spec
|
* @brief A concept matching all quantities with provided quantity spec
|
||||||
*
|
*
|
||||||
* Satisfied by all quantities with a dimension/quantity_spec being the instantiation derived from
|
* Satisfied by all quantities with a quantity_spec being the instantiation derived from
|
||||||
* the provided dimension/quantity_spec type.
|
* the provided quantity_spec type.
|
||||||
*/
|
*/
|
||||||
template<typename Q, auto V>
|
template<typename Q, auto QS>
|
||||||
concept QuantityOf = Quantity<Q> && ReferenceOf<std::remove_const_t<decltype(Q::reference)>, V>;
|
concept QuantityOf = Quantity<Q> && QuantitySpecOf<std::remove_const_t<decltype(Q::quantity_spec)>, QS>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A concept matching all external quantities like types
|
* @brief A concept matching all external quantities like types
|
||||||
|
@@ -145,15 +145,15 @@ concept SameAbsolutePointOriginAs =
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A concept matching all quantity points with provided dimension or quantity spec
|
* @brief A concept matching all quantity points with provided quantity spec
|
||||||
*
|
*
|
||||||
* Satisfied by all quantity points with a dimension/quantity_spec being the instantiation derived from
|
* Satisfied by all quantity points with a quantity_spec being the instantiation derived from
|
||||||
* the provided dimension/quantity_spec type, or quantity points having the origin with the same
|
* the provided quantity_spec type, or quantity points having the origin with the same
|
||||||
* `absolute_point_origin`.
|
* `absolute_point_origin`.
|
||||||
*/
|
*/
|
||||||
template<typename QP, auto V>
|
template<typename QP, auto V>
|
||||||
concept QuantityPointOf =
|
concept QuantityPointOf =
|
||||||
QuantityPoint<QP> && (ReferenceOf<std::remove_const_t<decltype(QP::reference)>, V> ||
|
QuantityPoint<QP> && (QuantitySpecOf<std::remove_const_t<decltype(QP::quantity_spec)>, V> ||
|
||||||
detail::SameAbsolutePointOriginAs<std::remove_const_t<decltype(QP::absolute_point_origin)>, V>);
|
detail::SameAbsolutePointOriginAs<std::remove_const_t<decltype(QP::absolute_point_origin)>, V>);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -66,14 +66,12 @@ template<auto Q, auto U>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A concept matching all references with provided dimension or quantity spec
|
* @brief A concept matching all references with provided quantity spec
|
||||||
*
|
*
|
||||||
* Satisfied by all references with a dimension/quantity_spec being the instantiation derived from
|
* Satisfied by all references with a quantity_spec being the instantiation derived from
|
||||||
* the provided dimension/quantity_spec type.
|
* the provided quantity_spec type.
|
||||||
*/
|
*/
|
||||||
template<typename T, auto V>
|
template<typename T, auto QS>
|
||||||
concept ReferenceOf =
|
concept ReferenceOf = Reference<T> && QuantitySpecOf<std::remove_const_t<decltype(get_quantity_spec(T{}))>, QS>;
|
||||||
Reference<T> && (DimensionOf<std::remove_const_t<decltype(get_quantity_spec(T{}).dimension)>, V> ||
|
|
||||||
QuantitySpecOf<std::remove_const_t<decltype(get_quantity_spec(T{}))>, V>);
|
|
||||||
|
|
||||||
} // namespace mp_units
|
} // namespace mp_units
|
||||||
|
@@ -30,17 +30,12 @@
|
|||||||
|
|
||||||
namespace mp_units::detail {
|
namespace mp_units::detail {
|
||||||
|
|
||||||
// determines the best available representation type
|
template<typename T, typename Other>
|
||||||
template<Quantity From, Quantity To>
|
struct get_common_type : std::common_type<T, Other> {};
|
||||||
[[nodiscard]] consteval auto common_rep_type(From, To)
|
|
||||||
{
|
template<typename T, typename Other>
|
||||||
if constexpr (requires { typename std::common_type_t<typename From::rep, typename To::rep>; })
|
using maybe_common_type = MP_UNITS_TYPENAME std::conditional_t<requires { typename std::common_type_t<T, Other>; },
|
||||||
// returns a common type of two representation types if available
|
get_common_type<T, Other>, std::type_identity<T>>::type;
|
||||||
// e.g. `double` and `int` will end up with `double` precision
|
|
||||||
return std::common_type_t<typename From::rep, typename To::rep>{};
|
|
||||||
else
|
|
||||||
return typename From::rep{};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Explicit cast between different quantity types
|
* @brief Explicit cast between different quantity types
|
||||||
@@ -73,15 +68,29 @@ template<Quantity To, typename From>
|
|||||||
constexpr Magnitude auto num = numerator(c_mag);
|
constexpr Magnitude auto num = numerator(c_mag);
|
||||||
constexpr Magnitude auto den = denominator(c_mag);
|
constexpr Magnitude auto den = denominator(c_mag);
|
||||||
constexpr Magnitude auto irr = c_mag * (den / num);
|
constexpr Magnitude auto irr = c_mag * (den / num);
|
||||||
using c_rep_type = decltype(common_rep_type(q, To{}));
|
using c_rep_type = maybe_common_type<typename std::remove_reference_t<From>::rep, typename To::rep>;
|
||||||
using c_mag_type = common_magnitude_type<c_mag>;
|
using c_mag_type = common_magnitude_type<c_mag>;
|
||||||
using multiplier_type =
|
using multiplier_type = conditional<treat_as_floating_point<c_rep_type>,
|
||||||
conditional<treat_as_floating_point<c_rep_type>, std::common_type_t<c_mag_type, long double>, c_mag_type>;
|
// ensure that the multiplier is also floating-point
|
||||||
|
conditional<std::is_arithmetic_v<underlying_type_t<c_rep_type>>,
|
||||||
|
// reuse user's type if possible
|
||||||
|
std::common_type_t<c_mag_type, underlying_type_t<c_rep_type>>,
|
||||||
|
std::common_type_t<c_mag_type, double>>,
|
||||||
|
c_mag_type>;
|
||||||
|
using c_type = maybe_common_type<c_rep_type, multiplier_type>;
|
||||||
constexpr auto val = [](Magnitude auto m) { return get_value<multiplier_type>(m); };
|
constexpr auto val = [](Magnitude auto m) { return get_value<multiplier_type>(m); };
|
||||||
return {static_cast<MP_UNITS_TYPENAME To::rep>(
|
if constexpr (std::is_floating_point_v<multiplier_type>) {
|
||||||
static_cast<c_rep_type>(std::forward<From>(q).numerical_value_is_an_implementation_detail_) * val(num) /
|
// this results in great assembly
|
||||||
val(den) * val(irr)),
|
constexpr auto ratio = val(num) / val(den) * val(irr);
|
||||||
To::reference};
|
auto res = static_cast<MP_UNITS_TYPENAME To::rep>(
|
||||||
|
static_cast<c_type>(q.numerical_value_is_an_implementation_detail_) * ratio);
|
||||||
|
return {res, To::reference};
|
||||||
|
} else {
|
||||||
|
// this is slower but allows conversions like 2000 m -> 2 km without loosing data
|
||||||
|
auto res = static_cast<MP_UNITS_TYPENAME To::rep>(
|
||||||
|
static_cast<c_type>(q.numerical_value_is_an_implementation_detail_) * val(num) / val(den) * val(irr));
|
||||||
|
return {res, To::reference};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -198,6 +198,24 @@ template<auto R, auto S, auto T, typename Rep1, typename Rep2, typename Rep3>
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Computes the floating-point remainder of the division operation x / y.
|
||||||
|
*/
|
||||||
|
template<auto R1, typename Rep1, auto R2, typename Rep2>
|
||||||
|
requires requires(Rep1 v1, Rep2 v2) {
|
||||||
|
common_reference(R1, R2);
|
||||||
|
requires requires { fmod(v1, v2); } || requires { std::fmod(v1, v2); };
|
||||||
|
}
|
||||||
|
[[nodiscard]] constexpr QuantityOf<get_quantity_spec(R1)> auto fmod(const quantity<R1, Rep1>& x,
|
||||||
|
const quantity<R2, Rep2>& y) noexcept
|
||||||
|
{
|
||||||
|
constexpr auto ref = common_reference(R1, R2);
|
||||||
|
constexpr auto unit = get_unit(ref);
|
||||||
|
using std::fmod;
|
||||||
|
return quantity{fmod(x.numerical_value_in(unit), y.numerical_value_in(unit)), ref};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the epsilon of the quantity
|
* @brief Returns the epsilon of the quantity
|
||||||
*
|
*
|
||||||
|
@@ -362,7 +362,7 @@ public:
|
|||||||
return std::forward<Q>(lhs);
|
return std::forward<Q>(lhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Q1, QuantityOf<dimension_one> Q2>
|
template<typename Q1, QuantityOf<dimensionless> Q2>
|
||||||
requires std::derived_from<std::remove_cvref_t<Q1>, quantity> && (Q2::unit == ::mp_units::one) &&
|
requires std::derived_from<std::remove_cvref_t<Q1>, quantity> && (Q2::unit == ::mp_units::one) &&
|
||||||
requires(rep a, const typename Q2::rep b) {
|
requires(rep a, const typename Q2::rep b) {
|
||||||
{
|
{
|
||||||
@@ -389,7 +389,7 @@ public:
|
|||||||
return std::forward<Q>(lhs);
|
return std::forward<Q>(lhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Q1, QuantityOf<dimension_one> Q2>
|
template<typename Q1, QuantityOf<dimensionless> Q2>
|
||||||
requires std::derived_from<std::remove_cvref_t<Q1>, quantity> && (Q2::unit == ::mp_units::one) &&
|
requires std::derived_from<std::remove_cvref_t<Q1>, quantity> && (Q2::unit == ::mp_units::one) &&
|
||||||
requires(rep a, const typename Q2::rep b) {
|
requires(rep a, const typename Q2::rep b) {
|
||||||
{
|
{
|
||||||
|
@@ -411,7 +411,11 @@ struct quantity_spec<Self, QS, Eq, Args...> : quantity_spec<Self, QS, Args...> {
|
|||||||
*/
|
*/
|
||||||
template<detail::IntermediateDerivedQuantitySpecExpr... Expr>
|
template<detail::IntermediateDerivedQuantitySpecExpr... Expr>
|
||||||
struct derived_quantity_spec :
|
struct derived_quantity_spec :
|
||||||
|
#ifdef __cpp_explicit_this_parameter
|
||||||
|
detail::quantity_spec_interface,
|
||||||
|
#else
|
||||||
detail::quantity_spec_interface<derived_quantity_spec<Expr...>>,
|
detail::quantity_spec_interface<derived_quantity_spec<Expr...>>,
|
||||||
|
#endif
|
||||||
detail::expr_fractions<detail::is_dimensionless, Expr...> {
|
detail::expr_fractions<detail::is_dimensionless, Expr...> {
|
||||||
using _base_ = detail::expr_fractions<detail::is_dimensionless, Expr...>;
|
using _base_ = detail::expr_fractions<detail::is_dimensionless, Expr...>;
|
||||||
|
|
||||||
@@ -443,9 +447,9 @@ concept QuantitySpecWithNoSpecifiers = detail::NamedQuantitySpec<T> || detail::I
|
|||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
#ifdef __cpp_explicit_this_parameter
|
#ifdef __cpp_explicit_this_parameter
|
||||||
template<detail::QuantitySpecWithNoSpecifiers auto Q>
|
template<auto Q>
|
||||||
requires(get_kind(Q) == Q)
|
requires(detail::QuantitySpecWithNoSpecifiers<std::remove_const_t<decltype(Q)>>) && (get_kind(Q) == Q)
|
||||||
struct kind_of_<Q> : Q {
|
struct kind_of_<Q> : std::remove_const_t<decltype(Q)> {
|
||||||
static constexpr auto _quantity_spec_ = Q;
|
static constexpr auto _quantity_spec_ = Q;
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
@@ -1416,12 +1420,9 @@ template<typename Self, NamedQuantitySpec auto QS, auto... Args>
|
|||||||
template<QuantitySpec Q>
|
template<QuantitySpec Q>
|
||||||
[[nodiscard]] consteval auto remove_kind(Q q)
|
[[nodiscard]] consteval auto remove_kind(Q q)
|
||||||
{
|
{
|
||||||
if constexpr (detail::QuantityKindSpec<Q>) {
|
if constexpr (detail::QuantityKindSpec<Q>)
|
||||||
if constexpr (requires { Q::_parent_; })
|
return Q::_quantity_spec_;
|
||||||
return Q::_parent_;
|
else
|
||||||
else
|
|
||||||
return Q::_equation_;
|
|
||||||
} else
|
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -605,6 +605,8 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
inline constexpr struct percent : named_unit<"%", mag<ratio{1, 100}> * one> {} percent;
|
inline constexpr struct percent : named_unit<"%", mag<ratio{1, 100}> * one> {} percent;
|
||||||
inline constexpr struct per_mille : named_unit<basic_symbol_text{"‰", "%o"}, mag<ratio(1, 1000)> * one> {} per_mille;
|
inline constexpr struct per_mille : named_unit<basic_symbol_text{"‰", "%o"}, mag<ratio(1, 1000)> * one> {} per_mille;
|
||||||
|
inline constexpr struct parts_per_million : named_unit<"ppm", mag<ratio(1, 1'000'000)> * one> {} parts_per_million;
|
||||||
|
inline constexpr auto ppm = parts_per_million;
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|
||||||
@@ -836,6 +838,11 @@ constexpr Out unit_symbol_impl(Out out, const derived_unit<Expr...>&, unit_symbo
|
|||||||
template<Unit auto U>
|
template<Unit auto U>
|
||||||
inline constexpr bool space_before_unit_symbol = true;
|
inline constexpr bool space_before_unit_symbol = true;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline constexpr bool space_before_unit_symbol<percent> = false;
|
||||||
|
template<>
|
||||||
|
inline constexpr bool space_before_unit_symbol<per_mille> = false;
|
||||||
|
|
||||||
template<typename CharT = char, std::output_iterator<CharT> Out, Unit U>
|
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, unit_symbol_formatting fmt = unit_symbol_formatting{})
|
||||||
{
|
{
|
||||||
|
@@ -119,4 +119,24 @@ template<ReferenceOf<dimensionless> auto R, typename Rep>
|
|||||||
return quantity{atan(q.numerical_value_in(one)), radian};
|
return quantity{atan(q.numerical_value_in(one)), radian};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<auto R1, typename Rep1, auto R2, typename Rep2>
|
||||||
|
requires requires(Rep1 v1, Rep2 v2) {
|
||||||
|
common_reference(R1, R2);
|
||||||
|
requires requires { atan2(v1, v2); } || requires { std::atan2(v1, v2); };
|
||||||
|
}
|
||||||
|
[[nodiscard]] inline QuantityOf<angle> auto atan2(const quantity<R1, Rep1>& y, const quantity<R2, Rep2>& x) noexcept
|
||||||
|
{
|
||||||
|
constexpr auto ref = common_reference(R1, R2);
|
||||||
|
constexpr auto unit = get_unit(ref);
|
||||||
|
using std::atan2;
|
||||||
|
if constexpr (!treat_as_floating_point<Rep1> || !treat_as_floating_point<Rep2>) {
|
||||||
|
// check what is the return type when called with the integral value
|
||||||
|
using rep = decltype(atan2(y.force_numerical_value_in(unit), x.force_numerical_value_in(unit)));
|
||||||
|
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
|
||||||
|
return quantity{atan2(value_cast<rep>(y).numerical_value_in(unit), value_cast<rep>(x).numerical_value_in(unit)),
|
||||||
|
radian};
|
||||||
|
} else
|
||||||
|
return quantity{atan2(y.numerical_value_in(unit), x.numerical_value_in(unit)), radian};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mp_units::angular
|
} // namespace mp_units::angular
|
||||||
|
@@ -120,4 +120,25 @@ template<ReferenceOf<dimensionless> auto R, typename Rep>
|
|||||||
return quantity{atan(q.numerical_value_in(one)), radian};
|
return quantity{atan(q.numerical_value_in(one)), radian};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<auto R1, typename Rep1, auto R2, typename Rep2>
|
||||||
|
requires requires(Rep1 v1, Rep2 v2) {
|
||||||
|
common_reference(R1, R2);
|
||||||
|
requires requires { atan2(v1, v2); } || requires { std::atan2(v1, v2); };
|
||||||
|
}
|
||||||
|
[[nodiscard]] inline QuantityOf<isq::angular_measure> auto atan2(const quantity<R1, Rep1>& y,
|
||||||
|
const quantity<R2, Rep2>& x) noexcept
|
||||||
|
{
|
||||||
|
constexpr auto ref = common_reference(R1, R2);
|
||||||
|
constexpr auto unit = get_unit(ref);
|
||||||
|
using std::atan2;
|
||||||
|
if constexpr (!treat_as_floating_point<Rep1> || !treat_as_floating_point<Rep2>) {
|
||||||
|
// check what is the return type when called with the integral value
|
||||||
|
using rep = decltype(atan2(y.force_numerical_value_in(unit), x.force_numerical_value_in(unit)));
|
||||||
|
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
|
||||||
|
return quantity{atan2(value_cast<rep>(y).numerical_value_in(unit), value_cast<rep>(x).numerical_value_in(unit)),
|
||||||
|
radian};
|
||||||
|
} else
|
||||||
|
return quantity{atan2(y.numerical_value_in(unit), x.numerical_value_in(unit)), radian};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mp_units::si
|
} // namespace mp_units::si
|
||||||
|
@@ -233,11 +233,11 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
|||||||
const auto q = value_cast<percent>(15. * isq::length[m] / (100. * isq::length[m]));
|
const auto q = value_cast<percent>(15. * isq::length[m] / (100. * isq::length[m]));
|
||||||
os << q;
|
os << q;
|
||||||
|
|
||||||
SECTION("iostream") { CHECK(os.str() == "15 %"); }
|
SECTION("iostream") { CHECK(os.str() == "15%"); }
|
||||||
|
|
||||||
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
SECTION("fmt with default format {} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{}", q) == os.str()); }
|
||||||
|
|
||||||
SECTION("fmt with format {:%Q %q} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == os.str()); }
|
SECTION("fmt with format {:%Q %q} on a quantity") { CHECK(MP_UNITS_STD_FMT::format("{:%Q %q}", q) == "15 %"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("radians")
|
SECTION("radians")
|
||||||
|
@@ -71,6 +71,24 @@ TEST_CASE("'fma()' on quantity changes the value and the dimension accordingly",
|
|||||||
REQUIRE(fma(isq::speed(10.0 * m / s), isq::time(2.0 * s), isq::height(42.0 * m)) == isq::length(62.0 * m));
|
REQUIRE(fma(isq::speed(10.0 * m / s), isq::time(2.0 * s), isq::height(42.0 * m)) == isq::length(62.0 * m));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("fmod functions", "[math][fmod]")
|
||||||
|
{
|
||||||
|
SECTION("fmod should work on the same quantities")
|
||||||
|
{
|
||||||
|
REQUIRE(fmod(4. * isq::length[km], 3. * isq::length[km]) == 1. * isq::length[km]);
|
||||||
|
REQUIRE(fmod(-9. * isq::length[km], 3. * isq::length[km]) == -0. * isq::length[km]);
|
||||||
|
REQUIRE(fmod(3 * isq::length[km], 2 * isq::length[km]) == 1 * isq::length[km]);
|
||||||
|
REQUIRE(fmod(4 * isq::length[km], 2.5f * isq::length[km]) == 1.5 * isq::length[km]);
|
||||||
|
}
|
||||||
|
SECTION("fmod should work with different units of the same dimension")
|
||||||
|
{
|
||||||
|
REQUIRE(fmod(4. * isq::length[km], 3000. * isq::length[m]) == 1000. * isq::length[m]);
|
||||||
|
REQUIRE(fmod(-9. * isq::length[km], 3000. * isq::length[m]) == -0. * isq::length[m]);
|
||||||
|
REQUIRE(fmod(3. * isq::length[km], 2000. * isq::length[m]) == 1000 * isq::length[m]);
|
||||||
|
REQUIRE(fmod(4 * isq::length[km], 2500 * isq::length[m]) == 1500 * isq::length[m]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("'isfinite()' accepts dimensioned arguments", "[math][isfinite]") { REQUIRE(isfinite(4.0 * isq::length[m])); }
|
TEST_CASE("'isfinite()' accepts dimensioned arguments", "[math][isfinite]") { REQUIRE(isfinite(4.0 * isq::length[m])); }
|
||||||
|
|
||||||
TEST_CASE("'isinf()' accepts dimensioned arguments", "[math][isinf]") { REQUIRE(!isinf(4.0 * isq::length[m])); }
|
TEST_CASE("'isinf()' accepts dimensioned arguments", "[math][isinf]") { REQUIRE(!isinf(4.0 * isq::length[m])); }
|
||||||
@@ -375,6 +393,22 @@ TEST_CASE("SI inverse trigonometric functions", "[inv trig][si]")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("SI atan2 functions", "[atan2][si]")
|
||||||
|
{
|
||||||
|
SECTION("atan2 should work on the same quantities")
|
||||||
|
{
|
||||||
|
REQUIRE_THAT(si::atan2(-1. * isq::length[km], 1. * isq::length[km]), AlmostEquals(-45. * deg));
|
||||||
|
REQUIRE_THAT(si::atan2(0. * isq::length[km], 1. * isq::length[km]), AlmostEquals(0. * deg));
|
||||||
|
REQUIRE_THAT(si::atan2(1. * isq::length[km], 1. * isq::length[km]), AlmostEquals(45. * deg));
|
||||||
|
}
|
||||||
|
SECTION("atan2 should work with different units of the same dimension")
|
||||||
|
{
|
||||||
|
REQUIRE_THAT(si::atan2(-1. * isq::length[km], 1000. * isq::length[m]), AlmostEquals(-45. * deg));
|
||||||
|
REQUIRE_THAT(si::atan2(0. * isq::length[km], 1000. * isq::length[m]), AlmostEquals(0. * deg));
|
||||||
|
REQUIRE_THAT(si::atan2(1. * isq::length[km], 1000. * isq::length[m]), AlmostEquals(45. * deg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("Angle trigonometric functions", "[trig][angle]")
|
TEST_CASE("Angle trigonometric functions", "[trig][angle]")
|
||||||
{
|
{
|
||||||
@@ -449,3 +483,23 @@ TEST_CASE("Angle inverse trigonometric functions", "[inv trig][angle]")
|
|||||||
REQUIRE_THAT(atan(1 * one), AlmostEquals(45. * angle[deg]));
|
REQUIRE_THAT(atan(1 * one), AlmostEquals(45. * angle[deg]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Angle atan2 functions", "[atan2][angle]")
|
||||||
|
{
|
||||||
|
using namespace mp_units::angular;
|
||||||
|
using namespace mp_units::angular::unit_symbols;
|
||||||
|
using mp_units::angular::unit_symbols::deg;
|
||||||
|
|
||||||
|
SECTION("atan2 should work on the same quantities")
|
||||||
|
{
|
||||||
|
REQUIRE_THAT(atan2(-1. * isq::length[km], 1. * isq::length[km]), AlmostEquals(-45. * angle[deg]));
|
||||||
|
REQUIRE_THAT(atan2(0. * isq::length[km], 1. * isq::length[km]), AlmostEquals(0. * angle[deg]));
|
||||||
|
REQUIRE_THAT(atan2(1. * isq::length[km], 1. * isq::length[km]), AlmostEquals(45. * angle[deg]));
|
||||||
|
}
|
||||||
|
SECTION("atan2 should work with different units of the same dimension")
|
||||||
|
{
|
||||||
|
REQUIRE_THAT(atan2(-1. * isq::length[km], 1000. * isq::length[m]), AlmostEquals(-45. * angle[deg]));
|
||||||
|
REQUIRE_THAT(atan2(0. * isq::length[km], 1000. * isq::length[m]), AlmostEquals(0. * angle[deg]));
|
||||||
|
REQUIRE_THAT(atan2(1. * isq::length[km], 1000. * isq::length[m]), AlmostEquals(45. * angle[deg]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -82,6 +82,9 @@ static_assert(!Dimension<base_dimension<"L">>);
|
|||||||
static_assert(!Dimension<struct si::metre>);
|
static_assert(!Dimension<struct si::metre>);
|
||||||
static_assert(!Dimension<int>);
|
static_assert(!Dimension<int>);
|
||||||
|
|
||||||
|
// DimensionOf
|
||||||
|
// TODO add tests
|
||||||
|
|
||||||
// QuantitySpec
|
// QuantitySpec
|
||||||
struct speed : decltype(isq::length / isq::time) {}; // this is not recommended
|
struct speed : decltype(isq::length / isq::time) {}; // this is not recommended
|
||||||
|
|
||||||
@@ -132,6 +135,9 @@ static_assert(!detail::QuantityKindSpec<speed>);
|
|||||||
static_assert(!detail::QuantityKindSpec<struct isq::dim_length>);
|
static_assert(!detail::QuantityKindSpec<struct isq::dim_length>);
|
||||||
static_assert(!detail::QuantityKindSpec<int>);
|
static_assert(!detail::QuantityKindSpec<int>);
|
||||||
|
|
||||||
|
// QuantitySpecOf
|
||||||
|
// TODO add tests
|
||||||
|
|
||||||
// Unit
|
// Unit
|
||||||
struct metre_per_second : decltype(si::metre / si::second) {};
|
struct metre_per_second : decltype(si::metre / si::second) {};
|
||||||
|
|
||||||
@@ -265,24 +271,16 @@ static_assert(ReferenceOf<std::remove_const_t<decltype(isq::length[si::metre])>,
|
|||||||
static_assert(!ReferenceOf<std::remove_const_t<decltype(isq::length[si::metre])>, isq::radius>);
|
static_assert(!ReferenceOf<std::remove_const_t<decltype(isq::length[si::metre])>, isq::radius>);
|
||||||
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::radius[si::metre])>, isq::length>);
|
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::radius[si::metre])>, isq::length>);
|
||||||
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::radius[si::metre])>, isq::radius>);
|
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::radius[si::metre])>, isq::radius>);
|
||||||
static_assert(ReferenceOf<struct si::metre, isq::dim_length>);
|
|
||||||
static_assert(!ReferenceOf<struct si::second, isq::dim_length>);
|
static_assert(!ReferenceOf<struct si::second, isq::dim_length>);
|
||||||
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::length[si::metre])>, isq::dim_length>);
|
|
||||||
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::radius[si::metre])>, isq::dim_length>);
|
|
||||||
|
|
||||||
static_assert(ReferenceOf<struct one, dimensionless>);
|
static_assert(ReferenceOf<struct one, dimensionless>);
|
||||||
static_assert(ReferenceOf<struct one, dimension_one>);
|
|
||||||
static_assert(ReferenceOf<std::remove_const_t<decltype(dimensionless[one])>, dimensionless>);
|
static_assert(ReferenceOf<std::remove_const_t<decltype(dimensionless[one])>, dimensionless>);
|
||||||
static_assert(ReferenceOf<std::remove_const_t<decltype(dimensionless[one])>, dimension_one>);
|
|
||||||
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::rotation[one])>, isq::rotation>);
|
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::rotation[one])>, isq::rotation>);
|
||||||
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::rotation[one])>, dimensionless>);
|
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::rotation[one])>, dimensionless>);
|
||||||
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::rotation[one])>, dimension_one>);
|
|
||||||
static_assert(ReferenceOf<struct si::radian, isq::angular_measure>);
|
static_assert(ReferenceOf<struct si::radian, isq::angular_measure>);
|
||||||
static_assert(!ReferenceOf<struct si::radian, dimensionless>);
|
static_assert(!ReferenceOf<struct si::radian, dimensionless>);
|
||||||
static_assert(ReferenceOf<struct si::radian, dimension_one>);
|
|
||||||
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::angular_measure[si::radian])>, isq::angular_measure>);
|
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::angular_measure[si::radian])>, isq::angular_measure>);
|
||||||
static_assert(!ReferenceOf<std::remove_const_t<decltype(isq::angular_measure[si::radian])>, dimensionless>);
|
static_assert(!ReferenceOf<std::remove_const_t<decltype(isq::angular_measure[si::radian])>, dimensionless>);
|
||||||
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::angular_measure[si::radian])>, dimension_one>);
|
|
||||||
static_assert(ReferenceOf<struct one, isq::rotation>);
|
static_assert(ReferenceOf<struct one, isq::rotation>);
|
||||||
static_assert(ReferenceOf<struct one, isq::angular_measure>);
|
static_assert(ReferenceOf<struct one, isq::angular_measure>);
|
||||||
static_assert(!ReferenceOf<std::remove_const_t<decltype(dimensionless[one])>, isq::rotation>);
|
static_assert(!ReferenceOf<std::remove_const_t<decltype(dimensionless[one])>, isq::rotation>);
|
||||||
@@ -323,24 +321,16 @@ static_assert(QuantityOf<quantity<isq::length[si::metre]>, isq::length>);
|
|||||||
static_assert(!QuantityOf<quantity<isq::length[si::metre]>, isq::radius>);
|
static_assert(!QuantityOf<quantity<isq::length[si::metre]>, isq::radius>);
|
||||||
static_assert(QuantityOf<quantity<isq::radius[si::metre]>, isq::length>);
|
static_assert(QuantityOf<quantity<isq::radius[si::metre]>, isq::length>);
|
||||||
static_assert(QuantityOf<quantity<isq::radius[si::metre]>, isq::radius>);
|
static_assert(QuantityOf<quantity<isq::radius[si::metre]>, isq::radius>);
|
||||||
static_assert(QuantityOf<quantity<si::metre>, isq::dim_length>);
|
|
||||||
static_assert(!QuantityOf<quantity<si::second>, isq::dim_length>);
|
static_assert(!QuantityOf<quantity<si::second>, isq::dim_length>);
|
||||||
static_assert(QuantityOf<quantity<isq::length[si::metre]>, isq::dim_length>);
|
|
||||||
static_assert(QuantityOf<quantity<isq::radius[si::metre]>, isq::dim_length>);
|
|
||||||
|
|
||||||
static_assert(QuantityOf<quantity<one>, dimensionless>);
|
static_assert(QuantityOf<quantity<one>, dimensionless>);
|
||||||
static_assert(QuantityOf<quantity<one>, dimension_one>);
|
|
||||||
static_assert(QuantityOf<quantity<dimensionless[one]>, dimensionless>);
|
static_assert(QuantityOf<quantity<dimensionless[one]>, dimensionless>);
|
||||||
static_assert(QuantityOf<quantity<dimensionless[one]>, dimension_one>);
|
|
||||||
static_assert(QuantityOf<quantity<isq::rotation[one]>, isq::rotation>);
|
static_assert(QuantityOf<quantity<isq::rotation[one]>, isq::rotation>);
|
||||||
static_assert(QuantityOf<quantity<isq::rotation[one]>, dimensionless>);
|
static_assert(QuantityOf<quantity<isq::rotation[one]>, dimensionless>);
|
||||||
static_assert(QuantityOf<quantity<isq::rotation[one]>, dimension_one>);
|
|
||||||
static_assert(QuantityOf<quantity<si::radian>, isq::angular_measure>);
|
static_assert(QuantityOf<quantity<si::radian>, isq::angular_measure>);
|
||||||
static_assert(!QuantityOf<quantity<si::radian>, dimensionless>);
|
static_assert(!QuantityOf<quantity<si::radian>, dimensionless>);
|
||||||
static_assert(QuantityOf<quantity<si::radian>, dimension_one>);
|
|
||||||
static_assert(QuantityOf<quantity<isq::angular_measure[si::radian]>, isq::angular_measure>);
|
static_assert(QuantityOf<quantity<isq::angular_measure[si::radian]>, isq::angular_measure>);
|
||||||
static_assert(!QuantityOf<quantity<isq::angular_measure[si::radian]>, dimensionless>);
|
static_assert(!QuantityOf<quantity<isq::angular_measure[si::radian]>, dimensionless>);
|
||||||
static_assert(QuantityOf<quantity<isq::angular_measure[si::radian]>, dimension_one>);
|
|
||||||
static_assert(QuantityOf<quantity<one>, isq::rotation>);
|
static_assert(QuantityOf<quantity<one>, isq::rotation>);
|
||||||
static_assert(QuantityOf<quantity<one>, isq::angular_measure>);
|
static_assert(QuantityOf<quantity<one>, isq::angular_measure>);
|
||||||
static_assert(!QuantityOf<quantity<dimensionless[one]>, isq::rotation>);
|
static_assert(!QuantityOf<quantity<dimensionless[one]>, isq::rotation>);
|
||||||
|
@@ -54,4 +54,8 @@ static_assert(basic_fixed_string('d') + txt2 == basic_fixed_string("dabc"));
|
|||||||
static_assert(txt2 + basic_fixed_string("def") == basic_fixed_string("abcdef"));
|
static_assert(txt2 + basic_fixed_string("def") == basic_fixed_string("abcdef"));
|
||||||
static_assert(basic_fixed_string("def") + txt2 == basic_fixed_string("defabc"));
|
static_assert(basic_fixed_string("def") + txt2 == basic_fixed_string("defabc"));
|
||||||
|
|
||||||
|
#ifndef MP_UNITS_COMP_GCC
|
||||||
|
static_assert(basic_fixed_string("abcd").view().find('c') == 2);
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@@ -57,6 +57,12 @@ static_assert(compare(fma(2.0 * one, 3.0 * m, 1.0 * m), 7.0 * m));
|
|||||||
static_assert(compare(fma(2.0 * m, 3.0 * one, 1.0 * m), 7.0 * m));
|
static_assert(compare(fma(2.0 * m, 3.0 * one, 1.0 * m), 7.0 * m));
|
||||||
static_assert(compare(fma(2 * m, 3.0f * m, 1.0 * m2), 7.0 * m2));
|
static_assert(compare(fma(2 * m, 3.0f * m, 1.0 * m2), 7.0 * m2));
|
||||||
static_assert(compare(fma(isq::width(2.0 * m), 2.0 * one, isq::height(3.0 * m)), isq::length(7.0 * m)));
|
static_assert(compare(fma(isq::width(2.0 * m), 2.0 * one, isq::height(3.0 * m)), isq::length(7.0 * m)));
|
||||||
|
static_assert(compare(fmod(4.0 * km, 3.0 * km), 1.0 * km));
|
||||||
|
static_assert(compare(fmod(-4.0 * km, 3.0 * km), -1.0 * km));
|
||||||
|
static_assert(compare(fmod(9.0 * km, -3.0 * km), 0.0 * km));
|
||||||
|
static_assert(compare(fmod(9.5 * km, -2000 * m), 1500.0 * m));
|
||||||
|
static_assert(compare(fmod(3 * km, 2 * km), 1.0 * km));
|
||||||
|
static_assert(compare(fmod(4 * km, 2.5f * km), 1.5 * km));
|
||||||
static_assert(compare(pow<0>(2 * m), 1 * one));
|
static_assert(compare(pow<0>(2 * m), 1 * one));
|
||||||
static_assert(compare(pow<1>(2 * m), 2 * m));
|
static_assert(compare(pow<1>(2 * m), 2 * m));
|
||||||
static_assert(compare(pow<2>(2 * m), 4 * pow<2>(m), 4 * m2));
|
static_assert(compare(pow<2>(2 * m), 4 * pow<2>(m), 4 * m2));
|
||||||
|
@@ -958,7 +958,6 @@ static_assert(QuantityOf<quantity<m / s>, isq::position_vector / isq::duration>)
|
|||||||
static_assert(QuantityOf<quantity<kind_of<isq::speed>[m / s]>, isq::position_vector / isq::duration>);
|
static_assert(QuantityOf<quantity<kind_of<isq::speed>[m / s]>, isq::position_vector / isq::duration>);
|
||||||
static_assert(QuantityOf<quantity<isq::velocity[m / s], int>, isq::position_vector / isq::duration>);
|
static_assert(QuantityOf<quantity<isq::velocity[m / s], int>, isq::position_vector / isq::duration>);
|
||||||
|
|
||||||
static_assert(QuantityOf<decltype(10 * isq::speed[m / s] / (2 * isq::length[m]) * (4 * isq::time[s])), dimension_one>);
|
|
||||||
static_assert(QuantityOf<decltype(10 * m), isq::height>); // kind of
|
static_assert(QuantityOf<decltype(10 * m), isq::height>); // kind of
|
||||||
static_assert(QuantityOf<decltype(10 * kind_of<isq::length>[m]), isq::height>); // kind of
|
static_assert(QuantityOf<decltype(10 * kind_of<isq::length>[m]), isq::height>); // kind of
|
||||||
static_assert(!QuantityOf<decltype(10 * isq::length[m]), isq::height>); // different kinds
|
static_assert(!QuantityOf<decltype(10 * isq::length[m]), isq::height>); // different kinds
|
||||||
|
@@ -120,6 +120,7 @@ static_assert(unit_symbol(one) == "");
|
|||||||
static_assert(unit_symbol(percent) == "%");
|
static_assert(unit_symbol(percent) == "%");
|
||||||
static_assert(unit_symbol(per_mille) == "‰");
|
static_assert(unit_symbol(per_mille) == "‰");
|
||||||
static_assert(unit_symbol<unit_symbol_formatting{.encoding = ascii}>(per_mille) == "%o");
|
static_assert(unit_symbol<unit_symbol_formatting{.encoding = ascii}>(per_mille) == "%o");
|
||||||
|
static_assert(unit_symbol(parts_per_million) == "ppm");
|
||||||
static_assert(unit_symbol(square(metre)) == "m²");
|
static_assert(unit_symbol(square(metre)) == "m²");
|
||||||
static_assert(unit_symbol<unit_symbol_formatting{.encoding = ascii}>(square(metre)) == "m^2");
|
static_assert(unit_symbol<unit_symbol_formatting{.encoding = ascii}>(square(metre)) == "m^2");
|
||||||
static_assert(unit_symbol(cubic(metre)) == "m³");
|
static_assert(unit_symbol(cubic(metre)) == "m³");
|
||||||
|
Reference in New Issue
Block a user