aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2020-01-03 13:10:02 +0100
committerFelix Morgner <felix.morgner@gmail.com>2020-01-03 13:10:02 +0100
commitd5970f8ed49a15d19265c71c8618e32a9534eeee (patch)
treec03bc611027f32d9639bfb645523e9bd29b68f42 /include
parent8551177740f435bd510df6af3fa3d32da39bb526 (diff)
downloadnewtype-d5970f8ed49a15d19265c71c8618e32a9534eeee.tar.xz
newtype-d5970f8ed49a15d19265c71c8618e32a9534eeee.zip
new_type: implement support for derivation of Hash
Diffstat (limited to 'include')
-rw-r--r--include/newtype/derivable.hpp7
-rw-r--r--include/newtype/impl/type_traits_extensions.hpp38
-rw-r--r--include/newtype/new_type.hpp16
3 files changed, 61 insertions, 0 deletions
diff --git a/include/newtype/derivable.hpp b/include/newtype/derivable.hpp
index 95353eb..38a2375 100644
--- a/include/newtype/derivable.hpp
+++ b/include/newtype/derivable.hpp
@@ -36,6 +36,13 @@ namespace nt
auto constexpr EqBase = derivable<struct eq_base_tag>{};
/**
+ * @brief A tag to enable derivation of a specialization of std::hash
+ *
+ * @since 1.0.0
+ */
+ auto constexpr Hash = derivable<struct hash_tag>{};
+
+ /**
* @brief A tag to enable derivation of the implicit "conversion to base type" operator
*
* @note If this tag is not present in the derivation clause of any given nt::new_type, the type instance only supports explicit
diff --git a/include/newtype/impl/type_traits_extensions.hpp b/include/newtype/impl/type_traits_extensions.hpp
index 10dbc07..d773d40 100644
--- a/include/newtype/impl/type_traits_extensions.hpp
+++ b/include/newtype/impl/type_traits_extensions.hpp
@@ -1,6 +1,8 @@
#ifndef NEWTYPE_IMPL_TYPE_TRAITS_EXTENSIONS_HPP
#define NEWTYPE_IMPL_TYPE_TRAITS_EXTENSIONS_HPP
+#include <cstddef>
+#include <functional>
#include <iosfwd>
#include <type_traits>
@@ -1011,6 +1013,42 @@ namespace nt::impl
} // namespace compound_arithmetic
+ inline namespace std_support
+ {
+
+ /**
+ * @brief A trait to test if a given type is hashable
+ *
+ * @tparam T The type to test
+ * @note This specialization forms the base case for non-hashable T
+ */
+ template<typename T, typename = void>
+ struct is_hashable : std::false_type
+ {
+ };
+
+ /**
+ * @brief A trait to test if a given type is hashable
+ *
+ * @tparam T The type to test
+ * @note This specialization forms the case for hashable T
+ */
+ 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 &>()))>
+ {
+ };
+
+ /**
+ * @brief A variable template to test if a given type is hashable
+ *
+ * @tparam T The type to test
+ */
+ template<typename T>
+ auto constexpr is_hashable_v = is_hashable<T>::value;
+
+ } // namespace std_support
+
} // namespace nt::impl
#endif \ No newline at end of file
diff --git a/include/newtype/new_type.hpp b/include/newtype/new_type.hpp
index a59a074..1477c95 100644
--- a/include/newtype/new_type.hpp
+++ b/include/newtype/new_type.hpp
@@ -6,6 +6,7 @@
#include "newtype/impl/new_type_storage.hpp"
#include "newtype/impl/type_traits_extensions.hpp"
+#include <functional>
#include <istream>
#include <ostream>
#include <type_traits>
@@ -569,4 +570,19 @@ namespace nt
} // namespace nt
+namespace std
+{
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ struct hash<nt::new_type<BaseType, TagType, DerivationClause>>
+ {
+ template<typename BaseTypeT = BaseType, auto DerivationClauseV = DerivationClause>
+ auto constexpr operator()(nt::new_type<BaseType, TagType, DerivationClause> const & object,
+ std::enable_if_t<DerivationClauseV(nt::Hash) && nt::impl::is_hashable_v<BaseTypeT>> * = nullptr) const
+ -> std::size_t
+ {
+ return std::hash<BaseType>{}(object.decay());
+ }
+ };
+} // namespace std
+
#endif