From 12ed7b5aad1dd577344503eeeb68f2de67845e11 Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Fri, 26 Jun 2026 18:40:50 +0200 Subject: [PATCH 01/30] feat: add basic Vector3d functionality --- CHANGELOG.md | 1 + .../mstd/linAlg/concepts/vector3dConcepts.hpp | 45 +++++++++ .../mstd/linAlg/concepts/vector3dDepth.hpp | 77 +++++++++++++++ include/mstd/linAlg/vector3d.hpp | 75 +++++++++++++++ include/mstd/linAlg/vector3d.tpp.hpp | 96 +++++++++++++++++++ include/mstd/linAlg/vector3dClass.hpp | 68 +++++++++++++ include/mstd/linAlg/vector3dClass.tpp.hpp | 74 ++++++++++++++ test/linAlg/CMakeLists.txt | 67 +++++++++++++ test/linAlg/vector3d.cpp | 47 +++++++++ 9 files changed, 550 insertions(+) create mode 100644 include/mstd/linAlg/concepts/vector3dConcepts.hpp create mode 100644 include/mstd/linAlg/concepts/vector3dDepth.hpp create mode 100644 include/mstd/linAlg/vector3d.hpp create mode 100644 include/mstd/linAlg/vector3d.tpp.hpp create mode 100644 include/mstd/linAlg/vector3dClass.hpp create mode 100644 include/mstd/linAlg/vector3dClass.tpp.hpp create mode 100644 test/linAlg/CMakeLists.txt create mode 100644 test/linAlg/vector3d.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ba366b..201a2c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. ### Feature - add mp-units library +- add static Vector3d with mp-units support ## [0.1.3](https://github.com/repo/owner/releases/tag/0.1.3) - 2026-06-13 diff --git a/include/mstd/linAlg/concepts/vector3dConcepts.hpp b/include/mstd/linAlg/concepts/vector3dConcepts.hpp new file mode 100644 index 0000000..9cc531f --- /dev/null +++ b/include/mstd/linAlg/concepts/vector3dConcepts.hpp @@ -0,0 +1,45 @@ +/***************************************************************************** + + + mstd library + Copyright (C) 2025-now Jakob Gamper + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + +******************************************************************************/ + +#ifndef __MSTD__LINALG__CONCEPTS__VECTOR3DCONCEPTS_HPP__ +#define __MSTD__LINALG__CONCEPTS__VECTOR3DCONCEPTS_HPP__ + +#include + +#include "vector3dDepth.hpp" + +namespace mstd +{ + template + class Vector3d; + + /** + * @brief Concept for Vector3d types + * + * @tparam T + */ + template + concept Vector3dConcept = std::same_as>; + +} // namespace mstd + +#endif // __MSTD__LINALG__CONCEPTS__VECTOR3DCONCEPTS_HPP__ diff --git a/include/mstd/linAlg/concepts/vector3dDepth.hpp b/include/mstd/linAlg/concepts/vector3dDepth.hpp new file mode 100644 index 0000000..5f63928 --- /dev/null +++ b/include/mstd/linAlg/concepts/vector3dDepth.hpp @@ -0,0 +1,77 @@ +/***************************************************************************** + + + mstd library + Copyright (C) 2025-now Jakob Gamper + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + +******************************************************************************/ + +#ifndef __MSTD__LINALG__CONCEPTS__VECTOR3DDEPTH_HPP__ +#define __MSTD__LINALG__CONCEPTS__VECTOR3DDEPTH_HPP__ + +#include + +namespace mstd +{ + template + class Vector3d; + + /** + * @brief type trait to determine the depth of a Vector3d + * + * @tparam T + */ + template + struct Vector3dDepth + { + static constexpr int value = 0; + }; + + /** + * @brief type trait to determine the depth of a Vector3d + * + * @details specialization for Vector3d + * + * @tparam T + */ + template + struct Vector3dDepth> + { + static constexpr int value = 1 + Vector3dDepth::value; + }; + + /** + * @brief constexpr variable to check the depth of a Vector3d + * + * @tparam T + */ + template + constexpr int Vector3dDepth_v = Vector3dDepth::value; + + /** + * @brief constexpr variable to check the depth difference of two Vector3ds + * + * @tparam T + * @tparam U + */ + template + constexpr int Vector3dDepthDifference_v = + Vector3dDepth_v - Vector3dDepth_v; + +} // namespace mstd + +#endif // __MSTD__LINALG__CONCEPTS__VECTOR3DDEPTH_HPP__ diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp new file mode 100644 index 0000000..3459d47 --- /dev/null +++ b/include/mstd/linAlg/vector3d.hpp @@ -0,0 +1,75 @@ +/***************************************************************************** + + + mstd library + Copyright (C) 2025-now Jakob Gamper + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + +******************************************************************************/ + +#ifndef __MSTD__LINALG__VECTOR3D_HPP__ +#define __MSTD__LINALG__VECTOR3D_HPP__ + +#include "concepts/vector3dConcepts.hpp" +#include "vector3dClass.hpp" + +namespace mstd +{ + /************************ + * comparison operators * + ************************/ + + template + requires requires(const Vector3d &lhs, const Vector3d &rhs) { + { lhs[0] == rhs[0] } -> std::convertible_to; + } + constexpr bool operator==(const Vector3d &lhs, const Vector3d &rhs); + + /********************* + * binary * operator * + *********************/ + + template + requires requires(const U &a, const V &b) { a[0] * b[0]; } && + (Vector3dDepthDifference_v == 0) + constexpr auto operator*(const U &lhs, const V &rhs) + -> Vector3d; + + /********************* + * binary / operator * + *********************/ + + template + requires requires(const U &a, const V &b) { a[0] / b[0]; } && + (Vector3dDepthDifference_v == 0) + constexpr auto operator/(const U &lhs, const V &rhs) + -> Vector3d; + + /************** + * ostream << * + **************/ + + template + requires requires(std::ostream &os, const U &a) { + { os << a[0] } -> std::same_as; + } + std::ostream &operator<<(std::ostream &os, U const &v); + +} // namespace mstd + +#include "vector3d.tpp.hpp" + +#endif // __MSTD__LINALG__VECTOR3D_HPP__ diff --git a/include/mstd/linAlg/vector3d.tpp.hpp b/include/mstd/linAlg/vector3d.tpp.hpp new file mode 100644 index 0000000..aae9a8f --- /dev/null +++ b/include/mstd/linAlg/vector3d.tpp.hpp @@ -0,0 +1,96 @@ +/***************************************************************************** + + + mstd library + Copyright (C) 2025-now Jakob Gamper + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + +******************************************************************************/ + +#ifndef __MSTD__LINALG__VECTOR3D_TPP_HPP__ +#define __MSTD__LINALG__VECTOR3D_TPP_HPP__ + +#include "vector3d.hpp" + +namespace mstd +{ + /************************ + * comparison operators * + ************************/ + + template + requires requires(const Vector3d &lhs, const Vector3d &rhs) { + { lhs[0] == rhs[0] } -> std::convertible_to; + } + constexpr bool operator==(const Vector3d &lhs, const Vector3d &rhs) + { + return lhs[0] == rhs[0] && lhs[1] == rhs[1] && lhs[2] == rhs[2]; + } + + /********************* + * binary * operator * + *********************/ + + template + requires requires(const U &a, const V &b) { a[0] * b[0]; } && + (Vector3dDepthDifference_v == 0) + constexpr auto operator*(const U &lhs, const V &rhs) + -> Vector3d + { + using ResultType = decltype(lhs[0] * rhs[0]); + + return Vector3d( + lhs[0] * rhs[0], + lhs[1] * rhs[1], + lhs[2] * rhs[2] + ); + } + + /********************* + * binary / operator * + *********************/ + + template + requires requires(const U &a, const V &b) { a[0] / b[0]; } && + (Vector3dDepthDifference_v == 0) + constexpr auto operator/(const U &lhs, const V &rhs) + -> Vector3d + { + using ResultType = decltype(lhs[0] / rhs[0]); + + return Vector3d( + lhs[0] / rhs[0], + lhs[1] / rhs[1], + lhs[2] / rhs[2] + ); + } + + /************** + * ostream << * + **************/ + + template + requires requires(std::ostream &os, const U &a) { + { os << a[0] } -> std::same_as; + } + std::ostream &operator<<(std::ostream &os, U const &v) + { + return os << v[0] << " " << v[1] << " " << v[2]; + } + +} // namespace mstd + +#endif // __MSTD__LINALG__VECTOR3D_TPP_HPP__ diff --git a/include/mstd/linAlg/vector3dClass.hpp b/include/mstd/linAlg/vector3dClass.hpp new file mode 100644 index 0000000..e8e069f --- /dev/null +++ b/include/mstd/linAlg/vector3dClass.hpp @@ -0,0 +1,68 @@ +/***************************************************************************** + + + mstd library + Copyright (C) 2025-now Jakob Gamper + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + +******************************************************************************/ + +#ifndef __MSTD__LINALG__VECTOR3D_CLASS_HPP__ +#define __MSTD__LINALG__VECTOR3D_CLASS_HPP__ + +#include +#include +#include + +namespace mstd +{ + template + class Vector3d + { + private: + std::array _xyz; + + public: + ~Vector3d() = default; + + constexpr Vector3d() = default; + constexpr Vector3d(const T x, const T y, const T z) : _xyz{x, y, z} {} + constexpr Vector3d(const Vector3d &xyz) = default; + constexpr explicit Vector3d(const T xyz) : _xyz{xyz, xyz, xyz} {} + + using value_type = T; + + /************************ + * assignment operators * + ************************/ + + // copy assignment operators + constexpr Vector3d &operator=(Vector3d &); + constexpr Vector3d &operator=(const Vector3d &); + + /********************** + * indexing operators * + **********************/ + + constexpr T &operator[](const size_t index); + constexpr const T &operator[](const size_t index) const; + }; + +} // namespace mstd + +#include "vector3dClass.tpp.hpp" + +#endif // __MSTD__LINALG__VECTOR3D_CLASS_HPP__ diff --git a/include/mstd/linAlg/vector3dClass.tpp.hpp b/include/mstd/linAlg/vector3dClass.tpp.hpp new file mode 100644 index 0000000..1a76d00 --- /dev/null +++ b/include/mstd/linAlg/vector3dClass.tpp.hpp @@ -0,0 +1,74 @@ +/***************************************************************************** + + + mstd library + Copyright (C) 2025-now Jakob Gamper + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + +******************************************************************************/ + +#ifndef __MSTD__LINALG__VECTOR3D_CLASS_TPP__ +#define __MSTD__LINALG__VECTOR3D_CLASS_TPP__ + +#include "vector3dClass.hpp" + +namespace mstd +{ + /************************ + * * + * assignment operators * + * * + ************************/ + + /******************* + * copy assignment * + *******************/ + + template + constexpr Vector3d &Vector3d::operator=(Vector3d &rhs) + { + _xyz = rhs._xyz; + return *this; + } + + template + constexpr Vector3d &Vector3d::operator=(const Vector3d &rhs) + { + _xyz = rhs._xyz; + return *this; + } + + /********************** + * * + * indexing operators * + * * + **********************/ + + template + constexpr T &Vector3d::operator[](const size_t index) + { + return _xyz[index]; + } + + template + constexpr const T &Vector3d::operator[](const size_t index) const + { + return _xyz[index]; + } + +} // namespace mstd + +#endif // __MSTD__LINALG__VECTOR3D_CLASS_TPP__ diff --git a/test/linAlg/CMakeLists.txt b/test/linAlg/CMakeLists.txt new file mode 100644 index 0000000..1f40aa8 --- /dev/null +++ b/test/linAlg/CMakeLists.txt @@ -0,0 +1,67 @@ +if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + cmake_minimum_required(VERSION 3.20) + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + project(mstd_tests_linAlg LANGUAGES CXX) + include(CTest) + enable_testing() + set(MSTD_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../..") +else() + set(MSTD_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/..") +endif() + +if(NOT TARGET mstd) + add_library(mstd INTERFACE) + target_include_directories(mstd + INTERFACE + "${MSTD_ROOT_DIR}/include" + ) + target_compile_features(mstd INTERFACE cxx_std_20) +endif() + +if(NOT TARGET Catch2::Catch2WithMain) + add_subdirectory( + "${MSTD_ROOT_DIR}/external/Catch2" + "${CMAKE_CURRENT_BINARY_DIR}/external/Catch2" + ) +endif() + +list(APPEND CMAKE_MODULE_PATH "${MSTD_ROOT_DIR}/external/Catch2/extras") + +if(TARGET mstd_test_support) + set(MSTD_TEST_LINK_TARGET mstd_test_support) +else() + add_library(mstd_test_support INTERFACE) + if(EXISTS "${MSTD_ROOT_DIR}/test/include") + target_include_directories(mstd_test_support + INTERFACE + "${MSTD_ROOT_DIR}/test/include" + ) + endif() + target_link_libraries(mstd_test_support + INTERFACE + mstd + Catch2::Catch2WithMain + ) + target_compile_features(mstd_test_support INTERFACE cxx_std_20) + set(MSTD_TEST_LINK_TARGET mstd_test_support) +endif() + +add_executable(mstd_tests_linAlg + vector3d.cpp +) + +target_link_libraries(mstd_tests_linAlg + PRIVATE + "${MSTD_TEST_LINK_TARGET}" + mp-units::mp-units +) + +target_compile_features(mstd_tests_linAlg PRIVATE cxx_std_20) + +include(Catch) +catch_discover_tests(mstd_tests_linAlg + TEST_PREFIX "mstd::linAlg::" + REPORTER compact +) + +set_property(GLOBAL APPEND PROPERTY MSTD_TEST_TARGETS mstd_tests_linAlg) diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp new file mode 100644 index 0000000..0d0dd1e --- /dev/null +++ b/test/linAlg/vector3d.cpp @@ -0,0 +1,47 @@ +/***************************************************************************** + + + mstd library + Copyright (C) 2025-now Jakob Gamper + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + +******************************************************************************/ + +#include "mstd/linAlg/vector3d.hpp" + +#include +#include + +#include +#include +#include + +using namespace mp_units; +using namespace mp_units::si::unit_symbols; +using namespace mstd; + +TEST_CASE("Vector3D") +{ + constexpr auto distance = Vector3d{1.0 * km, 2.0 * km, 3.0 * km}; + constexpr auto time = Vector3d{4.0 * h, 5.0 * h, 6.0 * h}; + constexpr auto speed = Vector3d{0.25 * km / h, 0.4 * km / h, 0.5 * km / h}; + constexpr auto distanceMeter = Vector3d{1000 * m, 2000 * m, 3000 * m}; + constexpr auto area = Vector3d{1e6 * m2, 4e6 * m2, 9e6 * m2}; + + STATIC_REQUIRE(speed == distance / time); + STATIC_REQUIRE(distance == distanceMeter); + STATIC_REQUIRE(area == distance * distance); +} \ No newline at end of file From 9619201bc5e6760aedb94847278ab39c031a087a Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Fri, 26 Jun 2026 18:45:58 +0200 Subject: [PATCH 02/30] fix: header guard macro --- include/mstd/linAlg/vector3dClass.hpp | 6 +++--- include/mstd/linAlg/vector3dClass.tpp.hpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/mstd/linAlg/vector3dClass.hpp b/include/mstd/linAlg/vector3dClass.hpp index e8e069f..6667ff7 100644 --- a/include/mstd/linAlg/vector3dClass.hpp +++ b/include/mstd/linAlg/vector3dClass.hpp @@ -20,8 +20,8 @@ ******************************************************************************/ -#ifndef __MSTD__LINALG__VECTOR3D_CLASS_HPP__ -#define __MSTD__LINALG__VECTOR3D_CLASS_HPP__ +#ifndef __MSTD__LINALG__VECTOR3DCLASS_HPP__ +#define __MSTD__LINALG__VECTOR3DCLASS_HPP__ #include #include @@ -65,4 +65,4 @@ namespace mstd #include "vector3dClass.tpp.hpp" -#endif // __MSTD__LINALG__VECTOR3D_CLASS_HPP__ +#endif // __MSTD__LINALG__VECTOR3DCLASS_HPP__ diff --git a/include/mstd/linAlg/vector3dClass.tpp.hpp b/include/mstd/linAlg/vector3dClass.tpp.hpp index 1a76d00..9ac1c46 100644 --- a/include/mstd/linAlg/vector3dClass.tpp.hpp +++ b/include/mstd/linAlg/vector3dClass.tpp.hpp @@ -20,8 +20,8 @@ ******************************************************************************/ -#ifndef __MSTD__LINALG__VECTOR3D_CLASS_TPP__ -#define __MSTD__LINALG__VECTOR3D_CLASS_TPP__ +#ifndef __MSTD__LINALG__VECTOR3DCLASS_TPP_HPP__ +#define __MSTD__LINALG__VECTOR3DCLASS_TPP_HPP__ #include "vector3dClass.hpp" @@ -71,4 +71,4 @@ namespace mstd } // namespace mstd -#endif // __MSTD__LINALG__VECTOR3D_CLASS_TPP__ +#endif // __MSTD__LINALG__VECTOR3DCLASS_TPP_HPP__ From fc1c715431b2e39f670d86e34ca8453d95ca4114 Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Mon, 29 Jun 2026 07:48:48 +0200 Subject: [PATCH 03/30] ci: rename .tpp.hpp files to .tpp --- include/mstd/linAlg/vector3d.hpp | 2 +- include/mstd/linAlg/{vector3d.tpp.hpp => vector3d.tpp} | 6 +++--- include/mstd/linAlg/vector3dClass.hpp | 2 +- .../linAlg/{vector3dClass.tpp.hpp => vector3dClass.tpp} | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) rename include/mstd/linAlg/{vector3d.tpp.hpp => vector3d.tpp} (95%) rename include/mstd/linAlg/{vector3dClass.tpp.hpp => vector3dClass.tpp} (92%) diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index 3459d47..30ab0fe 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -70,6 +70,6 @@ namespace mstd } // namespace mstd -#include "vector3d.tpp.hpp" +#include "vector3d.tpp" #endif // __MSTD__LINALG__VECTOR3D_HPP__ diff --git a/include/mstd/linAlg/vector3d.tpp.hpp b/include/mstd/linAlg/vector3d.tpp similarity index 95% rename from include/mstd/linAlg/vector3d.tpp.hpp rename to include/mstd/linAlg/vector3d.tpp index aae9a8f..aea2692 100644 --- a/include/mstd/linAlg/vector3d.tpp.hpp +++ b/include/mstd/linAlg/vector3d.tpp @@ -20,8 +20,8 @@ ******************************************************************************/ -#ifndef __MSTD__LINALG__VECTOR3D_TPP_HPP__ -#define __MSTD__LINALG__VECTOR3D_TPP_HPP__ +#ifndef __MSTD__LINALG__VECTOR3D_TPP__ +#define __MSTD__LINALG__VECTOR3D_TPP__ #include "vector3d.hpp" @@ -93,4 +93,4 @@ namespace mstd } // namespace mstd -#endif // __MSTD__LINALG__VECTOR3D_TPP_HPP__ +#endif // __MSTD__LINALG__VECTOR3D_TPP__ diff --git a/include/mstd/linAlg/vector3dClass.hpp b/include/mstd/linAlg/vector3dClass.hpp index 6667ff7..93c1569 100644 --- a/include/mstd/linAlg/vector3dClass.hpp +++ b/include/mstd/linAlg/vector3dClass.hpp @@ -63,6 +63,6 @@ namespace mstd } // namespace mstd -#include "vector3dClass.tpp.hpp" +#include "vector3dClass.tpp" #endif // __MSTD__LINALG__VECTOR3DCLASS_HPP__ diff --git a/include/mstd/linAlg/vector3dClass.tpp.hpp b/include/mstd/linAlg/vector3dClass.tpp similarity index 92% rename from include/mstd/linAlg/vector3dClass.tpp.hpp rename to include/mstd/linAlg/vector3dClass.tpp index 9ac1c46..4ae2633 100644 --- a/include/mstd/linAlg/vector3dClass.tpp.hpp +++ b/include/mstd/linAlg/vector3dClass.tpp @@ -20,8 +20,8 @@ ******************************************************************************/ -#ifndef __MSTD__LINALG__VECTOR3DCLASS_TPP_HPP__ -#define __MSTD__LINALG__VECTOR3DCLASS_TPP_HPP__ +#ifndef __MSTD__LINALG__VECTOR3DCLASS_TPP__ +#define __MSTD__LINALG__VECTOR3DCLASS_TPP__ #include "vector3dClass.hpp" @@ -71,4 +71,4 @@ namespace mstd } // namespace mstd -#endif // __MSTD__LINALG__VECTOR3DCLASS_TPP_HPP__ +#endif // __MSTD__LINALG__VECTOR3DCLASS_TPP__ From d50a9ba61a62cf5b4a5d24477b31415b7779c5ce Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Mon, 29 Jun 2026 09:25:20 +0200 Subject: [PATCH 04/30] internal: update Vector3d constructors --- include/mstd/linAlg/vector3dClass.hpp | 30 +++++++++++++-------------- include/mstd/linAlg/vector3dClass.tpp | 29 +++----------------------- 2 files changed, 17 insertions(+), 42 deletions(-) diff --git a/include/mstd/linAlg/vector3dClass.hpp b/include/mstd/linAlg/vector3dClass.hpp index 93c1569..ef2edda 100644 --- a/include/mstd/linAlg/vector3dClass.hpp +++ b/include/mstd/linAlg/vector3dClass.hpp @@ -36,29 +36,27 @@ namespace mstd std::array _xyz; public: - ~Vector3d() = default; - - constexpr Vector3d() = default; - constexpr Vector3d(const T x, const T y, const T z) : _xyz{x, y, z} {} - constexpr Vector3d(const Vector3d &xyz) = default; - constexpr explicit Vector3d(const T xyz) : _xyz{xyz, xyz, xyz} {} + // clang-format off + [[nodiscard]] constexpr Vector3d() noexcept = default; + constexpr ~Vector3d() noexcept = default; + [[nodiscard]] constexpr Vector3d(const Vector3d &) noexcept = default; + constexpr Vector3d &operator=(const Vector3d &) noexcept = default; + [[nodiscard]] constexpr Vector3d(Vector3d &&) noexcept = default; + constexpr Vector3d &operator=(Vector3d &&) noexcept = default; + + [[nodiscard]] constexpr explicit Vector3d(const T &xyz) noexcept : _xyz{xyz, xyz, xyz} {} + [[nodiscard]] constexpr Vector3d(const T &x, const T &y, const T &z) noexcept : _xyz{x, y, z} {} + // clang-format on using value_type = T; - /************************ - * assignment operators * - ************************/ - - // copy assignment operators - constexpr Vector3d &operator=(Vector3d &); - constexpr Vector3d &operator=(const Vector3d &); - /********************** * indexing operators * **********************/ - constexpr T &operator[](const size_t index); - constexpr const T &operator[](const size_t index) const; + constexpr T &operator[](const size_t index) noexcept; + [[nodiscard]] constexpr const T &operator[](const size_t index + ) const noexcept; }; } // namespace mstd diff --git a/include/mstd/linAlg/vector3dClass.tpp b/include/mstd/linAlg/vector3dClass.tpp index 4ae2633..694e109 100644 --- a/include/mstd/linAlg/vector3dClass.tpp +++ b/include/mstd/linAlg/vector3dClass.tpp @@ -27,30 +27,6 @@ namespace mstd { - /************************ - * * - * assignment operators * - * * - ************************/ - - /******************* - * copy assignment * - *******************/ - - template - constexpr Vector3d &Vector3d::operator=(Vector3d &rhs) - { - _xyz = rhs._xyz; - return *this; - } - - template - constexpr Vector3d &Vector3d::operator=(const Vector3d &rhs) - { - _xyz = rhs._xyz; - return *this; - } - /********************** * * * indexing operators * @@ -58,13 +34,14 @@ namespace mstd **********************/ template - constexpr T &Vector3d::operator[](const size_t index) + constexpr T &Vector3d::operator[](const size_t index) noexcept { return _xyz[index]; } template - constexpr const T &Vector3d::operator[](const size_t index) const + constexpr const T &Vector3d::operator[](const size_t index + ) const noexcept { return _xyz[index]; } From 05b5c45ffa1b31161de8e612e0d8b55e7c0ead34 Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Mon, 29 Jun 2026 11:18:33 +0200 Subject: [PATCH 05/30] feat: add binary operator overloads for Vector3d --- include/mstd/linAlg/vector3d.hpp | 53 ++++++++++++++++--- include/mstd/linAlg/vector3d.tpp | 87 +++++++++++++++++++++++++++++--- test/linAlg/vector3d.cpp | 5 +- 3 files changed, 129 insertions(+), 16 deletions(-) diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index 30ab0fe..b4f27ee 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -36,26 +36,63 @@ namespace mstd requires requires(const Vector3d &lhs, const Vector3d &rhs) { { lhs[0] == rhs[0] } -> std::convertible_to; } - constexpr bool operator==(const Vector3d &lhs, const Vector3d &rhs); + [[nodiscard]] constexpr bool operator==( + const Vector3d &lhs, + const Vector3d &rhs + ) noexcept; + + /********************* + * binary + operator * + *********************/ + + template + requires requires(const U &lhs, const V &rhs) { lhs[0] + rhs[0]; } && + (Vector3dDepthDifference_v == 0) + [[nodiscard]] constexpr auto operator+(const U &lhs, const V &rhs) + -> Vector3d; + + /********************* + * binary - operator * + *********************/ + + template + requires requires(const U &lhs, const V &rhs) { lhs[0] - rhs[0]; } && + (Vector3dDepthDifference_v == 0) + [[nodiscard]] constexpr auto operator-(const U &lhs, const V &rhs) + -> Vector3d; /********************* * binary * operator * *********************/ template - requires requires(const U &a, const V &b) { a[0] * b[0]; } && + requires requires(const U &lhs, const V &rhs) { lhs[0] * rhs[0]; } && (Vector3dDepthDifference_v == 0) - constexpr auto operator*(const U &lhs, const V &rhs) + [[nodiscard]] constexpr auto operator*(const U &lhs, const V &rhs) -> Vector3d; + template + requires requires(const U &scalar, const V &vector) { + scalar * vector[0]; + } && (!Vector3dConcept) + [[nodiscard]] constexpr auto operator*(const U &scalar, const V &rhs) + -> Vector3d; + + template + requires requires(const U &vector, const V &scalar) { + vector[0] * scalar; + } && (!Vector3dConcept) + [[nodiscard]] constexpr auto operator*(const U &vector, const V &scalar) + -> Vector3d; + /********************* * binary / operator * *********************/ template - requires requires(const U &a, const V &b) { a[0] / b[0]; } && + requires requires(const U &lhs, const V &rhs) { lhs[0] / rhs[0]; } && (Vector3dDepthDifference_v == 0) - constexpr auto operator/(const U &lhs, const V &rhs) + [[nodiscard]] constexpr auto operator/(const U &lhs, const V &rhs) -> Vector3d; /************** @@ -63,10 +100,10 @@ namespace mstd **************/ template - requires requires(std::ostream &os, const U &a) { - { os << a[0] } -> std::same_as; + requires requires(std::ostream &os, const U &vector) { + { os << vector[0] } -> std::same_as; } - std::ostream &operator<<(std::ostream &os, U const &v); + std::ostream &operator<<(std::ostream &os, const U &vector); } // namespace mstd diff --git a/include/mstd/linAlg/vector3d.tpp b/include/mstd/linAlg/vector3d.tpp index aea2692..78abc06 100644 --- a/include/mstd/linAlg/vector3d.tpp +++ b/include/mstd/linAlg/vector3d.tpp @@ -35,17 +35,58 @@ namespace mstd requires requires(const Vector3d &lhs, const Vector3d &rhs) { { lhs[0] == rhs[0] } -> std::convertible_to; } - constexpr bool operator==(const Vector3d &lhs, const Vector3d &rhs) + constexpr bool operator==( + const Vector3d &lhs, + const Vector3d &rhs + ) noexcept { return lhs[0] == rhs[0] && lhs[1] == rhs[1] && lhs[2] == rhs[2]; } + /********************* + * binary + operator * + *********************/ + + template + requires requires(const U &lhs, const V &rhs) { lhs[0] + rhs[0]; } && + (Vector3dDepthDifference_v == 0) + constexpr auto operator+(const U &lhs, const V &rhs) + -> Vector3d + { + using ResultType = decltype(lhs[0] + rhs[0]); + + return Vector3d( + lhs[0] + rhs[0], + lhs[1] + rhs[1], + lhs[2] + rhs[2] + ); + } + + /********************* + * binary - operator * + *********************/ + + template + requires requires(const U &lhs, const V &rhs) { lhs[0] - rhs[0]; } && + (Vector3dDepthDifference_v == 0) + constexpr auto operator-(const U &lhs, const V &rhs) + -> Vector3d + { + using ResultType = decltype(lhs[0] - rhs[0]); + + return Vector3d( + lhs[0] - rhs[0], + lhs[1] - rhs[1], + lhs[2] - rhs[2] + ); + } + /********************* * binary * operator * *********************/ template - requires requires(const U &a, const V &b) { a[0] * b[0]; } && + requires requires(const U &lhs, const V &rhs) { lhs[0] * rhs[0]; } && (Vector3dDepthDifference_v == 0) constexpr auto operator*(const U &lhs, const V &rhs) -> Vector3d @@ -59,12 +100,44 @@ namespace mstd ); } + template + requires requires(const U &scalar, const V &vector) { + scalar * vector[0]; + } && (!Vector3dConcept) + constexpr auto operator*(const U &scalar, const V &vector) + -> Vector3d + { + using ResultType = decltype(scalar * vector[0]); + + return Vector3d( + scalar * vector[0], + scalar * vector[1], + scalar * vector[2] + ); + } + + template + requires requires(const U &vector, const V &scalar) { + vector[0] * scalar; + } && (!Vector3dConcept) + constexpr auto operator*(const U &vector, const V &scalar) + -> Vector3d + { + using ResultType = decltype(vector[0] * scalar); + + return Vector3d( + vector[0] * scalar, + vector[1] * scalar, + vector[2] * scalar + ); + } + /********************* * binary / operator * *********************/ template - requires requires(const U &a, const V &b) { a[0] / b[0]; } && + requires requires(const U &lhs, const V &rhs) { lhs[0] / rhs[0]; } && (Vector3dDepthDifference_v == 0) constexpr auto operator/(const U &lhs, const V &rhs) -> Vector3d @@ -83,12 +156,12 @@ namespace mstd **************/ template - requires requires(std::ostream &os, const U &a) { - { os << a[0] } -> std::same_as; + requires requires(std::ostream &os, const U &vector) { + { os << vector[0] } -> std::same_as; } - std::ostream &operator<<(std::ostream &os, U const &v) + std::ostream &operator<<(std::ostream &os, const U &vector) { - return os << v[0] << " " << v[1] << " " << v[2]; + return os << vector[0] << " " << vector[1] << " " << vector[2]; } } // namespace mstd diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 0d0dd1e..6576cf7 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -33,7 +33,7 @@ using namespace mp_units; using namespace mp_units::si::unit_symbols; using namespace mstd; -TEST_CASE("Vector3D") +TEST_CASE("Vector3d") { constexpr auto distance = Vector3d{1.0 * km, 2.0 * km, 3.0 * km}; constexpr auto time = Vector3d{4.0 * h, 5.0 * h, 6.0 * h}; @@ -44,4 +44,7 @@ TEST_CASE("Vector3D") STATIC_REQUIRE(speed == distance / time); STATIC_REQUIRE(distance == distanceMeter); STATIC_REQUIRE(area == distance * distance); + STATIC_REQUIRE(distance + distanceMeter == 2 * distance); + STATIC_REQUIRE(distance - distanceMeter == Vector3d{0 * m}); + STATIC_REQUIRE(2 * distance == distance * 2); } \ No newline at end of file From 4e34642e7fdb4479109c27c9c01da432574b5e0e Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Mon, 29 Jun 2026 14:29:32 +0200 Subject: [PATCH 06/30] internal: update .clangd --- .clangd | 12 +++++++++++- .vscode/settings.json | 2 +- include/mstd/linAlg/vector3d.hpp | 2 ++ include/mstd/linAlg/vector3dClass.hpp | 6 ++---- include/mstd/linAlg/vector3dClass.tpp | 4 ++-- test/linAlg/vector3d.cpp | 3 +-- 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.clangd b/.clangd index c139880..4675865 100644 --- a/.clangd +++ b/.clangd @@ -1,2 +1,12 @@ CompileFlags: - CompilationDatabase: .build \ No newline at end of file + CompilationDatabase: .build + Add: + - -Wno-c2y-extensions + - -Wno-double-promotion + +Diagnostics: + Suppress: + - c2y-extensions + - -Wc2y-extensions + - typecheck_expression_not_modifiable_lvalue + - pp_including_mainfile_in_preamble \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 63f4e75..584b49a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -33,7 +33,7 @@ "-i ${workspaceFolder}/external/Catch2/src" // adjust path as needed ], "files.associations": { - "*.tpp": "c++", + "*.tpp": "cpp", "type_traits": "cpp", "functional": "cpp", "array": "cpp", diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index b4f27ee..9f40dac 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -26,6 +26,8 @@ #include "concepts/vector3dConcepts.hpp" #include "vector3dClass.hpp" +#include + namespace mstd { /************************ diff --git a/include/mstd/linAlg/vector3dClass.hpp b/include/mstd/linAlg/vector3dClass.hpp index ef2edda..7974ba4 100644 --- a/include/mstd/linAlg/vector3dClass.hpp +++ b/include/mstd/linAlg/vector3dClass.hpp @@ -24,8 +24,6 @@ #define __MSTD__LINALG__VECTOR3DCLASS_HPP__ #include -#include -#include namespace mstd { @@ -54,8 +52,8 @@ namespace mstd * indexing operators * **********************/ - constexpr T &operator[](const size_t index) noexcept; - [[nodiscard]] constexpr const T &operator[](const size_t index + constexpr T &operator[](const std::size_t index) noexcept; + [[nodiscard]] constexpr const T &operator[](const std::size_t index ) const noexcept; }; diff --git a/include/mstd/linAlg/vector3dClass.tpp b/include/mstd/linAlg/vector3dClass.tpp index 694e109..e6f3905 100644 --- a/include/mstd/linAlg/vector3dClass.tpp +++ b/include/mstd/linAlg/vector3dClass.tpp @@ -34,13 +34,13 @@ namespace mstd **********************/ template - constexpr T &Vector3d::operator[](const size_t index) noexcept + constexpr T &Vector3d::operator[](const std::size_t index) noexcept { return _xyz[index]; } template - constexpr const T &Vector3d::operator[](const size_t index + constexpr const T &Vector3d::operator[](const std::size_t index ) const noexcept { return _xyz[index]; diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 6576cf7..b92ecf2 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -27,7 +27,6 @@ #include #include -#include using namespace mp_units; using namespace mp_units::si::unit_symbols; @@ -38,7 +37,7 @@ TEST_CASE("Vector3d") constexpr auto distance = Vector3d{1.0 * km, 2.0 * km, 3.0 * km}; constexpr auto time = Vector3d{4.0 * h, 5.0 * h, 6.0 * h}; constexpr auto speed = Vector3d{0.25 * km / h, 0.4 * km / h, 0.5 * km / h}; - constexpr auto distanceMeter = Vector3d{1000 * m, 2000 * m, 3000 * m}; + constexpr auto distanceMeter = Vector3d{1000.0 * m, 2000.0 * m, 3000.0 * m}; constexpr auto area = Vector3d{1e6 * m2, 4e6 * m2, 9e6 * m2}; STATIC_REQUIRE(speed == distance / time); From 511ff2c5678f56cfd05b3a10a566bd20402fdddb Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Thu, 2 Jul 2026 10:42:47 +0200 Subject: [PATCH 07/30] feat: add binary operator overloads for Vector3d --- include/mstd/linAlg/vector3d.hpp | 32 ++++++++++- include/mstd/linAlg/vector3d.tpp | 96 ++++++++++++++++++++++++++++++++ test/linAlg/vector3d.cpp | 11 +++- 3 files changed, 135 insertions(+), 4 deletions(-) diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index 9f40dac..acbab87 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -23,11 +23,11 @@ #ifndef __MSTD__LINALG__VECTOR3D_HPP__ #define __MSTD__LINALG__VECTOR3D_HPP__ +#include + #include "concepts/vector3dConcepts.hpp" #include "vector3dClass.hpp" -#include - namespace mstd { /************************ @@ -53,6 +53,20 @@ namespace mstd [[nodiscard]] constexpr auto operator+(const U &lhs, const V &rhs) -> Vector3d; + template + requires requires(const U &scalar, const V &vector) { + scalar + vector[0]; + } && (!Vector3dConcept) + [[nodiscard]] constexpr auto operator+(const U &scalar, const V &rhs) + -> Vector3d; + + template + requires requires(const U &vector, const V &scalar) { + vector[0] + scalar; + } && (!Vector3dConcept) + [[nodiscard]] constexpr auto operator+(const U &vector, const V &scalar) + -> Vector3d; + /********************* * binary - operator * *********************/ @@ -97,6 +111,20 @@ namespace mstd [[nodiscard]] constexpr auto operator/(const U &lhs, const V &rhs) -> Vector3d; + template + requires requires(const U &scalar, const V &vector) { + scalar / vector[0]; + } && (!Vector3dConcept) + [[nodiscard]] constexpr auto operator/(const U &scalar, const V &rhs) + -> Vector3d; + + template + requires requires(const U &vector, const V &scalar) { + vector[0] / scalar; + } && (!Vector3dConcept) + [[nodiscard]] constexpr auto operator/(const U &vector, const V &scalar) + -> Vector3d; + /************** * ostream << * **************/ diff --git a/include/mstd/linAlg/vector3d.tpp b/include/mstd/linAlg/vector3d.tpp index 78abc06..e16775f 100644 --- a/include/mstd/linAlg/vector3d.tpp +++ b/include/mstd/linAlg/vector3d.tpp @@ -62,6 +62,38 @@ namespace mstd ); } + template + requires requires(const U &scalar, const V &vector) { + scalar + vector[0]; + } && (!Vector3dConcept) + constexpr auto operator+(const U &scalar, const V &vector) + -> Vector3d + { + using ResultType = decltype(scalar + vector[0]); + + return Vector3d( + scalar + vector[0], + scalar + vector[1], + scalar + vector[2] + ); + } + + template + requires requires(const U &vector, const V &scalar) { + vector[0] + scalar; + } && (!Vector3dConcept) + constexpr auto operator+(const U &vector, const V &scalar) + -> Vector3d + { + using ResultType = decltype(vector[0] + scalar); + + return Vector3d( + vector[0] + scalar, + vector[1] + scalar, + vector[2] + scalar + ); + } + /********************* * binary - operator * *********************/ @@ -81,6 +113,38 @@ namespace mstd ); } + template + requires requires(const U &scalar, const V &vector) { + scalar - vector[0]; + } && (!Vector3dConcept) + constexpr auto operator-(const U &scalar, const V &vector) + -> Vector3d + { + using ResultType = decltype(scalar - vector[0]); + + return Vector3d( + scalar - vector[0], + scalar - vector[1], + scalar - vector[2] + ); + } + + template + requires requires(const U &vector, const V &scalar) { + vector[0] - scalar; + } && (!Vector3dConcept) + constexpr auto operator-(const U &vector, const V &scalar) + -> Vector3d + { + using ResultType = decltype(vector[0] - scalar); + + return Vector3d( + vector[0] - scalar, + vector[1] - scalar, + vector[2] - scalar + ); + } + /********************* * binary * operator * *********************/ @@ -151,6 +215,38 @@ namespace mstd ); } + template + requires requires(const U &scalar, const V &vector) { + scalar / vector[0]; + } && (!Vector3dConcept) + constexpr auto operator/(const U &scalar, const V &vector) + -> Vector3d + { + using ResultType = decltype(scalar / vector[0]); + + return Vector3d( + scalar / vector[0], + scalar / vector[1], + scalar / vector[2] + ); + } + + template + requires requires(const U &vector, const V &scalar) { + vector[0] / scalar; + } && (!Vector3dConcept) + constexpr auto operator/(const U &vector, const V &scalar) + -> Vector3d + { + using ResultType = decltype(vector[0] / scalar); + + return Vector3d( + vector[0] / scalar, + vector[1] / scalar, + vector[2] / scalar + ); + } + /************** * ostream << * **************/ diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index b92ecf2..68730fd 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -39,11 +39,18 @@ TEST_CASE("Vector3d") constexpr auto speed = Vector3d{0.25 * km / h, 0.4 * km / h, 0.5 * km / h}; constexpr auto distanceMeter = Vector3d{1000.0 * m, 2000.0 * m, 3000.0 * m}; constexpr auto area = Vector3d{1e6 * m2, 4e6 * m2, 9e6 * m2}; + constexpr auto scalarMeter = 1.0 * m; - STATIC_REQUIRE(speed == distance / time); + // clang-format off STATIC_REQUIRE(distance == distanceMeter); STATIC_REQUIRE(area == distance * distance); + STATIC_REQUIRE(2 * distance == distance * 2); + STATIC_REQUIRE(speed == distance / time); + STATIC_REQUIRE(distance / 2 == distance * 0.5); + STATIC_REQUIRE(1 / distance == Vector3d{1.0 * (1/km), 0.5 * (1/km), (1.0 / 3.0) * (1/km)}); STATIC_REQUIRE(distance + distanceMeter == 2 * distance); + STATIC_REQUIRE(scalarMeter + distanceMeter == distanceMeter + scalarMeter); STATIC_REQUIRE(distance - distanceMeter == Vector3d{0 * m}); - STATIC_REQUIRE(2 * distance == distance * 2); + STATIC_REQUIRE(distanceMeter - scalarMeter == -1.0 * (scalarMeter - distanceMeter)); + // clang-format on } \ No newline at end of file From abae3c56be7508d68117f939b6656e12fdf7f73f Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Thu, 2 Jul 2026 11:20:45 +0200 Subject: [PATCH 08/30] feat: add unary +/- operator and != operator overloads for Vector3d --- include/mstd/linAlg/vector3d.hpp | 23 +++++++++++++++++++++++ include/mstd/linAlg/vector3d.tpp | 12 ++++++++++++ include/mstd/linAlg/vector3dClass.hpp | 7 +++++++ include/mstd/linAlg/vector3dClass.tpp | 18 ++++++++++++++++++ test/linAlg/vector3d.cpp | 5 ++++- 5 files changed, 64 insertions(+), 1 deletion(-) diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index acbab87..47be01c 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -43,6 +43,15 @@ namespace mstd const Vector3d &rhs ) noexcept; + template + requires requires(const Vector3d &lhs, const Vector3d &rhs) { + { lhs[0] != rhs[0] } -> std::convertible_to; + } + [[nodiscard]] constexpr bool operator!=( + const Vector3d &lhs, + const Vector3d &rhs + ) noexcept; + /********************* * binary + operator * *********************/ @@ -77,6 +86,20 @@ namespace mstd [[nodiscard]] constexpr auto operator-(const U &lhs, const V &rhs) -> Vector3d; + template + requires requires(const U &scalar, const V &vector) { + scalar - vector[0]; + } && (!Vector3dConcept) + [[nodiscard]] constexpr auto operator-(const U &scalar, const V &rhs) + -> Vector3d; + + template + requires requires(const U &vector, const V &scalar) { + vector[0] - scalar; + } && (!Vector3dConcept) + [[nodiscard]] constexpr auto operator-(const U &vector, const V &scalar) + -> Vector3d; + /********************* * binary * operator * *********************/ diff --git a/include/mstd/linAlg/vector3d.tpp b/include/mstd/linAlg/vector3d.tpp index e16775f..52e0f1f 100644 --- a/include/mstd/linAlg/vector3d.tpp +++ b/include/mstd/linAlg/vector3d.tpp @@ -43,6 +43,18 @@ namespace mstd return lhs[0] == rhs[0] && lhs[1] == rhs[1] && lhs[2] == rhs[2]; } + template + requires requires(const Vector3d &lhs, const Vector3d &rhs) { + { lhs[0] != rhs[0] } -> std::convertible_to; + } + constexpr bool operator!=( + const Vector3d &lhs, + const Vector3d &rhs + ) noexcept + { + return !(lhs == rhs); + } + /********************* * binary + operator * *********************/ diff --git a/include/mstd/linAlg/vector3dClass.hpp b/include/mstd/linAlg/vector3dClass.hpp index 7974ba4..5206718 100644 --- a/include/mstd/linAlg/vector3dClass.hpp +++ b/include/mstd/linAlg/vector3dClass.hpp @@ -48,6 +48,13 @@ namespace mstd using value_type = T; + /*********************** + * unary +/- operators * + ***********************/ + + [[nodiscard]] constexpr Vector3d operator+() const; + [[nodiscard]] constexpr Vector3d operator-() const; + /********************** * indexing operators * **********************/ diff --git a/include/mstd/linAlg/vector3dClass.tpp b/include/mstd/linAlg/vector3dClass.tpp index e6f3905..7486fd6 100644 --- a/include/mstd/linAlg/vector3dClass.tpp +++ b/include/mstd/linAlg/vector3dClass.tpp @@ -27,6 +27,24 @@ namespace mstd { + /*********************** + * * + * unary +/- operators * + * * + ***********************/ + + template + constexpr Vector3d Vector3d::operator+() const + { + return *this; + } + + template + constexpr Vector3d Vector3d::operator-() const + { + return Vector3d{-_xyz[0], -_xyz[1], -_xyz[2]}; + } + /********************** * * * indexing operators * diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 68730fd..1a07ba0 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -43,6 +43,9 @@ TEST_CASE("Vector3d") // clang-format off STATIC_REQUIRE(distance == distanceMeter); + STATIC_REQUIRE(+distance == distance); + STATIC_REQUIRE(-distance == -1.0 * distance); + STATIC_REQUIRE(distance != 2 * distance); STATIC_REQUIRE(area == distance * distance); STATIC_REQUIRE(2 * distance == distance * 2); STATIC_REQUIRE(speed == distance / time); @@ -51,6 +54,6 @@ TEST_CASE("Vector3d") STATIC_REQUIRE(distance + distanceMeter == 2 * distance); STATIC_REQUIRE(scalarMeter + distanceMeter == distanceMeter + scalarMeter); STATIC_REQUIRE(distance - distanceMeter == Vector3d{0 * m}); - STATIC_REQUIRE(distanceMeter - scalarMeter == -1.0 * (scalarMeter - distanceMeter)); + STATIC_REQUIRE(distanceMeter - scalarMeter == -(scalarMeter - distanceMeter)); // clang-format on } \ No newline at end of file From 903145b98a97a76d1ebb43fa19d8e7979a0ee586 Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Thu, 2 Jul 2026 15:49:04 +0200 Subject: [PATCH 09/30] feat: add unit conversion functions in() and force_in() for Vector3d --- include/mstd/linAlg/vector3dClass.hpp | 18 ++++++++++++- include/mstd/linAlg/vector3dClass.tpp | 39 +++++++++++++++++++++++++++ test/linAlg/vector3d.cpp | 5 +++- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/include/mstd/linAlg/vector3dClass.hpp b/include/mstd/linAlg/vector3dClass.hpp index 5206718..bc068b9 100644 --- a/include/mstd/linAlg/vector3dClass.hpp +++ b/include/mstd/linAlg/vector3dClass.hpp @@ -23,7 +23,8 @@ #ifndef __MSTD__LINALG__VECTOR3DCLASS_HPP__ #define __MSTD__LINALG__VECTOR3DCLASS_HPP__ -#include +#include // for array +#include // for declval namespace mstd { @@ -55,6 +56,21 @@ namespace mstd [[nodiscard]] constexpr Vector3d operator+() const; [[nodiscard]] constexpr Vector3d operator-() const; + /******************** + * unit conversions * + ********************/ + + template + requires requires(const T &v, const U &unit) { v.in(unit); } + [[nodiscard]] constexpr auto in(const U &unit) const -> Vector3d< + decltype(std::declval().in(std::declval()))>; + + template + requires requires(const T &v, const U &unit) { v.force_in(unit); } + [[nodiscard]] constexpr auto force_in(const U &unit) const + -> Vector3d() + .force_in(std::declval()))>; + /********************** * indexing operators * **********************/ diff --git a/include/mstd/linAlg/vector3dClass.tpp b/include/mstd/linAlg/vector3dClass.tpp index 7486fd6..4bff544 100644 --- a/include/mstd/linAlg/vector3dClass.tpp +++ b/include/mstd/linAlg/vector3dClass.tpp @@ -23,6 +23,8 @@ #ifndef __MSTD__LINALG__VECTOR3DCLASS_TPP__ #define __MSTD__LINALG__VECTOR3DCLASS_TPP__ +#include // for declval + #include "vector3dClass.hpp" namespace mstd @@ -45,6 +47,43 @@ namespace mstd return Vector3d{-_xyz[0], -_xyz[1], -_xyz[2]}; } + /******************* + * unit conversion * + *******************/ + + template + template + requires requires(const T &v, const U &unit) { v.in(unit); } + constexpr auto Vector3d::in(const U &unit) const -> Vector3d< + decltype(std::declval().in(std::declval()))> + { + using ResultType = + decltype(std::declval().in(std::declval())); + + return Vector3d{ + _xyz[0].in(unit), + _xyz[1].in(unit), + _xyz[2].in(unit), + }; + } + + template + template + requires requires(const T &v, const U &unit) { v.force_in(unit); } + constexpr auto Vector3d::force_in(const U &unit) const -> Vector3d< + decltype(std::declval().force_in(std::declval()))> + { + using ResultType = decltype(std::declval().force_in( + std::declval() + )); + + return Vector3d{ + _xyz[0].force_in(unit), + _xyz[1].force_in(unit), + _xyz[2].force_in(unit), + }; + } + /********************** * * * indexing operators * diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 1a07ba0..46325cb 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -40,10 +40,13 @@ TEST_CASE("Vector3d") constexpr auto distanceMeter = Vector3d{1000.0 * m, 2000.0 * m, 3000.0 * m}; constexpr auto area = Vector3d{1e6 * m2, 4e6 * m2, 9e6 * m2}; constexpr auto scalarMeter = 1.0 * m; + constexpr auto distanceInt = Vector3d{1 * m, 2 * m, 3 * m}; // clang-format off STATIC_REQUIRE(distance == distanceMeter); - STATIC_REQUIRE(+distance == distance); + STATIC_REQUIRE(distance.in(m) == distanceMeter); + STATIC_REQUIRE(distanceInt.force_in(km) == Vector3d{0 * m}); + STATIC_REQUIRE(+distance == distance); STATIC_REQUIRE(-distance == -1.0 * distance); STATIC_REQUIRE(distance != 2 * distance); STATIC_REQUIRE(area == distance * distance); From ef9482961d32a01786e495b97be9fcaeacaea209 Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Fri, 3 Jul 2026 10:30:57 +0200 Subject: [PATCH 10/30] feat: add unit conversion functions numerical_value_in() and force_numerical_value_in() for Vector3d --- include/mstd/linAlg/vector3d.hpp | 2 +- include/mstd/linAlg/vector3dClass.hpp | 24 ++++++++++---- include/mstd/linAlg/vector3dClass.tpp | 47 +++++++++++++++++++++------ test/linAlg/vector3d.cpp | 2 ++ 4 files changed, 57 insertions(+), 18 deletions(-) diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index 47be01c..8ddecf6 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -23,7 +23,7 @@ #ifndef __MSTD__LINALG__VECTOR3D_HPP__ #define __MSTD__LINALG__VECTOR3D_HPP__ -#include +#include // for std::ostream #include "concepts/vector3dConcepts.hpp" #include "vector3dClass.hpp" diff --git a/include/mstd/linAlg/vector3dClass.hpp b/include/mstd/linAlg/vector3dClass.hpp index bc068b9..5fd3d0a 100644 --- a/include/mstd/linAlg/vector3dClass.hpp +++ b/include/mstd/linAlg/vector3dClass.hpp @@ -23,8 +23,7 @@ #ifndef __MSTD__LINALG__VECTOR3DCLASS_HPP__ #define __MSTD__LINALG__VECTOR3DCLASS_HPP__ -#include // for array -#include // for declval +#include // for std::array namespace mstd { @@ -62,14 +61,25 @@ namespace mstd template requires requires(const T &v, const U &unit) { v.in(unit); } - [[nodiscard]] constexpr auto in(const U &unit) const -> Vector3d< - decltype(std::declval().in(std::declval()))>; + [[nodiscard]] constexpr auto in(const U &unit) const; template requires requires(const T &v, const U &unit) { v.force_in(unit); } - [[nodiscard]] constexpr auto force_in(const U &unit) const - -> Vector3d() - .force_in(std::declval()))>; + [[nodiscard]] constexpr auto force_in(const U &unit) const; + + template + requires requires(const T &v, const U &unit) { + v.numerical_value_in(unit); + } + [[nodiscard]] constexpr auto numerical_value_in(const U &unit) const; + + template + requires requires(const T &v, const U &unit) { + v.force_numerical_value_in(unit); + } + [[nodiscard]] constexpr auto force_numerical_value_in( + const U &unit + ) const; /********************** * indexing operators * diff --git a/include/mstd/linAlg/vector3dClass.tpp b/include/mstd/linAlg/vector3dClass.tpp index 4bff544..7deb4dd 100644 --- a/include/mstd/linAlg/vector3dClass.tpp +++ b/include/mstd/linAlg/vector3dClass.tpp @@ -23,7 +23,7 @@ #ifndef __MSTD__LINALG__VECTOR3DCLASS_TPP__ #define __MSTD__LINALG__VECTOR3DCLASS_TPP__ -#include // for declval +#include // for std::declval #include "vector3dClass.hpp" @@ -54,11 +54,9 @@ namespace mstd template template requires requires(const T &v, const U &unit) { v.in(unit); } - constexpr auto Vector3d::in(const U &unit) const -> Vector3d< - decltype(std::declval().in(std::declval()))> + constexpr auto Vector3d::in(const U &unit) const { - using ResultType = - decltype(std::declval().in(std::declval())); + using ResultType = decltype(std::declval().in(unit)); return Vector3d{ _xyz[0].in(unit), @@ -70,12 +68,9 @@ namespace mstd template template requires requires(const T &v, const U &unit) { v.force_in(unit); } - constexpr auto Vector3d::force_in(const U &unit) const -> Vector3d< - decltype(std::declval().force_in(std::declval()))> + constexpr auto Vector3d::force_in(const U &unit) const { - using ResultType = decltype(std::declval().force_in( - std::declval() - )); + using ResultType = decltype(std::declval().force_in(unit)); return Vector3d{ _xyz[0].force_in(unit), @@ -84,6 +79,38 @@ namespace mstd }; } + template + template + requires requires(const T &v, const U &unit) { v.numerical_value_in(unit); } + constexpr auto Vector3d::numerical_value_in(const U &unit) const + { + using ResultType = + decltype(std::declval().numerical_value_in(unit)); + + return Vector3d{ + _xyz[0].numerical_value_in(unit), + _xyz[1].numerical_value_in(unit), + _xyz[2].numerical_value_in(unit), + }; + } + + template + template + requires requires(const T &v, const U &unit) { + v.force_numerical_value_in(unit); + } + constexpr auto Vector3d::force_numerical_value_in(const U &unit) const + { + using ResultType = + decltype(std::declval().force_numerical_value_in(unit)); + + return Vector3d{ + _xyz[0].force_numerical_value_in(unit), + _xyz[1].force_numerical_value_in(unit), + _xyz[2].force_numerical_value_in(unit), + }; + } + /********************** * * * indexing operators * diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 46325cb..7c38803 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -46,6 +46,8 @@ TEST_CASE("Vector3d") STATIC_REQUIRE(distance == distanceMeter); STATIC_REQUIRE(distance.in(m) == distanceMeter); STATIC_REQUIRE(distanceInt.force_in(km) == Vector3d{0 * m}); + STATIC_REQUIRE(distance.numerical_value_in(m) == Vector3d{1000.0, 2000.0, 3000.0}); + STATIC_REQUIRE(distanceInt.force_numerical_value_in(km) == Vector3d{0.0}); STATIC_REQUIRE(+distance == distance); STATIC_REQUIRE(-distance == -1.0 * distance); STATIC_REQUIRE(distance != 2 * distance); From 3e59a3095242744a062bfc0295c3fb6cf988d49f Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Fri, 3 Jul 2026 16:35:21 +0200 Subject: [PATCH 11/30] feat: add norm functions for Vector3d --- include/mstd/linAlg/vector3d.hpp | 24 ++++++++++++++++++++++ include/mstd/linAlg/vector3d.tpp | 34 ++++++++++++++++++++++++++++++++ test/linAlg/vector3d.cpp | 9 +++++++-- 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index 8ddecf6..dc45224 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -23,6 +23,9 @@ #ifndef __MSTD__LINALG__VECTOR3D_HPP__ #define __MSTD__LINALG__VECTOR3D_HPP__ +#include // for mp_units::sqrt + +#include // for std:sqrt #include // for std::ostream #include "concepts/vector3dConcepts.hpp" @@ -148,6 +151,27 @@ namespace mstd [[nodiscard]] constexpr auto operator/(const U &vector, const V &scalar) -> Vector3d; + /****************** + * norm functions * + ******************/ + + template + requires requires(const U &vec) { std::sqrt(normSquared(vec)); } + [[nodiscard]] auto norm(const U &vec) + -> decltype(std::sqrt(normSquared(vec))); + + template + requires requires(const U &vec) { mp_units::sqrt(normSquared(vec)); } + [[nodiscard]] auto norm(const U &vec) + -> decltype(mp_units::sqrt(normSquared(vec))); + + template + requires requires(const U &vec) { + vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]; + } + [[nodiscard]] constexpr auto normSquared(const U &vec) + -> decltype(vec[0] * vec[0]); + /************** * ostream << * **************/ diff --git a/include/mstd/linAlg/vector3d.tpp b/include/mstd/linAlg/vector3d.tpp index 52e0f1f..2894aad 100644 --- a/include/mstd/linAlg/vector3d.tpp +++ b/include/mstd/linAlg/vector3d.tpp @@ -23,6 +23,10 @@ #ifndef __MSTD__LINALG__VECTOR3D_TPP__ #define __MSTD__LINALG__VECTOR3D_TPP__ +#include // for mp_units::sqrt + +#include // for std::sqrt + #include "vector3d.hpp" namespace mstd @@ -259,6 +263,36 @@ namespace mstd ); } + /****************** + * norm functions * + ******************/ + + template + requires requires(const U &vec) { std::sqrt(normSquared(vec)); } + [[nodiscard]] auto norm(const U &vec) + -> decltype(std::sqrt(normSquared(vec))) + { + return std::sqrt(normSquared(vec)); + } + + template + requires requires(const U &vec) { mp_units::sqrt(normSquared(vec)); } + [[nodiscard]] auto norm(const U &vec) + -> decltype(mp_units::sqrt(normSquared(vec))) + { + return mp_units::sqrt(normSquared(vec)); + } + + template + requires requires(const U &vec) { + vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]; + } + [[nodiscard]] constexpr auto normSquared(const U &vec) + -> decltype(vec[0] * vec[0]) + { + return vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]; + } + /************** * ostream << * **************/ diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 7c38803..1470187 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -35,12 +35,13 @@ using namespace mstd; TEST_CASE("Vector3d") { constexpr auto distance = Vector3d{1.0 * km, 2.0 * km, 3.0 * km}; - constexpr auto time = Vector3d{4.0 * h, 5.0 * h, 6.0 * h}; - constexpr auto speed = Vector3d{0.25 * km / h, 0.4 * km / h, 0.5 * km / h}; + constexpr auto time = Vector3d{2.0 * h, 1.0 * h, 2.0 * h}; + constexpr auto speed = Vector3d{0.5 * km / h, 2.0 * km / h, 1.5 * km / h}; constexpr auto distanceMeter = Vector3d{1000.0 * m, 2000.0 * m, 3000.0 * m}; constexpr auto area = Vector3d{1e6 * m2, 4e6 * m2, 9e6 * m2}; constexpr auto scalarMeter = 1.0 * m; constexpr auto distanceInt = Vector3d{1 * m, 2 * m, 3 * m}; + constexpr auto dimlessVector = Vector3d{1.0, 2.0, 2.0}; // clang-format off STATIC_REQUIRE(distance == distanceMeter); @@ -60,5 +61,9 @@ TEST_CASE("Vector3d") STATIC_REQUIRE(scalarMeter + distanceMeter == distanceMeter + scalarMeter); STATIC_REQUIRE(distance - distanceMeter == Vector3d{0 * m}); STATIC_REQUIRE(distanceMeter - scalarMeter == -(scalarMeter - distanceMeter)); + STATIC_REQUIRE(normSquared(dimlessVector) == 9.0); + STATIC_REQUIRE(normSquared(time) == (9.0 * h * h)); + REQUIRE(norm(dimlessVector) == 3.0); + REQUIRE(norm(time) == (3.0 * h)); // clang-format on } \ No newline at end of file From 53373d8b8e4c23d4a02c0ee0249796aa5f1aff48 Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Wed, 8 Jul 2026 17:11:56 +0200 Subject: [PATCH 12/30] refactor: Vector3d unit test into two files with and without mp-units --- include/mstd/linAlg/vector3d.hpp | 2 +- test/linAlg/CMakeLists.txt | 1 + test/linAlg/vector3d.cpp | 81 ++++++++++++++--------- test/linAlg/vector3d_mp-units.cpp | 106 ++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+), 33 deletions(-) create mode 100644 test/linAlg/vector3d_mp-units.cpp diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index dc45224..85544dc 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -29,7 +29,7 @@ #include // for std::ostream #include "concepts/vector3dConcepts.hpp" -#include "vector3dClass.hpp" +#include "vector3dClass.hpp" // IWYU pragma: export namespace mstd { diff --git a/test/linAlg/CMakeLists.txt b/test/linAlg/CMakeLists.txt index 1f40aa8..ac5293b 100644 --- a/test/linAlg/CMakeLists.txt +++ b/test/linAlg/CMakeLists.txt @@ -48,6 +48,7 @@ endif() add_executable(mstd_tests_linAlg vector3d.cpp + vector3d_mp-units.cpp ) target_link_libraries(mstd_tests_linAlg diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 1470187..738352d 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -22,48 +22,65 @@ #include "mstd/linAlg/vector3d.hpp" -#include -#include - #include #include -using namespace mp_units; -using namespace mp_units::si::unit_symbols; using namespace mstd; -TEST_CASE("Vector3d") +TEST_CASE("Vector3d - Comparison Operators") { - constexpr auto distance = Vector3d{1.0 * km, 2.0 * km, 3.0 * km}; - constexpr auto time = Vector3d{2.0 * h, 1.0 * h, 2.0 * h}; - constexpr auto speed = Vector3d{0.5 * km / h, 2.0 * km / h, 1.5 * km / h}; - constexpr auto distanceMeter = Vector3d{1000.0 * m, 2000.0 * m, 3000.0 * m}; - constexpr auto area = Vector3d{1e6 * m2, 4e6 * m2, 9e6 * m2}; - constexpr auto scalarMeter = 1.0 * m; - constexpr auto distanceInt = Vector3d{1 * m, 2 * m, 3 * m}; - constexpr auto dimlessVector = Vector3d{1.0, 2.0, 2.0}; + constexpr auto distance = Vector3d{1.0, 2.0, 3.0}; + constexpr auto distanceInt = Vector3d{1, 2, 3}; + constexpr auto anotherDistance = Vector3d{1.1, 2.2, 3.3}; + + STATIC_REQUIRE(distance == distance); + STATIC_REQUIRE(distance == distanceInt); + STATIC_REQUIRE(distance != anotherDistance); +} + +TEST_CASE("Vector3d - Unary +/- Operators") +{ + constexpr auto distance = Vector3d{1.0, 2.0, 3.0}; + constexpr auto negativeDistance = Vector3d{-1.0, -2.0, -3.0}; - // clang-format off - STATIC_REQUIRE(distance == distanceMeter); - STATIC_REQUIRE(distance.in(m) == distanceMeter); - STATIC_REQUIRE(distanceInt.force_in(km) == Vector3d{0 * m}); - STATIC_REQUIRE(distance.numerical_value_in(m) == Vector3d{1000.0, 2000.0, 3000.0}); - STATIC_REQUIRE(distanceInt.force_numerical_value_in(km) == Vector3d{0.0}); STATIC_REQUIRE(+distance == distance); - STATIC_REQUIRE(-distance == -1.0 * distance); - STATIC_REQUIRE(distance != 2 * distance); + STATIC_REQUIRE(-distance == negativeDistance); +} + +TEST_CASE("Vector3d - Binary + and - Operators") +{ + constexpr auto distance = Vector3d{1.0, 2.0, 3.0}; + constexpr auto distanceMeter = Vector3d{1000.0, 2000.0, 3000.0}; + constexpr auto distanceTwice = Vector3d{2.0, 4.0, 6.0}; + constexpr auto scalarMeter = 1.0; + + // clang-format off + STATIC_REQUIRE(distance + distance == distanceTwice); + STATIC_REQUIRE(scalarMeter + distanceMeter == distanceMeter + scalarMeter); + STATIC_REQUIRE(distance - distance == Vector3d{0}); + STATIC_REQUIRE(distanceMeter - scalarMeter == -(scalarMeter - distanceMeter)); + // clang-format on +} + +TEST_CASE("Vector3d - Binary * and / Operators") +{ + constexpr auto distance = Vector3d{1.0, 2.0, 4.0}; + constexpr auto time = Vector3d{2.0, 1.0, 4.0}; + constexpr auto speed = Vector3d{0.5, 2.0, 1.0}; + constexpr auto area = Vector3d{1.0, 4.0, 16.0}; + constexpr auto invDistance = Vector3d{1.0, 0.5, 0.25}; + STATIC_REQUIRE(area == distance * distance); STATIC_REQUIRE(2 * distance == distance * 2); STATIC_REQUIRE(speed == distance / time); STATIC_REQUIRE(distance / 2 == distance * 0.5); - STATIC_REQUIRE(1 / distance == Vector3d{1.0 * (1/km), 0.5 * (1/km), (1.0 / 3.0) * (1/km)}); - STATIC_REQUIRE(distance + distanceMeter == 2 * distance); - STATIC_REQUIRE(scalarMeter + distanceMeter == distanceMeter + scalarMeter); - STATIC_REQUIRE(distance - distanceMeter == Vector3d{0 * m}); - STATIC_REQUIRE(distanceMeter - scalarMeter == -(scalarMeter - distanceMeter)); - STATIC_REQUIRE(normSquared(dimlessVector) == 9.0); - STATIC_REQUIRE(normSquared(time) == (9.0 * h * h)); - REQUIRE(norm(dimlessVector) == 3.0); - REQUIRE(norm(time) == (3.0 * h)); - // clang-format on + STATIC_REQUIRE(1 / distance == invDistance); +} + +TEST_CASE("Vector3d - Norm Functions") +{ + constexpr auto time = Vector3d{2.0, 3.0, 6.0}; + + STATIC_REQUIRE(normSquared(time) == (49.0)); + REQUIRE(norm(time) == (7.0)); } \ No newline at end of file diff --git a/test/linAlg/vector3d_mp-units.cpp b/test/linAlg/vector3d_mp-units.cpp new file mode 100644 index 0000000..fa93b64 --- /dev/null +++ b/test/linAlg/vector3d_mp-units.cpp @@ -0,0 +1,106 @@ +/***************************************************************************** + + + mstd library + Copyright (C) 2025-now Jakob Gamper + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + +******************************************************************************/ + +#include +#include + +#include +#include + +#include "mstd/linAlg/vector3d.hpp" + +using namespace mp_units; +using namespace mp_units::si::unit_symbols; +using namespace mstd; + +TEST_CASE("Vector3d mp-units - Comparison Operators") +{ + constexpr auto distance = Vector3d{1.0 * km, 2.0 * km, 3.0 * km}; + constexpr auto distanceMeter = Vector3d{1000.0 * m, 2000.0 * m, 3000.0 * m}; + constexpr auto anotherDistance = Vector3d{1.1 * km, 2.2 * km, 3.3 * km}; + + STATIC_REQUIRE(distance == distanceMeter); + STATIC_REQUIRE(distance != anotherDistance); +} + +TEST_CASE("Vector3d mp-units Specific Functions") +{ + constexpr auto distance = Vector3d{1.0 * km, 2.0 * km, 3.0 * km}; + constexpr auto distanceMeter = Vector3d{1000.0 * m, 2000.0 * m, 3000.0 * m}; + constexpr auto distanceMeterInt = Vector3d{1 * m, 2 * m, 3 * m}; + + // clang-format off + STATIC_REQUIRE(distance.in(m) == distanceMeter); + STATIC_REQUIRE(distanceMeterInt.force_in(km) == Vector3d{0 * m}); + STATIC_REQUIRE(distance.numerical_value_in(m) == Vector3d{1000.0, 2000.0, 3000.0}); + STATIC_REQUIRE(distanceMeterInt.force_numerical_value_in(km) == Vector3d{0.0}); + // clang-format on +} + +TEST_CASE("Vector3d mp-units - Unary +/- Operators") +{ + constexpr auto distance = Vector3d{1.0 * km, 2.0 * km, 3.0 * km}; + constexpr auto negativeDistance = Vector3d{-1.0 * km, -2.0 * km, -3.0 * km}; + + STATIC_REQUIRE(+distance == distance); + STATIC_REQUIRE(-distance == negativeDistance); +} + +TEST_CASE("Vector3d mp-units - Binary + and - Operators") +{ + constexpr auto distance = Vector3d{1.0 * km, 2.0 * km, 3.0 * km}; + constexpr auto distanceMeter = Vector3d{1000.0 * m, 2000.0 * m, 3000.0 * m}; + constexpr auto distanceTwice = Vector3d{2.0 * km, 4.0 * km, 6.0 * km}; + constexpr auto scalarMeter = 1.0 * m; + + // clang-format off + STATIC_REQUIRE(distance + distanceMeter == distanceTwice); + STATIC_REQUIRE(scalarMeter + distanceMeter == distanceMeter + scalarMeter); + STATIC_REQUIRE(distance - distanceMeter == Vector3d{0 * m}); + STATIC_REQUIRE(distanceMeter - scalarMeter == -(scalarMeter - distanceMeter)); + // clang-format on +} + +TEST_CASE("Vector3d mp-units - Binary * and / Operators") +{ + // clang-format off + constexpr auto distance = Vector3d{1.0 * km, 2.0 * km, 4.0 * km}; + constexpr auto time = Vector3d{2.0 * h, 1.0 * h, 4.0 * h}; + constexpr auto speed = Vector3d{0.5 * km / h, 2.0 * km / h, 1.0 * km / h}; + constexpr auto area = Vector3d{1e6 * m2, 4e6 * m2, 16e6 * m2}; + constexpr auto invDistance = Vector3d{1.0 * (1/km), 0.5 * (1/km), 0.25 * (1/km)}; + // clang-format on + + STATIC_REQUIRE(area == distance * distance); + STATIC_REQUIRE(2 * distance == distance * 2); + STATIC_REQUIRE(speed == distance / time); + STATIC_REQUIRE(distance / 2 == distance * 0.5); + STATIC_REQUIRE(1 / distance == invDistance); +} + +TEST_CASE("Vector3d mp-units - Norm Functions") +{ + constexpr auto time = Vector3d{2.0 * h, 3.0 * h, 6.0 * h}; + + STATIC_REQUIRE(normSquared(time) == (49.0 * h * h)); + REQUIRE(norm(time) == (7.0 * h)); +} \ No newline at end of file From ef0bf2ae5a2065476cce79a43a1d279353b4de98 Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Wed, 8 Jul 2026 17:47:04 +0200 Subject: [PATCH 13/30] refactor: Vector3d comparison operators requires clauses --- include/mstd/linAlg/vector3d.hpp | 11 ++++------- include/mstd/linAlg/vector3d.tpp | 9 +++------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index 85544dc..1000cf0 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -25,7 +25,8 @@ #include // for mp_units::sqrt -#include // for std:sqrt +#include // for std:sqrt +#include #include // for std::ostream #include "concepts/vector3dConcepts.hpp" @@ -38,18 +39,14 @@ namespace mstd ************************/ template - requires requires(const Vector3d &lhs, const Vector3d &rhs) { - { lhs[0] == rhs[0] } -> std::convertible_to; - } + requires std::equality_comparable_with [[nodiscard]] constexpr bool operator==( const Vector3d &lhs, const Vector3d &rhs ) noexcept; template - requires requires(const Vector3d &lhs, const Vector3d &rhs) { - { lhs[0] != rhs[0] } -> std::convertible_to; - } + requires std::equality_comparable_with [[nodiscard]] constexpr bool operator!=( const Vector3d &lhs, const Vector3d &rhs diff --git a/include/mstd/linAlg/vector3d.tpp b/include/mstd/linAlg/vector3d.tpp index 2894aad..8c13c36 100644 --- a/include/mstd/linAlg/vector3d.tpp +++ b/include/mstd/linAlg/vector3d.tpp @@ -26,6 +26,7 @@ #include // for mp_units::sqrt #include // for std::sqrt +#include #include "vector3d.hpp" @@ -36,9 +37,7 @@ namespace mstd ************************/ template - requires requires(const Vector3d &lhs, const Vector3d &rhs) { - { lhs[0] == rhs[0] } -> std::convertible_to; - } + requires std::equality_comparable_with constexpr bool operator==( const Vector3d &lhs, const Vector3d &rhs @@ -48,9 +47,7 @@ namespace mstd } template - requires requires(const Vector3d &lhs, const Vector3d &rhs) { - { lhs[0] != rhs[0] } -> std::convertible_to; - } + requires std::equality_comparable_with constexpr bool operator!=( const Vector3d &lhs, const Vector3d &rhs From 4e7e6e2bb8c5db99574e58099d42a1daacca0cba Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Wed, 8 Jul 2026 18:00:41 +0200 Subject: [PATCH 14/30] refactor: Vector3d binary "+" operator --- include/mstd/linAlg/vector3d.hpp | 12 +++++++----- include/mstd/linAlg/vector3d.tpp | 14 ++++++++------ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index 1000cf0..aadbc33 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -28,6 +28,7 @@ #include // for std:sqrt #include #include // for std::ostream +#include #include "concepts/vector3dConcepts.hpp" #include "vector3dClass.hpp" // IWYU pragma: export @@ -56,11 +57,12 @@ namespace mstd * binary + operator * *********************/ - template - requires requires(const U &lhs, const V &rhs) { lhs[0] + rhs[0]; } && - (Vector3dDepthDifference_v == 0) - [[nodiscard]] constexpr auto operator+(const U &lhs, const V &rhs) - -> Vector3d; + template + requires requires(const U &u, const V &v) { u + v; } + [[nodiscard]] constexpr auto operator+( + const Vector3d &lhs, + const Vector3d &rhs + ) -> Vector3d() + std::declval())>; template requires requires(const U &scalar, const V &vector) { diff --git a/include/mstd/linAlg/vector3d.tpp b/include/mstd/linAlg/vector3d.tpp index 8c13c36..785f3f8 100644 --- a/include/mstd/linAlg/vector3d.tpp +++ b/include/mstd/linAlg/vector3d.tpp @@ -27,6 +27,7 @@ #include // for std::sqrt #include +#include #include "vector3d.hpp" @@ -60,13 +61,14 @@ namespace mstd * binary + operator * *********************/ - template - requires requires(const U &lhs, const V &rhs) { lhs[0] + rhs[0]; } && - (Vector3dDepthDifference_v == 0) - constexpr auto operator+(const U &lhs, const V &rhs) - -> Vector3d + template + requires requires(const U &u, const V &v) { u + v; } + [[nodiscard]] constexpr auto operator+( + const Vector3d &lhs, + const Vector3d &rhs + ) -> Vector3d() + std::declval())> { - using ResultType = decltype(lhs[0] + rhs[0]); + using ResultType = decltype(std::declval() + std::declval()); return Vector3d( lhs[0] + rhs[0], From 97d1c896ba808ae60d70829ad283f1a227737f9c Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Thu, 9 Jul 2026 13:50:17 +0200 Subject: [PATCH 15/30] refactor: consider nested Vector3d of same depth and disallow scalar - or / Vector3d --- .../mstd/linAlg/concepts/vector3dDepth.hpp | 2 - include/mstd/linAlg/vector3d.hpp | 127 +++++++-------- include/mstd/linAlg/vector3d.tpp | 147 +++++++----------- test/linAlg/vector3d.cpp | 97 +++++++++++- test/linAlg/vector3d_mp-units.cpp | 91 ++++++++++- 5 files changed, 291 insertions(+), 173 deletions(-) diff --git a/include/mstd/linAlg/concepts/vector3dDepth.hpp b/include/mstd/linAlg/concepts/vector3dDepth.hpp index 5f63928..3a48993 100644 --- a/include/mstd/linAlg/concepts/vector3dDepth.hpp +++ b/include/mstd/linAlg/concepts/vector3dDepth.hpp @@ -23,8 +23,6 @@ #ifndef __MSTD__LINALG__CONCEPTS__VECTOR3DDEPTH_HPP__ #define __MSTD__LINALG__CONCEPTS__VECTOR3DDEPTH_HPP__ -#include - namespace mstd { template diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index aadbc33..2c6d6a2 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -58,97 +58,90 @@ namespace mstd *********************/ template - requires requires(const U &u, const V &v) { u + v; } + requires requires(const U &u, const V &v) { u + v; } && + (Vector3dDepthDifference_v == 0) [[nodiscard]] constexpr auto operator+( const Vector3d &lhs, const Vector3d &rhs ) -> Vector3d() + std::declval())>; - template - requires requires(const U &scalar, const V &vector) { - scalar + vector[0]; - } && (!Vector3dConcept) - [[nodiscard]] constexpr auto operator+(const U &scalar, const V &rhs) - -> Vector3d; + template + requires requires(const U &u, const V &v) { u + v; } + [[nodiscard]] constexpr auto operator+( + const U &scalar, + const Vector3d &vector + ) -> Vector3d() + std::declval())>; - template - requires requires(const U &vector, const V &scalar) { - vector[0] + scalar; - } && (!Vector3dConcept) - [[nodiscard]] constexpr auto operator+(const U &vector, const V &scalar) - -> Vector3d; + template + requires requires(const U &u, const V &v) { u + v; } + [[nodiscard]] constexpr auto operator+( + const Vector3d &vector, + const V &scalar + ) -> Vector3d() + std::declval())>; /********************* * binary - operator * *********************/ - template - requires requires(const U &lhs, const V &rhs) { lhs[0] - rhs[0]; } && + template + requires requires(const U &u, const V &v) { u - v; } && (Vector3dDepthDifference_v == 0) - [[nodiscard]] constexpr auto operator-(const U &lhs, const V &rhs) - -> Vector3d; - - template - requires requires(const U &scalar, const V &vector) { - scalar - vector[0]; - } && (!Vector3dConcept) - [[nodiscard]] constexpr auto operator-(const U &scalar, const V &rhs) - -> Vector3d; - - template - requires requires(const U &vector, const V &scalar) { - vector[0] - scalar; - } && (!Vector3dConcept) - [[nodiscard]] constexpr auto operator-(const U &vector, const V &scalar) - -> Vector3d; + [[nodiscard]] constexpr auto operator-( + const Vector3d &lhs, + const Vector3d &rhs + ) -> Vector3d() - std::declval())>; + + template + requires requires(const U &u, const V &v) { u - v; } + [[nodiscard]] constexpr auto operator-( + const Vector3d &vector, + const V &scalar + ) -> Vector3d() - std::declval())>; /********************* * binary * operator * *********************/ - template - requires requires(const U &lhs, const V &rhs) { lhs[0] * rhs[0]; } && + template + requires requires(const U &u, const V &v) { u * v; } && (Vector3dDepthDifference_v == 0) - [[nodiscard]] constexpr auto operator*(const U &lhs, const V &rhs) - -> Vector3d; - - template - requires requires(const U &scalar, const V &vector) { - scalar * vector[0]; - } && (!Vector3dConcept) - [[nodiscard]] constexpr auto operator*(const U &scalar, const V &rhs) - -> Vector3d; - - template - requires requires(const U &vector, const V &scalar) { - vector[0] * scalar; - } && (!Vector3dConcept) - [[nodiscard]] constexpr auto operator*(const U &vector, const V &scalar) - -> Vector3d; + [[nodiscard]] constexpr auto operator*( + const Vector3d &lhs, + const Vector3d &rhs + ) -> Vector3d() * std::declval())>; + + template + requires requires(const U &u, const V &v) { u * v; } + [[nodiscard]] constexpr auto operator*( + const U &scalar, + const Vector3d &vector + ) -> Vector3d() * std::declval())>; + + template + requires requires(const U &u, const V &v) { u * v; } + [[nodiscard]] constexpr auto operator*( + const Vector3d &vector, + const V &scalar + ) -> Vector3d() * std::declval())>; /********************* * binary / operator * *********************/ - template - requires requires(const U &lhs, const V &rhs) { lhs[0] / rhs[0]; } && + template + requires requires(const U &u, const V &v) { u / v; } && (Vector3dDepthDifference_v == 0) - [[nodiscard]] constexpr auto operator/(const U &lhs, const V &rhs) - -> Vector3d; - - template - requires requires(const U &scalar, const V &vector) { - scalar / vector[0]; - } && (!Vector3dConcept) - [[nodiscard]] constexpr auto operator/(const U &scalar, const V &rhs) - -> Vector3d; - - template - requires requires(const U &vector, const V &scalar) { - vector[0] / scalar; - } && (!Vector3dConcept) - [[nodiscard]] constexpr auto operator/(const U &vector, const V &scalar) - -> Vector3d; + [[nodiscard]] constexpr auto operator/( + const Vector3d &lhs, + const Vector3d &rhs + ) -> Vector3d() / std::declval())>; + + template + requires requires(const U &u, const V &v) { u / v; } + [[nodiscard]] constexpr auto operator/( + const Vector3d &vector, + const V &scalar + ) -> Vector3d() / std::declval())>; /****************** * norm functions * diff --git a/include/mstd/linAlg/vector3d.tpp b/include/mstd/linAlg/vector3d.tpp index 785f3f8..4a3570f 100644 --- a/include/mstd/linAlg/vector3d.tpp +++ b/include/mstd/linAlg/vector3d.tpp @@ -23,9 +23,9 @@ #ifndef __MSTD__LINALG__VECTOR3D_TPP__ #define __MSTD__LINALG__VECTOR3D_TPP__ -#include // for mp_units::sqrt +#include -#include // for std::sqrt +#include #include #include @@ -62,7 +62,8 @@ namespace mstd *********************/ template - requires requires(const U &u, const V &v) { u + v; } + requires requires(const U &u, const V &v) { u + v; } && + (Vector3dDepthDifference_v == 0) [[nodiscard]] constexpr auto operator+( const Vector3d &lhs, const Vector3d &rhs @@ -77,14 +78,12 @@ namespace mstd ); } - template - requires requires(const U &scalar, const V &vector) { - scalar + vector[0]; - } && (!Vector3dConcept) - constexpr auto operator+(const U &scalar, const V &vector) - -> Vector3d + template + requires requires(const U &u, const V &v) { u + v; } + constexpr auto operator+(const U &scalar, const Vector3d &vector) + -> Vector3d() + std::declval())> { - using ResultType = decltype(scalar + vector[0]); + using ResultType = decltype(std::declval() + std::declval()); return Vector3d( scalar + vector[0], @@ -93,14 +92,12 @@ namespace mstd ); } - template - requires requires(const U &vector, const V &scalar) { - vector[0] + scalar; - } && (!Vector3dConcept) - constexpr auto operator+(const U &vector, const V &scalar) - -> Vector3d + template + requires requires(const U &u, const V &v) { u + v; } + constexpr auto operator+(const Vector3d &vector, const V &scalar) + -> Vector3d() + std::declval())> { - using ResultType = decltype(vector[0] + scalar); + using ResultType = decltype(std::declval() + std::declval()); return Vector3d( vector[0] + scalar, @@ -113,13 +110,15 @@ namespace mstd * binary - operator * *********************/ - template - requires requires(const U &lhs, const V &rhs) { lhs[0] - rhs[0]; } && + template + requires requires(const U &u, const V &v) { u - v; } && (Vector3dDepthDifference_v == 0) - constexpr auto operator-(const U &lhs, const V &rhs) - -> Vector3d + [[nodiscard]] constexpr auto operator-( + const Vector3d &lhs, + const Vector3d &rhs + ) -> Vector3d() - std::declval())> { - using ResultType = decltype(lhs[0] - rhs[0]); + using ResultType = decltype(std::declval() - std::declval()); return Vector3d( lhs[0] - rhs[0], @@ -128,30 +127,12 @@ namespace mstd ); } - template - requires requires(const U &scalar, const V &vector) { - scalar - vector[0]; - } && (!Vector3dConcept) - constexpr auto operator-(const U &scalar, const V &vector) - -> Vector3d - { - using ResultType = decltype(scalar - vector[0]); - - return Vector3d( - scalar - vector[0], - scalar - vector[1], - scalar - vector[2] - ); - } - - template - requires requires(const U &vector, const V &scalar) { - vector[0] - scalar; - } && (!Vector3dConcept) - constexpr auto operator-(const U &vector, const V &scalar) - -> Vector3d + template + requires requires(const U &u, const V &v) { u - v; } + constexpr auto operator-(const Vector3d &vector, const V &scalar) + -> Vector3d() - std::declval())> { - using ResultType = decltype(vector[0] - scalar); + using ResultType = decltype(std::declval() - std::declval()); return Vector3d( vector[0] - scalar, @@ -164,13 +145,15 @@ namespace mstd * binary * operator * *********************/ - template - requires requires(const U &lhs, const V &rhs) { lhs[0] * rhs[0]; } && + template + requires requires(const U &u, const V &v) { u * v; } && (Vector3dDepthDifference_v == 0) - constexpr auto operator*(const U &lhs, const V &rhs) - -> Vector3d + [[nodiscard]] constexpr auto operator*( + const Vector3d &lhs, + const Vector3d &rhs + ) -> Vector3d() * std::declval())> { - using ResultType = decltype(lhs[0] * rhs[0]); + using ResultType = decltype(std::declval() * std::declval()); return Vector3d( lhs[0] * rhs[0], @@ -179,14 +162,12 @@ namespace mstd ); } - template - requires requires(const U &scalar, const V &vector) { - scalar * vector[0]; - } && (!Vector3dConcept) - constexpr auto operator*(const U &scalar, const V &vector) - -> Vector3d + template + requires requires(const U &u, const V &v) { u * v; } + constexpr auto operator*(const U &scalar, const Vector3d &vector) + -> Vector3d() * std::declval())> { - using ResultType = decltype(scalar * vector[0]); + using ResultType = decltype(std::declval() * std::declval()); return Vector3d( scalar * vector[0], @@ -195,14 +176,12 @@ namespace mstd ); } - template - requires requires(const U &vector, const V &scalar) { - vector[0] * scalar; - } && (!Vector3dConcept) - constexpr auto operator*(const U &vector, const V &scalar) - -> Vector3d + template + requires requires(const U &u, const V &v) { u * v; } + constexpr auto operator*(const Vector3d &vector, const V &scalar) + -> Vector3d() * std::declval())> { - using ResultType = decltype(vector[0] * scalar); + using ResultType = decltype(std::declval() * std::declval()); return Vector3d( vector[0] * scalar, @@ -215,13 +194,15 @@ namespace mstd * binary / operator * *********************/ - template - requires requires(const U &lhs, const V &rhs) { lhs[0] / rhs[0]; } && + template + requires requires(const U &u, const V &v) { u / v; } && (Vector3dDepthDifference_v == 0) - constexpr auto operator/(const U &lhs, const V &rhs) - -> Vector3d + [[nodiscard]] constexpr auto operator/( + const Vector3d &lhs, + const Vector3d &rhs + ) -> Vector3d() / std::declval())> { - using ResultType = decltype(lhs[0] / rhs[0]); + using ResultType = decltype(std::declval() / std::declval()); return Vector3d( lhs[0] / rhs[0], @@ -230,30 +211,12 @@ namespace mstd ); } - template - requires requires(const U &scalar, const V &vector) { - scalar / vector[0]; - } && (!Vector3dConcept) - constexpr auto operator/(const U &scalar, const V &vector) - -> Vector3d - { - using ResultType = decltype(scalar / vector[0]); - - return Vector3d( - scalar / vector[0], - scalar / vector[1], - scalar / vector[2] - ); - } - - template - requires requires(const U &vector, const V &scalar) { - vector[0] / scalar; - } && (!Vector3dConcept) - constexpr auto operator/(const U &vector, const V &scalar) - -> Vector3d + template + requires requires(const U &u, const V &v) { u / v; } + constexpr auto operator/(const Vector3d &vector, const V &scalar) + -> Vector3d() / std::declval())> { - using ResultType = decltype(vector[0] / scalar); + using ResultType = decltype(std::declval() / std::declval()); return Vector3d( vector[0] / scalar, diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 738352d..82012c0 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -52,29 +52,28 @@ TEST_CASE("Vector3d - Binary + and - Operators") constexpr auto distance = Vector3d{1.0, 2.0, 3.0}; constexpr auto distanceMeter = Vector3d{1000.0, 2000.0, 3000.0}; constexpr auto distanceTwice = Vector3d{2.0, 4.0, 6.0}; + constexpr auto distanceDiff = Vector3d{999.0, 1999.0, 2999.0}; constexpr auto scalarMeter = 1.0; // clang-format off STATIC_REQUIRE(distance + distance == distanceTwice); STATIC_REQUIRE(scalarMeter + distanceMeter == distanceMeter + scalarMeter); STATIC_REQUIRE(distance - distance == Vector3d{0}); - STATIC_REQUIRE(distanceMeter - scalarMeter == -(scalarMeter - distanceMeter)); + STATIC_REQUIRE(distanceMeter - scalarMeter == distanceDiff); // clang-format on } TEST_CASE("Vector3d - Binary * and / Operators") { - constexpr auto distance = Vector3d{1.0, 2.0, 4.0}; - constexpr auto time = Vector3d{2.0, 1.0, 4.0}; - constexpr auto speed = Vector3d{0.5, 2.0, 1.0}; - constexpr auto area = Vector3d{1.0, 4.0, 16.0}; - constexpr auto invDistance = Vector3d{1.0, 0.5, 0.25}; + constexpr auto distance = Vector3d{1.0, 2.0, 4.0}; + constexpr auto time = Vector3d{2.0, 1.0, 4.0}; + constexpr auto speed = Vector3d{0.5, 2.0, 1.0}; + constexpr auto area = Vector3d{1.0, 4.0, 16.0}; STATIC_REQUIRE(area == distance * distance); STATIC_REQUIRE(2 * distance == distance * 2); STATIC_REQUIRE(speed == distance / time); STATIC_REQUIRE(distance / 2 == distance * 0.5); - STATIC_REQUIRE(1 / distance == invDistance); } TEST_CASE("Vector3d - Norm Functions") @@ -83,4 +82,88 @@ TEST_CASE("Vector3d - Norm Functions") STATIC_REQUIRE(normSquared(time) == (49.0)); REQUIRE(norm(time) == (7.0)); +} + +TEST_CASE("Vector3d - Nested Vector3d Binary +") +{ + constexpr auto pos1 = Vector3d{1, 2, 3}; + constexpr auto pos2 = Vector3d{4, 5, 6}; + constexpr auto pos3 = Vector3d{7, 8, 9}; + constexpr auto pos = Vector3d{pos1, pos2, pos3}; + + constexpr auto shift1 = Vector3d{10, 11, 12}; + constexpr auto shift2 = Vector3d{13, 14, 15}; + constexpr auto shift3 = Vector3d{16, 17, 18}; + constexpr auto shift = Vector3d{shift1, shift2, shift3}; + + constexpr auto pos1_shifted = Vector3d{11, 13, 15}; + constexpr auto pos2_shifted = Vector3d{17, 19, 21}; + constexpr auto pos3_shifted = Vector3d{23, 25, 27}; + constexpr auto pos_shifted = + Vector3d{pos1_shifted, pos2_shifted, pos3_shifted}; + + STATIC_REQUIRE(pos + shift == pos_shifted); + STATIC_REQUIRE(shift + pos == pos_shifted); +} + +TEST_CASE("Vector3d - Nested Vector3d Binary -") +{ + constexpr auto pos1 = Vector3d{10, 11, 12}; + constexpr auto pos2 = Vector3d{13, 14, 15}; + constexpr auto pos3 = Vector3d{16, 17, 18}; + constexpr auto pos = Vector3d{pos1, pos2, pos3}; + + constexpr auto shift1 = Vector3d{9, 8, 7}; + constexpr auto shift2 = Vector3d{6, 5, 4}; + constexpr auto shift3 = Vector3d{3, 2, 1}; + constexpr auto shift = Vector3d{shift1, shift2, shift3}; + + constexpr auto pos1_shifted = Vector3d{1, 3, 5}; + constexpr auto pos2_shifted = Vector3d{7, 9, 11}; + constexpr auto pos3_shifted = Vector3d{13, 15, 17}; + constexpr auto pos_shifted = + Vector3d{pos1_shifted, pos2_shifted, pos3_shifted}; + + STATIC_REQUIRE(pos - shift == pos_shifted); +} + +TEST_CASE("Vector3d - Nested Vector3d Binary *") +{ + constexpr auto pos1 = Vector3d{1, 2, 3}; + constexpr auto pos2 = Vector3d{4, 5, 6}; + constexpr auto pos3 = Vector3d{7, 8, 9}; + constexpr auto pos = Vector3d{pos1, pos2, pos3}; + + constexpr auto factor1 = Vector3d{10, 11, 12}; + constexpr auto factor2 = Vector3d{13, 14, 15}; + constexpr auto factor3 = Vector3d{16, 17, 18}; + constexpr auto factor = Vector3d{factor1, factor2, factor3}; + + constexpr auto pos1_scaled = Vector3d{10, 22, 36}; + constexpr auto pos2_scaled = Vector3d{52, 70, 90}; + constexpr auto pos3_scaled = Vector3d{112, 136, 162}; + constexpr auto pos_scaled = Vector3d{pos1_scaled, pos2_scaled, pos3_scaled}; + + STATIC_REQUIRE(pos * factor == pos_scaled); + STATIC_REQUIRE(factor * pos == pos_scaled); +} + +TEST_CASE("Vector3d - Nested Vector3d Binary /") +{ + constexpr auto num1 = Vector3d{1, 4, 9}; + constexpr auto num2 = Vector3d{16, 25, 36}; + constexpr auto num3 = Vector3d{49, 64, 81}; + constexpr auto num = Vector3d{num1, num2, num3}; + + constexpr auto den1 = Vector3d{1, 2, 3}; + constexpr auto den2 = Vector3d{4, 5, 6}; + constexpr auto den3 = Vector3d{7, 8, 9}; + constexpr auto den = Vector3d{den1, den2, den3}; + + constexpr auto quotient1 = Vector3d{1, 2, 3}; + constexpr auto quotient2 = Vector3d{4, 5, 6}; + constexpr auto quotient3 = Vector3d{7, 8, 9}; + constexpr auto quotient = Vector3d{quotient1, quotient2, quotient3}; + + STATIC_REQUIRE(num / den == quotient); } \ No newline at end of file diff --git a/test/linAlg/vector3d_mp-units.cpp b/test/linAlg/vector3d_mp-units.cpp index fa93b64..f135845 100644 --- a/test/linAlg/vector3d_mp-units.cpp +++ b/test/linAlg/vector3d_mp-units.cpp @@ -71,30 +71,27 @@ TEST_CASE("Vector3d mp-units - Binary + and - Operators") constexpr auto distanceMeter = Vector3d{1000.0 * m, 2000.0 * m, 3000.0 * m}; constexpr auto distanceTwice = Vector3d{2.0 * km, 4.0 * km, 6.0 * km}; constexpr auto scalarMeter = 1.0 * m; + constexpr auto distanceDiff = Vector3d{999.0 * m, 1999.0 * m, 2999.0 * m}; // clang-format off STATIC_REQUIRE(distance + distanceMeter == distanceTwice); STATIC_REQUIRE(scalarMeter + distanceMeter == distanceMeter + scalarMeter); STATIC_REQUIRE(distance - distanceMeter == Vector3d{0 * m}); - STATIC_REQUIRE(distanceMeter - scalarMeter == -(scalarMeter - distanceMeter)); + STATIC_REQUIRE(distanceMeter - scalarMeter == distanceDiff); // clang-format on } TEST_CASE("Vector3d mp-units - Binary * and / Operators") { - // clang-format off constexpr auto distance = Vector3d{1.0 * km, 2.0 * km, 4.0 * km}; constexpr auto time = Vector3d{2.0 * h, 1.0 * h, 4.0 * h}; constexpr auto speed = Vector3d{0.5 * km / h, 2.0 * km / h, 1.0 * km / h}; constexpr auto area = Vector3d{1e6 * m2, 4e6 * m2, 16e6 * m2}; - constexpr auto invDistance = Vector3d{1.0 * (1/km), 0.5 * (1/km), 0.25 * (1/km)}; - // clang-format on STATIC_REQUIRE(area == distance * distance); STATIC_REQUIRE(2 * distance == distance * 2); STATIC_REQUIRE(speed == distance / time); STATIC_REQUIRE(distance / 2 == distance * 0.5); - STATIC_REQUIRE(1 / distance == invDistance); } TEST_CASE("Vector3d mp-units - Norm Functions") @@ -103,4 +100,88 @@ TEST_CASE("Vector3d mp-units - Norm Functions") STATIC_REQUIRE(normSquared(time) == (49.0 * h * h)); REQUIRE(norm(time) == (7.0 * h)); +} + +TEST_CASE("Vector3d mp-units - Nested Vector3d Binary +") +{ + constexpr auto pos1 = Vector3d{1 * m, 2 * m, 3 * m}; + constexpr auto pos2 = Vector3d{4 * m, 5 * m, 6 * m}; + constexpr auto pos3 = Vector3d{7 * m, 8 * m, 9 * m}; + constexpr auto pos = Vector3d{pos1, pos2, pos3}; + + constexpr auto shift1 = Vector3d{10 * m, 11 * m, 12 * m}; + constexpr auto shift2 = Vector3d{13 * m, 14 * m, 15 * m}; + constexpr auto shift3 = Vector3d{16 * m, 17 * m, 18 * m}; + constexpr auto shift = Vector3d{shift1, shift2, shift3}; + + constexpr auto pos1_shifted = Vector3d{11 * m, 13 * m, 15 * m}; + constexpr auto pos2_shifted = Vector3d{17 * m, 19 * m, 21 * m}; + constexpr auto pos3_shifted = Vector3d{23 * m, 25 * m, 27 * m}; + constexpr auto pos_shifted = + Vector3d{pos1_shifted, pos2_shifted, pos3_shifted}; + + STATIC_REQUIRE(pos + shift == pos_shifted); + STATIC_REQUIRE(shift + pos == pos_shifted); +} + +TEST_CASE("Vector3d mp-units - Nested Vector3d Binary -") +{ + constexpr auto pos1 = Vector3d{10 * m, 11 * m, 12 * m}; + constexpr auto pos2 = Vector3d{13 * m, 14 * m, 15 * m}; + constexpr auto pos3 = Vector3d{16 * m, 17 * m, 18 * m}; + constexpr auto pos = Vector3d{pos1, pos2, pos3}; + + constexpr auto shift1 = Vector3d{9 * m, 8 * m, 7 * m}; + constexpr auto shift2 = Vector3d{6 * m, 5 * m, 4 * m}; + constexpr auto shift3 = Vector3d{3 * m, 2 * m, 1 * m}; + constexpr auto shift = Vector3d{shift1, shift2, shift3}; + + constexpr auto pos1_shifted = Vector3d{1 * m, 3 * m, 5 * m}; + constexpr auto pos2_shifted = Vector3d{7 * m, 9 * m, 11 * m}; + constexpr auto pos3_shifted = Vector3d{13 * m, 15 * m, 17 * m}; + constexpr auto pos_shifted = + Vector3d{pos1_shifted, pos2_shifted, pos3_shifted}; + + STATIC_REQUIRE(pos - shift == pos_shifted); +} + +TEST_CASE("Vector3d mp-units - Nested Vector3d Binary *") +{ + constexpr auto pos1 = Vector3d{1 * m, 2 * m, 3 * m}; + constexpr auto pos2 = Vector3d{4 * m, 5 * m, 6 * m}; + constexpr auto pos3 = Vector3d{7 * m, 8 * m, 9 * m}; + constexpr auto pos = Vector3d{pos1, pos2, pos3}; + + constexpr auto factor1 = Vector3d{10 * m, 11 * m, 12 * m}; + constexpr auto factor2 = Vector3d{13 * m, 14 * m, 15 * m}; + constexpr auto factor3 = Vector3d{16 * m, 17 * m, 18 * m}; + constexpr auto factor = Vector3d{factor1, factor2, factor3}; + + constexpr auto pos1_scaled = Vector3d{10 * m2, 22 * m2, 36 * m2}; + constexpr auto pos2_scaled = Vector3d{52 * m2, 70 * m2, 90 * m2}; + constexpr auto pos3_scaled = Vector3d{112 * m2, 136 * m2, 162 * m2}; + constexpr auto pos_scaled = Vector3d{pos1_scaled, pos2_scaled, pos3_scaled}; + + STATIC_REQUIRE(pos * factor == pos_scaled); + STATIC_REQUIRE(factor * pos == pos_scaled); +} + +TEST_CASE("Vector3d mp-units - Nested Vector3d Binary /") +{ + constexpr auto num1 = Vector3d{1 * m2, 4 * m2, 9 * m2}; + constexpr auto num2 = Vector3d{16 * m2, 25 * m2, 36 * m2}; + constexpr auto num3 = Vector3d{49 * m2, 64 * m2, 81 * m2}; + constexpr auto num = Vector3d{num1, num2, num3}; + + constexpr auto den1 = Vector3d{1 * m, 2 * m, 3 * m}; + constexpr auto den2 = Vector3d{4 * m, 5 * m, 6 * m}; + constexpr auto den3 = Vector3d{7 * m, 8 * m, 9 * m}; + constexpr auto den = Vector3d{den1, den2, den3}; + + constexpr auto quotient1 = Vector3d{1 * m, 2 * m, 3 * m}; + constexpr auto quotient2 = Vector3d{4 * m, 5 * m, 6 * m}; + constexpr auto quotient3 = Vector3d{7 * m, 8 * m, 9 * m}; + constexpr auto quotient = Vector3d{quotient1, quotient2, quotient3}; + + STATIC_REQUIRE(num / den == quotient); } \ No newline at end of file From 160abf6863a1cc6d3cb7200706c05d951405fd2b Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Thu, 9 Jul 2026 13:54:59 +0200 Subject: [PATCH 16/30] test: add tests for unary +/- for nested Vector3d --- test/linAlg/vector3d.cpp | 12 ++++++++++++ test/linAlg/vector3d_mp-units.cpp | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 82012c0..c86688b 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -84,6 +84,18 @@ TEST_CASE("Vector3d - Norm Functions") REQUIRE(norm(time) == (7.0)); } +TEST_CASE("Vector3d - Nested Vector3d Unary +/-") +{ + constexpr auto pos1 = Vector3d{1, 2, 3}; + constexpr auto pos2 = Vector3d{4, 5, 6}; + constexpr auto pos3 = Vector3d{7, 8, 9}; + constexpr auto pos = Vector3d{pos1, pos2, pos3}; + constexpr auto negativePos = Vector3d{-pos1, -pos2, -pos3}; + + STATIC_REQUIRE(+pos == pos); + STATIC_REQUIRE(-pos == negativePos); +} + TEST_CASE("Vector3d - Nested Vector3d Binary +") { constexpr auto pos1 = Vector3d{1, 2, 3}; diff --git a/test/linAlg/vector3d_mp-units.cpp b/test/linAlg/vector3d_mp-units.cpp index f135845..94192bd 100644 --- a/test/linAlg/vector3d_mp-units.cpp +++ b/test/linAlg/vector3d_mp-units.cpp @@ -102,6 +102,18 @@ TEST_CASE("Vector3d mp-units - Norm Functions") REQUIRE(norm(time) == (7.0 * h)); } +TEST_CASE("Vector3d mp-units - Nested Vector3d Unary +/-") +{ + constexpr auto pos1 = Vector3d{1 * m, 2 * m, 3 * m}; + constexpr auto pos2 = Vector3d{4 * m, 5 * m, 6 * m}; + constexpr auto pos3 = Vector3d{7 * m, 8 * m, 9 * m}; + constexpr auto pos = Vector3d{pos1, pos2, pos3}; + constexpr auto negativePos = Vector3d{-pos1, -pos2, -pos3}; + + STATIC_REQUIRE(+pos == pos); + STATIC_REQUIRE(-pos == negativePos); +} + TEST_CASE("Vector3d mp-units - Nested Vector3d Binary +") { constexpr auto pos1 = Vector3d{1 * m, 2 * m, 3 * m}; From fc440a1de90bfb04480f206a98eb5342f230e24d Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Thu, 9 Jul 2026 14:06:02 +0200 Subject: [PATCH 17/30] test: add tests for Vector3d indexing operator --- test/linAlg/vector3d.cpp | 33 +++++++++++++++++++++++++++++++ test/linAlg/vector3d_mp-units.cpp | 33 +++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index c86688b..c630fad 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -27,6 +27,15 @@ using namespace mstd; +TEST_CASE("Vector3d - Indexing Operator") +{ + constexpr auto distance = Vector3d{1.0, 2.0, 3.0}; + + STATIC_REQUIRE(distance[0] == 1.0); + STATIC_REQUIRE(distance[1] == 2.0); + STATIC_REQUIRE(distance[2] == 3.0); +} + TEST_CASE("Vector3d - Comparison Operators") { constexpr auto distance = Vector3d{1.0, 2.0, 3.0}; @@ -84,6 +93,30 @@ TEST_CASE("Vector3d - Norm Functions") REQUIRE(norm(time) == (7.0)); } +TEST_CASE("Vector3d - Nested Vector3d Indexing Operator") +{ + constexpr auto pos1 = Vector3d{1, 2, 3}; + constexpr auto pos2 = Vector3d{4, 5, 6}; + constexpr auto pos3 = Vector3d{7, 8, 9}; + constexpr auto pos = Vector3d{pos1, pos2, pos3}; + + STATIC_REQUIRE(pos[0] == pos1); + STATIC_REQUIRE(pos[1] == pos2); + STATIC_REQUIRE(pos[2] == pos3); + + STATIC_REQUIRE(pos[0][0] == 1); + STATIC_REQUIRE(pos[0][1] == 2); + STATIC_REQUIRE(pos[0][2] == 3); + + STATIC_REQUIRE(pos[1][0] == 4); + STATIC_REQUIRE(pos[1][1] == 5); + STATIC_REQUIRE(pos[1][2] == 6); + + STATIC_REQUIRE(pos[2][0] == 7); + STATIC_REQUIRE(pos[2][1] == 8); + STATIC_REQUIRE(pos[2][2] == 9); +} + TEST_CASE("Vector3d - Nested Vector3d Unary +/-") { constexpr auto pos1 = Vector3d{1, 2, 3}; diff --git a/test/linAlg/vector3d_mp-units.cpp b/test/linAlg/vector3d_mp-units.cpp index 94192bd..2398752 100644 --- a/test/linAlg/vector3d_mp-units.cpp +++ b/test/linAlg/vector3d_mp-units.cpp @@ -32,6 +32,15 @@ using namespace mp_units; using namespace mp_units::si::unit_symbols; using namespace mstd; +TEST_CASE("Vector3d mp-units - Indexing Operator") +{ + constexpr auto distance = Vector3d{1000 * m, 2000 * m, 3000 * m}; + + STATIC_REQUIRE(distance[0] == 1 * km); + STATIC_REQUIRE(distance[1] == 2 * km); + STATIC_REQUIRE(distance[2] == 3 * km); +} + TEST_CASE("Vector3d mp-units - Comparison Operators") { constexpr auto distance = Vector3d{1.0 * km, 2.0 * km, 3.0 * km}; @@ -102,6 +111,30 @@ TEST_CASE("Vector3d mp-units - Norm Functions") REQUIRE(norm(time) == (7.0 * h)); } +TEST_CASE("Vector3d mp-units - Nested Vector3d Indexing Operator") +{ + constexpr auto pos1 = Vector3d{1000 * m, 2000 * m, 3000 * m}; + constexpr auto pos2 = Vector3d{4000 * m, 5000 * m, 6000 * m}; + constexpr auto pos3 = Vector3d{7000 * m, 8000 * m, 9000 * m}; + constexpr auto pos = Vector3d{pos1, pos2, pos3}; + + STATIC_REQUIRE(pos[0] == pos1); + STATIC_REQUIRE(pos[1] == pos2); + STATIC_REQUIRE(pos[2] == pos3); + + STATIC_REQUIRE(pos[0][0] == 1 * km); + STATIC_REQUIRE(pos[0][1] == 2 * km); + STATIC_REQUIRE(pos[0][2] == 3 * km); + + STATIC_REQUIRE(pos[1][0] == 4 * km); + STATIC_REQUIRE(pos[1][1] == 5 * km); + STATIC_REQUIRE(pos[1][2] == 6 * km); + + STATIC_REQUIRE(pos[2][0] == 7 * km); + STATIC_REQUIRE(pos[2][1] == 8 * km); + STATIC_REQUIRE(pos[2][2] == 9 * km); +} + TEST_CASE("Vector3d mp-units - Nested Vector3d Unary +/-") { constexpr auto pos1 = Vector3d{1 * m, 2 * m, 3 * m}; From 9961138422d105619073a0566a0b45a9580bbc1b Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Thu, 9 Jul 2026 14:51:11 +0200 Subject: [PATCH 18/30] test: add tests for Vector3d constructors --- test/linAlg/vector3d.cpp | 47 ++++++++++++++++++++++++++++++- test/linAlg/vector3d_mp-units.cpp | 19 ++++++++++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index c630fad..06ebadd 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -24,16 +24,61 @@ #include #include +#include using namespace mstd; -TEST_CASE("Vector3d - Indexing Operator") +TEST_CASE("Vector3d - Default Constructor") +{ + constexpr Vector3d defaultConstructed{}; + + STATIC_REQUIRE(defaultConstructed == Vector3d{0, 0, 0}); +} + +TEST_CASE("Vector3d - Copy Constructors") +{ + constexpr Vector3d copySource{1, 2, 3}; + constexpr auto copyConstructed{copySource}; + constexpr auto copyAssigned = copyConstructed; + + STATIC_REQUIRE(copyConstructed == copySource); + STATIC_REQUIRE(copyAssigned == copySource); +} + +TEST_CASE("Vector3d - Move Constructors") +{ + constexpr Vector3d moveSource{4, 5, 6}; + constexpr auto moveConstructed{std::move(moveSource)}; + constexpr auto moveAssigned = std::move(moveConstructed); + + STATIC_REQUIRE(moveConstructed == moveSource); + STATIC_REQUIRE(moveAssigned == moveSource); +} + +TEST_CASE("Vector3d - Parametrized Constructors") +{ + constexpr auto valueConstructed = Vector3d{1, 2, 3}; + STATIC_REQUIRE(valueConstructed == Vector3d{1, 2, 3}); + + constexpr auto scalarConstructed = Vector3d{7}; + STATIC_REQUIRE(scalarConstructed == Vector3d{7, 7, 7}); +} + +TEST_CASE("Vector3d - Indexing Operators") { constexpr auto distance = Vector3d{1.0, 2.0, 3.0}; STATIC_REQUIRE(distance[0] == 1.0); STATIC_REQUIRE(distance[1] == 2.0); STATIC_REQUIRE(distance[2] == 3.0); + + auto position = Vector3d{0.0}; + + position[0] = 1.0; + position[1] = 2.0; + position[2] = 3.0; + + REQUIRE(distance == position); } TEST_CASE("Vector3d - Comparison Operators") diff --git a/test/linAlg/vector3d_mp-units.cpp b/test/linAlg/vector3d_mp-units.cpp index 2398752..7ebef77 100644 --- a/test/linAlg/vector3d_mp-units.cpp +++ b/test/linAlg/vector3d_mp-units.cpp @@ -32,13 +32,30 @@ using namespace mp_units; using namespace mp_units::si::unit_symbols; using namespace mstd; -TEST_CASE("Vector3d mp-units - Indexing Operator") +TEST_CASE("Vector3d mp-units - Parametrized Constructors") +{ + constexpr auto valueConstructed = Vector3d{1 * m, 2 * m, 3 * m}; + STATIC_REQUIRE(valueConstructed == Vector3d{1 * m, 2 * m, 3 * m}); + + constexpr auto scalarConstructed = Vector3d{7 * m}; + STATIC_REQUIRE(scalarConstructed == Vector3d{7 * m, 7 * m, 7 * m}); +} + +TEST_CASE("Vector3d mp-units - Indexing Operators") { constexpr auto distance = Vector3d{1000 * m, 2000 * m, 3000 * m}; STATIC_REQUIRE(distance[0] == 1 * km); STATIC_REQUIRE(distance[1] == 2 * km); STATIC_REQUIRE(distance[2] == 3 * km); + + auto position = Vector3d{0 * km}; + + position[0] = 1 * km; + position[1] = 2 * km; + position[2] = 3 * km; + + REQUIRE(distance == position); } TEST_CASE("Vector3d mp-units - Comparison Operators") From 05c76e6f36c40017c6f696b48deb1518393438a4 Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Thu, 9 Jul 2026 15:05:28 +0200 Subject: [PATCH 19/30] test: add tests for Vector3d ostream << operator --- include/mstd/linAlg/vector3d.hpp | 8 ++++---- include/mstd/linAlg/vector3d.tpp | 8 ++++---- test/linAlg/vector3d.cpp | 13 ++++++++++++- test/linAlg/vector3d_mp-units.cpp | 12 +++++++++++- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index 2c6d6a2..1aec0cd 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -168,11 +168,11 @@ namespace mstd * ostream << * **************/ - template - requires requires(std::ostream &os, const U &vector) { - { os << vector[0] } -> std::same_as; + template + requires requires(std::ostream &os, const U &u) { + { os << u } -> std::same_as; } - std::ostream &operator<<(std::ostream &os, const U &vector); + std::ostream &operator<<(std::ostream &os, const Vector3d &vector); } // namespace mstd diff --git a/include/mstd/linAlg/vector3d.tpp b/include/mstd/linAlg/vector3d.tpp index 4a3570f..20027fa 100644 --- a/include/mstd/linAlg/vector3d.tpp +++ b/include/mstd/linAlg/vector3d.tpp @@ -259,11 +259,11 @@ namespace mstd * ostream << * **************/ - template - requires requires(std::ostream &os, const U &vector) { - { os << vector[0] } -> std::same_as; + template + requires requires(std::ostream &os, const U &u) { + { os << u } -> std::same_as; } - std::ostream &operator<<(std::ostream &os, const U &vector) + std::ostream &operator<<(std::ostream &os, const Vector3d &vector) { return os << vector[0] << " " << vector[1] << " " << vector[2]; } diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 06ebadd..7a560a6 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -24,6 +24,7 @@ #include #include +#include #include using namespace mstd; @@ -138,6 +139,16 @@ TEST_CASE("Vector3d - Norm Functions") REQUIRE(norm(time) == (7.0)); } +TEST_CASE("Vector3d - ostream <<") +{ + constexpr auto distance = Vector3d{1, 2, 3}; + + std::ostringstream oss; + oss << distance; + + REQUIRE(oss.str() == "1 2 3"); +} + TEST_CASE("Vector3d - Nested Vector3d Indexing Operator") { constexpr auto pos1 = Vector3d{1, 2, 3}; @@ -256,4 +267,4 @@ TEST_CASE("Vector3d - Nested Vector3d Binary /") constexpr auto quotient = Vector3d{quotient1, quotient2, quotient3}; STATIC_REQUIRE(num / den == quotient); -} \ No newline at end of file +} diff --git a/test/linAlg/vector3d_mp-units.cpp b/test/linAlg/vector3d_mp-units.cpp index 7ebef77..0895921 100644 --- a/test/linAlg/vector3d_mp-units.cpp +++ b/test/linAlg/vector3d_mp-units.cpp @@ -128,6 +128,16 @@ TEST_CASE("Vector3d mp-units - Norm Functions") REQUIRE(norm(time) == (7.0 * h)); } +TEST_CASE("Vector3d mp-units - ostream <<") +{ + constexpr auto distance = Vector3d{1 * km, 2 * km, 3 * km}; + + std::ostringstream oss; + oss << distance; + + REQUIRE(oss.str() == "1 km 2 km 3 km"); +} + TEST_CASE("Vector3d mp-units - Nested Vector3d Indexing Operator") { constexpr auto pos1 = Vector3d{1000 * m, 2000 * m, 3000 * m}; @@ -246,4 +256,4 @@ TEST_CASE("Vector3d mp-units - Nested Vector3d Binary /") constexpr auto quotient = Vector3d{quotient1, quotient2, quotient3}; STATIC_REQUIRE(num / den == quotient); -} \ No newline at end of file +} From 0487c12640843dadf1e42cd0dc8de2dd5bf8b18c Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Thu, 9 Jul 2026 15:13:17 +0200 Subject: [PATCH 20/30] refactor: update requires expression for Vector3d norm function --- include/mstd/linAlg/vector3d.hpp | 10 ++++------ include/mstd/linAlg/vector3d.tpp | 10 ++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index 1aec0cd..e56ebd5 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -157,12 +157,10 @@ namespace mstd [[nodiscard]] auto norm(const U &vec) -> decltype(mp_units::sqrt(normSquared(vec))); - template - requires requires(const U &vec) { - vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]; - } - [[nodiscard]] constexpr auto normSquared(const U &vec) - -> decltype(vec[0] * vec[0]); + template + requires requires(const U &u) { u * u + u * u; } + [[nodiscard]] constexpr auto normSquared(const Vector3d &vec) + -> decltype(std::declval() * std::declval()); /************** * ostream << * diff --git a/include/mstd/linAlg/vector3d.tpp b/include/mstd/linAlg/vector3d.tpp index 20027fa..abe8ece 100644 --- a/include/mstd/linAlg/vector3d.tpp +++ b/include/mstd/linAlg/vector3d.tpp @@ -245,12 +245,10 @@ namespace mstd return mp_units::sqrt(normSquared(vec)); } - template - requires requires(const U &vec) { - vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]; - } - [[nodiscard]] constexpr auto normSquared(const U &vec) - -> decltype(vec[0] * vec[0]) + template + requires requires(const U &u) { u * u + u * u; } + [[nodiscard]] constexpr auto normSquared(const Vector3d &vec) + -> decltype(std::declval() * std::declval()) { return vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]; } From 3d686cfb219e4e650b9035860857007722996abf Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Thu, 6 Aug 2026 11:46:44 +0200 Subject: [PATCH 21/30] style: remove redundant IWYU pragma --- include/mstd/linAlg/vector3d.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index e56ebd5..b0fbcb4 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -31,7 +31,7 @@ #include #include "concepts/vector3dConcepts.hpp" -#include "vector3dClass.hpp" // IWYU pragma: export +#include "vector3dClass.hpp" namespace mstd { From dfce8e4f98416f850f7958dd8b9208e43d44f67b Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Thu, 6 Aug 2026 11:52:22 +0200 Subject: [PATCH 22/30] fix: cppcheck warning about unitialized member variable in Vector3d class --- include/mstd/linAlg/vector3dClass.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mstd/linAlg/vector3dClass.hpp b/include/mstd/linAlg/vector3dClass.hpp index 5fd3d0a..aa7448f 100644 --- a/include/mstd/linAlg/vector3dClass.hpp +++ b/include/mstd/linAlg/vector3dClass.hpp @@ -31,7 +31,7 @@ namespace mstd class Vector3d { private: - std::array _xyz; + std::array _xyz{}; public: // clang-format off From 049414663611b43c06fb51373f4d36a52575d471 Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Thu, 6 Aug 2026 13:26:14 +0200 Subject: [PATCH 23/30] style: remove "noexcept" qualifiers from Vector3d class functions --- include/mstd/linAlg/vector3d.hpp | 4 ++-- include/mstd/linAlg/vector3d.tpp | 10 ++-------- include/mstd/linAlg/vector3dClass.hpp | 20 ++++++++++---------- include/mstd/linAlg/vector3dClass.tpp | 4 ++-- 4 files changed, 16 insertions(+), 22 deletions(-) diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index b0fbcb4..689d1e2 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -44,14 +44,14 @@ namespace mstd [[nodiscard]] constexpr bool operator==( const Vector3d &lhs, const Vector3d &rhs - ) noexcept; + ); template requires std::equality_comparable_with [[nodiscard]] constexpr bool operator!=( const Vector3d &lhs, const Vector3d &rhs - ) noexcept; + ); /********************* * binary + operator * diff --git a/include/mstd/linAlg/vector3d.tpp b/include/mstd/linAlg/vector3d.tpp index abe8ece..f4dcbf8 100644 --- a/include/mstd/linAlg/vector3d.tpp +++ b/include/mstd/linAlg/vector3d.tpp @@ -39,20 +39,14 @@ namespace mstd template requires std::equality_comparable_with - constexpr bool operator==( - const Vector3d &lhs, - const Vector3d &rhs - ) noexcept + constexpr bool operator==(const Vector3d &lhs, const Vector3d &rhs) { return lhs[0] == rhs[0] && lhs[1] == rhs[1] && lhs[2] == rhs[2]; } template requires std::equality_comparable_with - constexpr bool operator!=( - const Vector3d &lhs, - const Vector3d &rhs - ) noexcept + constexpr bool operator!=(const Vector3d &lhs, const Vector3d &rhs) { return !(lhs == rhs); } diff --git a/include/mstd/linAlg/vector3dClass.hpp b/include/mstd/linAlg/vector3dClass.hpp index aa7448f..167466f 100644 --- a/include/mstd/linAlg/vector3dClass.hpp +++ b/include/mstd/linAlg/vector3dClass.hpp @@ -35,15 +35,15 @@ namespace mstd public: // clang-format off - [[nodiscard]] constexpr Vector3d() noexcept = default; - constexpr ~Vector3d() noexcept = default; - [[nodiscard]] constexpr Vector3d(const Vector3d &) noexcept = default; - constexpr Vector3d &operator=(const Vector3d &) noexcept = default; - [[nodiscard]] constexpr Vector3d(Vector3d &&) noexcept = default; - constexpr Vector3d &operator=(Vector3d &&) noexcept = default; + [[nodiscard]] constexpr Vector3d() = default; + constexpr ~Vector3d() = default; + [[nodiscard]] constexpr Vector3d(const Vector3d &) = default; + constexpr Vector3d &operator=(const Vector3d &) = default; + [[nodiscard]] constexpr Vector3d(Vector3d &&) = default; + constexpr Vector3d &operator=(Vector3d &&) = default; - [[nodiscard]] constexpr explicit Vector3d(const T &xyz) noexcept : _xyz{xyz, xyz, xyz} {} - [[nodiscard]] constexpr Vector3d(const T &x, const T &y, const T &z) noexcept : _xyz{x, y, z} {} + [[nodiscard]] constexpr explicit Vector3d(const T &xyz) : _xyz{xyz, xyz, xyz} {} + [[nodiscard]] constexpr Vector3d(const T &x, const T &y, const T &z) : _xyz{x, y, z} {} // clang-format on using value_type = T; @@ -85,9 +85,9 @@ namespace mstd * indexing operators * **********************/ - constexpr T &operator[](const std::size_t index) noexcept; + constexpr T &operator[](const std::size_t index); [[nodiscard]] constexpr const T &operator[](const std::size_t index - ) const noexcept; + ) const; }; } // namespace mstd diff --git a/include/mstd/linAlg/vector3dClass.tpp b/include/mstd/linAlg/vector3dClass.tpp index 7deb4dd..c95a229 100644 --- a/include/mstd/linAlg/vector3dClass.tpp +++ b/include/mstd/linAlg/vector3dClass.tpp @@ -118,14 +118,14 @@ namespace mstd **********************/ template - constexpr T &Vector3d::operator[](const std::size_t index) noexcept + constexpr T &Vector3d::operator[](const std::size_t index) { return _xyz[index]; } template constexpr const T &Vector3d::operator[](const std::size_t index - ) const noexcept + ) const { return _xyz[index]; } From fa08e0edc38d763eca2c7768ce40be0485c78330 Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Thu, 6 Aug 2026 16:18:47 +0200 Subject: [PATCH 24/30] feat: add Vector3d += and -= operators --- include/mstd/linAlg/vector3dClass.hpp | 24 +++++++++++ include/mstd/linAlg/vector3dClass.tpp | 60 ++++++++++++++++++++++++++- test/linAlg/vector3d.cpp | 13 ++++++ 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/include/mstd/linAlg/vector3dClass.hpp b/include/mstd/linAlg/vector3dClass.hpp index 167466f..8494bde 100644 --- a/include/mstd/linAlg/vector3dClass.hpp +++ b/include/mstd/linAlg/vector3dClass.hpp @@ -25,6 +25,8 @@ #include // for std::array +#include "concepts/vector3dConcepts.hpp" + namespace mstd { template @@ -55,6 +57,28 @@ namespace mstd [[nodiscard]] constexpr Vector3d operator+() const; [[nodiscard]] constexpr Vector3d operator-() const; + /********************************* + * compound assignment operators * + *********************************/ + + template + requires requires(T &t, const U &u) { t += u; } && + (Vector3dDepthDifference_v == 0) + constexpr Vector3d &operator+=(const Vector3d &rhs); + + template + requires requires(T &t, const U &u) { t += u; } + constexpr Vector3d &operator+=(const U &rhs); + + template + requires requires(T &t, const U &u) { t -= u; } && + (Vector3dDepthDifference_v == 0) + constexpr Vector3d &operator-=(const Vector3d &rhs); + + template + requires requires(T &t, const U &u) { t -= u; } + constexpr Vector3d &operator-=(const U &rhs); + /******************** * unit conversions * ********************/ diff --git a/include/mstd/linAlg/vector3dClass.tpp b/include/mstd/linAlg/vector3dClass.tpp index c95a229..4cfd871 100644 --- a/include/mstd/linAlg/vector3dClass.tpp +++ b/include/mstd/linAlg/vector3dClass.tpp @@ -25,6 +25,7 @@ #include // for std::declval +#include "concepts/vector3dConcepts.hpp" #include "vector3dClass.hpp" namespace mstd @@ -47,6 +48,62 @@ namespace mstd return Vector3d{-_xyz[0], -_xyz[1], -_xyz[2]}; } + /********************************* + * * + * compound assignment operators * + * * + *********************************/ + + template + template + requires requires(T &t, const U &u) { t += u; } && + (Vector3dDepthDifference_v == 0) + constexpr Vector3d &Vector3d::operator+=(const Vector3d &rhs) + { + _xyz[0] += rhs[0]; + _xyz[1] += rhs[1]; + _xyz[2] += rhs[2]; + + return *this; + } + + template + template + requires requires(T &t, const U &u) { t += u; } + constexpr Vector3d &Vector3d::operator+=(const U &rhs) + { + _xyz[0] += rhs; + _xyz[1] += rhs; + _xyz[2] += rhs; + + return *this; + } + + template + template + requires requires(T &t, const U &u) { t -= u; } && + (Vector3dDepthDifference_v == 0) + constexpr Vector3d &Vector3d::operator-=(const Vector3d &rhs) + { + _xyz[0] -= rhs[0]; + _xyz[1] -= rhs[1]; + _xyz[2] -= rhs[2]; + + return *this; + } + + template + template + requires requires(T &t, const U &u) { t -= u; } + constexpr Vector3d &Vector3d::operator-=(const U &rhs) + { + _xyz[0] -= rhs; + _xyz[1] -= rhs; + _xyz[2] -= rhs; + + return *this; + } + /******************* * unit conversion * *******************/ @@ -124,8 +181,7 @@ namespace mstd } template - constexpr const T &Vector3d::operator[](const std::size_t index - ) const + constexpr const T &Vector3d::operator[](const std::size_t index) const { return _xyz[index]; } diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 7a560a6..74b6f5f 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -102,6 +102,19 @@ TEST_CASE("Vector3d - Unary +/- Operators") STATIC_REQUIRE(-distance == negativeDistance); } +TEST_CASE("Vector3d - Compound Assignment Operators") +{ + auto distance = Vector3d{1.0, 2.0, 3.0}; + constexpr auto anotherDistance = Vector3d{5.0, 5.0, 5.0}; + constexpr auto scalarDistance = 5.0; + constexpr auto distanceSum = Vector3d{6.0, 7.0, 8.0}; + + REQUIRE((distance += anotherDistance) == distanceSum); + REQUIRE((distance -= anotherDistance) == distance); + REQUIRE((distance += scalarDistance) == distanceSum); + REQUIRE((distance -= scalarDistance) == distance); +} + TEST_CASE("Vector3d - Binary + and - Operators") { constexpr auto distance = Vector3d{1.0, 2.0, 3.0}; From a8703d051bde586d7d32d2fab8bb7c7d016252ee Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Thu, 6 Aug 2026 16:28:55 +0200 Subject: [PATCH 25/30] test: add tests for += and -= Vector3d with mp-units --- test/linAlg/vector3d_mp-units.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/linAlg/vector3d_mp-units.cpp b/test/linAlg/vector3d_mp-units.cpp index 0895921..73fdc65 100644 --- a/test/linAlg/vector3d_mp-units.cpp +++ b/test/linAlg/vector3d_mp-units.cpp @@ -91,6 +91,19 @@ TEST_CASE("Vector3d mp-units - Unary +/- Operators") STATIC_REQUIRE(-distance == negativeDistance); } +TEST_CASE("Vector3d mp-units - Compound Assignment Operators") +{ + auto distance = Vector3d{1.0 * km, 2.0 * km, 3.0 * km}; + constexpr auto anotherDistance = Vector3d{5000.0 * m}; + constexpr auto scalarDistance = 5000.0 * m; + constexpr auto distanceSum = Vector3d{6.0 * km, 7.0 * km, 8.0 * km}; + + REQUIRE((distance += anotherDistance) == distanceSum); + REQUIRE((distance -= anotherDistance) == distance); + REQUIRE((distance += scalarDistance) == distanceSum); + REQUIRE((distance -= scalarDistance) == distance); +} + TEST_CASE("Vector3d mp-units - Binary + and - Operators") { constexpr auto distance = Vector3d{1.0 * km, 2.0 * km, 3.0 * km}; From 65b18cfb2cf1e879cd07b54c233185860131ea17 Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Thu, 6 Aug 2026 16:45:03 +0200 Subject: [PATCH 26/30] feat: add Vector3d *= and /= operators --- include/mstd/linAlg/vector3dClass.hpp | 18 ++++++++++ include/mstd/linAlg/vector3dClass.tpp | 50 +++++++++++++++++++++++++++ test/linAlg/vector3d.cpp | 6 ++++ 3 files changed, 74 insertions(+) diff --git a/include/mstd/linAlg/vector3dClass.hpp b/include/mstd/linAlg/vector3dClass.hpp index 8494bde..bea0a96 100644 --- a/include/mstd/linAlg/vector3dClass.hpp +++ b/include/mstd/linAlg/vector3dClass.hpp @@ -79,6 +79,24 @@ namespace mstd requires requires(T &t, const U &u) { t -= u; } constexpr Vector3d &operator-=(const U &rhs); + template + requires requires(T &t, const U &u) { t *= u; } && + (Vector3dDepthDifference_v == 0) + constexpr Vector3d &operator*=(const Vector3d &rhs); + + template + requires requires(T &t, const U &u) { t *= u; } + constexpr Vector3d &operator*=(const U &rhs); + + template + requires requires(T &t, const U &u) { t /= u; } && + (Vector3dDepthDifference_v == 0) + constexpr Vector3d &operator/=(const Vector3d &rhs); + + template + requires requires(T &t, const U &u) { t /= u; } + constexpr Vector3d &operator/=(const U &rhs); + /******************** * unit conversions * ********************/ diff --git a/include/mstd/linAlg/vector3dClass.tpp b/include/mstd/linAlg/vector3dClass.tpp index 4cfd871..120e432 100644 --- a/include/mstd/linAlg/vector3dClass.tpp +++ b/include/mstd/linAlg/vector3dClass.tpp @@ -104,6 +104,56 @@ namespace mstd return *this; } + template + template + requires requires(T &t, const U &u) { t *= u; } && + (Vector3dDepthDifference_v == 0) + constexpr Vector3d &Vector3d::operator*=(const Vector3d &rhs) + { + _xyz[0] *= rhs[0]; + _xyz[1] *= rhs[1]; + _xyz[2] *= rhs[2]; + + return *this; + } + + template + template + requires requires(T &t, const U &u) { t *= u; } + constexpr Vector3d &Vector3d::operator*=(const U &rhs) + { + _xyz[0] *= rhs; + _xyz[1] *= rhs; + _xyz[2] *= rhs; + + return *this; + } + + template + template + requires requires(T &t, const U &u) { t /= u; } && + (Vector3dDepthDifference_v == 0) + constexpr Vector3d &Vector3d::operator/=(const Vector3d &rhs) + { + _xyz[0] /= rhs[0]; + _xyz[1] /= rhs[1]; + _xyz[2] /= rhs[2]; + + return *this; + } + + template + template + requires requires(T &t, const U &u) { t /= u; } + constexpr Vector3d &Vector3d::operator/=(const U &rhs) + { + _xyz[0] /= rhs; + _xyz[1] /= rhs; + _xyz[2] /= rhs; + + return *this; + } + /******************* * unit conversion * *******************/ diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 74b6f5f..9fe32a8 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -108,11 +108,17 @@ TEST_CASE("Vector3d - Compound Assignment Operators") constexpr auto anotherDistance = Vector3d{5.0, 5.0, 5.0}; constexpr auto scalarDistance = 5.0; constexpr auto distanceSum = Vector3d{6.0, 7.0, 8.0}; + constexpr auto distanceProduct = Vector3d{5.0, 10.0, 15.0}; REQUIRE((distance += anotherDistance) == distanceSum); REQUIRE((distance -= anotherDistance) == distance); REQUIRE((distance += scalarDistance) == distanceSum); REQUIRE((distance -= scalarDistance) == distance); + + REQUIRE((distance *= anotherDistance) == distanceProduct); + REQUIRE((distance /= anotherDistance) == distance); + REQUIRE((distance *= scalarDistance) == distanceProduct); + REQUIRE((distance /= scalarDistance) == distance); } TEST_CASE("Vector3d - Binary + and - Operators") From 27eaaebdbc5e9b6d3a7366e8b677625cbcd9e9f8 Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Fri, 7 Aug 2026 11:50:35 +0200 Subject: [PATCH 27/30] feat: add Vector3d static_cast --- include/mstd/linAlg/vector3dClass.hpp | 8 ++++++++ include/mstd/linAlg/vector3dClass.tpp | 18 ++++++++++++++++++ test/linAlg/vector3d.cpp | 10 ++++++++++ 3 files changed, 36 insertions(+) diff --git a/include/mstd/linAlg/vector3dClass.hpp b/include/mstd/linAlg/vector3dClass.hpp index bea0a96..083435f 100644 --- a/include/mstd/linAlg/vector3dClass.hpp +++ b/include/mstd/linAlg/vector3dClass.hpp @@ -130,6 +130,14 @@ namespace mstd constexpr T &operator[](const std::size_t index); [[nodiscard]] constexpr const T &operator[](const std::size_t index ) const; + + /*********** + * casting * + ***********/ + + template + requires requires(const T &value) { static_cast(value); } + constexpr operator Vector3d() const; }; } // namespace mstd diff --git a/include/mstd/linAlg/vector3dClass.tpp b/include/mstd/linAlg/vector3dClass.tpp index 120e432..623d796 100644 --- a/include/mstd/linAlg/vector3dClass.tpp +++ b/include/mstd/linAlg/vector3dClass.tpp @@ -236,6 +236,24 @@ namespace mstd return _xyz[index]; } + /*********** + * * + * casting * + * * + ***********/ + + template + template + requires requires(const T &value) { static_cast(value); } + constexpr Vector3d::operator Vector3d() const + { + return Vector3d{ + static_cast(_xyz[0]), + static_cast(_xyz[1]), + static_cast(_xyz[2]), + }; + } + } // namespace mstd #endif // __MSTD__LINALG__VECTOR3DCLASS_TPP__ diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 9fe32a8..021c8e9 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -121,6 +121,16 @@ TEST_CASE("Vector3d - Compound Assignment Operators") REQUIRE((distance /= scalarDistance) == distance); } +TEST_CASE("Vector3d - Static Cast") +{ + constexpr auto distance = Vector3d{1.1, 2.2, 3.3}; + constexpr auto distanceInt = Vector3d{1, 2, 3}; + constexpr auto distanceCasted = static_cast>(distance); + + STATIC_REQUIRE(distance != distanceInt); + STATIC_REQUIRE(distanceCasted == distanceInt); +} + TEST_CASE("Vector3d - Binary + and - Operators") { constexpr auto distance = Vector3d{1.0, 2.0, 3.0}; From 7747ef1549bd48591fc63c2cdb1d7da2e7d4ce94 Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Fri, 7 Aug 2026 15:19:30 +0200 Subject: [PATCH 28/30] feat: add Vector3d dot and cross product functions --- include/mstd/linAlg/vector3d.hpp | 22 +++++++++++++++++++ include/mstd/linAlg/vector3d.tpp | 35 +++++++++++++++++++++++++++++++ test/linAlg/vector3d.cpp | 10 +++++++++ test/linAlg/vector3d_mp-units.cpp | 10 +++++++++ 4 files changed, 77 insertions(+) diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index 689d1e2..4df8200 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -162,6 +162,28 @@ namespace mstd [[nodiscard]] constexpr auto normSquared(const Vector3d &vec) -> decltype(std::declval() * std::declval()); + /********************* + * product functions * + *********************/ + + template + requires requires(const U &u, const V &v) { u * v + u * v; } && + (Vector3dDepthDifference_v == 0) + [[nodiscard]] constexpr auto dot( + const Vector3d &lhs, + const Vector3d &rhs + ) -> decltype(std::declval() * std::declval() + std::declval() * std::declval()); + + template + requires requires(const U &u, const V &v) { u * v - u * v; } && + (Vector3dDepthDifference_v == 0) + [[nodiscard]] constexpr auto cross( + const Vector3d &lhs, + const Vector3d &rhs + ) + -> Vector3d< + decltype(std::declval() * std::declval() - std::declval() * std::declval())>; + /************** * ostream << * **************/ diff --git a/include/mstd/linAlg/vector3d.tpp b/include/mstd/linAlg/vector3d.tpp index f4dcbf8..cec5ddf 100644 --- a/include/mstd/linAlg/vector3d.tpp +++ b/include/mstd/linAlg/vector3d.tpp @@ -247,6 +247,41 @@ namespace mstd return vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]; } + /********************* + * product functions * + *********************/ + + template + requires requires(const U &u, const V &v) { u * v + u * v; } && + (Vector3dDepthDifference_v == 0) + [[nodiscard]] constexpr auto dot( + const Vector3d &lhs, + const Vector3d &rhs + ) -> decltype(std::declval() * std::declval() + std::declval() * std::declval()) + { + return lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2]; + } + + template + requires requires(const U &u, const V &v) { u * v - u * v; } && + (Vector3dDepthDifference_v == 0) + [[nodiscard]] constexpr auto cross( + const Vector3d &lhs, + const Vector3d &rhs + ) + -> Vector3d< + decltype(std::declval() * std::declval() - std::declval() * std::declval())> + { + using ResultType = + decltype(std::declval() * std::declval() - std::declval() * std::declval()); + return Vector3d( + lhs[1] * rhs[2] - lhs[2] * rhs[1], + lhs[2] * rhs[0] - lhs[0] * rhs[2], + lhs[0] * rhs[1] - lhs[1] * rhs[0] + + ); + } + /************** * ostream << * **************/ diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 021c8e9..9a7ed2c 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -168,6 +168,16 @@ TEST_CASE("Vector3d - Norm Functions") REQUIRE(norm(time) == (7.0)); } +TEST_CASE("Vector3d - Product Functions") +{ + constexpr auto length1 = Vector3d{1.0, 2.0, 3.0}; + constexpr auto length2 = Vector3d{4.0, 5.0, 6.0}; + constexpr auto length3 = Vector3d{-3.0, 6.0, -3.0}; + + STATIC_REQUIRE(dot(length1, length2) == (32.0)); + STATIC_REQUIRE(cross(length1, length2) == length3); +} + TEST_CASE("Vector3d - ostream <<") { constexpr auto distance = Vector3d{1, 2, 3}; diff --git a/test/linAlg/vector3d_mp-units.cpp b/test/linAlg/vector3d_mp-units.cpp index 73fdc65..95a0247 100644 --- a/test/linAlg/vector3d_mp-units.cpp +++ b/test/linAlg/vector3d_mp-units.cpp @@ -141,6 +141,16 @@ TEST_CASE("Vector3d mp-units - Norm Functions") REQUIRE(norm(time) == (7.0 * h)); } +TEST_CASE("Vector3d mp-units - Product Functions") +{ + constexpr auto length1 = Vector3d{1.0 * m, 2.0 * m, 3.0 * m}; + constexpr auto length2 = Vector3d{4.0 * m, 5.0 * m, 6.0 * m}; + constexpr auto length3 = Vector3d{-3.0 * m2, 6.0 * m2, -3.0 * m2}; + + STATIC_REQUIRE(dot(length1, length2) == (32.0 * m2)); + STATIC_REQUIRE(cross(length1, length2) == length3); +} + TEST_CASE("Vector3d mp-units - ostream <<") { constexpr auto distance = Vector3d{1 * km, 2 * km, 3 * km}; From cd7ba034afa0bcf6fbe67946cc5c079b69cb1a9c Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Fri, 7 Aug 2026 15:48:16 +0200 Subject: [PATCH 29/30] feat: add Vector3d normalize function --- include/mstd/linAlg/vector3d.hpp | 11 ++++++++--- include/mstd/linAlg/vector3d.tpp | 25 +++++++++++++++++++++---- test/linAlg/vector3d.cpp | 7 ++++--- test/linAlg/vector3d_mp-units.cpp | 7 ++++--- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index 4df8200..d95e412 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -147,6 +147,11 @@ namespace mstd * norm functions * ******************/ + template + requires requires(const U &u) { u * u + u * u; } + [[nodiscard]] constexpr auto normSquared(const Vector3d &vec) + -> decltype(std::declval() * std::declval()); + template requires requires(const U &vec) { std::sqrt(normSquared(vec)); } [[nodiscard]] auto norm(const U &vec) @@ -158,9 +163,9 @@ namespace mstd -> decltype(mp_units::sqrt(normSquared(vec))); template - requires requires(const U &u) { u * u + u * u; } - [[nodiscard]] constexpr auto normSquared(const Vector3d &vec) - -> decltype(std::declval() * std::declval()); + requires requires(const Vector3d &vec) { vec[0] / norm(vec); } + [[nodiscard]] constexpr auto normalize(const Vector3d &vec) -> Vector3d< + decltype(std::declval() / norm(std::declval &>()))>; /********************* * product functions * diff --git a/include/mstd/linAlg/vector3d.tpp b/include/mstd/linAlg/vector3d.tpp index cec5ddf..d2d7011 100644 --- a/include/mstd/linAlg/vector3d.tpp +++ b/include/mstd/linAlg/vector3d.tpp @@ -223,6 +223,14 @@ namespace mstd * norm functions * ******************/ + template + requires requires(const U &u) { u * u + u * u; } + [[nodiscard]] constexpr auto normSquared(const Vector3d &vec) + -> decltype(std::declval() * std::declval()) + { + return vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]; + } + template requires requires(const U &vec) { std::sqrt(normSquared(vec)); } [[nodiscard]] auto norm(const U &vec) @@ -240,11 +248,20 @@ namespace mstd } template - requires requires(const U &u) { u * u + u * u; } - [[nodiscard]] constexpr auto normSquared(const Vector3d &vec) - -> decltype(std::declval() * std::declval()) + requires requires(const Vector3d &vec) { vec[0] / norm(vec); } + [[nodiscard]] constexpr auto normalize(const Vector3d &vec) -> Vector3d< + decltype(std::declval() / norm(std::declval &>()))> { - return vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]; + using ResultType = + decltype(std::declval() / norm(std::declval &>())); + + const auto normValue = norm(vec); + + return Vector3d( + vec[0] / normValue, + vec[1] / normValue, + vec[2] / normValue + ); } /********************* diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 9a7ed2c..82cda3a 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -162,10 +162,11 @@ TEST_CASE("Vector3d - Binary * and / Operators") TEST_CASE("Vector3d - Norm Functions") { - constexpr auto time = Vector3d{2.0, 3.0, 6.0}; + constexpr auto time = Vector3d{3.0, 4.0, 0.0}; - STATIC_REQUIRE(normSquared(time) == (49.0)); - REQUIRE(norm(time) == (7.0)); + STATIC_REQUIRE(normSquared(time) == (25.0)); + REQUIRE(norm(time) == (5.0)); + REQUIRE(normalize(time) == Vector3d{0.6, 0.8, 0.0}); } TEST_CASE("Vector3d - Product Functions") diff --git a/test/linAlg/vector3d_mp-units.cpp b/test/linAlg/vector3d_mp-units.cpp index 95a0247..fdc7cb9 100644 --- a/test/linAlg/vector3d_mp-units.cpp +++ b/test/linAlg/vector3d_mp-units.cpp @@ -135,10 +135,11 @@ TEST_CASE("Vector3d mp-units - Binary * and / Operators") TEST_CASE("Vector3d mp-units - Norm Functions") { - constexpr auto time = Vector3d{2.0 * h, 3.0 * h, 6.0 * h}; + constexpr auto time = Vector3d{3.0 * h, 4.0 * h, 0.0 * h}; - STATIC_REQUIRE(normSquared(time) == (49.0 * h * h)); - REQUIRE(norm(time) == (7.0 * h)); + STATIC_REQUIRE(normSquared(time) == (25.0 * h * h)); + REQUIRE(norm(time) == (5.0 * h)); + REQUIRE(normalize(time) == Vector3d{0.6, 0.8, 0.0}); } TEST_CASE("Vector3d mp-units - Product Functions") From 3829e42d9137a0981afb70cd015035b908fb202c Mon Sep 17 00:00:00 2001 From: Armin Penz Date: Fri, 7 Aug 2026 16:07:21 +0200 Subject: [PATCH 30/30] feat: add Vector3d normalize in-place function --- include/mstd/linAlg/vector3d.hpp | 6 +++++- include/mstd/linAlg/vector3d.tpp | 9 ++++++++- test/linAlg/vector3d.cpp | 5 ++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/include/mstd/linAlg/vector3d.hpp b/include/mstd/linAlg/vector3d.hpp index d95e412..51ff12c 100644 --- a/include/mstd/linAlg/vector3d.hpp +++ b/include/mstd/linAlg/vector3d.hpp @@ -164,9 +164,13 @@ namespace mstd template requires requires(const Vector3d &vec) { vec[0] / norm(vec); } - [[nodiscard]] constexpr auto normalize(const Vector3d &vec) -> Vector3d< + [[nodiscard]] auto normalize(const Vector3d &vec) -> Vector3d< decltype(std::declval() / norm(std::declval &>()))>; + template + requires requires(Vector3d &vec) { vec /= norm(vec); } + void normalize(Vector3d &vec); + /********************* * product functions * *********************/ diff --git a/include/mstd/linAlg/vector3d.tpp b/include/mstd/linAlg/vector3d.tpp index d2d7011..7a85510 100644 --- a/include/mstd/linAlg/vector3d.tpp +++ b/include/mstd/linAlg/vector3d.tpp @@ -249,7 +249,7 @@ namespace mstd template requires requires(const Vector3d &vec) { vec[0] / norm(vec); } - [[nodiscard]] constexpr auto normalize(const Vector3d &vec) -> Vector3d< + [[nodiscard]] auto normalize(const Vector3d &vec) -> Vector3d< decltype(std::declval() / norm(std::declval &>()))> { using ResultType = @@ -264,6 +264,13 @@ namespace mstd ); } + template + requires requires(Vector3d &vec) { vec /= norm(vec); } + void normalize(Vector3d &vec) + { + vec /= norm(vec); + } + /********************* * product functions * *********************/ diff --git a/test/linAlg/vector3d.cpp b/test/linAlg/vector3d.cpp index 82cda3a..f299da4 100644 --- a/test/linAlg/vector3d.cpp +++ b/test/linAlg/vector3d.cpp @@ -162,11 +162,14 @@ TEST_CASE("Vector3d - Binary * and / Operators") TEST_CASE("Vector3d - Norm Functions") { - constexpr auto time = Vector3d{3.0, 4.0, 0.0}; + constexpr auto time = Vector3d{3.0, 4.0, 0.0}; + auto distance = Vector3d{3.0, 4.0, 0.0}; STATIC_REQUIRE(normSquared(time) == (25.0)); REQUIRE(norm(time) == (5.0)); REQUIRE(normalize(time) == Vector3d{0.6, 0.8, 0.0}); + normalize(distance); + REQUIRE(distance == Vector3d{0.6, 0.8, 0.0}); } TEST_CASE("Vector3d - Product Functions")