-
-
Notifications
You must be signed in to change notification settings - Fork 119
Implement simple vector and tensor types #735
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
edec240
ab3c2e8
a4f0682
73d8554
fa57a3a
7bc1e18
90a371c
26c88fe
00b2e74
59f9298
1ecb38f
40fb1ee
8cfa4c8
5b8ffe3
7313258
dedc039
bfde546
84ebb5c
b516aa7
e82ac7d
9ffc374
1f6e9f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,6 +27,7 @@ | |
| #include <mp-units/bits/module_macros.h> | ||
| #include <mp-units/framework/customization_points.h> | ||
| #include <mp-units/framework/representation_concepts.h> | ||
| #include <type_traits> | ||
|
|
||
| #if MP_UNITS_HOSTED | ||
| #include <mp-units/bits/fmt.h> | ||
|
|
@@ -37,8 +38,10 @@ | |
| import std; | ||
| #else | ||
| #include <cmath> | ||
| #include <concepts> | ||
| #include <cstddef> | ||
| #include <type_traits> | ||
| #include <utility> | ||
| #if MP_UNITS_HOSTED | ||
| #include <ostream> | ||
| #endif | ||
|
|
@@ -50,104 +53,18 @@ namespace mp_units { | |
| MP_UNITS_EXPORT template<detail::Scalar T> | ||
| class cartesian_vector; | ||
|
|
||
| namespace detail { | ||
|
|
||
| struct cartesian_vector_iface { | ||
| template<typename T, typename U> | ||
| requires requires(T t, U u) { t + u; } | ||
| [[nodiscard]] friend constexpr auto operator+(const cartesian_vector<T>& lhs, const cartesian_vector<U>& 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<typename T, typename U> | ||
| requires requires(T t, U u) { t - u; } | ||
| [[nodiscard]] friend constexpr auto operator-(const cartesian_vector<T>& lhs, const cartesian_vector<U>& 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<typename T, typename U> | ||
| requires requires(T t, U u) { t * u; } | ||
| [[nodiscard]] friend constexpr auto operator*(const cartesian_vector<T>& lhs, const U& rhs) | ||
| { | ||
| return ::mp_units::cartesian_vector{lhs._coordinates_[0] * rhs, lhs._coordinates_[1] * rhs, | ||
| lhs._coordinates_[2] * rhs}; | ||
| } | ||
|
|
||
| template<typename T, typename 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<typename T, typename U> | ||
| requires requires(T t, U u) { t / u; } | ||
| [[nodiscard]] friend constexpr auto operator/(const cartesian_vector<T>& lhs, const U& rhs) | ||
| { | ||
| return ::mp_units::cartesian_vector{lhs._coordinates_[0] / rhs, lhs._coordinates_[1] / rhs, | ||
| lhs._coordinates_[2] / rhs}; | ||
| } | ||
|
|
||
| template<typename T, std::equality_comparable_with<T> U> | ||
| [[nodiscard]] friend constexpr bool operator==(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs) | ||
| { | ||
| return lhs._coordinates_[0] == rhs._coordinates_[0] && lhs._coordinates_[1] == rhs._coordinates_[1] && | ||
| lhs._coordinates_[2] == rhs._coordinates_[2]; | ||
| } | ||
|
|
||
| template<typename T, typename U> | ||
| requires requires(T t, U u, decltype(t * u) v) { | ||
| t * u; | ||
| v + v; | ||
| } | ||
| [[nodiscard]] friend constexpr auto scalar_product(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs) | ||
| { | ||
| return lhs._coordinates_[0] * rhs._coordinates_[0] + lhs._coordinates_[1] * rhs._coordinates_[1] + | ||
| lhs._coordinates_[2] * rhs._coordinates_[2]; | ||
| } | ||
|
|
||
| template<typename T, typename U> | ||
| requires requires(T t, U u, decltype(t * u) v) { | ||
| t * u; | ||
| v - v; | ||
| } | ||
| [[nodiscard]] friend constexpr auto vector_product(const cartesian_vector<T>& lhs, const cartesian_vector<U>& 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]}; | ||
| } | ||
| }; | ||
|
|
||
| } // namespace detail | ||
|
|
||
| MP_UNITS_EXPORT template<detail::Scalar T = double> | ||
| class cartesian_vector : public detail::cartesian_vector_iface { | ||
| class cartesian_vector { | ||
| public: | ||
| // public members required to satisfy structural type requirements :-( | ||
| T _coordinates_[3]; | ||
| using value_type = T; | ||
|
|
||
| template<typename... Args> | ||
| requires(... && std::constructible_from<T, Args>) | ||
| constexpr explicit(!(... && std::convertible_to<Args, T>)) cartesian_vector(Args&&... args) : | ||
| _coordinates_{static_cast<T>(std::forward<Args>(args))...} | ||
| { | ||
| } | ||
| constexpr cartesian_vector() = default; | ||
|
|
||
| template<typename U> | ||
| requires std::constructible_from<T, U> | ||
| constexpr explicit(!std::convertible_to<U, T>) cartesian_vector(const cartesian_vector<U>& other) : | ||
| _coordinates_{static_cast<T>(other[0]), static_cast<T>(other[1]), static_cast<T>(other[2])} | ||
| { | ||
| } | ||
| explicit constexpr cartesian_vector(T x) : _coordinates_{x, T{}, T{}} {} | ||
| constexpr cartesian_vector(T x, T y) : _coordinates_{x, y, T{}} {} | ||
| constexpr cartesian_vector(T x, T y, T z) : _coordinates_{x, y, z} {} | ||
|
|
||
| template<typename U> | ||
| requires std::constructible_from<T, U> | ||
|
|
@@ -157,23 +74,6 @@ class cartesian_vector : public detail::cartesian_vector_iface { | |
| { | ||
| } | ||
|
|
||
| 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; | ||
| } | ||
|
Comment on lines
-160
to
-176
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you delete those? |
||
|
|
||
| [[nodiscard]] constexpr T magnitude() const | ||
| requires treat_as_floating_point<T> | ||
|
|
@@ -198,11 +98,11 @@ class cartesian_vector : public detail::cartesian_vector_iface { | |
| [[nodiscard]] constexpr cartesian_vector operator+() const { return *this; } | ||
| [[nodiscard]] constexpr cartesian_vector operator-() const | ||
| { | ||
| return {-_coordinates_[0], -_coordinates_[1], -_coordinates_[2]}; | ||
| return cartesian_vector{-_coordinates_[0], -_coordinates_[1], -_coordinates_[2]}; | ||
|
Comment on lines
-201
to
+101
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should not be needed. |
||
| } | ||
|
|
||
| template<typename U> | ||
| requires requires(T t, U u) { | ||
| requires requires(T& t, const U& u) { | ||
| { t += u } -> std::same_as<T&>; | ||
| } | ||
| constexpr cartesian_vector& operator+=(const cartesian_vector<U>& other) | ||
|
|
@@ -214,7 +114,7 @@ class cartesian_vector : public detail::cartesian_vector_iface { | |
| } | ||
|
|
||
| template<typename U> | ||
| requires requires(T t, U u) { | ||
| requires requires(T& t, const U& u) { | ||
| { t -= u } -> std::same_as<T&>; | ||
| } | ||
| constexpr cartesian_vector& operator-=(const cartesian_vector<U>& other) | ||
|
|
@@ -225,27 +125,27 @@ class cartesian_vector : public detail::cartesian_vector_iface { | |
| return *this; | ||
| } | ||
|
|
||
| template<typename U> | ||
| requires requires(T t, U u) { | ||
| { t *= u } -> std::same_as<T&>; | ||
| template<typename S> | ||
| requires requires(T& t, const S& s) { | ||
| { t *= s } -> std::same_as<T&>; | ||
| } | ||
| constexpr cartesian_vector& operator*=(const U& value) | ||
| constexpr cartesian_vector& operator*=(const S& scalar) | ||
| { | ||
| _coordinates_[0] *= value; | ||
| _coordinates_[1] *= value; | ||
| _coordinates_[2] *= value; | ||
| _coordinates_[0] *= scalar; | ||
| _coordinates_[1] *= scalar; | ||
| _coordinates_[2] *= scalar; | ||
| return *this; | ||
| } | ||
|
|
||
| template<typename U> | ||
| requires requires(T t, U u) { | ||
| { t /= u } -> std::same_as<T&>; | ||
| template<typename S> | ||
| requires requires(T& t, const S& s) { | ||
| { t /= s } -> std::same_as<T&>; | ||
| } | ||
| constexpr cartesian_vector& operator/=(const U& value) | ||
| constexpr cartesian_vector& operator/=(const S& scalar) | ||
| { | ||
| _coordinates_[0] /= value; | ||
| _coordinates_[1] /= value; | ||
| _coordinates_[2] /= value; | ||
| _coordinates_[0] /= scalar; | ||
| _coordinates_[1] /= scalar; | ||
| _coordinates_[2] /= scalar; | ||
| return *this; | ||
| } | ||
|
|
||
|
|
@@ -261,8 +161,90 @@ class cartesian_vector : public detail::cartesian_vector_iface { | |
| return vec.unit(); | ||
| } | ||
|
|
||
| template<typename U> | ||
| requires requires(const T& t, const U& u) { t + u; } | ||
| [[nodiscard]] friend constexpr auto operator+(const cartesian_vector& lhs, const cartesian_vector<U>& 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<typename U> | ||
| requires requires(const T& t, const U& u) { t - u; } | ||
| [[nodiscard]] friend constexpr auto operator-(const cartesian_vector& lhs, const cartesian_vector<U>& 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<typename U> | ||
| requires(!treat_as_floating_point<T> && !treat_as_floating_point<U> && requires(const T& t, const U& u) { t % u; }) | ||
| [[nodiscard]] friend constexpr auto operator%(const cartesian_vector& lhs, const cartesian_vector<U>& rhs) | ||
| { | ||
| using CT = std::common_type_t<T, U>; | ||
| return ::mp_units::cartesian_vector<CT>{static_cast<CT>(lhs._coordinates_[0] % rhs._coordinates_[0]), | ||
| static_cast<CT>(lhs._coordinates_[1] % rhs._coordinates_[1]), | ||
| static_cast<CT>(lhs._coordinates_[2] % rhs._coordinates_[2])}; | ||
| } | ||
|
|
||
| template<typename S> | ||
| requires(!std::same_as<std::remove_cvref_t<S>, cartesian_vector>) && detail::NotQuantity<S> | ||
| [[nodiscard]] friend constexpr auto operator*(const cartesian_vector& vector, const S& scalar) | ||
| { | ||
| return ::mp_units::cartesian_vector{vector._coordinates_[0] * scalar, vector._coordinates_[1] * scalar, | ||
| vector._coordinates_[2] * scalar}; | ||
| } | ||
|
|
||
| template<typename S> | ||
| requires(!std::same_as<std::remove_cvref_t<S>, cartesian_vector>) && detail::NotQuantity<S> | ||
| [[nodiscard]] friend constexpr auto operator*(const S& scalar, const cartesian_vector& vector) | ||
| { | ||
| return vector * scalar; | ||
| } | ||
|
|
||
| template<typename S> | ||
| requires(!std::same_as<std::remove_cvref_t<S>, cartesian_vector>) && detail::NotQuantity<S> | ||
| [[nodiscard]] friend constexpr auto operator/(const cartesian_vector& vector, const S& scalar) | ||
| { | ||
| return ::mp_units::cartesian_vector{vector._coordinates_[0] / scalar, vector._coordinates_[1] / scalar, | ||
| vector._coordinates_[2] / scalar}; | ||
| } | ||
|
|
||
| template<std::equality_comparable_with<T> U> | ||
| [[nodiscard]] friend constexpr bool operator==(const cartesian_vector& lhs, const cartesian_vector<U>& rhs) | ||
| { | ||
| return lhs._coordinates_[0] == rhs._coordinates_[0] && lhs._coordinates_[1] == rhs._coordinates_[1] && | ||
| lhs._coordinates_[2] == rhs._coordinates_[2]; | ||
| } | ||
|
|
||
| template<typename U> | ||
| requires requires(const T& t, const U& u, decltype(t * u) v) { | ||
| t * u; | ||
| v + v; | ||
| } | ||
| [[nodiscard]] friend constexpr auto scalar_product(const cartesian_vector& lhs, const cartesian_vector<U>& rhs) | ||
| { | ||
| return lhs._coordinates_[0] * rhs._coordinates_[0] + lhs._coordinates_[1] * rhs._coordinates_[1] + | ||
| lhs._coordinates_[2] * rhs._coordinates_[2]; | ||
| } | ||
|
|
||
| template<typename U> | ||
| requires requires(const T& t, const U& u, decltype(t * u) v) { | ||
| t * u; | ||
| v - v; | ||
| } | ||
| [[nodiscard]] friend constexpr auto vector_product(const cartesian_vector& lhs, const cartesian_vector<U>& 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]}; | ||
| } | ||
|
|
||
|
Comment on lines
+164
to
+245
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All of those make the class template operations asymmetrical. RHS argument will not convert, while the LHS will. Please restore my |
||
| #if MP_UNITS_HOSTED | ||
| friend constexpr std::ostream& operator<<(std::ostream& os, const cartesian_vector& vec) | ||
| friend std::ostream& operator<<(std::ostream& os, const cartesian_vector& vec) | ||
| { | ||
| return os << '[' << vec[0] << ", " << vec[1] << ", " << vec[2] << ']'; | ||
| } | ||
|
|
@@ -273,8 +255,30 @@ 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> | ||
| inline constexpr bool treat_as_floating_point<cartesian_vector<T>> = treat_as_floating_point<T>; | ||
|
|
||
| template<class S, class T> | ||
| inline constexpr bool is_value_preserving<S, cartesian_vector<T>> = is_value_preserving<S, T>; | ||
|
Comment on lines
+258
to
+262
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not needed as this class provides |
||
| } // namespace mp_units | ||
|
|
||
| namespace std { | ||
| template<class T, class U> | ||
| struct common_type<mp_units::cartesian_vector<T>, mp_units::cartesian_vector<U>> { | ||
| using type = mp_units::cartesian_vector<common_type_t<T, U>>; | ||
| }; | ||
|
|
||
| template<class T, class U> | ||
| struct common_type<mp_units::cartesian_vector<T>, U> { | ||
| using type = mp_units::cartesian_vector<common_type_t<T, U>>; | ||
| }; | ||
|
|
||
| template<class T, class U> | ||
| struct common_type<U, mp_units::cartesian_vector<T>> { | ||
| using type = mp_units::cartesian_vector<common_type_t<U, T>>; | ||
| }; | ||
|
Comment on lines
+265
to
+279
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, it seems correct, but why did you have to do it? Was it required by some specific test? |
||
| } // namespace std | ||
|
|
||
| #if MP_UNITS_HOSTED | ||
| // TODO use parse and use formatter for the underlying type | ||
| template<typename T, typename Char> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is not needed (included below). Also, this is not a correct section to include this file as it will collide with
import std;if used.