Merge branch 'master' into chiphogg/mod#509

This commit is contained in:
Chip Hogg
2024-11-13 08:41:52 -05:00
39 changed files with 3235 additions and 1923 deletions
+1
View File
@@ -91,6 +91,7 @@ if(NOT ${projectPrefix}API_FREESTANDING)
include/mp-units/bits/fmt.h
include/mp-units/bits/requires_hosted.h
include/mp-units/ext/format.h
include/mp-units/cartesian_vector.h
include/mp-units/complex.h
include/mp-units/format.h
include/mp-units/math.h
@@ -0,0 +1,230 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/module_macros.h>
#include <mp-units/framework/customization_points.h>
#if MP_UNITS_HOSTED
#include <mp-units/bits/fmt.h>
#endif
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#ifdef MP_UNITS_IMPORT_STD
import std;
#else
#include <cmath>
#include <cstddef>
#include <type_traits>
#if MP_UNITS_HOSTED
#include <ostream>
#endif
#endif
#endif
namespace mp_units {
MP_UNITS_EXPORT template<typename T = double>
class cartesian_vector {
public:
// public members required to satisfy structural type requirements :-(
T _coordinates_[3];
using value_type = T;
cartesian_vector() = default;
cartesian_vector(const cartesian_vector&) = default;
cartesian_vector(cartesian_vector&&) = default;
cartesian_vector& operator=(const cartesian_vector&) = default;
cartesian_vector& operator=(cartesian_vector&&) = default;
template<std::convertible_to<T> Arg1, std::convertible_to<T>... Args>
constexpr cartesian_vector(Arg1&& arg1, Args&&... args) :
_coordinates_(std::forward<Arg1>(arg1), std::forward<Args>(args)...)
{
}
template<std::convertible_to<T> U>
constexpr cartesian_vector(const cartesian_vector<U>& other) : _coordinates_{other[0], other[1], other[2]}
{
}
template<std::convertible_to<T> U>
constexpr cartesian_vector(cartesian_vector<U>&& other) :
_coordinates_{std::move(other[0]), std::move(other[1]), std::move(other[2])}
{
}
template<std::convertible_to<T> U>
constexpr cartesian_vector& operator=(const cartesian_vector<U>& other)
{
_coordinates_[0] = other[0];
_coordinates_[1] = other[1];
_coordinates_[2] = other[2];
return *this;
}
template<std::convertible_to<T> U>
constexpr cartesian_vector& operator=(cartesian_vector<U>&& other)
{
_coordinates_[0] = std::move(other[0]);
_coordinates_[1] = std::move(other[1]);
_coordinates_[2] = std::move(other[2]);
return *this;
}
[[nodiscard]] constexpr T magnitude() const
requires treat_as_floating_point<T>
{
return std::hypot(_coordinates_[0], _coordinates_[1], _coordinates_[2]);
}
[[nodiscard]] constexpr cartesian_vector unit() const
requires treat_as_floating_point<T>
{
return *this / magnitude();
}
[[nodiscard]] constexpr T& operator[](std::size_t i) { return _coordinates_[i]; }
[[nodiscard]] constexpr const T& operator[](std::size_t i) const { return _coordinates_[i]; }
[[nodiscard]] constexpr cartesian_vector operator+() const { return *this; }
[[nodiscard]] constexpr cartesian_vector operator-() const
{
return {-_coordinates_[0], -_coordinates_[1], -_coordinates_[2]};
}
template<std::same_as<T> U, typename V>
requires requires(U u, V v) { u + v; }
[[nodiscard]] friend constexpr auto operator+(const cartesian_vector<U>& lhs, const cartesian_vector<V>& rhs)
{
return ::mp_units::cartesian_vector{lhs._coordinates_[0] + rhs._coordinates_[0],
lhs._coordinates_[1] + rhs._coordinates_[1],
lhs._coordinates_[2] + rhs._coordinates_[2]};
}
template<std::same_as<T> U, typename V>
requires requires(U u, V v) { u - v; }
[[nodiscard]] friend constexpr auto operator-(const cartesian_vector<U>& lhs, const cartesian_vector<V>& rhs)
{
return ::mp_units::cartesian_vector{lhs._coordinates_[0] - rhs._coordinates_[0],
lhs._coordinates_[1] - rhs._coordinates_[1],
lhs._coordinates_[2] - rhs._coordinates_[2]};
}
template<std::same_as<T> U>
requires requires(U u, T t) { u* t; }
[[nodiscard]] friend constexpr auto operator*(const cartesian_vector<U>& lhs, const T& rhs)
{
return ::mp_units::cartesian_vector{lhs._coordinates_[0] * rhs, lhs._coordinates_[1] * rhs,
lhs._coordinates_[2] * rhs};
}
template<std::same_as<T> U>
requires requires(T t, U u) { t* u; }
[[nodiscard]] friend constexpr auto operator*(const T& lhs, const cartesian_vector<U>& rhs)
{
return rhs * lhs;
}
template<std::same_as<T> U>
requires requires(U u, T t) { u / t; }
[[nodiscard]] friend constexpr auto operator/(const cartesian_vector<U>& lhs, const T& rhs)
{
return ::mp_units::cartesian_vector{lhs._coordinates_[0] / rhs, lhs._coordinates_[1] / rhs,
lhs._coordinates_[2] / rhs};
}
template<std::same_as<T> U, std::equality_comparable_with<U> V>
[[nodiscard]] friend constexpr bool operator==(const cartesian_vector<U>& lhs, const cartesian_vector<V>& rhs)
{
return lhs._coordinates_[0] == rhs._coordinates_[0] && lhs._coordinates_[1] == rhs._coordinates_[1] &&
lhs._coordinates_[2] == rhs._coordinates_[2];
}
[[nodiscard]] friend constexpr T norm(const cartesian_vector& vec)
requires treat_as_floating_point<T>
{
return vec.magnitude();
}
[[nodiscard]] friend constexpr cartesian_vector unit_vector(const cartesian_vector& vec)
requires treat_as_floating_point<T>
{
return vec.unit();
}
template<std::same_as<T> U, typename V>
requires requires(U u, V v, decltype(u * v) t) {
u* v;
t + t;
}
[[nodiscard]] friend constexpr auto scalar_product(const cartesian_vector<U>& lhs, const cartesian_vector<V>& rhs)
{
return lhs._coordinates_[0] * rhs._coordinates_[0] + lhs._coordinates_[1] * rhs._coordinates_[1] +
lhs._coordinates_[2] * rhs._coordinates_[2];
}
template<std::same_as<T> U, typename V>
requires requires(U u, V v, decltype(u * v) t) {
u* v;
t - t;
}
[[nodiscard]] friend constexpr auto vector_product(const cartesian_vector<U>& lhs, const cartesian_vector<V>& rhs)
{
return ::mp_units::cartesian_vector{
lhs._coordinates_[1] * rhs._coordinates_[2] - lhs._coordinates_[2] * rhs._coordinates_[1],
lhs._coordinates_[2] * rhs._coordinates_[0] - lhs._coordinates_[0] * rhs._coordinates_[2],
lhs._coordinates_[0] * rhs._coordinates_[1] - lhs._coordinates_[1] * rhs._coordinates_[0]};
}
#if MP_UNITS_HOSTED
friend constexpr std::ostream& operator<<(std::ostream& os, const cartesian_vector& vec)
{
return os << '[' << vec[0] << ", " << vec[1] << ", " << vec[2] << ']';
}
#endif
};
template<typename Arg, typename... Args>
requires(sizeof...(Args) <= 2) && requires { typename std::common_type_t<Arg, Args...>; }
cartesian_vector(Arg, Args...) -> cartesian_vector<std::common_type_t<Arg, Args...>>;
template<class T>
constexpr bool is_vector<cartesian_vector<T>> = true;
} // namespace mp_units
#if MP_UNITS_HOSTED
// TODO use parse and use formatter for the underlying type
template<typename T, typename Char>
struct MP_UNITS_STD_FMT::formatter<mp_units::cartesian_vector<T>, Char> :
formatter<std::basic_string_view<Char>, Char> {
template<typename FormatContext>
auto format(const mp_units::cartesian_vector<T>& vec, FormatContext& ctx) const
{
return format_to(ctx.out(), "[{}, {}, {}]", vec[0], vec[1], vec[2]);
}
};
#endif
+1
View File
@@ -28,6 +28,7 @@
#include <mp-units/framework.h>
#if MP_UNITS_HOSTED
#include <mp-units/cartesian_vector.h>
#include <mp-units/complex.h>
#include <mp-units/format.h>
#include <mp-units/math.h>
@@ -90,16 +90,16 @@ public:
constexpr T* data() noexcept { return data_; }
constexpr const T* data() const noexcept { return data_; }
constexpr reference push_back(const T& v)
constexpr reference push_back(const T& val)
requires std::constructible_from<T, const T&>
{
return emplace_back(v);
return emplace_back(val);
}
constexpr reference push_back(T&& v)
constexpr reference push_back(T&& val)
requires std::constructible_from<T, T&&>
{
return emplace_back(std::forward<T&&>(v));
return emplace_back(std::forward<T&&>(val));
}
template<typename... Args>
+20 -20
View File
@@ -174,21 +174,21 @@ public:
template<typename FwdValue, Reference R2>
requires detail::SameValueAs<R2{}, R, std::remove_cvref_t<FwdValue>, Rep>
constexpr quantity(FwdValue&& v, R2) : numerical_value_is_an_implementation_detail_(std::forward<FwdValue>(v))
constexpr quantity(FwdValue&& val, R2) : numerical_value_is_an_implementation_detail_(std::forward<FwdValue>(val))
{
}
template<typename FwdValue, Reference R2, typename Value = std::remove_cvref_t<FwdValue>>
requires(!detail::SameValueAs<R2{}, R, Value, Rep>) &&
detail::QuantityConvertibleTo<quantity<R2{}, Value>, quantity>
constexpr quantity(FwdValue&& v, R2) : quantity(quantity<R2{}, Value>{std::forward<FwdValue>(v), R2{}})
constexpr quantity(FwdValue&& val, R2) : quantity(quantity<R2{}, Value>{std::forward<FwdValue>(val), R2{}})
{
}
template<detail::ValuePreservingTo<Rep> FwdValue>
requires(unit == ::mp_units::one)
constexpr explicit(false) quantity(FwdValue&& v) :
numerical_value_is_an_implementation_detail_(std::forward<FwdValue>(v))
constexpr explicit(false) quantity(FwdValue&& val) :
numerical_value_is_an_implementation_detail_(std::forward<FwdValue>(val))
{
}
@@ -214,9 +214,9 @@ public:
template<detail::ValuePreservingTo<Rep> FwdValue>
requires(unit == ::mp_units::one)
constexpr quantity& operator=(FwdValue&& v)
constexpr quantity& operator=(FwdValue&& val)
{
numerical_value_is_an_implementation_detail_ = std::forward<FwdValue>(v);
numerical_value_is_an_implementation_detail_ = std::forward<FwdValue>(val);
return *this;
}
@@ -422,11 +422,11 @@ public:
requires(!Quantity<Value>) && requires(rep a, Value b) {
{ a *= b } -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& v)
friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& val)
{
// TODO use *= when compiler bug is resolved:
// https://developercommunity.visualstudio.com/t/Discrepancy-in-Behavior-of-operator-an/10732445
lhs.numerical_value_is_an_implementation_detail_ = lhs.numerical_value_is_an_implementation_detail_ * v;
lhs.numerical_value_is_an_implementation_detail_ = lhs.numerical_value_is_an_implementation_detail_ * val;
return std::forward<Q>(lhs);
}
@@ -444,12 +444,12 @@ public:
requires(!Quantity<Value>) && requires(rep a, Value b) {
{ a /= b } -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& v)
friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& val)
{
MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
MP_UNITS_EXPECTS_DEBUG(val != quantity_values<Value>::zero());
// TODO use /= when compiler bug is resolved:
// https://developercommunity.visualstudio.com/t/Discrepancy-in-Behavior-of-operator-an/10732445
lhs.numerical_value_is_an_implementation_detail_ = lhs.numerical_value_is_an_implementation_detail_ / v;
lhs.numerical_value_is_an_implementation_detail_ = lhs.numerical_value_is_an_implementation_detail_ / val;
return std::forward<Q>(lhs);
}
@@ -551,17 +551,17 @@ public:
template<std::derived_from<quantity> Q, typename Value>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::multiplies<>, Rep, const Value&>
[[nodiscard]] friend constexpr QuantityOf<quantity_spec> auto operator*(const Q& q, const Value& v)
[[nodiscard]] friend constexpr QuantityOf<quantity_spec> auto operator*(const Q& q, const Value& val)
{
return ::mp_units::quantity{q.numerical_value_ref_in(unit) * v, R};
return ::mp_units::quantity{q.numerical_value_ref_in(unit) * val, R};
}
template<typename Value, std::derived_from<quantity> Q>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::multiplies<>, const Value&, Rep>
[[nodiscard]] friend constexpr QuantityOf<quantity_spec> auto operator*(const Value& v, const Q& q)
[[nodiscard]] friend constexpr QuantityOf<quantity_spec> auto operator*(const Value& val, const Q& q)
{
return ::mp_units::quantity{v * q.numerical_value_ref_in(unit), R};
return ::mp_units::quantity{val * q.numerical_value_ref_in(unit), R};
}
template<std::derived_from<quantity> Q, auto R2, typename Rep2>
@@ -575,18 +575,18 @@ public:
template<std::derived_from<quantity> Q, typename Value>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::divides<>, Rep, const Value&>
[[nodiscard]] friend constexpr QuantityOf<quantity_spec> auto operator/(const Q& q, const Value& v)
[[nodiscard]] friend constexpr QuantityOf<quantity_spec> auto operator/(const Q& q, const Value& val)
{
MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
return ::mp_units::quantity{q.numerical_value_ref_in(unit) / v, R};
MP_UNITS_EXPECTS_DEBUG(val != quantity_values<Value>::zero());
return ::mp_units::quantity{q.numerical_value_ref_in(unit) / val, R};
}
template<typename Value, std::derived_from<quantity> Q>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::divides<>, const Value&, Rep>
[[nodiscard]] friend constexpr QuantityOf<inverse(quantity_spec)> auto operator/(const Value& v, const Q& q)
[[nodiscard]] friend constexpr QuantityOf<inverse(quantity_spec)> auto operator/(const Value& val, const Q& q)
{
return ::mp_units::quantity{v / q.numerical_value_ref_in(unit), ::mp_units::one / R};
return ::mp_units::quantity{val / q.numerical_value_ref_in(unit), ::mp_units::one / R};
}
template<std::derived_from<quantity> Q, auto R2, typename Rep2>
@@ -59,7 +59,7 @@ template<QuantitySpec QS, Unit U>
requires(!AssociatedUnit<U>) || UnitOf<U, QS{}>
[[nodiscard]] consteval Reference auto make_reference(QS, U u)
{
if constexpr (QuantityKindSpec<QS>)
if constexpr (requires { requires(get_quantity_spec(U{}) == QS{}); })
return u;
else
return reference<QS, U>{};
@@ -118,12 +118,11 @@ concept ComplexRepresentation = Complex<T> && WeaklyRegular<T> && requires(T a,
{ a - b } -> Complex;
{ a* b } -> Complex;
{ a / b } -> Complex;
// TBD
// { re(a) } -> Scalar;
// { im(a) } -> Scalar;
// { mod(a) } -> Scalar;
// { arg(a) } -> Scalar;
// { conj(a) } -> Complex;
{ real(a) } -> Scalar;
{ imag(a) } -> Scalar;
{ abs(a) } -> Scalar;
{ arg(a) } -> Scalar;
{ conj(a) } -> Complex;
};
// TODO how to check for a complex(Scalar, Scalar) -> Complex?
+6 -6
View File
@@ -68,8 +68,8 @@ void to_stream_impl(std::basic_ostream<CharT, Traits>& os, const quantity<R, Rep
}
template<typename CharT, class Traits, typename T>
std::basic_ostream<CharT, Traits>& to_stream(std::basic_ostream<CharT, Traits>& os, const T& v)
requires requires { detail::to_stream_impl(os, v); }
std::basic_ostream<CharT, Traits>& to_stream(std::basic_ostream<CharT, Traits>& os, const T& val)
requires requires { detail::to_stream_impl(os, val); }
{
if (os.width()) {
// std::setw() applies to the whole output so it has to be first put into std::string
@@ -77,11 +77,11 @@ std::basic_ostream<CharT, Traits>& to_stream(std::basic_ostream<CharT, Traits>&
oss.flags(os.flags());
oss.imbue(os.getloc());
oss.precision(os.precision());
detail::to_stream_impl(oss, v);
detail::to_stream_impl(oss, val);
return os << std::move(oss).str();
}
detail::to_stream_impl(os, v);
detail::to_stream_impl(os, val);
return os;
}
@@ -93,10 +93,10 @@ constexpr bool is_mp_units_stream = requires(OStream os, T v) { detail::to_strea
MP_UNITS_EXPORT_BEGIN
template<typename CharT, typename Traits, typename T>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const T& v)
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const T& val)
requires detail::is_mp_units_stream<std::basic_ostream<CharT, Traits>, T>
{
return detail::to_stream(os, v);
return detail::to_stream(os, val);
}
MP_UNITS_EXPORT_END
@@ -83,10 +83,10 @@ struct quantity_like_traits<std::chrono::duration<Rep, Period>> {
return q.count();
}
[[nodiscard]] static constexpr T from_numerical_value(const rep& v) noexcept(
[[nodiscard]] static constexpr T from_numerical_value(const rep& val) noexcept(
std::is_nothrow_copy_constructible_v<rep>)
{
return T(v);
return T(val);
}
};
@@ -113,10 +113,10 @@ struct quantity_point_like_traits<std::chrono::time_point<C, std::chrono::durati
return tp.time_since_epoch().count();
}
[[nodiscard]] static constexpr T from_numerical_value(const rep& v) noexcept(
[[nodiscard]] static constexpr T from_numerical_value(const rep& val) noexcept(
std::is_nothrow_copy_constructible_v<rep>)
{
return T(std::chrono::duration<Rep, Period>(v));
return T(std::chrono::duration<Rep, Period>(val));
}
};