diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 20707ca..b34c4f8 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -17,10 +17,14 @@ jobs: with: submodules: recursive + - uses: actions/setup-python@v5 + with: + python-version: 3.13 + cache: 'pip' + - name: Install cppcheck run: | - sudo apt update - sudo apt install -y cppcheck + pip install --break-system-packages cppcheck - name: Run cppcheck run: | @@ -57,4 +61,4 @@ jobs: - name: Install clang-tidy and dependencies run: | - cpp_checks --dirs include --dirs test \ No newline at end of file + cpp_checks --dirs include --dirs test diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..a9f3f2e --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,109 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Cppcheck", + "type": "shell", + "command": "cppcheck", + "args": [ + "--enable=all", + "--enable=performance", + "--enable=style", + "--enable=information", + "--enable=portability", + "--error-exitcode=1", + "--suppressions-list=.cppcheck.suppress", + "--suppress=missingIncludeSystem", + "--inline-suppr", + "--inconclusive", + "--std=c++23", + "-I", + "include", + "include", + "test" + ], + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": { + "owner": "cppcheck", + "fileLocation": [ + "relative", + "${workspaceFolder}" + ], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error|style|performance|portability|information):\\s+(.*)\\s+\\[(\\w+)\\]$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5, + "code": 6 + } + }, + "group": "build", + "presentation": { + "reveal": "always", + "panel": "dedicated", + "clear": true + } + }, + { + "label": "Clang-Tidy (cpp_checks)", + "type": "shell", + "command": "cpp_checks", + "args": [ + "--dirs", + "include", + "--dirs", + "test" + ], + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": { + "owner": "clang-tidy", + "fileLocation": [ + "relative", + "${workspaceFolder}" + ], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)\\s+\\[([\\w,-]+)\\]$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5, + "code": 6 + } + }, + "group": "build", + "presentation": { + "reveal": "always", + "panel": "dedicated", + "clear": true + } + }, + { + "label": "Static Analysis: All", + "dependsOn": [ + "Cppcheck", + "Clang-Tidy (cpp_checks)" + ], + "dependsOrder": "sequence", + "problemMatcher": [], + "group": "build" + }, + { + "type": "cmake", + "label": "CMake: build", + "command": "build", + "targets": [ + "all" + ], + "group": "build", + "problemMatcher": [], + "detail": "CMake template build task" + } + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 7623e28..2fe311a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file. ## Next Release +### Types + +- add convenient template for creating strong types easily + +### Type Traits + +- Introduce new concept `HasToString` + ## [0.1.5](https://github.com/repo/owner/releases/tag/0.1.5) - 2026-08-13 diff --git a/include/mstd/enum.hpp b/include/mstd/enum.hpp index a0b71ee..0ace569 100644 --- a/include/mstd/enum.hpp +++ b/include/mstd/enum.hpp @@ -124,26 +124,45 @@ #define MSTD_ENUM(EnumName, Underlying, LIST) enum class EnumName : Underlying; #endif -#define MSTD_ENUM_BITFLAG(EnumName, Underlying, LIST) \ - MSTD_ENUM(EnumName, Underlying, LIST) \ - \ - inline EnumName operator|(EnumName lhs, EnumName rhs) \ - { \ - return static_cast( \ - static_cast(lhs) | static_cast(rhs) \ - ); \ - } \ - inline EnumName& operator|=(EnumName& lhs, EnumName rhs) \ - { \ - lhs = lhs | rhs; \ - return lhs; \ - } \ - \ - inline EnumName operator&(EnumName lhs, EnumName rhs) \ - { \ - return static_cast( \ - static_cast(lhs) & static_cast(rhs) \ - ); \ +#define MSTD_ENUM_BITFLAG(EnumName, Underlying, LIST) \ + MSTD_ENUM(EnumName, Underlying, LIST) \ + \ + inline constexpr EnumName operator|(EnumName lhs, EnumName rhs) \ + { \ + return static_cast( \ + static_cast(lhs) | static_cast(rhs) \ + ); \ + } \ + inline constexpr EnumName& operator|=(EnumName& lhs, EnumName rhs) \ + { \ + lhs = lhs | rhs; \ + return lhs; \ + } \ + \ + struct EnumName##FlagTest \ + { \ + Underlying value; \ + constexpr operator EnumName() const noexcept \ + { \ + return static_cast(value); \ + } \ + \ + constexpr explicit operator bool() const noexcept \ + { \ + return value != Underlying{0}; \ + } \ + }; \ + \ + inline constexpr EnumName##FlagTest operator&(EnumName lhs, EnumName rhs) \ + { \ + return EnumName##FlagTest{static_cast( \ + static_cast(lhs) & static_cast(rhs) \ + )}; \ + } \ + \ + inline constexpr bool operator!(EnumName lhs) \ + { \ + return !static_cast(lhs); \ } #endif // __MSTD__ENUM_HPP__ diff --git a/include/mstd/type_traits.hpp b/include/mstd/type_traits.hpp index dc30437..8a37714 100644 --- a/include/mstd/type_traits.hpp +++ b/include/mstd/type_traits.hpp @@ -29,5 +29,6 @@ #include "type_traits/quantity_traits.hpp" // IWYU pragma: export #include "type_traits/ranges_traits.hpp" // IWYU pragma: export #include "type_traits/ratio_traits.hpp" // IWYU pragma: export +#include "type_traits/string.hpp" // IWYU pragma: export -#endif // __MSTD__TYPE_TRAITS_HPP__ \ No newline at end of file +#endif // __MSTD__TYPE_TRAITS_HPP__ diff --git a/include/mstd/type_traits/string.hpp b/include/mstd/type_traits/string.hpp new file mode 100644 index 0000000..953092b --- /dev/null +++ b/include/mstd/type_traits/string.hpp @@ -0,0 +1,44 @@ +/***************************************************************************** + + + 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__TYPE_TRAITS__STRING_HPP__ +#define __MSTD__TYPE_TRAITS__STRING_HPP__ + +#include +#include + +namespace mstd +{ + /** + * @brief Concept checking whether Tag::toString(const T&) is a valid + * expression that returns something convertible to std::string. + * + * @tparam Tag the tag type expected to provide a static toString member + * @tparam T the value type passed to Tag::toString + */ + template + concept HasToString = requires(const T &value) { + { Tag::toString(value) } -> std::convertible_to; + }; +} // namespace mstd + +#endif // __MSTD__TYPE_TRAITS__STRING_HPP__ diff --git a/include/mstd/types.hpp b/include/mstd/types.hpp new file mode 100644 index 0000000..1d3e0c1 --- /dev/null +++ b/include/mstd/types.hpp @@ -0,0 +1,28 @@ +/***************************************************************************** + + + 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__TYPES_HPP__ +#define __MSTD__TYPES_HPP__ + +#include "types/strong_type.hpp" // IWYU pragma: export + +#endif // __MSTD__TYPES_HPP__ diff --git a/include/mstd/types/strong_type.hpp b/include/mstd/types/strong_type.hpp new file mode 100644 index 0000000..304d199 --- /dev/null +++ b/include/mstd/types/strong_type.hpp @@ -0,0 +1,186 @@ +/***************************************************************************** + + + 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__TYPES__STRONG_TYPE_HPP__ +#define __MSTD__TYPES__STRONG_TYPE_HPP__ + +#include +#include +#include + +#include "mstd/enum.hpp" +#include "mstd/type_traits/string.hpp" + +namespace mstd +{ + +#define STRONG_TYPE_TRAIT_LIST(X) \ + X(NONE, 0) \ + X(ORDERED, 1u << 0) \ + X(ARITHMETIC, 1u << 1) \ + X(INCREMENT, 1u << 2) \ + X(HASHABLE, 1u << 3) \ + X(STREAMABLE, 1u << 4) \ + X(BOOLEAN, 1u << 5) + + MSTD_ENUM_BITFLAG(StrongTypeTrait, unsigned, STRONG_TYPE_TRAIT_LIST); + + /** + * @brief A generalized strong type wrapper. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * Usage: + * struct EnergyTag{}; + * using Energy = StrongType; + */ + template < + typename T, + typename Tag, + StrongTypeTrait Traits = StrongTypeTrait::NONE> + class StrongType + { + private: + T _value{}; + + public: + using ValueType = T; + using TagType = Tag; + static constexpr auto traitFlags = Traits; + + constexpr StrongType() = default; + + constexpr explicit StrongType( + const T &value + ) noexcept(std::is_nothrow_copy_constructible_v); + + constexpr explicit StrongType( + T &&value + ) noexcept(std::is_nothrow_move_constructible_v); + + [[nodiscard]] constexpr const T &get() const noexcept; + [[nodiscard]] constexpr T &get() noexcept; + + [[nodiscard]] constexpr explicit operator const T &() const noexcept; + + // + // boolean and ordering + // + + [[nodiscard]] + constexpr explicit operator bool() const noexcept + requires( + (Traits & StrongTypeTrait::BOOLEAN) && std::convertible_to + ); + + [[nodiscard]] + constexpr auto operator<=>(const StrongType &) const + requires(Traits &StrongTypeTrait::ORDERED && + std::three_way_comparable) + = default; + + [[nodiscard]] + constexpr bool operator==(const StrongType &) const + requires(Traits &StrongTypeTrait::ORDERED && + std::equality_comparable) + = default; + + // + // Arithmetic + // + + constexpr StrongType &operator+=(const StrongType &other) + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)); + + constexpr StrongType &operator-=(const StrongType &other) + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)); + + constexpr StrongType &operator*=(const T &scalar) + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)); + + constexpr StrongType &operator/=(const T &scalar) + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)); + + [[nodiscard]] + constexpr StrongType operator+(const StrongType &other) const + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)); + + [[nodiscard]] + constexpr StrongType operator-(const StrongType &other) const + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)); + + [[nodiscard]] + constexpr StrongType operator*(const T &scalar) const + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)); + + [[nodiscard]] + constexpr StrongType operator/(const T &scalar) const + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)); + + [[nodiscard]] + constexpr StrongType operator-() const + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)); + + // + // Increment / decrement + // + + constexpr StrongType &operator++() + requires(bool(Traits &StrongTypeTrait::INCREMENT)); + + constexpr StrongType operator++(int) + requires(bool(Traits &StrongTypeTrait::INCREMENT)); + + constexpr StrongType &operator--() + requires(bool(Traits &StrongTypeTrait::INCREMENT)); + + constexpr StrongType operator--(int) + requires(bool(Traits &StrongTypeTrait::INCREMENT)); + + std::string toString() const + requires HasToString; + }; + +} // namespace mstd + +#ifndef __MSTD__TYPES__STRONG_TYPE_TPP__ +#include "strong_type.tpp" // IWYU pragma: export +#endif // __MSTD__TYPES__STRONG_TYPE_TPP__ + +// Streaming - free function, only valid to call if STREAMABLE trait set +template +std::ostream &operator<<( + std::ostream &os, + const mstd::StrongType &strongType +) +requires(Traits &mstd::StrongTypeTrait::STREAMABLE && true) +{ + return os << strongType.get(); +} + +#endif // __MSTD__TYPES__STRONG_TYPE_HPP__ diff --git a/include/mstd/types/strong_type.tpp b/include/mstd/types/strong_type.tpp new file mode 100644 index 0000000..8842ac1 --- /dev/null +++ b/include/mstd/types/strong_type.tpp @@ -0,0 +1,461 @@ +#ifndef __MSTD__TYPES__STRONG_TYPE_TPP__ +#define __MSTD__TYPES__STRONG_TYPE_TPP__ + +#include "strong_type.hpp" + +namespace mstd +{ + /** + * @brief StrongType constructor from const reference. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @param value the underlying value to wrap + */ + template + constexpr StrongType::StrongType( + const T &value + ) noexcept(std::is_nothrow_copy_constructible_v) + : _value(value) + { + } + + /** + * @brief StrongType constructor from rvalue reference. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @param value the underlying value to wrap + */ + template + constexpr StrongType::StrongType( + T &&value + ) noexcept(std::is_nothrow_move_constructible_v) + : _value(std::move(value)) + { + } + + /** + * @brief Get the underlying value. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @return const T& reference to the underlying value + */ + template + constexpr const T &StrongType::get() const noexcept + { + return _value; + } + + /** + * @brief Get the underlying value. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @return T& reference to the underlying value + */ + template + constexpr T &StrongType::get() noexcept + { + return _value; + } + + /** + * @brief Explicit conversion operator to const T&. + * + * This operator allows explicit conversion from StrongType to the + * underlying type T. It is only enabled if the + * STRONG_TYPE_TRAIT::EXPLICIT_CONVERSION trait is set. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @return const T& reference to the underlying value + */ + template + constexpr StrongType::operator const T &() const noexcept + { + return _value; + } + + /** + * @brief Explicit conversion operator to bool. + * + * This operator allows explicit conversion from StrongType to bool. It is + * only enabled if the STRONG_TYPE_TRAIT::BOOLEAN trait is set and T is + * convertible to bool. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @return true if the underlying value is truthy, false otherwise + */ + template + constexpr StrongType::operator bool() const noexcept + requires( + (Traits & StrongTypeTrait::BOOLEAN) && std::convertible_to + ) + { + return static_cast(_value); + } + + /** + * @brief Compound assignment operator for addition. + * + * This operator allows adding another StrongType of the same type to this + * StrongType. It is only enabled if the STRONG_TYPE_TRAIT::ARITHMETIC trait + * is set. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @param other the other StrongType to add + * @return reference to this StrongType after addition + */ + template + constexpr StrongType &StrongType:: + operator+=(const StrongType &other) + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)) + { + _value += other._value; + return *this; + } + + /** + * @brief Compound assignment operator for subtraction. + * + * This operator allows subtracting another StrongType of the same type from + * this StrongType. It is only enabled if the STRONG_TYPE_TRAIT::ARITHMETIC + * trait is set. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @param other the other StrongType to subtract + * @return reference to this StrongType after subtraction + */ + template + constexpr StrongType &StrongType:: + operator-=(const StrongType &other) + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)) + { + _value -= other._value; + return *this; + } + + /** + * @brief Compound assignment operator for multiplication by a scalar. + * + * This operator allows multiplying this StrongType by a scalar of type T. + * It is only enabled if the STRONG_TYPE_TRAIT::ARITHMETIC trait is set. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @param scalar the scalar value to multiply by + * @return reference to this StrongType after multiplication + */ + template + constexpr StrongType &StrongType:: + operator*=(const T &scalar) + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)) + { + _value *= scalar; + return *this; + } + + /** + * @brief Compound assignment operator for division by a scalar. + * + * This operator allows dividing this StrongType by a scalar of type T. It + * is only enabled if the STRONG_TYPE_TRAIT::ARITHMETIC trait is set. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @param scalar the scalar value to divide by + * @return reference to this StrongType after division + */ + template + constexpr StrongType &StrongType:: + operator/=(const T &scalar) + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)) + { + _value /= scalar; + return *this; + } + + /** + * @brief Addition operator for StrongType. + * + * This operator allows adding two StrongType objects of the same type. It + * is only enabled if the STRONG_TYPE_TRAIT::ARITHMETIC trait is set. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @param other the other StrongType to add + * @return a new StrongType representing the sum + */ + template + constexpr StrongType StrongType::operator+( + const StrongType &other + ) const + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)) + { + return StrongType{_value + other._value}; + } + + /** + * @brief Subtraction operator for StrongType. + * + * This operator allows subtracting one StrongType from another of the same + * type. It is only enabled if the STRONG_TYPE_TRAIT::ARITHMETIC trait is + * set. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @param other the other StrongType to subtract + * @return a new StrongType representing the difference + */ + template + constexpr StrongType StrongType::operator-( + const StrongType &other + ) const + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)) + { + return StrongType{_value - other._value}; + } + + /** + * @brief Multiplication operator for StrongType by a scalar. + * + * This operator allows multiplying a StrongType by a scalar of type T. It + * is only enabled if the STRONG_TYPE_TRAIT::ARITHMETIC trait is set. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @param scalar the scalar value to multiply by + * @return a new StrongType representing the product + */ + template + constexpr StrongType StrongType::operator*( + const T &scalar + ) const + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)) + { + return StrongType{_value * scalar}; + } + + /** + * @brief Division operator for StrongType by a scalar. + * + * This operator allows dividing a StrongType by a scalar of type T. It is + * only enabled if the STRONG_TYPE_TRAIT::ARITHMETIC trait is set. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @param scalar the scalar value to divide by + * @return a new StrongType representing the quotient + */ + template + constexpr StrongType StrongType::operator/( + const T &scalar + ) const + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)) + { + return StrongType{_value / scalar}; + } + + /** + * @brief Unary negation operator for StrongType. + * + * This operator allows negating a StrongType. It is only enabled if the + * STRONG_TYPE_TRAIT::ARITHMETIC trait is set. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @return a new StrongType representing the negated value + */ + template + constexpr StrongType StrongType::operator-( + ) const + requires(bool(Traits &StrongTypeTrait::ARITHMETIC)) + { + return StrongType{-_value}; + } + + /** + * @brief Pre-increment operator for StrongType. + * + * This operator allows pre-incrementing a StrongType. It is only enabled if + * the STRONG_TYPE_TRAIT::INCREMENT trait is set. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @return reference to this StrongType after incrementing + */ + template + constexpr StrongType &StrongType:: + operator++() + requires(bool(Traits &StrongTypeTrait::INCREMENT)) + { + ++_value; + return *this; + } + + /** + * @brief Post-increment operator for StrongType. + * + * This operator allows post-incrementing a StrongType. It is only enabled + * if the STRONG_TYPE_TRAIT::INCREMENT trait is set. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @return a new StrongType representing the value before incrementing + */ + template + constexpr StrongType StrongType::operator++( + int + ) + requires(bool(Traits &StrongTypeTrait::INCREMENT)) + { + auto tmp = *this; + ++_value; + return tmp; + } + + /** + * @brief Pre-decrement operator for StrongType. + * + * This operator allows pre-decrementing a StrongType. It is only enabled if + * the STRONG_TYPE_TRAIT::INCREMENT trait is set. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @return reference to this StrongType after decrementing + */ + template + constexpr StrongType &StrongType:: + operator--() + requires(bool(Traits &StrongTypeTrait::INCREMENT)) + { + --_value; + return *this; + } + + /** + * @brief Post-decrement operator for StrongType. + * + * This operator allows post-decrementing a StrongType. It is only enabled + * if the STRONG_TYPE_TRAIT::INCREMENT trait is set. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @return a new StrongType representing the value before decrementing + */ + template + constexpr StrongType StrongType::operator--( + int + ) + requires(bool(Traits &StrongTypeTrait::INCREMENT)) + { + auto tmp = *this; + --_value; + return tmp; + } + + /** + * @brief Convert StrongType to string. + * + * This function converts the StrongType to a string representation. It is + * only enabled if the Tag type provides a static toString function that + * accepts the underlying type T. + * + * @tparam T underlying value type + * @tparam Tag a unique tag type used only for disambiguation, e.g. `struct + * EnergyTag;` + * @tparam Traits bitwise-OR of StrongTypeTrait flags enabling specific + * operations + * + * @return a string representation of the StrongType + */ + template + std::string StrongType::toString() const + requires HasToString + { + return Tag::toString(_value); + } +} // namespace mstd + +#endif // __MSTD__TYPES__STRONG_TYPE_TPP__