Skip to content

Commit 830cf42

Browse files
committed
fix after review
1 parent 40fb1ee commit 830cf42

File tree

4 files changed

+131
-108
lines changed

4 files changed

+131
-108
lines changed

src/core/include/mp-units/cartesian_tensor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222

2323
#pragma once
2424

25-
#include <mp-units/bits/module_macros.h>
2625
#include <mp-units/bits/requires_hosted.h>
26+
#include <mp-units/bits/module_macros.h>
2727
#include <mp-units/cartesian_vector.h>
2828
#include <mp-units/framework/customization_points.h>
2929
#include <mp-units/framework/representation_concepts.h>

src/core/include/mp-units/cartesian_vector.h

Lines changed: 99 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222

2323
#pragma once
2424

25-
#include <mp-units/bits/module_macros.h>
2625
#include <mp-units/bits/requires_hosted.h>
26+
#include <mp-units/bits/module_macros.h>
2727
#include <mp-units/framework/customization_points.h>
2828
#include <mp-units/framework/representation_concepts.h>
2929
#include <type_traits>
@@ -56,10 +56,22 @@ MP_UNITS_EXPORT template<detail::Scalar T = double>
5656
class cartesian_vector {
5757
public:
5858
// public members required to satisfy structural type requirements :-(
59-
// NOTE: This type is intentionally an aggregate (like std::array).
6059
T _coordinates_[3];
6160
using value_type = T;
6261

62+
constexpr cartesian_vector() = default;
63+
64+
explicit constexpr cartesian_vector(T x) : _coordinates_{x, T{}, T{}} {}
65+
constexpr cartesian_vector(T x, T y) : _coordinates_{x, y, T{}} {}
66+
constexpr cartesian_vector(T x, T y, T z) : _coordinates_{x, y, z} {}
67+
68+
template<typename U>
69+
requires std::constructible_from<T, U> && (!std::same_as<std::remove_cvref_t<U>, T>) &&
70+
(!std::same_as<std::remove_cvref_t<U>, cartesian_vector>)
71+
explicit constexpr cartesian_vector(U&& val) : _coordinates_{T(val), T(val), T(val)}
72+
{
73+
}
74+
6375
[[nodiscard]] constexpr T magnitude() const
6476
requires treat_as_floating_point<T>
6577
{
@@ -142,6 +154,91 @@ class cartesian_vector {
142154
return vec.unit();
143155
}
144156

157+
template<typename U>
158+
requires requires(const T& t, const U& u) { t + u; }
159+
[[nodiscard]] friend constexpr auto operator+(const cartesian_vector& lhs, const cartesian_vector<U>& rhs)
160+
{
161+
return ::mp_units::cartesian_vector{lhs._coordinates_[0] + rhs._coordinates_[0],
162+
lhs._coordinates_[1] + rhs._coordinates_[1],
163+
lhs._coordinates_[2] + rhs._coordinates_[2]};
164+
}
165+
166+
template<typename U>
167+
requires requires(const T& t, const U& u) { t - u; }
168+
[[nodiscard]] friend constexpr auto operator-(const cartesian_vector& lhs, const cartesian_vector<U>& rhs)
169+
{
170+
return ::mp_units::cartesian_vector{lhs._coordinates_[0] - rhs._coordinates_[0],
171+
lhs._coordinates_[1] - rhs._coordinates_[1],
172+
lhs._coordinates_[2] - rhs._coordinates_[2]};
173+
}
174+
175+
template<typename U>
176+
requires(!treat_as_floating_point<T> && !treat_as_floating_point<U> && requires(const T& t, const U& u) { t % u; })
177+
[[nodiscard]] friend constexpr auto operator%(const cartesian_vector& lhs, const cartesian_vector<U>& rhs)
178+
{
179+
using CT = std::common_type_t<T, U>;
180+
return ::mp_units::cartesian_vector<CT>{static_cast<CT>(lhs._coordinates_[0] % rhs._coordinates_[0]),
181+
static_cast<CT>(lhs._coordinates_[1] % rhs._coordinates_[1]),
182+
static_cast<CT>(lhs._coordinates_[2] % rhs._coordinates_[2])};
183+
}
184+
185+
template<typename S>
186+
requires(!std::same_as<std::remove_cvref_t<S>, cartesian_vector>) && (!detail::is_quantity<S>) &&
187+
requires(const T& t, const S& s) { t * s; }
188+
[[nodiscard]] friend constexpr auto operator*(const cartesian_vector& vector, const S& scalar)
189+
{
190+
return ::mp_units::cartesian_vector{vector._coordinates_[0] * scalar, vector._coordinates_[1] * scalar,
191+
vector._coordinates_[2] * scalar};
192+
}
193+
194+
template<typename S>
195+
requires(!std::same_as<std::remove_cvref_t<S>, cartesian_vector>) && (!detail::is_quantity<S>) &&
196+
requires(const S& s, const T& t) { s * t; }
197+
[[nodiscard]] friend constexpr auto operator*(const S& scalar, const cartesian_vector& vector)
198+
{
199+
return vector * scalar;
200+
}
201+
202+
template<typename S>
203+
requires(!std::same_as<std::remove_cvref_t<S>, cartesian_vector>) && (!detail::is_quantity<S>) &&
204+
requires(const T& t, const S& s) { t / s; }
205+
[[nodiscard]] friend constexpr auto operator/(const cartesian_vector& vector, const S& scalar)
206+
{
207+
return ::mp_units::cartesian_vector{vector._coordinates_[0] / scalar, vector._coordinates_[1] / scalar,
208+
vector._coordinates_[2] / scalar};
209+
}
210+
211+
template<std::equality_comparable_with<T> U>
212+
[[nodiscard]] friend constexpr bool operator==(const cartesian_vector& lhs, const cartesian_vector<U>& rhs)
213+
{
214+
return lhs._coordinates_[0] == rhs._coordinates_[0] && lhs._coordinates_[1] == rhs._coordinates_[1] &&
215+
lhs._coordinates_[2] == rhs._coordinates_[2];
216+
}
217+
218+
template<typename U>
219+
requires requires(const T& t, const U& u, decltype(t * u) v) {
220+
t * u;
221+
v + v;
222+
}
223+
[[nodiscard]] friend constexpr auto scalar_product(const cartesian_vector& lhs, const cartesian_vector<U>& rhs)
224+
{
225+
return lhs._coordinates_[0] * rhs._coordinates_[0] + lhs._coordinates_[1] * rhs._coordinates_[1] +
226+
lhs._coordinates_[2] * rhs._coordinates_[2];
227+
}
228+
229+
template<typename U>
230+
requires requires(const T& t, const U& u, decltype(t * u) v) {
231+
t * u;
232+
v - v;
233+
}
234+
[[nodiscard]] friend constexpr auto vector_product(const cartesian_vector& lhs, const cartesian_vector<U>& rhs)
235+
{
236+
return ::mp_units::cartesian_vector{
237+
lhs._coordinates_[1] * rhs._coordinates_[2] - lhs._coordinates_[2] * rhs._coordinates_[1],
238+
lhs._coordinates_[2] * rhs._coordinates_[0] - lhs._coordinates_[0] * rhs._coordinates_[2],
239+
lhs._coordinates_[0] * rhs._coordinates_[1] - lhs._coordinates_[1] * rhs._coordinates_[0]};
240+
}
241+
145242
#if MP_UNITS_HOSTED
146243
friend std::ostream& operator<<(std::ostream& os, const cartesian_vector& vec)
147244
{
@@ -154,88 +251,6 @@ template<typename Arg, typename... Args>
154251
requires(sizeof...(Args) <= 2) && requires { typename std::common_type_t<Arg, Args...>; }
155252
cartesian_vector(Arg, Args...) -> cartesian_vector<std::common_type_t<Arg, Args...>>;
156253

157-
MP_UNITS_EXPORT template<typename T, typename U>
158-
requires requires(const T& t, const U& u) { t + u; }
159-
[[nodiscard]] constexpr auto operator+(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
160-
{
161-
return ::mp_units::cartesian_vector{lhs._coordinates_[0] + rhs._coordinates_[0],
162-
lhs._coordinates_[1] + rhs._coordinates_[1],
163-
lhs._coordinates_[2] + rhs._coordinates_[2]};
164-
}
165-
166-
MP_UNITS_EXPORT template<typename T, typename U>
167-
requires requires(const T& t, const U& u) { t - u; }
168-
[[nodiscard]] constexpr auto operator-(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
169-
{
170-
return ::mp_units::cartesian_vector{lhs._coordinates_[0] - rhs._coordinates_[0],
171-
lhs._coordinates_[1] - rhs._coordinates_[1],
172-
lhs._coordinates_[2] - rhs._coordinates_[2]};
173-
}
174-
175-
MP_UNITS_EXPORT template<typename T, typename U>
176-
requires(!treat_as_floating_point<T> && !treat_as_floating_point<U> && requires(const T& t, const U& u) { t % u; })
177-
[[nodiscard]] constexpr auto operator%(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
178-
{
179-
using CT = std::common_type_t<T, U>;
180-
return ::mp_units::cartesian_vector<CT>{static_cast<CT>(lhs._coordinates_[0] % rhs._coordinates_[0]),
181-
static_cast<CT>(lhs._coordinates_[1] % rhs._coordinates_[1]),
182-
static_cast<CT>(lhs._coordinates_[2] % rhs._coordinates_[2])};
183-
}
184-
185-
MP_UNITS_EXPORT template<typename T, typename S>
186-
requires requires(const T& t, const S& s) { t * s; }
187-
[[nodiscard]] constexpr auto operator*(const cartesian_vector<T>& vector, const S& scalar)
188-
{
189-
return ::mp_units::cartesian_vector{vector._coordinates_[0] * scalar, vector._coordinates_[1] * scalar,
190-
vector._coordinates_[2] * scalar};
191-
}
192-
193-
MP_UNITS_EXPORT template<typename S, typename U>
194-
requires requires(const S& s, const U& u) { s * u; }
195-
[[nodiscard]] constexpr auto operator*(const S& scalar, const cartesian_vector<U>& vector)
196-
{
197-
return vector * scalar;
198-
}
199-
200-
MP_UNITS_EXPORT template<typename T, typename S>
201-
requires requires(const T& t, const S& s) { t / s; }
202-
[[nodiscard]] constexpr auto operator/(const cartesian_vector<T>& vector, const S& scalar)
203-
{
204-
return ::mp_units::cartesian_vector{vector._coordinates_[0] / scalar, vector._coordinates_[1] / scalar,
205-
vector._coordinates_[2] / scalar};
206-
}
207-
208-
MP_UNITS_EXPORT template<typename T, std::equality_comparable_with<T> U>
209-
[[nodiscard]] constexpr bool operator==(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
210-
{
211-
return lhs._coordinates_[0] == rhs._coordinates_[0] && lhs._coordinates_[1] == rhs._coordinates_[1] &&
212-
lhs._coordinates_[2] == rhs._coordinates_[2];
213-
}
214-
215-
MP_UNITS_EXPORT template<typename T, typename U>
216-
requires requires(const T& t, const U& u, decltype(t * u) v) {
217-
t * u;
218-
v + v;
219-
}
220-
[[nodiscard]] constexpr auto scalar_product(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
221-
{
222-
return lhs._coordinates_[0] * rhs._coordinates_[0] + lhs._coordinates_[1] * rhs._coordinates_[1] +
223-
lhs._coordinates_[2] * rhs._coordinates_[2];
224-
}
225-
226-
MP_UNITS_EXPORT template<typename T, typename U>
227-
requires requires(const T& t, const U& u, decltype(t * u) v) {
228-
t * u;
229-
v - v;
230-
}
231-
[[nodiscard]] constexpr auto vector_product(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
232-
{
233-
return ::mp_units::cartesian_vector{
234-
lhs._coordinates_[1] * rhs._coordinates_[2] - lhs._coordinates_[2] * rhs._coordinates_[1],
235-
lhs._coordinates_[2] * rhs._coordinates_[0] - lhs._coordinates_[0] * rhs._coordinates_[2],
236-
lhs._coordinates_[0] * rhs._coordinates_[1] - lhs._coordinates_[1] * rhs._coordinates_[0]};
237-
}
238-
239254
template<class T>
240255
inline constexpr bool treat_as_floating_point<cartesian_vector<T>> = treat_as_floating_point<T>;
241256

test/runtime/cartesian_vector_test.cpp

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,15 @@
2424
#include <catch2/matchers/catch_matchers_floating_point.hpp>
2525

2626
#ifdef MP_UNITS_MODULES
27+
import std;
2728
import mp_units;
2829
#else
2930
#include <mp-units/cartesian_vector.h>
3031
#include <mp-units/ext/format.h>
3132
#include <sstream>
3233
#endif
3334

34-
#ifndef MP_UNITS_MODULES
35-
#include <sstream>
36-
#endif
37-
3835
using namespace mp_units;
39-
using Catch::Matchers::WithinAbs;
4036

4137
TEST_CASE("cartesian_vector", "[vector]")
4238
{
@@ -84,7 +80,7 @@ TEST_CASE("cartesian_vector", "[vector]")
8480
SECTION("aggregate copy assignment")
8581
{
8682
cartesian_vector v1{1.0, 2.0, 3.0};
87-
cartesian_vector<double> v2 = v1; // Use initialization instead of assignment
83+
cartesian_vector<double> v2 = v1;
8884
REQUIRE(v2[0] == 1.0);
8985
REQUIRE(v2[1] == 2.0);
9086
REQUIRE(v2[2] == 3.0);
@@ -218,23 +214,12 @@ TEST_CASE("cartesian_vector", "[vector]")
218214
SECTION("magnitude and unit (floating types)")
219215
{
220216
cartesian_vector<double> v{3.0, 4.0, 0.0};
221-
REQUIRE_THAT(v.magnitude(), WithinAbs(5.0, 1e-12));
217+
REQUIRE_THAT(v.magnitude(), Catch::Matchers::WithinULP(5.0, 2));
222218
auto u = v.unit();
223-
REQUIRE_THAT(u.magnitude(), WithinAbs(1.0, 1e-12));
224-
REQUIRE_THAT(u[0], WithinAbs(3.0 / 5.0, 1e-12));
225-
REQUIRE_THAT(u[1], WithinAbs(4.0 / 5.0, 1e-12));
226-
REQUIRE_THAT(u[2], WithinAbs(0.0, 1e-12));
227-
}
228-
229-
SECTION("text output (ostream + fmt)")
230-
{
231-
cartesian_vector v{1, 2, 3};
232-
std::ostringstream os;
233-
os << v;
234-
CHECK(os.str() == "[1, 2, 3]");
235-
#ifndef MP_UNITS_MODULES
236-
CHECK(MP_UNITS_STD_FMT::format("{}", v) == os.str());
237-
#endif
219+
REQUIRE_THAT(u.magnitude(), Catch::Matchers::WithinULP(1.0, 2));
220+
REQUIRE_THAT(u[0], Catch::Matchers::WithinULP(3.0 / 5.0, 2));
221+
REQUIRE_THAT(u[1], Catch::Matchers::WithinULP(4.0 / 5.0, 2));
222+
REQUIRE_THAT(u[2], Catch::Matchers::WithinULP(0.0, 2));
238223
}
239224

240225
SECTION("constexpr basics")
@@ -246,3 +231,26 @@ TEST_CASE("cartesian_vector", "[vector]")
246231
(void)c;
247232
}
248233
}
234+
235+
TEST_CASE("cartesian_vector text output", "[vector][fmt][ostream]")
236+
{
237+
std::ostringstream os;
238+
239+
SECTION("integral representation")
240+
{
241+
cartesian_vector v{1, 2, 3};
242+
os << v;
243+
244+
SECTION("iostream") { CHECK(os.str() == "[1, 2, 3]"); }
245+
SECTION("fmt with default format {}") { CHECK(MP_UNITS_STD_FMT::format("{}", v) == os.str()); }
246+
}
247+
248+
SECTION("floating-point representation")
249+
{
250+
cartesian_vector v{1.2, 2.3, 3.4};
251+
os << v;
252+
253+
SECTION("iostream") { CHECK(os.str() == "[1.2, 2.3, 3.4]"); }
254+
SECTION("fmt with default format {}") { CHECK(MP_UNITS_STD_FMT::format("{}", v) == os.str()); }
255+
}
256+
}

test/static/quantity_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ static_assert(std::constructible_from<std::complex<double>, quantity<one, double
303303
static_assert(!std::convertible_to<quantity<one, cartesian_vector<double>>, cartesian_vector<double>>);
304304
static_assert(std::constructible_from<cartesian_vector<double>, quantity<one, cartesian_vector<double>>>);
305305
static_assert(!std::convertible_to<quantity<one, double>, cartesian_vector<double>>);
306-
static_assert(std::is_aggregate_v<cartesian_vector<double>>);
306+
static_assert(std::constructible_from<cartesian_vector<double>, quantity<one, double>>);
307307

308308
#endif
309309

0 commit comments

Comments
 (0)