Skip to content

Commit c8e0644

Browse files
committed
Container: Vec2/Vec3
1 parent 857866c commit c8e0644

File tree

5 files changed

+404
-40
lines changed

5 files changed

+404
-40
lines changed

modules/Container/Vec2.mpp

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,24 +43,26 @@ export namespace CppUtils::Container
4343
return self;
4444
}
4545

46-
inline constexpr auto operator+=(const Vec2<T>& rhs) noexcept -> decltype(auto)
46+
template<class U>
47+
inline constexpr auto operator+=(this auto&& self, const Vec2<U>& rhs) noexcept -> decltype(self)
4748
{
48-
return apply([this, rhs](std::size_t axis) { m_values[axis] += rhs[axis]; });
49+
return self.apply([&](std::size_t axis) { self.m_values[axis] += static_cast<T>(rhs[axis]); });
4950
}
5051

51-
inline constexpr auto operator-=(const Vec2<T>& rhs) noexcept -> decltype(auto)
52+
template<class U>
53+
inline constexpr auto operator-=(this auto&& self, const Vec2<U>& rhs) noexcept -> decltype(self)
5254
{
53-
return apply([this, rhs](std::size_t axis) { m_values[axis] -= rhs[axis]; });
55+
return self.apply([&](std::size_t axis) { self.m_values[axis] -= static_cast<T>(rhs[axis]); });
5456
}
5557

56-
inline constexpr auto operator*=(T value) noexcept -> decltype(auto)
58+
inline constexpr auto operator*=(this auto&& self, auto value) noexcept -> decltype(self)
5759
{
58-
return apply([this, value](std::size_t axis) { m_values[axis] *= value; });
60+
return self.apply([&](std::size_t axis) { self.m_values[axis] = static_cast<T>(self.m_values[axis] * value); });
5961
}
6062

61-
inline constexpr auto operator/=(T value) noexcept -> decltype(auto)
63+
inline constexpr auto operator/=(this auto&& self, auto value) noexcept -> decltype(self)
6264
{
63-
return apply([this, value](std::size_t axis) { m_values[axis] /= value; });
65+
return self.apply([&](std::size_t axis) { self.m_values[axis] = static_cast<T>(self.m_values[axis] / value); });
6466
}
6567

6668
std::array<T, 2> m_values;
@@ -69,34 +71,74 @@ export namespace CppUtils::Container
6971
template<class T>
7072
Vec2(T, T) -> Vec2<T>;
7173

72-
template<class T>
73-
[[nodiscard]] inline constexpr auto operator+(const Vec2<T>& lhs, const Vec2<T>& rhs) noexcept -> Vec2<T>
74+
template<class T, class U>
75+
[[nodiscard]] inline constexpr auto operator+(const Vec2<T>& lhs, const Vec2<U>& rhs) noexcept
7476
{
75-
return auto{lhs} += rhs;
77+
using Common = std::common_type_t<T, U>;
78+
return Vec2<Common>{
79+
static_cast<Common>(lhs.x()) + static_cast<Common>(rhs.x()),
80+
static_cast<Common>(lhs.y()) + static_cast<Common>(rhs.y())};
7681
}
7782

78-
template<class T>
79-
[[nodiscard]] inline constexpr auto operator-(const Vec2<T>& lhs, const Vec2<T>& rhs) noexcept -> Vec2<T>
83+
template<class T, class U>
84+
[[nodiscard]] inline constexpr auto operator-(const Vec2<T>& lhs, const Vec2<U>& rhs) noexcept
8085
{
81-
return auto{lhs} -= rhs;
86+
using Common = std::common_type_t<T, U>;
87+
return Vec2<Common>{
88+
static_cast<Common>(lhs.x()) - static_cast<Common>(rhs.x()),
89+
static_cast<Common>(lhs.y()) - static_cast<Common>(rhs.y())};
8290
}
8391

8492
template<class T>
85-
[[nodiscard]] inline constexpr auto operator*(const Vec2<T>& lhs, T value) noexcept -> Vec2<T>
93+
[[nodiscard]] inline constexpr auto operator*(const Vec2<T>& lhs, auto value) noexcept
8694
{
87-
return auto{lhs} *= value;
95+
using Common = std::common_type_t<T, decltype(value)>;
96+
return Vec2<Common>{
97+
static_cast<Common>(lhs.x()) * static_cast<Common>(value),
98+
static_cast<Common>(lhs.y()) * static_cast<Common>(value)};
8899
}
89100

90101
template<class T>
91-
[[nodiscard]] inline constexpr auto operator*(T value, const Vec2<T>& rhs) noexcept -> Vec2<T>
102+
[[nodiscard]] inline constexpr auto operator*(auto value, const Vec2<T>& rhs) noexcept
92103
{
93-
return auto{rhs} += value;
104+
using Common = std::common_type_t<T, decltype(value)>;
105+
return Vec2<Common>{
106+
static_cast<Common>(value) * static_cast<Common>(rhs.x()),
107+
static_cast<Common>(value) * static_cast<Common>(rhs.y())};
94108
}
95109

96110
template<class T>
97-
[[nodiscard]] inline constexpr auto operator/(const Vec2<T>& lhs, T value) noexcept -> Vec2<T>
111+
[[nodiscard]] inline constexpr auto operator/(const Vec2<T>& lhs, auto value) noexcept
98112
{
99-
return auto{lhs} /= value;
113+
using Common = std::common_type_t<T, decltype(value)>;
114+
return Vec2<Common>{
115+
static_cast<Common>(lhs.x()) / static_cast<Common>(value),
116+
static_cast<Common>(lhs.y()) / static_cast<Common>(value)};
100117
}
118+
}
119+
120+
export namespace std
121+
{
122+
template<class T, class CharT>
123+
struct formatter<CppUtils::Container::Vec2<T>, CharT>
124+
{
125+
formatter<T, CharT> m_formatter;
101126

127+
inline constexpr auto parse(auto& context)
128+
{
129+
return m_formatter.parse(context);
130+
}
131+
132+
inline auto format(const CppUtils::Container::Vec2<T>& vec, auto& context) const
133+
{
134+
auto out = context.out();
135+
out = std::format_to(out, "(");
136+
context.advance_to(out);
137+
out = m_formatter.format(vec.x(), context);
138+
out = std::format_to(out, ", ");
139+
context.advance_to(out);
140+
out = m_formatter.format(vec.y(), context);
141+
return std::format_to(out, ")");
142+
}
143+
};
102144
}

modules/Container/Vec3.mpp

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,24 +45,26 @@ export namespace CppUtils::Container
4545
return self;
4646
}
4747

48-
inline constexpr auto operator+=(const Vec3<T>& rhs) noexcept -> decltype(auto)
48+
template<class U>
49+
inline constexpr auto operator+=(this auto&& self, const Vec3<U>& rhs) noexcept -> decltype(self)
4950
{
50-
return apply([this, rhs](std::size_t axis) { m_values[axis] += rhs[axis]; });
51+
return self.apply([&](std::size_t axis) { self.m_values[axis] += static_cast<T>(rhs[axis]); });
5152
}
5253

53-
inline constexpr auto operator-=(const Vec3<T>& rhs) noexcept -> decltype(auto)
54+
template<class U>
55+
inline constexpr auto operator-=(this auto&& self, const Vec3<U>& rhs) noexcept -> decltype(self)
5456
{
55-
return apply([this, rhs](std::size_t axis) { m_values[axis] -= rhs[axis]; });
57+
return self.apply([&](std::size_t axis) { self.m_values[axis] -= static_cast<T>(rhs[axis]); });
5658
}
5759

58-
inline constexpr auto operator*=(T value) noexcept -> decltype(auto)
60+
inline constexpr auto operator*=(this auto&& self, auto value) noexcept -> decltype(self)
5961
{
60-
return apply([this, value](std::size_t axis) { m_values[axis] *= value; });
62+
return self.apply([&](std::size_t axis) { self.m_values[axis] = static_cast<T>(self.m_values[axis] * value); });
6163
}
6264

63-
inline constexpr auto operator/=(T value) noexcept -> decltype(auto)
65+
inline constexpr auto operator/=(this auto&& self, auto value) noexcept -> decltype(self)
6466
{
65-
return apply([this, value](std::size_t axis) { m_values[axis] /= value; });
67+
return self.apply([&](std::size_t axis) { self.m_values[axis] = static_cast<T>(self.m_values[axis] / value); });
6668
}
6769

6870
std::array<T, 3> m_values;
@@ -71,33 +73,82 @@ export namespace CppUtils::Container
7173
template<class T>
7274
Vec3(T, T, T) -> Vec3<T>;
7375

74-
template<class T>
75-
[[nodiscard]] inline constexpr auto operator+(const Vec3<T>& lhs, const Vec3<T>& rhs) noexcept -> Vec3<T>
76+
template<class T, class U>
77+
[[nodiscard]] inline constexpr auto operator+(const Vec3<T>& lhs, const Vec3<U>& rhs) noexcept
7678
{
77-
return auto{lhs} += rhs;
79+
using Common = std::common_type_t<T, U>;
80+
return Vec3<Common>{
81+
static_cast<Common>(lhs.x()) + static_cast<Common>(rhs.x()),
82+
static_cast<Common>(lhs.y()) + static_cast<Common>(rhs.y()),
83+
static_cast<Common>(lhs.z()) + static_cast<Common>(rhs.z())};
7884
}
7985

80-
template<class T>
81-
[[nodiscard]] inline constexpr auto operator-(const Vec3<T>& lhs, const Vec3<T>& rhs) noexcept -> Vec3<T>
86+
template<class T, class U>
87+
[[nodiscard]] inline constexpr auto operator-(const Vec3<T>& lhs, const Vec3<U>& rhs) noexcept
8288
{
83-
return auto{lhs} -= rhs;
89+
using Common = std::common_type_t<T, U>;
90+
return Vec3<Common>{
91+
static_cast<Common>(lhs.x()) - static_cast<Common>(rhs.x()),
92+
static_cast<Common>(lhs.y()) - static_cast<Common>(rhs.y()),
93+
static_cast<Common>(lhs.z()) - static_cast<Common>(rhs.z())};
8494
}
8595

8696
template<class T>
87-
[[nodiscard]] inline constexpr auto operator*(const Vec3<T>& lhs, T value) noexcept -> Vec3<T>
97+
[[nodiscard]] inline constexpr auto operator*(const Vec3<T>& lhs, auto value) noexcept
8898
{
89-
return auto{lhs} *= value;
99+
using Common = std::common_type_t<T, decltype(value)>;
100+
return Vec3<Common>{
101+
static_cast<Common>(lhs.x()) * static_cast<Common>(value),
102+
static_cast<Common>(lhs.y()) * static_cast<Common>(value),
103+
static_cast<Common>(lhs.z()) * static_cast<Common>(value)};
90104
}
91105

92106
template<class T>
93-
[[nodiscard]] inline constexpr auto operator*(T value, const Vec3<T>& rhs) noexcept -> Vec3<T>
107+
[[nodiscard]] inline constexpr auto operator*(auto value, const Vec3<T>& rhs) noexcept
94108
{
95-
return auto{rhs} *= value;
109+
using Common = std::common_type_t<T, decltype(value)>;
110+
return Vec3<Common>{
111+
static_cast<Common>(value) * static_cast<Common>(rhs.x()),
112+
static_cast<Common>(value) * static_cast<Common>(rhs.y()),
113+
static_cast<Common>(value) * static_cast<Common>(rhs.z())};
96114
}
97115

98116
template<class T>
99-
[[nodiscard]] inline constexpr auto operator/(const Vec3<T>& lhs, T value) noexcept -> Vec3<T>
117+
[[nodiscard]] inline constexpr auto operator/(const Vec3<T>& lhs, auto value) noexcept
100118
{
101-
return auto{lhs} /= value;
119+
using Common = std::common_type_t<T, decltype(value)>;
120+
return Vec3<Common>{
121+
static_cast<Common>(lhs.x()) / static_cast<Common>(value),
122+
static_cast<Common>(lhs.y()) / static_cast<Common>(value),
123+
static_cast<Common>(lhs.z()) / static_cast<Common>(value)};
102124
}
103125
}
126+
127+
export namespace std
128+
{
129+
template<class T, class CharT>
130+
struct formatter<CppUtils::Container::Vec3<T>, CharT>
131+
{
132+
formatter<T, CharT> m_formatter;
133+
134+
inline constexpr auto parse(auto& context)
135+
{
136+
return m_formatter.parse(context);
137+
}
138+
139+
inline auto format(const CppUtils::Container::Vec3<T>& vec, auto& context) const
140+
{
141+
auto out = context.out();
142+
out = std::format_to(out, "(");
143+
context.advance_to(out);
144+
out = m_formatter.format(vec.x(), context);
145+
out = std::format_to(out, ", ");
146+
context.advance_to(out);
147+
out = m_formatter.format(vec.y(), context);
148+
out = std::format_to(out, ", ");
149+
context.advance_to(out);
150+
out = m_formatter.format(vec.z(), context);
151+
return std::format_to(out, ")");
152+
}
153+
};
154+
}

tests/Container/Vec2.mpp

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
export module CppUtils.UnitTests.Container.Vec2;
2+
3+
import std;
4+
import CppUtils;
5+
6+
export namespace CppUtils::UnitTest::Container::Vec2
7+
{
8+
inline auto _ = TestSuite{"Container/Vec2", [](auto& suite) {
9+
suite.addTest("Constructor & Accessors", [&] {
10+
constexpr auto vec = CppUtils::Container::Vec2{1, 2};
11+
12+
suite.expectEqual(vec.x(), 1);
13+
suite.expectEqual(vec.y(), 2);
14+
suite.expectEqual(vec[0], 1);
15+
suite.expectEqual(vec[1], 2);
16+
suite.expectEqual(vec.width(), 1);
17+
suite.expectEqual(vec.height(), 2);
18+
});
19+
20+
suite.addTest("Comparison", [&] {
21+
constexpr auto v1 = CppUtils::Container::Vec2{1, 2};
22+
constexpr auto v2 = CppUtils::Container::Vec2{1, 2};
23+
constexpr auto v3 = CppUtils::Container::Vec2{3, 4};
24+
25+
suite.expectEqual(v1, v2);
26+
suite.expect(v1 != v3);
27+
});
28+
29+
suite.addTest("operator+=", [&] {
30+
{
31+
auto lhs = CppUtils::Container::Vec2{1, 2};
32+
constexpr auto rhs = CppUtils::Container::Vec2{3, 4};
33+
34+
lhs += rhs;
35+
36+
suite.expectEqual(lhs, CppUtils::Container::Vec2{4, 6});
37+
}
38+
{
39+
auto vec = CppUtils::Container::Vec2{1, 2};
40+
41+
vec += CppUtils::Container::Vec2{0.5, 0.5};
42+
43+
suite.expectEqual(vec, CppUtils::Container::Vec2{1, 2});
44+
}
45+
{
46+
auto vec = CppUtils::Container::Vec2{1.5, 2.5};
47+
48+
vec += CppUtils::Container::Vec2{2, 3};
49+
50+
suite.expectEqual(vec, CppUtils::Container::Vec2{3.5, 5.5});
51+
}
52+
});
53+
54+
suite.addTest("operator-=", [&] {
55+
auto lhs = CppUtils::Container::Vec2{1, 2};
56+
constexpr auto rhs = CppUtils::Container::Vec2{3, 4};
57+
58+
lhs -= rhs;
59+
60+
suite.expectEqual(lhs, CppUtils::Container::Vec2{-2, -2});
61+
});
62+
63+
suite.addTest("operator*=", [&] {
64+
{
65+
auto vec = CppUtils::Container::Vec2{1, 2};
66+
67+
vec *= 2;
68+
69+
suite.expectEqual(vec, CppUtils::Container::Vec2{2, 4});
70+
}
71+
{
72+
auto vec = CppUtils::Container::Vec2{1.5, 2.5};
73+
74+
vec *= 2.0;
75+
76+
suite.expectEqual(vec, CppUtils::Container::Vec2{3.0, 5.0});
77+
}
78+
{
79+
auto vec = CppUtils::Container::Vec2{3, 5};
80+
81+
vec *= 0.5;
82+
83+
suite.expectEqual(vec, CppUtils::Container::Vec2{1, 2});
84+
}
85+
});
86+
87+
suite.addTest("operator/=", [&] {
88+
auto vec = CppUtils::Container::Vec2{2, 4};
89+
90+
vec /= 2;
91+
92+
suite.expectEqual(vec, CppUtils::Container::Vec2{1, 2});
93+
});
94+
95+
suite.addTest("operator+", [&] {
96+
constexpr auto intVec = CppUtils::Container::Vec2{1, 2};
97+
constexpr auto floatVec = CppUtils::Container::Vec2{3.0f, 4.0f};
98+
99+
constexpr auto result = intVec + floatVec;
100+
101+
static_assert(std::is_same_v<decltype(result), const CppUtils::Container::Vec2<float>>);
102+
suite.expectEqual(result, CppUtils::Container::Vec2{4.0f, 6.0f});
103+
});
104+
105+
suite.addTest("operator*", [&] {
106+
constexpr auto intVec = CppUtils::Container::Vec2{1, 2};
107+
108+
{
109+
constexpr auto result = intVec * 1.5;
110+
111+
static_assert(std::is_same_v<decltype(result), const CppUtils::Container::Vec2<double>>);
112+
suite.expectEqual(result, CppUtils::Container::Vec2{1.5, 3.0});
113+
}
114+
{
115+
constexpr auto result = 2.5 * intVec;
116+
117+
static_assert(std::is_same_v<decltype(result), const CppUtils::Container::Vec2<double>>);
118+
suite.expectEqual(result, CppUtils::Container::Vec2{2.5, 5.0});
119+
}
120+
});
121+
122+
suite.addTest("Formatting", [&] {
123+
{
124+
constexpr auto vec = CppUtils::Container::Vec2{1.5, 2.5};
125+
suite.expectEqual(std::format("{}", vec), "(1.5, 2.5)");
126+
}
127+
{
128+
constexpr auto vec = CppUtils::Container::Vec2{1.11, 2.22};
129+
suite.expectEqual(std::format("{:.1f}", vec), "(1.1, 2.2)");
130+
}
131+
});
132+
}};
133+
}

0 commit comments

Comments
 (0)