diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2023-06-08 13:49:36 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2023-06-08 13:49:36 +0200 |
| commit | 3e90982d29b54523c3a617cfff7ec6bcc42ba1e8 (patch) | |
| tree | feaa0f95471f485cd37418cc6369cf5f417d26ec | |
| parent | 7adcce5945e48cfcf87642d248317d54d8c1963d (diff) | |
| download | newtype-3e90982d29b54523c3a617cfff7ec6bcc42ba1e8.tar.xz newtype-3e90982d29b54523c3a617cfff7ec6bcc42ba1e8.zip | |
concepts: replace is_hashable_v
| -rw-r--r-- | source/lib/include/newtype/concepts.hpp | 19 | ||||
| -rw-r--r-- | source/lib/include/newtype/impl/type_traits_extensions.hpp | 19 | ||||
| -rw-r--r-- | source/lib/include/newtype/newtype.hpp | 7 | ||||
| -rw-r--r-- | source/tests/src/hash.cpp | 19 |
4 files changed, 35 insertions, 29 deletions
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 <concepts> +#include <cstddef> +#include <functional> + +namespace nt::concepts +{ + template<typename SubjectType> + concept hashable = requires(SubjectType subject) { + { + std::hash<SubjectType>{}(subject) + } -> std::convertible_to<std::size_t>; + }; + +} // 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<typename T, typename = void> - struct is_hashable : std::false_type - { - }; - - template<typename T> - struct is_hashable<T, std::void_t<decltype(std::declval<std::hash<T> const &>()(std::declval<T const &>()))>> - : std::is_same<std::size_t, decltype(std::declval<std::hash<T> const &>()(std::declval<T const &>()))> - { - }; - - template<typename T> - auto constexpr is_hashable_v = is_hashable<T>::value; - - } // namespace std_support - inline namespace iterable_begin { template<typename T, typename = void> 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<typename BaseType, typename TagType, auto DerivationClause> + requires(nt::concepts::hashable<BaseType> && DerivationClause(nt::Hash)) struct hash<nt::new_type<BaseType, TagType, DerivationClause>> { - template<typename BaseTypeT = BaseType> - auto constexpr operator()(nt::new_type<BaseType, TagType, DerivationClause> const & object, - std::enable_if_t<DerivationClause(nt::Hash) && nt::impl::is_hashable_v<BaseTypeT>> * = nullptr) const - -> std::size_t + auto constexpr operator()(nt::new_type<BaseType, TagType, DerivationClause> const & object) const { return std::hash<BaseType>{}(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 <catch2/catch_template_test_macros.hpp> #include <catch2/catch_test_macros.hpp> +#include <string> #include <unordered_map> -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<int, struct tag>; + using type_alias = nt::new_type<TestType, struct tag>; + static_assert(nt::concepts::hashable<typename type_alias::base_type>); THEN("it is not hashable") { - STATIC_REQUIRE_FALSE(nt::impl::is_hashable_v<type_alias>); + STATIC_REQUIRE_FALSE(nt::concepts::hashable<type_alias>); } } GIVEN("A new_type over a hashable type deriving nt::Hash") { - using type_alias = nt::new_type<int, struct tag, deriving(nt::Hash)>; + using type_alias = nt::new_type<TestType, struct tag, deriving(nt::Hash)>; + static_assert(nt::concepts::hashable<typename type_alias::base_type>); THEN("it is hashable") { - STATIC_REQUIRE(nt::impl::is_hashable_v<type_alias>); + STATIC_REQUIRE(nt::concepts::hashable<type_alias>); } } @@ -35,16 +40,18 @@ SCENARIO("Hash", "[hash]") { }; using type_alias = nt::new_type<non_hashable, struct tag, deriving(nt::Hash)>; + static_assert(!nt::concepts::hashable<typename type_alias::base_type>); THEN("it is not hashable") { - STATIC_REQUIRE_FALSE(nt::impl::is_hashable_v<type_alias>); + STATIC_REQUIRE_FALSE(nt::concepts::hashable<type_alias>); } } GIVEN("A hashable new_type") { using type_alias = nt::new_type<int, struct tag, deriving(nt::Hash)>; + static_assert(nt::concepts::hashable<typename type_alias::base_type>); THEN("it can be used a the key in an unordered_map") { |
