From 7adcce5945e48cfcf87642d248317d54d8c1963d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 8 Jun 2023 13:27:41 +0200 Subject: ide: adjust LSP configuration --- .vscode/c_cpp_properties.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index d1852ca..eeb9f71 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -3,13 +3,14 @@ { "name": "Linux", "includePath": [ - "${workspaceFolder}/**" + "${workspaceFolder}/source/lib/include" ], "defines": [], - "compilerPath": "/usr/bin/gcc", + "compilerPath": "/usr/bin/g++", "cppStandard": "c++20", "intelliSenseMode": "gcc-x64", - "configurationProvider": "ms-vscode.cmake-tools" + "configurationProvider": "ms-vscode.cmake-tools", + "compileCommands": "${workspaceFolder}/build/compile_commands.json" } ], "version": 4 -- cgit v1.2.3 From 3e90982d29b54523c3a617cfff7ec6bcc42ba1e8 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 8 Jun 2023 13:49:36 +0200 Subject: concepts: replace is_hashable_v --- source/lib/include/newtype/concepts.hpp | 19 +++++++++++++++++++ .../include/newtype/impl/type_traits_extensions.hpp | 19 ------------------- source/lib/include/newtype/newtype.hpp | 7 +++---- source/tests/src/hash.cpp | 19 +++++++++++++------ 4 files changed, 35 insertions(+), 29 deletions(-) create mode 100644 source/lib/include/newtype/concepts.hpp diff --git a/source/lib/include/newtype/concepts.hpp b/source/lib/include/newtype/concepts.hpp new file mode 100644 index 0000000..a29ba37 --- /dev/null +++ b/source/lib/include/newtype/concepts.hpp @@ -0,0 +1,19 @@ +#ifndef NEWTYPE_CONCEPTS_HPP +#define NEWTYPE_CONCEPTS_HPP + +#include +#include +#include + +namespace nt::concepts +{ + template + concept hashable = requires(SubjectType subject) { + { + std::hash{}(subject) + } -> std::convertible_to; + }; + +} // namespace nt::concepts + +#endif \ No newline at end of file diff --git a/source/lib/include/newtype/impl/type_traits_extensions.hpp b/source/lib/include/newtype/impl/type_traits_extensions.hpp index dc41649..bdd1cba 100644 --- a/source/lib/include/newtype/impl/type_traits_extensions.hpp +++ b/source/lib/include/newtype/impl/type_traits_extensions.hpp @@ -469,25 +469,6 @@ namespace nt::impl } // namespace compound_arithmetic - inline namespace std_support - { - - template - struct is_hashable : std::false_type - { - }; - - template - struct is_hashable const &>()(std::declval()))>> - : std::is_same const &>()(std::declval()))> - { - }; - - template - auto constexpr is_hashable_v = is_hashable::value; - - } // namespace std_support - inline namespace iterable_begin { template diff --git a/source/lib/include/newtype/newtype.hpp b/source/lib/include/newtype/newtype.hpp index 2e71553..b833c10 100644 --- a/source/lib/include/newtype/newtype.hpp +++ b/source/lib/include/newtype/newtype.hpp @@ -1,6 +1,7 @@ #ifndef NEWTYPE_NEWTYPE_HPP #define NEWTYPE_NEWTYPE_HPP +#include "newtype/concepts.hpp" #include "newtype/derivable.hpp" #include "newtype/deriving.hpp" #include "newtype/impl/new_type_iterator_types.hpp" @@ -535,12 +536,10 @@ namespace nt namespace std { template + requires(nt::concepts::hashable && DerivationClause(nt::Hash)) struct hash> { - template - auto constexpr operator()(nt::new_type const & object, - std::enable_if_t> * = nullptr) const - -> std::size_t + auto constexpr operator()(nt::new_type const & object) const { return std::hash{}(object.decay()); } diff --git a/source/tests/src/hash.cpp b/source/tests/src/hash.cpp index e3f624f..bcf793c 100644 --- a/source/tests/src/hash.cpp +++ b/source/tests/src/hash.cpp @@ -1,31 +1,36 @@ +#include "newtype/concepts.hpp" #include "newtype/derivable.hpp" #include "newtype/deriving.hpp" #include "newtype/impl/type_traits_extensions.hpp" #include "newtype/newtype.hpp" +#include #include +#include #include -SCENARIO("Hash", "[hash]") +TEMPLATE_TEST_CASE("Hash", "[hash]", std::string, int) { GIVEN("A new_type not deriving nt::Hash") { - using type_alias = nt::new_type; + using type_alias = nt::new_type; + static_assert(nt::concepts::hashable); THEN("it is not hashable") { - STATIC_REQUIRE_FALSE(nt::impl::is_hashable_v); + STATIC_REQUIRE_FALSE(nt::concepts::hashable); } } GIVEN("A new_type over a hashable type deriving nt::Hash") { - using type_alias = nt::new_type; + using type_alias = nt::new_type; + static_assert(nt::concepts::hashable); THEN("it is hashable") { - STATIC_REQUIRE(nt::impl::is_hashable_v); + STATIC_REQUIRE(nt::concepts::hashable); } } @@ -35,16 +40,18 @@ SCENARIO("Hash", "[hash]") { }; using type_alias = nt::new_type; + static_assert(!nt::concepts::hashable); THEN("it is not hashable") { - STATIC_REQUIRE_FALSE(nt::impl::is_hashable_v); + STATIC_REQUIRE_FALSE(nt::concepts::hashable); } } GIVEN("A hashable new_type") { using type_alias = nt::new_type; + static_assert(nt::concepts::hashable); THEN("it can be used a the key in an unordered_map") { -- cgit v1.2.3 From 2b92a0db8c3f171b6f947b749fa3a3c14e309d62 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 8 Jun 2023 14:47:01 +0200 Subject: concepts: replace is_*_*equality_comparable --- source/lib/include/newtype/concepts.hpp | 31 ++++++++++++ .../newtype/impl/type_traits_extensions.hpp | 59 ---------------------- source/lib/include/newtype/newtype.hpp | 34 ++++++------- source/tests/src/equality_comparison.cpp | 15 +++--- 4 files changed, 55 insertions(+), 84 deletions(-) diff --git a/source/lib/include/newtype/concepts.hpp b/source/lib/include/newtype/concepts.hpp index a29ba37..6db528c 100644 --- a/source/lib/include/newtype/concepts.hpp +++ b/source/lib/include/newtype/concepts.hpp @@ -7,6 +7,37 @@ namespace nt::concepts { + + template + concept equality_comparable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs == rhs + } -> std::convertible_to; + }; + + template + concept nothrow_equality_comparable = requires(SubjectType lhs, SubjectType rhs) { + requires equality_comparable; + { + lhs == rhs + } noexcept; + }; + + template + concept inequality_comparable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs != rhs + } -> std::convertible_to; + }; + + template + concept nothrow_inequality_comparable = requires(SubjectType lhs, SubjectType rhs) { + requires inequality_comparable; + { + lhs != rhs + } noexcept; + }; + template concept hashable = requires(SubjectType subject) { { diff --git a/source/lib/include/newtype/impl/type_traits_extensions.hpp b/source/lib/include/newtype/impl/type_traits_extensions.hpp index bdd1cba..c4b9bee 100644 --- a/source/lib/include/newtype/impl/type_traits_extensions.hpp +++ b/source/lib/include/newtype/impl/type_traits_extensions.hpp @@ -11,65 +11,6 @@ namespace nt::impl { - inline namespace equality_comparable - { - - template - struct is_equality_comparable : std::false_type - { - }; - - template - struct is_equality_comparable() == std::declval())>> : std::true_type - { - }; - - template - auto constexpr is_equality_comparable_v = is_equality_comparable::value; - - template - struct is_nothrow_equality_comparable : std::false_type - { - }; - - template - struct is_nothrow_equality_comparable() == std::declval())>> - : std::bool_constant() == std::declval())> - { - }; - - template - auto constexpr is_nothrow_equality_comparable_v = is_nothrow_equality_comparable::value; - - template - struct is_inequality_comparable : std::false_type - { - }; - - template - struct is_inequality_comparable() != std::declval())>> : std::true_type - { - }; - - template - auto constexpr is_inequality_comparable_v = is_inequality_comparable::value; - - template - struct is_nothrow_inequality_comparable : std::false_type - { - }; - - template - struct is_nothrow_inequality_comparable() != std::declval())>> - : std::bool_constant() != std::declval())> - { - }; - - template - auto constexpr is_nothrow_inequality_comparable_v = is_nothrow_inequality_comparable::value; - - } // namespace equality_comparable - inline namespace relationally_comparable { diff --git a/source/lib/include/newtype/newtype.hpp b/source/lib/include/newtype/newtype.hpp index b833c10..126c439 100644 --- a/source/lib/include/newtype/newtype.hpp +++ b/source/lib/include/newtype/newtype.hpp @@ -251,54 +251,52 @@ namespace nt } }; - template + template auto constexpr operator==(new_type const & lhs, - new_type const & rhs) noexcept(impl::is_nothrow_equality_comparable_v) - -> std::enable_if_t, bool> + new_type const & rhs) noexcept(nt::concepts::nothrow_equality_comparable) -> bool { return lhs.decay() == rhs.decay(); } - template + template + requires(DerivationClause(nt::EqBase)) auto constexpr operator==(new_type const & lhs, - BaseType const & rhs) noexcept(impl::is_nothrow_equality_comparable_v) - -> std::enable_if_t, bool> + BaseType const & rhs) noexcept(nt::concepts::nothrow_equality_comparable) -> bool { return lhs.decay() == rhs; } - template + template + requires(DerivationClause(nt::EqBase)) auto constexpr operator==(BaseType const & lhs, - new_type const & rhs) noexcept(impl::is_nothrow_equality_comparable_v) - -> std::enable_if_t, bool> + new_type const & rhs) noexcept(nt::concepts::nothrow_equality_comparable) -> bool { return lhs == rhs.decay(); } - template + template auto constexpr operator!=(new_type const & lhs, - new_type const & rhs) noexcept(impl::is_nothrow_inequality_comparable_v) - -> std::enable_if_t, bool> + new_type const & rhs) noexcept(nt::concepts::nothrow_inequality_comparable) -> bool { return lhs.decay() != rhs.decay(); } - template + template + requires(DerivationClause(nt::EqBase)) auto constexpr operator!=(new_type const & lhs, - BaseType const & rhs) noexcept(impl::is_nothrow_inequality_comparable_v) - -> std::enable_if_t, bool> + BaseType const & rhs) noexcept(nt::concepts::nothrow_inequality_comparable) -> bool { return lhs.decay() != rhs; } - template + template + requires(DerivationClause(nt::EqBase)) auto constexpr operator!=(BaseType const & lhs, - new_type const & rhs) noexcept(impl::is_nothrow_inequality_comparable_v) - -> std::enable_if_t, bool> + new_type const & rhs) noexcept(nt::concepts::nothrow_inequality_comparable) -> bool { return lhs != rhs.decay(); } diff --git a/source/tests/src/equality_comparison.cpp b/source/tests/src/equality_comparison.cpp index d857d9b..0876dc2 100644 --- a/source/tests/src/equality_comparison.cpp +++ b/source/tests/src/equality_comparison.cpp @@ -1,3 +1,4 @@ +#include "newtype/concepts.hpp" #include "newtype/derivable.hpp" #include "newtype/deriving.hpp" #include "newtype/newtype.hpp" @@ -64,17 +65,17 @@ SCENARIO("Equality Comparison", "[compare]") { using type_alias = nt::new_type; - static_assert(noexcept(std::declval() == std::declval())); - static_assert(noexcept(std::declval() != std::declval())); + static_assert(nt::concepts::nothrow_equality_comparable); + static_assert(nt::concepts::nothrow_inequality_comparable); THEN("it is nothrow-equality-comparable") { - STATIC_REQUIRE(noexcept(std::declval() == std::declval())); + STATIC_REQUIRE(nt::concepts::nothrow_equality_comparable); } THEN("it is nothrow-inequality-comparable") { - STATIC_REQUIRE(noexcept(std::declval() != std::declval())); + STATIC_REQUIRE(nt::concepts::nothrow_inequality_comparable); } } @@ -88,12 +89,12 @@ SCENARIO("Equality Comparison", "[compare]") using type_alias = nt::new_type; - static_assert(!noexcept(std::declval() == std::declval())); - static_assert(!noexcept(std::declval() != std::declval())); + static_assert(!nt::concepts::nothrow_equality_comparable); + static_assert(!nt::concepts::nothrow_inequality_comparable); THEN("it is not nothrow-equality-comparable") { - STATIC_REQUIRE_FALSE(noexcept(std::declval() == std::declval())); + STATIC_REQUIRE_FALSE(nt::concepts::nothrow_equality_comparable); } THEN("it is not nothrow-inequality-comparable") -- cgit v1.2.3 From 2b22ef0132e041917b6d8a566b12e955fea163b7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 8 Jun 2023 14:52:36 +0200 Subject: derivations: introduce nt::contains concept --- source/lib/include/newtype/derivation_clause.hpp | 3 +++ source/lib/include/newtype/newtype.hpp | 15 +++++---------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/source/lib/include/newtype/derivation_clause.hpp b/source/lib/include/newtype/derivation_clause.hpp index 6de70e1..c4aa051 100644 --- a/source/lib/include/newtype/derivation_clause.hpp +++ b/source/lib/include/newtype/derivation_clause.hpp @@ -65,6 +65,9 @@ namespace nt } }; + template + concept contains = requires(DerivationClause clause) { requires clause(Feature); }; + } // namespace nt #endif \ No newline at end of file diff --git a/source/lib/include/newtype/newtype.hpp b/source/lib/include/newtype/newtype.hpp index 126c439..33863ac 100644 --- a/source/lib/include/newtype/newtype.hpp +++ b/source/lib/include/newtype/newtype.hpp @@ -259,16 +259,14 @@ namespace nt return lhs.decay() == rhs.decay(); } - template - requires(DerivationClause(nt::EqBase)) + template auto DerivationClause> auto constexpr operator==(new_type const & lhs, BaseType const & rhs) noexcept(nt::concepts::nothrow_equality_comparable) -> bool { return lhs.decay() == rhs; } - template - requires(DerivationClause(nt::EqBase)) + template auto DerivationClause> auto constexpr operator==(BaseType const & lhs, new_type const & rhs) noexcept(nt::concepts::nothrow_equality_comparable) -> bool @@ -284,16 +282,14 @@ namespace nt return lhs.decay() != rhs.decay(); } - template - requires(DerivationClause(nt::EqBase)) + template auto DerivationClause> auto constexpr operator!=(new_type const & lhs, BaseType const & rhs) noexcept(nt::concepts::nothrow_inequality_comparable) -> bool { return lhs.decay() != rhs; } - template - requires(DerivationClause(nt::EqBase)) + template auto DerivationClause> auto constexpr operator!=(BaseType const & lhs, new_type const & rhs) noexcept(nt::concepts::nothrow_inequality_comparable) -> bool @@ -533,8 +529,7 @@ namespace nt namespace std { - template - requires(nt::concepts::hashable && DerivationClause(nt::Hash)) + template auto DerivationClause> struct hash> { auto constexpr operator()(nt::new_type const & object) const -- cgit v1.2.3 From 93e02a01568519344310897e8e9f4ee4f32ff75f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 8 Jun 2023 15:42:41 +0200 Subject: concets: replace is_*_input_streamable* --- source/lib/include/newtype/concepts.hpp | 16 +++++++++++++ .../newtype/impl/type_traits_extensions.hpp | 27 ---------------------- source/lib/include/newtype/newtype.hpp | 20 +++++++++------- 3 files changed, 28 insertions(+), 35 deletions(-) diff --git a/source/lib/include/newtype/concepts.hpp b/source/lib/include/newtype/concepts.hpp index 6db528c..c053612 100644 --- a/source/lib/include/newtype/concepts.hpp +++ b/source/lib/include/newtype/concepts.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace nt::concepts { @@ -38,6 +39,21 @@ namespace nt::concepts } noexcept; }; + template + concept input_streamable = requires(SubjectType subject) { + { + std::declval &>() >> subject + } -> std::same_as &>; + }; + + template + concept nothrow_input_streamable = requires(SubjectType subject) { + requires input_streamable; + { + std::declval &>() >> subject + } noexcept; + }; + template concept hashable = requires(SubjectType subject) { { diff --git a/source/lib/include/newtype/impl/type_traits_extensions.hpp b/source/lib/include/newtype/impl/type_traits_extensions.hpp index c4b9bee..7db8e66 100644 --- a/source/lib/include/newtype/impl/type_traits_extensions.hpp +++ b/source/lib/include/newtype/impl/type_traits_extensions.hpp @@ -155,33 +155,6 @@ namespace nt::impl template auto constexpr is_nothrow_output_streamable_v = is_nothrow_output_streamable::value; - template - struct is_input_streamable : std::false_type - { - }; - - template - struct is_input_streamable() >> std::declval())>> : std::true_type - { - }; - - template - auto constexpr is_input_streamable_v = is_input_streamable::value; - - template - struct is_nothrow_input_streamable : std::false_type - { - }; - - template - struct is_nothrow_input_streamable() >> std::declval())>> - : std::bool_constant() >> std::declval())> - { - }; - - template - auto constexpr is_nothrow_input_streamable_v = is_nothrow_input_streamable::value; - } // namespace iostreamable inline namespace arithmetic diff --git a/source/lib/include/newtype/newtype.hpp b/source/lib/include/newtype/newtype.hpp index 33863ac..acfd2f9 100644 --- a/source/lib/include/newtype/newtype.hpp +++ b/source/lib/include/newtype/newtype.hpp @@ -25,11 +25,13 @@ namespace nt static_assert(!std::is_reference_v, "The base type must not be a reference type"); static_assert(!std::is_void_v>, "The base type must not be possibly cv-qualified void"); - template + template BaseTypeT, + typename TagTypeT, + nt::contains auto DerivationClauseV> auto friend operator>>(std::basic_istream &, new_type &) noexcept( - impl::is_nothrow_input_streamable_v, BaseTypeT>) - -> std::enable_if_t, BaseTypeT>, - std::basic_istream> &; + nt::concepts::nothrow_input_streamable) -> std::basic_istream &; template auto constexpr friend @@ -342,11 +344,13 @@ namespace nt return output << source.decay(); } - template + template BaseType, + typename TagType, + nt::contains auto DerivationClause> auto operator>>(std::basic_istream & input, new_type & target) noexcept( - impl::is_nothrow_input_streamable_v, BaseType>) - -> std::enable_if_t, BaseType>, - std::basic_istream> & + nt::concepts::nothrow_input_streamable) -> std::basic_istream & { return input >> target.m_value; } -- cgit v1.2.3 From eb13bd9991ceef34cacb0913df90045b08726f81 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 8 Jun 2023 17:31:29 +0200 Subject: concepts: replace is_*_output_streamable* --- source/lib/include/newtype/concepts.hpp | 15 ++++++++++ .../newtype/impl/type_traits_extensions.hpp | 33 ---------------------- source/lib/include/newtype/newtype.hpp | 10 ++++--- source/tests/src/io_operators.cpp | 2 +- 4 files changed, 22 insertions(+), 38 deletions(-) diff --git a/source/lib/include/newtype/concepts.hpp b/source/lib/include/newtype/concepts.hpp index c053612..c9ef951 100644 --- a/source/lib/include/newtype/concepts.hpp +++ b/source/lib/include/newtype/concepts.hpp @@ -54,6 +54,21 @@ namespace nt::concepts } noexcept; }; + template + concept output_streamable = requires(SubjectType subject) { + { + std::declval &>() << subject + } -> std::same_as &>; + }; + + template + concept nothrow_output_streamable = requires(SubjectType subject) { + requires output_streamable; + { + std::declval &>() << subject + } noexcept; + }; + template concept hashable = requires(SubjectType subject) { { diff --git a/source/lib/include/newtype/impl/type_traits_extensions.hpp b/source/lib/include/newtype/impl/type_traits_extensions.hpp index 7db8e66..22834f2 100644 --- a/source/lib/include/newtype/impl/type_traits_extensions.hpp +++ b/source/lib/include/newtype/impl/type_traits_extensions.hpp @@ -124,39 +124,6 @@ namespace nt::impl auto constexpr is_nothrow_greater_than_equal_to_comparable_v = is_nothrow_greater_than_equal_to_comparable::value; } // namespace relationally_comparable - inline namespace iostreamable - { - - template - struct is_output_streamable : std::false_type - { - }; - - template - struct is_output_streamable() << std::declval())>> - : std::true_type - { - }; - - template - auto constexpr is_output_streamable_v = is_output_streamable::value; - - template - struct is_nothrow_output_streamable : std::false_type - { - }; - - template - struct is_nothrow_output_streamable() << std::declval())>> - : std::bool_constant() << std::declval())> - { - }; - - template - auto constexpr is_nothrow_output_streamable_v = is_nothrow_output_streamable::value; - - } // namespace iostreamable - inline namespace arithmetic { diff --git a/source/lib/include/newtype/newtype.hpp b/source/lib/include/newtype/newtype.hpp index acfd2f9..e40097d 100644 --- a/source/lib/include/newtype/newtype.hpp +++ b/source/lib/include/newtype/newtype.hpp @@ -335,11 +335,13 @@ namespace nt return lhs.decay() >= rhs.decay(); } - template + template BaseType, + typename TagType, + nt::contains auto DerivationClause> auto operator<<(std::basic_ostream & output, new_type const & source) noexcept( - impl::is_nothrow_output_streamable_v, BaseType>) - -> std::enable_if_t, BaseType>, - std::basic_ostream> & + nt::concepts::nothrow_output_streamable) -> std::basic_ostream & { return output << source.decay(); } diff --git a/source/tests/src/io_operators.cpp b/source/tests/src/io_operators.cpp index 23be171..2be41eb 100644 --- a/source/tests/src/io_operators.cpp +++ b/source/tests/src/io_operators.cpp @@ -83,7 +83,7 @@ SCENARIO("Stream Output") using type_alias = nt::new_type; static_assert(has_stream_output_v); - THEN("it has the stream input operator") + THEN("it has the stream output operator") { STATIC_REQUIRE(has_stream_output_v); } -- cgit v1.2.3 From 8f9e88a9c5d83ea043be341a2b8663130e85f5eb Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 8 Jun 2023 17:34:00 +0200 Subject: concepts: group in namespaces --- source/lib/include/newtype/concepts.hpp | 147 ++++++++++++++++++-------------- 1 file changed, 81 insertions(+), 66 deletions(-) diff --git a/source/lib/include/newtype/concepts.hpp b/source/lib/include/newtype/concepts.hpp index c9ef951..8f94a42 100644 --- a/source/lib/include/newtype/concepts.hpp +++ b/source/lib/include/newtype/concepts.hpp @@ -9,72 +9,87 @@ namespace nt::concepts { - template - concept equality_comparable = requires(SubjectType lhs, SubjectType rhs) { - { - lhs == rhs - } -> std::convertible_to; - }; - - template - concept nothrow_equality_comparable = requires(SubjectType lhs, SubjectType rhs) { - requires equality_comparable; - { - lhs == rhs - } noexcept; - }; - - template - concept inequality_comparable = requires(SubjectType lhs, SubjectType rhs) { - { - lhs != rhs - } -> std::convertible_to; - }; - - template - concept nothrow_inequality_comparable = requires(SubjectType lhs, SubjectType rhs) { - requires inequality_comparable; - { - lhs != rhs - } noexcept; - }; - - template - concept input_streamable = requires(SubjectType subject) { - { - std::declval &>() >> subject - } -> std::same_as &>; - }; - - template - concept nothrow_input_streamable = requires(SubjectType subject) { - requires input_streamable; - { - std::declval &>() >> subject - } noexcept; - }; - - template - concept output_streamable = requires(SubjectType subject) { - { - std::declval &>() << subject - } -> std::same_as &>; - }; - - template - concept nothrow_output_streamable = requires(SubjectType subject) { - requires output_streamable; - { - std::declval &>() << subject - } noexcept; - }; - - template - concept hashable = requires(SubjectType subject) { - { - std::hash{}(subject) - } -> std::convertible_to; - }; + inline namespace comparability + { + + template + concept equality_comparable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs == rhs + } -> std::convertible_to; + }; + + template + concept nothrow_equality_comparable = requires(SubjectType lhs, SubjectType rhs) { + requires equality_comparable; + { + lhs == rhs + } noexcept; + }; + + template + concept inequality_comparable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs != rhs + } -> std::convertible_to; + }; + + template + concept nothrow_inequality_comparable = requires(SubjectType lhs, SubjectType rhs) { + requires inequality_comparable; + { + lhs != rhs + } noexcept; + }; + + } // namespace comparability + + inline namespace iostreamable + { + + template + concept input_streamable = requires(SubjectType subject) { + { + std::declval &>() >> subject + } -> std::same_as &>; + }; + + template + concept nothrow_input_streamable = requires(SubjectType subject) { + requires input_streamable; + { + std::declval &>() >> subject + } noexcept; + }; + + template + concept output_streamable = requires(SubjectType subject) { + { + std::declval &>() << subject + } -> std::same_as &>; + }; + + template + concept nothrow_output_streamable = requires(SubjectType subject) { + requires output_streamable; + { + std::declval &>() << subject + } noexcept; + }; + + } // namespace iostreamable + + inline namespace standard_extensions + { + + template + concept hashable = requires(SubjectType subject) { + { + std::hash{}(subject) + } -> std::convertible_to; + }; + + } } // namespace nt::concepts -- cgit v1.2.3 From b55156bed4a56b2e9af46e0d17adc092ac16342e Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 8 Jun 2023 17:55:22 +0200 Subject: concepts: replace relational traits --- source/lib/include/newtype/concepts.hpp | 60 +++++++ .../newtype/impl/type_traits_extensions.hpp | 113 ------------ source/lib/include/newtype/newtype.hpp | 20 +-- source/tests/src/relational_operators.cpp | 198 ++++++++------------- 4 files changed, 141 insertions(+), 250 deletions(-) diff --git a/source/lib/include/newtype/concepts.hpp b/source/lib/include/newtype/concepts.hpp index 8f94a42..a50b2b3 100644 --- a/source/lib/include/newtype/concepts.hpp +++ b/source/lib/include/newtype/concepts.hpp @@ -42,6 +42,66 @@ namespace nt::concepts } noexcept; }; + template + concept less_than_comparable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs < rhs + } -> std::convertible_to; + }; + + template + concept nothrow_less_than_comparable = requires(SubjectType lhs, SubjectType rhs) { + requires less_than_comparable; + { + lhs < rhs + } noexcept; + }; + + template + concept less_than_equal_comparable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs <= rhs + } -> std::convertible_to; + }; + + template + concept nothrow_less_than_equal_comparable = requires(SubjectType lhs, SubjectType rhs) { + requires less_than_equal_comparable; + { + lhs <= rhs + } noexcept; + }; + + template + concept greater_than_comparable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs > rhs + } -> std::convertible_to; + }; + + template + concept nothrow_greater_than_comparable = requires(SubjectType lhs, SubjectType rhs) { + requires greater_than_comparable; + { + lhs > rhs + } noexcept; + }; + + template + concept greater_than_equal_comparable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs >= rhs + } -> std::convertible_to; + }; + + template + concept nothrow_greater_than_equal_comparable = requires(SubjectType lhs, SubjectType rhs) { + requires greater_than_equal_comparable; + { + lhs >= rhs + } noexcept; + }; + } // namespace comparability inline namespace iostreamable diff --git a/source/lib/include/newtype/impl/type_traits_extensions.hpp b/source/lib/include/newtype/impl/type_traits_extensions.hpp index 22834f2..c2caf51 100644 --- a/source/lib/include/newtype/impl/type_traits_extensions.hpp +++ b/source/lib/include/newtype/impl/type_traits_extensions.hpp @@ -11,119 +11,6 @@ namespace nt::impl { - inline namespace relationally_comparable - { - - template - struct is_less_than_comparable : std::false_type - { - }; - - template - struct is_less_than_comparable() < std::declval())>> : std::true_type - { - }; - - template - auto constexpr is_less_than_comparable_v = is_less_than_comparable::value; - - template - struct is_nothrow_less_than_comparable : std::false_type - { - }; - - template - struct is_nothrow_less_than_comparable() < std::declval())>> - : std::bool_constant() < std::declval())> - { - }; - - template - auto constexpr is_nothrow_less_than_comparable_v = is_nothrow_less_than_comparable::value; - - template - struct is_greater_than_comparable : std::false_type - { - }; - - template - struct is_greater_than_comparable() > std::declval())>> : std::true_type - { - }; - - template - auto constexpr is_greater_than_comparable_v = is_greater_than_comparable::value; - - template - struct is_nothrow_greater_than_comparable : std::false_type - { - }; - - template - struct is_nothrow_greater_than_comparable() > std::declval())>> - : std::bool_constant() > std::declval())> - { - }; - - template - auto constexpr is_nothrow_greater_than_comparable_v = is_nothrow_greater_than_comparable::value; - - template - struct is_less_than_equal_to_comparable : std::false_type - { - }; - - template - struct is_less_than_equal_to_comparable() <= std::declval())>> : std::true_type - { - }; - - template - auto constexpr is_less_than_equal_to_comparable_v = is_less_than_equal_to_comparable::value; - - template - struct is_nothrow_less_than_equal_to_comparable : std::false_type - { - }; - - template - struct is_nothrow_less_than_equal_to_comparable() <= std::declval())>> - : std::bool_constant() <= std::declval())> - { - }; - - template - auto constexpr is_nothrow_less_than_equal_to_comparable_v = is_nothrow_less_than_equal_to_comparable::value; - - template - struct is_greater_than_equal_to_comparable : std::false_type - { - }; - - template - struct is_greater_than_equal_to_comparable() >= std::declval())>> - : std::true_type - { - }; - - template - auto constexpr is_greater_than_equal_to_comparable_v = is_greater_than_equal_to_comparable::value; - - template - struct is_nothrow_greater_than_equal_to_comparable : std::false_type - { - }; - - template - struct is_nothrow_greater_than_equal_to_comparable() >= std::declval())>> - : std::bool_constant() >= std::declval())> - { - }; - - template - auto constexpr is_nothrow_greater_than_equal_to_comparable_v = is_nothrow_greater_than_equal_to_comparable::value; - } // namespace relationally_comparable - inline namespace arithmetic { diff --git a/source/lib/include/newtype/newtype.hpp b/source/lib/include/newtype/newtype.hpp index e40097d..44bd1b8 100644 --- a/source/lib/include/newtype/newtype.hpp +++ b/source/lib/include/newtype/newtype.hpp @@ -299,38 +299,34 @@ namespace nt return lhs != rhs.decay(); } - template + template auto DerivationClause> auto constexpr operator<(new_type const & lhs, - new_type const & rhs) noexcept(impl::is_nothrow_less_than_comparable_v) - -> std::enable_if_t, bool> + new_type const & rhs) noexcept(nt::concepts::nothrow_less_than_comparable) { return lhs.decay() < rhs.decay(); } - template + template auto DerivationClause> auto constexpr operator>(new_type const & lhs, - new_type const & rhs) noexcept(impl::is_nothrow_greater_than_comparable_v) - -> std::enable_if_t, bool> + new_type const & rhs) noexcept(nt::concepts::nothrow_greater_than_comparable) { return lhs.decay() > rhs.decay(); } - template + template auto DerivationClause> auto constexpr operator<=(new_type const & lhs, - new_type const & rhs) noexcept(impl::is_nothrow_less_than_equal_to_comparable_v) - -> std::enable_if_t, bool> + new_type const & rhs) noexcept(nt::concepts::nothrow_less_than_equal_comparable) { return lhs.decay() <= rhs.decay(); } - template + template auto DerivationClause> auto constexpr operator>=(new_type const & lhs, - new_type const & rhs) noexcept(impl::is_nothrow_greater_than_equal_to_comparable_v) - -> std::enable_if_t, bool> + new_type const & rhs) noexcept(nt::concepts::nothrow_greater_than_equal_comparable) { return lhs.decay() >= rhs.decay(); } diff --git a/source/tests/src/relational_operators.cpp b/source/tests/src/relational_operators.cpp index 95e1bd4..de6f7f3 100644 --- a/source/tests/src/relational_operators.cpp +++ b/source/tests/src/relational_operators.cpp @@ -9,190 +9,121 @@ #include #include -inline namespace traits_extensions -{ - - template - struct has_less_than : std::false_type - { - }; - - template - struct has_less_than() < std::declval())>> : std::true_type - { - }; - - template - auto constexpr has_less_than_v = has_less_than::value; - - template - auto constexpr has_nothrow_less_than_v = has_less_than_v && noexcept(std::declval() < std::declval()); - - template - struct has_greater_than : std::false_type - { - }; - - template - struct has_greater_than() > std::declval())>> : std::true_type - { - }; - - template - auto constexpr has_greater_than_v = has_greater_than::value; - - template - auto constexpr has_nothrow_greater_than_v = has_less_than_v && noexcept(std::declval() < std::declval()); - - template - struct has_less_than_equal_to : std::false_type - { - }; - - template - struct has_less_than_equal_to() <= std::declval())>> : std::true_type - { - }; - - template - auto constexpr has_less_than_equal_to_v = has_less_than_equal_to::value; - - template - auto constexpr has_nothrow_less_than_equal_to_v = has_less_than_v && noexcept(std::declval() < std::declval()); - - template - struct has_greater_than_equal_to : std::false_type - { - }; - - template - struct has_greater_than_equal_to() >= std::declval())>> : std::true_type - { - }; - - template - auto constexpr has_greater_than_equal_to_v = has_greater_than_equal_to::value; - - template - auto constexpr has_nothrow_greater_than_equal_to_v = has_less_than_v && noexcept(std::declval() < std::declval()); - -} // namespace traits_extensions - SCENARIO("Relational Operator Availability") { GIVEN("A new_type over a relationally comparable type not deriving nt::Relational") { using type_alias = nt::new_type; - static_assert(has_less_than_v); - static_assert(has_less_than_equal_to_v); - static_assert(has_greater_than_v); - static_assert(has_greater_than_equal_to_v); + static_assert(nt::concepts::less_than_comparable); + static_assert(nt::concepts::less_than_equal_comparable); + static_assert(nt::concepts::greater_than_comparable); + static_assert(nt::concepts::greater_than_equal_comparable); THEN("it does not have <") { - STATIC_REQUIRE_FALSE(has_less_than_v); + STATIC_REQUIRE_FALSE(nt::concepts::less_than_comparable); } THEN("it does not have <=") { - STATIC_REQUIRE_FALSE(has_less_than_equal_to_v); + STATIC_REQUIRE_FALSE(nt::concepts::less_than_equal_comparable); } THEN("it does not have >") { - STATIC_REQUIRE_FALSE(has_greater_than_v); + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_comparable); } THEN("it does not have >=") { - STATIC_REQUIRE_FALSE(has_greater_than_equal_to_v); + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_equal_comparable); } } GIVEN("A new_type over a relationally comparable type deriving nt::Relational") { using type_alias = nt::new_type; - static_assert(has_less_than_v); - static_assert(has_less_than_equal_to_v); - static_assert(has_greater_than_v); - static_assert(has_greater_than_equal_to_v); + static_assert(nt::concepts::less_than_comparable); + static_assert(nt::concepts::less_than_equal_comparable); + static_assert(nt::concepts::greater_than_comparable); + static_assert(nt::concepts::greater_than_equal_comparable); THEN("it does have <") { - STATIC_REQUIRE(has_less_than_v); + STATIC_REQUIRE(nt::concepts::less_than_comparable); } THEN("it does have <=") { - STATIC_REQUIRE(has_less_than_equal_to_v); + STATIC_REQUIRE(nt::concepts::less_than_equal_comparable); } THEN("it does have >") { - STATIC_REQUIRE(has_greater_than_v); + STATIC_REQUIRE(nt::concepts::greater_than_comparable); } THEN("it does have >=") { - STATIC_REQUIRE(has_greater_than_equal_to_v); + STATIC_REQUIRE(nt::concepts::greater_than_equal_comparable); } } GIVEN("A new_type over a type that is not relationally comparable not deriving nt::Relational") { using type_alias = nt::new_type; - static_assert(!has_less_than_v); - static_assert(!has_less_than_equal_to_v); - static_assert(!has_greater_than_v); - static_assert(!has_greater_than_equal_to_v); + static_assert(!nt::concepts::less_than_comparable); + static_assert(!nt::concepts::less_than_equal_comparable); + static_assert(!nt::concepts::greater_than_comparable); + static_assert(!nt::concepts::greater_than_equal_comparable); THEN("it does not have <") { - STATIC_REQUIRE_FALSE(has_less_than_v); + STATIC_REQUIRE_FALSE(nt::concepts::less_than_comparable); } THEN("it does not have <=") { - STATIC_REQUIRE_FALSE(has_less_than_equal_to_v); + STATIC_REQUIRE_FALSE(nt::concepts::less_than_equal_comparable); } THEN("it does not have >") { - STATIC_REQUIRE_FALSE(has_greater_than_v); + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_comparable); } THEN("it does not have >=") { - STATIC_REQUIRE_FALSE(has_greater_than_equal_to_v); + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_equal_comparable); } } GIVEN("A new_type over a type that is not relationally comparable deriving nt::Relational") { using type_alias = nt::new_type; - static_assert(!has_less_than_v); - static_assert(!has_less_than_equal_to_v); - static_assert(!has_greater_than_v); - static_assert(!has_greater_than_equal_to_v); + static_assert(!nt::concepts::less_than_comparable); + static_assert(!nt::concepts::less_than_equal_comparable); + static_assert(!nt::concepts::greater_than_comparable); + static_assert(!nt::concepts::greater_than_equal_comparable); THEN("it does not have <") { - STATIC_REQUIRE_FALSE(has_less_than_v); + STATIC_REQUIRE_FALSE(nt::concepts::less_than_comparable); } THEN("it does not have <=") { - STATIC_REQUIRE_FALSE(has_less_than_equal_to_v); + STATIC_REQUIRE_FALSE(nt::concepts::less_than_equal_comparable); } THEN("it does not have >") { - STATIC_REQUIRE_FALSE(has_greater_than_v); + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_comparable); } THEN("it does not have >=") { - STATIC_REQUIRE_FALSE(has_greater_than_equal_to_v); + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_equal_comparable); } } } @@ -202,10 +133,10 @@ SCENARIO("Relational Comparisons") GIVEN("A new_type over a relationally comparable type deriving nt::Relational") { using type_alias = nt::new_type; - static_assert(has_less_than_v); - static_assert(has_less_than_equal_to_v); - static_assert(has_greater_than_v); - static_assert(has_greater_than_equal_to_v); + static_assert(nt::concepts::less_than_comparable); + static_assert(nt::concepts::less_than_equal_comparable); + static_assert(nt::concepts::greater_than_comparable); + static_assert(nt::concepts::greater_than_equal_comparable); THEN("comparing two instances using < yields the same result as it does for the base type") { @@ -238,29 +169,29 @@ SCENARIO("Nothrow Relational Comparison") GIVEN("A new_type over a nothrow relationally comparable type deriving nt::Relational") { using type_alias = nt::new_type; - static_assert(has_nothrow_less_than_v); - static_assert(has_nothrow_less_than_equal_to_v); - static_assert(has_nothrow_greater_than_v); - static_assert(has_nothrow_greater_than_equal_to_v); + static_assert(nt::concepts::nothrow_less_than_comparable); + static_assert(nt::concepts::nothrow_less_than_equal_comparable); + static_assert(nt::concepts::nothrow_greater_than_comparable); + static_assert(nt::concepts::nothrow_greater_than_equal_comparable); THEN("it is nothrow-comparable using < ") { - STATIC_REQUIRE(has_nothrow_less_than_v); + STATIC_REQUIRE(nt::concepts::nothrow_less_than_comparable); } THEN("it is nothrow-comparable using <= ") { - STATIC_REQUIRE(has_nothrow_less_than_equal_to_v); + STATIC_REQUIRE(nt::concepts::nothrow_less_than_equal_comparable); } THEN("it is nothrow-comparable using > ") { - STATIC_REQUIRE(has_nothrow_greater_than_v); + STATIC_REQUIRE(nt::concepts::nothrow_greater_than_comparable); } THEN("it is nothrow-comparable using >= ") { - STATIC_REQUIRE(has_nothrow_greater_than_equal_to_v); + STATIC_REQUIRE(nt::concepts::nothrow_greater_than_equal_comparable); } } @@ -268,36 +199,53 @@ SCENARIO("Nothrow Relational Comparison") { struct strange_type { - auto constexpr operator<(strange_type const & other) const noexcept(false) -> bool; - auto constexpr operator>(strange_type const & other) const noexcept(false) -> bool; - auto constexpr operator<=(strange_type const & other) const noexcept(false) -> bool; - auto constexpr operator>=(strange_type const & other) const noexcept(false) -> bool; + auto constexpr operator<(strange_type const &) const noexcept(false) -> bool + { + return false; + } + auto constexpr operator>(strange_type const &) const noexcept(false) -> bool + { + return false; + } + auto constexpr operator<=(strange_type const &) const noexcept(false) -> bool + { + return false; + } + auto constexpr operator>=(strange_type const &) const noexcept(false) -> bool + { + return false; + } }; using type_alias = nt::new_type; - static_assert(has_less_than_v && !has_nothrow_less_than_v); - static_assert(has_less_than_equal_to_v && !has_nothrow_less_than_equal_to_v); - static_assert(has_greater_than_v && !has_nothrow_greater_than_v); - static_assert(has_greater_than_equal_to_v && !has_nothrow_greater_than_equal_to_v); + static_assert(nt::concepts::less_than_comparable && + !nt::concepts::nothrow_less_than_comparable); + static_assert(nt::concepts::less_than_equal_comparable && + !nt::concepts::nothrow_less_than_equal_comparable); + static_assert(nt::concepts::greater_than_comparable && + !nt::concepts::nothrow_greater_than_comparable); + static_assert(nt::concepts::greater_than_equal_comparable && + !nt::concepts::nothrow_greater_than_equal_comparable); THEN("it is not nothrow-comparable using < ") { - STATIC_REQUIRE(has_less_than_v && !has_nothrow_less_than_v); + STATIC_REQUIRE(nt::concepts::less_than_comparable && !nt::concepts::nothrow_less_than_comparable); } THEN("it is not nothrow-comparable using <= ") { - STATIC_REQUIRE(has_less_than_equal_to_v && !has_nothrow_less_than_equal_to_v); + STATIC_REQUIRE(nt::concepts::less_than_equal_comparable && !nt::concepts::nothrow_less_than_equal_comparable); } THEN("it is not nothrow-comparable using > ") { - STATIC_REQUIRE(has_greater_than_v && !has_nothrow_greater_than_v); + STATIC_REQUIRE(nt::concepts::greater_than_comparable && !nt::concepts::nothrow_greater_than_comparable); } THEN("it is not nothrow-comparable using >= ") { - STATIC_REQUIRE(has_greater_than_equal_to_v && !has_nothrow_greater_than_equal_to_v); + STATIC_REQUIRE(nt::concepts::greater_than_equal_comparable && + !nt::concepts::nothrow_greater_than_equal_comparable); } } } -- cgit v1.2.3 From bc83f6dd1330b6b9cb39c8600242d17ff964de36 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 8 Jun 2023 18:09:00 +0200 Subject: concepts: replace arithmetic traits --- source/lib/include/newtype/concepts.hpp | 65 ++++++++++++ .../newtype/impl/type_traits_extensions.hpp | 113 --------------------- source/lib/include/newtype/newtype.hpp | 24 ++--- source/tests/src/arithmetic.cpp | 32 +++--- 4 files changed, 93 insertions(+), 141 deletions(-) diff --git a/source/lib/include/newtype/concepts.hpp b/source/lib/include/newtype/concepts.hpp index a50b2b3..42713f5 100644 --- a/source/lib/include/newtype/concepts.hpp +++ b/source/lib/include/newtype/concepts.hpp @@ -9,6 +9,71 @@ namespace nt::concepts { + inline namespace arithmetic + { + + template + concept addable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs + rhs + } -> std::same_as; + }; + + template + concept nothrow_addable = requires(SubjectType lhs, SubjectType rhs) { + requires addable; + { + lhs + rhs + } noexcept; + }; + + template + concept divisible = requires(SubjectType lhs, SubjectType rhs) { + { + lhs / rhs + } -> std::same_as; + }; + + template + concept nothrow_divisible = requires(SubjectType lhs, SubjectType rhs) { + requires divisible; + { + lhs / rhs + } noexcept; + }; + + template + concept multipliable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs * rhs + } -> std::same_as; + }; + + template + concept nothrow_multipliable = requires(SubjectType lhs, SubjectType rhs) { + requires multipliable; + { + lhs / rhs + } noexcept; + }; + + template + concept subtractable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs - rhs + } -> std::same_as; + }; + + template + concept nothrow_subtractable = requires(SubjectType lhs, SubjectType rhs) { + requires subtractable; + { + lhs - rhs + } noexcept; + }; + + } // namespace arithmetic + inline namespace comparability { diff --git a/source/lib/include/newtype/impl/type_traits_extensions.hpp b/source/lib