aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/lib/include/newtype/newtype.hpp22
-rw-r--r--source/tests/CMakeLists.txt17
-rw-r--r--source/tests/src/threeway_comparison.cpp52
3 files changed, 81 insertions, 10 deletions
diff --git a/source/lib/include/newtype/newtype.hpp b/source/lib/include/newtype/newtype.hpp
index 8e7729b..3654afd 100644
--- a/source/lib/include/newtype/newtype.hpp
+++ b/source/lib/include/newtype/newtype.hpp
@@ -747,6 +747,7 @@ namespace nt
auto constexpr Read = derivable<struct read_tag>{};
auto constexpr Relational = derivable<struct relational_tag>{};
auto constexpr Show = derivable<struct show_tag>{};
+ auto constexpr ThreewayCompare = derivable<struct threeway_compare_tag>{};
} // namespace derivables
@@ -767,6 +768,9 @@ namespace nt
template<typename DerivationClause, auto... Features>
concept derives = requires(DerivationClause clause) { requires DerivationClause::template derives<Features...>::value; };
+ template<typename DerivationClause, auto... Features>
+ concept doesnt_derive = !derives<DerivationClause, Features...>;
+
template<typename... DerivableTags>
auto constexpr deriving(derivable<DerivableTags>... features) noexcept -> derivation_clause<DerivableTags...>
{
@@ -780,6 +784,8 @@ namespace nt
{
static_assert(!std::is_reference_v<BaseType>, "The base type must not be a reference type");
static_assert(!std::is_void_v<std::remove_cv_t<BaseType>>, "The base type must not be possibly cv-qualified void");
+ static_assert(!derives<decltype(DerivationClause), nt::Relational, nt::ThreewayCompare>,
+ "Cannot derive both nt::Relational and nt::ThreewayCompare at the same time.");
template<typename CharType,
typename StreamTraits,
@@ -985,7 +991,7 @@ namespace nt
}
};
- template<nt::concepts::equality_comparable BaseType, typename TagType, auto DerivationClause>
+ template<nt::concepts::equality_comparable BaseType, typename TagType, doesnt_derive<nt::ThreewayCompare> auto DerivationClause>
auto constexpr
operator==(new_type<BaseType, TagType, DerivationClause> const & lhs,
new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(nt::concepts::nothrow_equality_comparable<BaseType>) -> bool
@@ -993,6 +999,13 @@ namespace nt
return lhs.decay() == rhs.decay();
}
+ template<std::three_way_comparable BaseType, typename TagType, derives<nt::ThreewayCompare> auto DerivationClause>
+ auto constexpr operator==(new_type<BaseType, TagType, DerivationClause> const & lhs,
+ new_type<BaseType, TagType, DerivationClause> const & rhs) -> bool
+ {
+ return lhs.decay() == rhs.decay();
+ }
+
template<nt::concepts::equality_comparable BaseType, typename TagType, nt::derives<nt::EqBase> auto DerivationClause>
auto constexpr operator==(new_type<BaseType, TagType, DerivationClause> const & lhs,
BaseType const & rhs) noexcept(nt::concepts::nothrow_equality_comparable<BaseType>) -> bool
@@ -1008,6 +1021,13 @@ namespace nt
return lhs == rhs.decay();
}
+ template<std::three_way_comparable BaseType, typename TagType, nt::derives<nt::ThreewayCompare> auto DerivationClause>
+ auto constexpr operator<=>(new_type<BaseType, TagType, DerivationClause> const & lhs,
+ new_type<BaseType, TagType, DerivationClause> const & rhs)
+ {
+ return lhs.decay() <=> rhs.decay();
+ }
+
template<nt::concepts::inequality_comparable BaseType, typename TagType, auto DerivationClause>
auto constexpr
operator!=(new_type<BaseType, TagType, DerivationClause> const & lhs,
diff --git a/source/tests/CMakeLists.txt b/source/tests/CMakeLists.txt
index ce6b707..47b8331 100644
--- a/source/tests/CMakeLists.txt
+++ b/source/tests/CMakeLists.txt
@@ -6,16 +6,15 @@ find_package("Catch2" "3.1"
include("CTest")
include("Catch")
+file(GLOB SOURCES
+ RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
+ CONFIGURE_DEPENDS
+ "src/*.cpp"
+)
+
+
add_executable("${PROJECT_NAME}_tests"
- "src/arithmetic.cpp"
- "src/constructors.cpp"
- "src/conversion.cpp"
- "src/derivation_clause.cpp"
- "src/equality_comparison.cpp"
- "src/hash.cpp"
- "src/io_operators.cpp"
- "src/iterable.cpp"
- "src/relational_operators.cpp"
+ ${SOURCES}
)
target_link_libraries("${PROJECT_NAME}_tests"
diff --git a/source/tests/src/threeway_comparison.cpp b/source/tests/src/threeway_comparison.cpp
new file mode 100644
index 0000000..ddca7f3
--- /dev/null
+++ b/source/tests/src/threeway_comparison.cpp
@@ -0,0 +1,52 @@
+#include "newtype/newtype.hpp"
+
+#include <catch2/catch_template_test_macros.hpp>
+#include <catch2/catch_test_macros.hpp>
+
+#include <compare>
+#include <string>
+#include <vector>
+
+TEMPLATE_TEST_CASE("Scenario: Three-way Comparison", "[comparison]", int, std::string, std::vector<double>)
+{
+ GIVEN("A new_type over a <=> comparable base type deriving nt::ThreewayCompare")
+ {
+ using type_alias = nt::new_type<TestType, struct tag, deriving(nt::ThreewayCompare)>;
+ static_assert(std::three_way_comparable<TestType>);
+
+ THEN("it is equality-comparable")
+ {
+ STATIC_REQUIRE(std::equality_comparable<type_alias>);
+ }
+
+ THEN("it is inequality-comparable")
+ {
+ STATIC_REQUIRE(nt::concepts::inequality_comparable<type_alias>);
+ }
+
+ THEN("it is three-way comparable")
+ {
+ STATIC_REQUIRE(std::three_way_comparable<type_alias>);
+ }
+
+ THEN("it is less-than comparable")
+ {
+ STATIC_REQUIRE(nt::concepts::less_than_comparable<type_alias>);
+ }
+
+ THEN("it is less-than-equal comparable")
+ {
+ STATIC_REQUIRE(nt::concepts::greater_than_equal_comparable<type_alias>);
+ }
+
+ THEN("it is greater-than comparable")
+ {
+ STATIC_REQUIRE(nt::concepts::less_than_comparable<type_alias>);
+ }
+
+ THEN("it is greater-than-equal comparable")
+ {
+ STATIC_REQUIRE(nt::concepts::greater_than_equal_comparable<type_alias>);
+ }
+ }
+} \ No newline at end of file