aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2020-03-01 12:19:49 +0100
committerFelix Morgner <felix.morgner@gmail.com>2020-03-01 12:19:49 +0100
commit1bd35044ee96e2bccb66749be5a48307c6e28218 (patch)
treea2e1b4760713a20ae63c3a72ae47425a71e7053c /include
parentf00fb5779dcf2443b74d114093afbbd2441523ad (diff)
parent8c5f53f0c3052cc30c2fe78feb1432b2a5c4e847 (diff)
downloadnewtype-master.tar.xz
newtype-master.zip
newtype: release version 1.1.0v1.1.0master
Diffstat (limited to 'include')
-rw-r--r--include/newtype/derivable.hpp58
-rw-r--r--include/newtype/derivation_clause.hpp45
-rw-r--r--include/newtype/deriving.hpp3
-rw-r--r--include/newtype/impl/new_type_iterator_types.hpp66
-rw-r--r--include/newtype/impl/type_traits_extensions.hpp923
-rw-r--r--include/newtype/new_type.hpp527
-rw-r--r--include/newtype/version.hpp6
7 files changed, 674 insertions, 954 deletions
diff --git a/include/newtype/derivable.hpp b/include/newtype/derivable.hpp
index 19c79d9..c798c59 100644
--- a/include/newtype/derivable.hpp
+++ b/include/newtype/derivable.hpp
@@ -12,73 +12,17 @@ namespace nt
using tag_type = DerivableTag;
};
- /**
- * @brief A set of standard derivation tags
- *
- * This convenience namespace contains all standard derivation tags.
- *
- * @since 1.0.0
- */
inline namespace derivables
{
- /**
- * @brief A tag to enable derivation of arithmetic operators
- *
- * @since 1.0.0
- */
auto constexpr Arithmetic = derivable<struct arithmetic_tag>{};
-
- /**
- * @brief A tag to enable derivation of "equality comparison with base type" operators
- *
- * @note Deriving this feature seriously weakens the using nt::new_type instance
- * @since 1.0.0
- */
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
- * "conversion to base type"
- * @since 1.0.0
- */
auto constexpr ImplicitConversion = derivable<struct implicit_conversion_tag>{};
-
- /**
- * @brief A tag to enable access to the members of the base type object through a pointer
- *
- * @since 1.0.0
- */
auto constexpr Indirection = derivable<struct indirection_tag>{};
-
- /**
- * @brief A tag to enable derivation of the stream input operator
- *
- * @since 1.0.0
- */
+ auto constexpr Iterable = derivable<struct iterable_tag>{};
auto constexpr Read = derivable<struct read_tag>{};
-
- /**
- * @brief A tag to enable derivation of the relational operators
- *
- * @since 1.0.0
- */
auto constexpr Relational = derivable<struct relational_tag>{};
-
- /**
- * @brief A tag to enable derivation of the stream output operator
- *
- * @since 1.0.0
- */
auto constexpr Show = derivable<struct show_tag>{};
} // namespace derivables
diff --git a/include/newtype/derivation_clause.hpp b/include/newtype/derivation_clause.hpp
index edb2f85..6de70e1 100644
--- a/include/newtype/derivation_clause.hpp
+++ b/include/newtype/derivation_clause.hpp
@@ -9,11 +9,6 @@
namespace nt
{
- /**
- * A @p deriving clause type
- *
- * @tparam DerivableTags A list of tag types defining a set of derivable features
- */
template<typename... DerivableTags>
struct derivation_clause
{
@@ -21,88 +16,48 @@ namespace nt
{
}
- /**
- * Check whether the derivation clause contains a given derivable
- */
template<typename DerivableTag>
auto constexpr operator()(derivable<DerivableTag>) const noexcept -> bool
{
return (std::is_same_v<DerivableTags, DerivableTag> || ...);
}
- /**
- * Check whether the derivation clause contains all derivables in a given lists
- */
template<typename DerivableTag, typename... RemainingDerivableTags>
auto constexpr operator()(derivable<DerivableTag>, derivable<RemainingDerivableTags>...) const noexcept -> bool
{
return (*this)(derivable<DerivableTag>{}) && (*this)(derivable<RemainingDerivableTags>{}...);
}
- /**
- * Check whether this derivation clause is less than an other derivation clause
- *
- * A derivation clause is considered less than an other derivation clause iff. its set of derivables is a strict subset of
- * the set derivables of the other.
- */
template<typename... OtherDerivableTags>
auto constexpr operator<(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool
{
return (sizeof...(DerivableTags) < sizeof...(OtherDerivableTags)) && other(derivable<DerivableTags>{}...);
}
- /**
- * Check whether this derivation clause is greater than an other derivation clause
- *
- * A derivation clause is considered greater than an other derivation clause iff. its set of derivables is a strict superset
- * of the set derivables of the other.
- */
template<typename... OtherDerivableTags>
auto constexpr operator>(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool
{
return other < *this;
}
- /**
- * Check whether this derivation clause is equal to an other derivation clause
- *
- * Two derivation clauses are considered equal if both have the same set of derivables
- */
template<typename... OtherDerivableTags>
auto constexpr operator==(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool
{
return sizeof...(DerivableTags) == sizeof...(OtherDerivableTags) && other(derivable<DerivableTags>{}...);
}
- /**
- * Check whether this derivation clause is not equal to an other derivation clause
- *
- * Two derivation clauses are considered not equal if neither has the same set of derivables as the other
- */
template<typename... OtherDerivableTags>
auto constexpr operator!=(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool
{
return !(*this == other);
}
- /**
- * Check whether this derivation clause is less-than or equal to an other derivation clause
- *
- * @see nt::distinct::operator==
- * @see nt::distinct::operator<
- */
template<typename... OtherDerivableTags>
auto constexpr operator<=(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool
{
return *this < other || *this == other;
}
- /**
- * Check whether this derivation clause is greater-than or equal to an other derivation clause
- *
- * @see nt::distinct::operator==
- * @see nt::distinct::operator<
- */
template<typename... OtherDerivableTags>
auto constexpr operator>=(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool
{
diff --git a/include/newtype/deriving.hpp b/include/newtype/deriving.hpp
index e762c9b..ae10bab 100644
--- a/include/newtype/deriving.hpp
+++ b/include/newtype/deriving.hpp
@@ -10,9 +10,6 @@
namespace nt
{
- /**
- * Create a new derivation clause with the given derivables
- */
template<typename... DerivableTags>
auto constexpr deriving(derivable<DerivableTags>... features) noexcept -> derivation_clause<DerivableTags...>
{
diff --git a/include/newtype/impl/new_type_iterator_types.hpp b/include/newtype/impl/new_type_iterator_types.hpp
new file mode 100644
index 0000000..2ea8274
--- /dev/null
+++ b/include/newtype/impl/new_type_iterator_types.hpp
@@ -0,0 +1,66 @@
+#ifndef NEWTYPE_IMPL_NEW_TYPE_ITERATOR_TYPES_HPP
+#define NEWTYPE_IMPL_NEW_TYPE_ITERATOR_TYPES_HPP
+
+#include "newtype/version.hpp"
+
+#include <type_traits>
+
+namespace nt::impl
+{
+
+ template<typename T, bool = false, typename = std::void_t<>>
+ struct new_type_iterator
+ {
+ };
+
+ template<typename T>
+ struct new_type_iterator<T, true, std::void_t<typename T::iterator>>
+ {
+ using iterator = typename T::iterator;
+ };
+
+ template<typename T, bool = false, typename = std::void_t<>>
+ struct new_type_const_iterator
+ {
+ };
+
+ template<typename T>
+ struct new_type_const_iterator<T, true, std::void_t<typename T::const_iterator>>
+ {
+ using const_iterator = typename T::const_iterator;
+ };
+
+ template<typename T, bool = false, typename = std::void_t<>>
+ struct new_type_reverse_iterator
+ {
+ };
+
+ template<typename T>
+ struct new_type_reverse_iterator<T, true, std::void_t<typename T::reverse_iterator>>
+ {
+ using reverse_iterator = typename T::reverse_iterator;
+ };
+
+ template<typename T, bool = false, typename = std::void_t<>>
+ struct new_type_const_reverse_iterator
+ {
+ };
+
+ template<typename T>
+ struct new_type_const_reverse_iterator<T, true, std::void_t<typename T::const_reverse_iterator>>
+ {
+ using const_reverse_iterator = typename T::const_reverse_iterator;
+ };
+
+ template<typename T, bool Enabled>
+ struct new_type_iterator_types
+ : new_type_iterator<T, Enabled>
+ , new_type_const_iterator<T, Enabled>
+ , new_type_reverse_iterator<T, Enabled>
+ , new_type_const_reverse_iterator<T, Enabled>
+ {
+ };
+
+} // namespace nt::impl
+
+#endif \ No newline at end of file
diff --git a/include/newtype/impl/type_traits_extensions.hpp b/include/newtype/impl/type_traits_extensions.hpp
index 1f46fb4..dc41649 100644
--- a/include/newtype/impl/type_traits_extensions.hpp
+++ b/include/newtype/impl/type_traits_extensions.hpp
@@ -14,125 +14,57 @@ namespace nt::impl
inline namespace equality_comparable
{
- /**
- * @brief A trait to test if a given type is comparable using operator==
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-equals-comparable T
- */
template<typename T, typename = void>
struct is_equality_comparable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is comparable using operator==
- *
- * @tparam T The type to test
- * @note This specialization forms the case for equals-comparable T
- */
template<typename T>
struct is_equality_comparable<T, std::void_t<decltype(std::declval<T const &>() == std::declval<T const &>())>> : std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is comparable using operator==
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_equality_comparable_v = is_equality_comparable<T>::value;
- /**
- * @brief A trait to test if a given type is noexcept comparable using operator==
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept equals-comparable or non-equals-comparable T
- */
template<typename T, typename = void>
struct is_nothrow_equality_comparable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept comparable using operator==
- *
- * @tparam T The type to test
- * @note This specialization forms the case for equals-comparable T detemining if T is noexcept comparable using operator==
- */
template<typename T>
struct is_nothrow_equality_comparable<T, std::void_t<decltype(std::declval<T const &>() == std::declval<T const &>())>>
: std::bool_constant<noexcept(std::declval<T const &>() == std::declval<T const &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept comparable using operator==
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_nothrow_equality_comparable_v = is_nothrow_equality_comparable<T>::value;
- /**
- * @brief A trait to test if a given type is comparable using operator!=
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-not-equals-comparable T
- */
template<typename T, typename = void>
struct is_inequality_comparable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is comparable using operator!=
- *
- * @tparam T The type to test
- * @note This specialization forms the case for not-equals-comparable T
- */
template<typename T>
struct is_inequality_comparable<T, std::void_t<decltype(std::declval<T const &>() != std::declval<T const &>())>> : std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is comparable using operator!=
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_inequality_comparable_v = is_inequality_comparable<T>::value;
- /**
- * @brief A trait to test if a given type is noexcept comparable using operator!=
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept not-equals-comparable or non-not-equals-comparable T
- */
template<typename T, typename = void>
struct is_nothrow_inequality_comparable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept comparable using operator==
- *
- * @tparam T The type to test
- * @note This specialization forms the case for equals-comparable T detemining if T is noexcept comparable using operator!=
- */
template<typename T>
struct is_nothrow_inequality_comparable<T, std::void_t<decltype(std::declval<T const &>() != std::declval<T const &>())>>
: std::bool_constant<noexcept(std::declval<T const &>() != std::declval<T const &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept comparable using operator!=
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_nothrow_inequality_comparable_v = is_nothrow_inequality_comparable<T>::value;
@@ -141,250 +73,112 @@ namespace nt::impl
inline namespace relationally_comparable
{
- /**
- * @brief A trait to test if a given type is comparable using operator<
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-less-than-comparable T
- */
template<typename T, typename = void>
struct is_less_than_comparable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is comparable using operator<
- *
- * @tparam T The type to test
- * @note This specialization forms the case for less-than-comparable T
- */
template<typename T>
struct is_less_than_comparable<T, std::void_t<decltype(std::declval<T const &>() < std::declval<T const &>())>> : std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is comparable using operator<
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_less_than_comparable_v = is_less_than_comparable<T>::value;
- /**
- * @brief A trait to test if a given type is noexcept comparable using operator<
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept less-than-comparable or non-less-than-comparable T
- */
template<typename T, typename = void>
struct is_nothrow_less_than_comparable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept comparable using operator<
- *
- * @tparam T The type to test
- * @note This specialization forms the case for less-than-comparable T detemining if T is noexcept comparable using operator<
- */
template<typename T>
struct is_nothrow_less_than_comparable<T, std::void_t<decltype(std::declval<T const &>() < std::declval<T const &>())>>
: std::bool_constant<noexcept(std::declval<T const &>() < std::declval<T const &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept comparable using operator<
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_nothrow_less_than_comparable_v = is_nothrow_less_than_comparable<T>::value;
- /**
- * @brief A trait to test if a given type is comparable using operator>
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-greater-than-comparable T
- */
template<typename T, typename = void>
struct is_greater_than_comparable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is comparable using operator>
- *
- * @tparam T The type to test
- * @note This specialization forms the case for greater-than-comparable T
- */
template<typename T>
struct is_greater_than_comparable<T, std::void_t<decltype(std::declval<T const &>() > std::declval<T const &>())>> : std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is comparable using operator>
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_greater_than_comparable_v = is_greater_than_comparable<T>::value;
- /**
- * @brief A trait to test if a given type is noexcept comparable using operator>
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept greater-than-comparable or non-greater-than-comparable T
- */
template<typename T, typename = void>
struct is_nothrow_greater_than_comparable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept comparable using operator>
- *
- * @tparam T The type to test
- * @note This specialization forms the case for greater-than-comparable T detemining if T is noexcept comparable using operator>
- */
template<typename T>
struct is_nothrow_greater_than_comparable<T, std::void_t<decltype(std::declval<T const &>() > std::declval<T const &>())>>
: std::bool_constant<noexcept(std::declval<T const &>() > std::declval<T const &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept comparable using operator>
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_nothrow_greater_than_comparable_v = is_nothrow_greater_than_comparable<T>::value;
- /**
- * @brief A trait to test if a given type is comparable using operator<=
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-less-than-or-equal-to-comparable T
- */
template<typename T, typename = void>
struct is_less_than_equal_to_comparable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is comparable using operator<=
- *
- * @tparam T The type to test
- * @note This specialization forms the case for less-than-or-equal-to-comparable T
- */
template<typename T>
struct is_less_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() <= std::declval<T const &>())>> : std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is comparable using operator<=
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_less_than_equal_to_comparable_v = is_less_than_equal_to_comparable<T>::value;
- /**
- * @brief A trait to test if a given type is noexcept comparable using operator<=
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept less-than-or-equal-to-comparable or non-less-than-or-equal-to-comparable T
- */
template<typename T, typename = void>
struct is_nothrow_less_than_equal_to_comparable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept comparable using operator<=
- *
- * @tparam T The type to test
- * @note This specialization forms the case for less-than-or-equal-to-comparable T detemining if T is noexcept comparable using operator<=
- */
template<typename T>
struct is_nothrow_less_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() <= std::declval<T const &>())>>
: std::bool_constant<noexcept(std::declval<T const &>() <= std::declval<T const &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept comparable using operator<=
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_nothrow_less_than_equal_to_comparable_v = is_nothrow_less_than_equal_to_comparable<T>::value;
- /**
- * @brief A trait to test if a given type is comparable using operator>=
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-greater-than-or-equal-to-comparable T
- */
template<typename T, typename = void>
struct is_greater_than_equal_to_comparable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is comparable using operator>=
- *
- * @tparam T The type to test
- * @note This specialization forms the case for greater-than-or-equal-to-comparable T
- */
template<typename T>
struct is_greater_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() >= std::declval<T const &>())>>
: std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is comparable using operator>=
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_greater_than_equal_to_comparable_v = is_greater_than_equal_to_comparable<T>::value;
- /**
- * @brief A trait to test if a given type is noexcept comparable using operator>=
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept greater-than-or-equal-to-comparable or
- * non-greater-than-or-equal-to-comparable T
- */
template<typename T, typename = void>
struct is_nothrow_greater_than_equal_to_comparable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept comparable using operator>=
- *
- * @tparam T The type to test
- * @note This specialization forms the case for greater-than-or-equal-to-comparable T detemining if T is noexcept comparable using
- * operator>=
- */
template<typename T>
struct is_nothrow_greater_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() >= std::declval<T const &>())>>
: std::bool_constant<noexcept(std::declval<T const &>() >= std::declval<T const &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept comparable using operator>=
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_nothrow_greater_than_equal_to_comparable_v = is_nothrow_greater_than_equal_to_comparable<T>::value;
} // namespace relationally_comparable
@@ -392,126 +186,58 @@ namespace nt::impl
inline namespace iostreamable
{
- /**
- * @brief A trait to test if a given type is output streamable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-output-streamable T
- */
template<typename StreamType, typename T, typename = void>
struct is_output_streamable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is output streamable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for output-streamable T
- */
template<typename StreamType, typename T>
struct is_output_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() << std::declval<T const &>())>>
: std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is output streamable
- *
- * @tparam T The type to test
- */
template<typename StreamType, typename T>
auto constexpr is_output_streamable_v = is_output_streamable<StreamType, T>::value;
- /**
- * @brief A trait to test if a given type is noexcept output streamable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept output-streamable or non-output-streamable T
- */
template<typename StreamType, typename T, typename = void>
struct is_nothrow_output_streamable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept output streamable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for output-streamable T detemining if T is noexcept output-streamable
- */
template<typename StreamType, typename T>
struct is_nothrow_output_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() << std::declval<T const &>())>>
: std::bool_constant<noexcept(std::declval<StreamType &>() << std::declval<T const &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept output streamable
- *
- * @tparam T The type to test
- */
template<typename StreamType, typename T>
auto constexpr is_nothrow_output_streamable_v = is_nothrow_output_streamable<StreamType, T>::value;
- /**
- * @brief A trait to test if a given type is input streamable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-input-streamable T
- */
template<typename StreamType, typename T, typename = void>
struct is_input_streamable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is input streamable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for input-streamable T
- */
template<typename StreamType, typename T>
struct is_input_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() >> std::declval<T &>())>> : std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is input streamable
- *
- * @tparam T The type to test
- */
template<typename StreamType, typename T>
auto constexpr is_input_streamable_v = is_input_streamable<StreamType, T>::value;
- /**
- * @brief A trait to test if a given type is noexcept input streamable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept input-streamable or non-input-streamable T
- */
template<typename StreamType, typename T, typename = void>
struct is_nothrow_input_streamable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept input streamable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for input-streamable T detemining if T is noexcept input-streamable
- */
template<typename StreamType, typename T>
struct is_nothrow_input_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() >> std::declval<T &>())>>
: std::bool_constant<noexcept(std::declval<StreamType &>() >> std::declval<T &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept input streamable
- *
- * @tparam T The type to test
- */
template<typename StreamType, typename T>
auto constexpr is_nothrow_input_streamable_v = is_nothrow_input_streamable<StreamType, T>::value;
@@ -520,247 +246,111 @@ namespace nt::impl
inline namespace arithmetic
{
- /**
- * @brief A trait to test if a given type is addable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-addable T
- */
template<typename T, typename = void>
struct is_addable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is addable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for addable T
- */
template<typename T>
struct is_addable<T, std::void_t<decltype(std::declval<T const &>() + std::declval<T const &>())>> : std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is addable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_addable_v = is_addable<T>::value;
- /**
- * @brief A trait to test if a given type is noexcept addable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept addable or non-addable T
- */
template<typename T, typename = void>
struct is_nothrow_addable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept addable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for addable T detemining if T is noexcept addable
- */
template<typename T>
struct is_nothrow_addable<T, std::void_t<decltype(std::declval<T const &>() + std::declval<T const &>())>>
: std::bool_constant<noexcept(std::declval<T const &>() + std::declval<T const &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept addable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_nothrow_addable_v = is_nothrow_addable<T>::value;
- /**
- * @brief A trait to test if a given type is subtractable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-subtractable T
- */
template<typename T, typename = void>
struct is_subtractable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is subtractable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for subtractable T
- */
template<typename T>
struct is_subtractable<T, std::void_t<decltype(std::declval<T const &>() - std::declval<T const &>())>> : std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is subtractable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_subtractable_v = is_subtractable<T>::value;
- /**
- * @brief A trait to test if a given type is noexcept subtractable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept subtractable or non-subtractable T
- */
template<typename T, typename = void>
struct is_nothrow_subtractable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept subtractable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for subtractable T detemining if T is noexcept subtractable
- */
template<typename T>
struct is_nothrow_subtractable<T, std::void_t<decltype(std::declval<T const &>() - std::declval<T const &>())>>
: std::bool_constant<noexcept(std::declval<T const &>() - std::declval<T const &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept subtractable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_nothrow_subtractable_v = is_nothrow_subtractable<T>::value;
- /**
- * @brief A trait to test if a given type is multipliable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-multipliable T
- */
template<typename T, typename = void>
struct is_multipliable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is multipliable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for multipliable T
- */
template<typename T>
struct is_multipliable<T, std::void_t<decltype(std::declval<T const &>() * std::declval<T const &>())>> : std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is multipliable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_multipliable_v = is_multipliable<T>::value;
- /**
- * @brief A trait to test if a given type is noexcept multipliable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept multipliable or non-multipliable T
- */
template<typename T, typename = void>
struct is_nothrow_multipliable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept multipliable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for multipliable T detemining if T is noexcept multipliable
- */
template<typename T>
struct is_nothrow_multipliable<T, std::void_t<decltype(std::declval<T const &>() * std::declval<T const &>())>>
: std::bool_constant<noexcept(std::declval<T const &>() * std::declval<T const &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept multipliable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_nothrow_multipliable_v = is_nothrow_multipliable<T>::value;
- /**
- * @brief A trait to test if a given type is dividable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-dividable T
- */
template<typename T, typename = void>
struct is_dividable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is dividable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for dividable T
- */
template<typename T>
struct is_dividable<T, std::void_t<decltype(std::declval<T const &>() / std::declval<T const &>())>> : std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is dividable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_dividable_v = is_dividable<T>::value;
- /**
- * @brief A trait to test if a given type is noexcept dividable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept dividable or non-dividable T
- */
template<typename T, typename = void>
struct is_nothrow_dividable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept dividable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for dividable T detemining if T is noexcept dividable
- */
template<typename T>
struct is_nothrow_dividable<T, std::void_t<decltype(std::declval<T const &>() / std::declval<T const &>())>>
: std::bool_constant<noexcept(std::declval<T const &>() / std::declval<T const &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept dividable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_nothrow_dividable_v = is_nothrow_dividable<T>::value;
@@ -769,247 +359,111 @@ namespace nt::impl
inline namespace compound_arithmetic
{
- /**
- * @brief A trait to test if a given type is add-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-add-assignable T
- */
template<typename T, typename = void>
struct is_add_assignable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is add-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for add-assignable T
- */
template<typename T>
struct is_add_assignable<T, std::void_t<decltype(std::declval<T &>() += std::declval<T const &>())>> : std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is add-assignable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_add_assignable_v = is_add_assignable<T>::value;
- /**
- * @brief A trait to test if a given type is noexcept add-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept add-assignable or non-add-assignable T
- */
template<typename T, typename = void>
struct is_nothrow_add_assignable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept add-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for add-assignable T detemining if T is noexcept add-assignable
- */
template<typename T>
struct is_nothrow_add_assignable<T, std::void_t<decltype(std::declval<T &>() += std::declval<T const &>())>>
: std::bool_constant<noexcept(std::declval<T &>() += std::declval<T const &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept add-assignable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_nothrow_add_assignable_v = is_nothrow_add_assignable<T>::value;
- /**
- * @brief A trait to test if a given type is subtract-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-subtract-assignable T
- */
template<typename T, typename = void>
struct is_subtract_assignable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is subtract-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for subtract-assignable T
- */
template<typename T>
struct is_subtract_assignable<T, std::void_t<decltype(std::declval<T &>() -= std::declval<T const &>())>> : std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is subtract-assignable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_subtract_assignable_v = is_subtract_assignable<T>::value;
- /**
- * @brief A trait to test if a given type is noexcept subtract-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept subtract-assignable or non-subtract-assignable T
- */
template<typename T, typename = void>
struct is_nothrow_subtract_assignable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept subtract-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for subtract-assignable T detemining if T is noexcept subtract-assignable
- */
template<typename T>
struct is_nothrow_subtract_assignable<T, std::void_t<decltype(std::declval<T &>() -= std::declval<T const &>())>>
: std::bool_constant<noexcept(std::declval<T &>() -= std::declval<T const &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept subtract-assignable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_nothrow_subtract_assignable_v = is_nothrow_subtract_assignable<T>::value;
- /**
- * @brief A trait to test if a given type is multiply-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-multiply-assignable T
- */
template<typename T, typename = void>
struct is_multiply_assignable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is multiply-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for multiply-assignable T
- */
template<typename T>
struct is_multiply_assignable<T, std::void_t<decltype(std::declval<T &>() *= std::declval<T const &>())>> : std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is multiply-assignable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_multiply_assignable_v = is_multiply_assignable<T>::value;
- /**
- * @brief A trait to test if a given type is noexcept multiply-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept multiply-assignable or non-multiply-assignable T
- */
template<typename T, typename = void>
struct is_nothrow_multiply_assignable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept multiply-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for multiply-assignable T detemining if T is noexcept multiply-assignable
- */
template<typename T>
struct is_nothrow_multiply_assignable<T, std::void_t<decltype(std::declval<T &>() *= std::declval<T const &>())>>
: std::bool_constant<noexcept(std::declval<T &>() *= std::declval<T const &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept multiply-assignable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_nothrow_multiply_assignable_v = is_nothrow_multiply_assignable<T>::value;
- /**
- * @brief A trait to test if a given type is divide-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-divide-assignable T
- */
template<typename T, typename = void>
struct is_divide_assignable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is divide-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for divide-assignable T
- */
template<typename T>
struct is_divide_assignable<T, std::void_t<decltype(std::declval<T &>() /= std::declval<T const &>())>> : std::true_type
{
};
- /**
- * @brief A variable template to test if a given type is divide-assignable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_divide_assignable_v = is_divide_assignable<T>::value;
- /**
- * @brief A trait to test if a given type is noexcept divide-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the base case for non-noexcept divide-assignable or non-divide-assignable T
- */
template<typename T, typename = void>
struct is_nothrow_divide_assignable : std::false_type
{
};
- /**
- * @brief A trait to test if a given type is noexcept divide-assignable
- *
- * @tparam T The type to test
- * @note This specialization forms the case for divide-assignable T detemining if T is noexcept divide-assignable
- */
template<typename T>
struct is_nothrow_divide_assignable<T, std::void_t<decltype(std::declval<T &>() /= std::declval<T const &>())>>
: std::bool_constant<noexcept(std::declval<T &>() /= std::declval<T const &>())>
{
};
- /**
- * @brief A variable template to test if a given type is noexcept divide-assignable
- *
- * @tparam T The type to test
- */
template<typename T>
auto constexpr is_nothrow_divide_assignable_v = is_nothrow_divide_assignable<T>::value;
@@ -1018,39 +472,382 @@ namespace nt::impl
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
+ inline namespace iterable_begin
+ {
+ template<typename T, typename = void>
+ struct has_free_begin : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_free_begin<T, std::void_t<decltype(begin(std::declval<T &>()))>>
+ : std::is_same<typename T::iterator, std::remove_cvref_t<decltype(begin(std::declval<T &>()))>>
+ {
+ };
+
+ template<typename T>
+ struct has_free_begin<T const, std::void_t<decltype(begin(std::declval<T const &>()))>>
+ : std::is_same<typename T::const_iterator, std::remove_cvref_t<decltype(begin(std::declval<T const &>()))>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_free_begin_v = has_free_begin<T>::value;
+
+ template<typename T, typename = void>
+ struct has_member_begin : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_member_begin<T, std::void_t<decltype(std::declval<T &>().begin())>>
+ : std::is_same<typename T::iterator, std::remove_cvref_t<decltype(std::declval<T &>().begin())>>
+ {
+ };
+
+ template<typename T>
+ struct has_member_begin<T const, std::void_t<decltype(std::declval<T const &>().begin())>>
+ : std::is_same<typename T::const_iterator, std::remove_cvref_t<decltype(std::declval<T const &>().begin())>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_member_begin_v = has_member_begin<T>::value;
+
+ template<typename T>
+ struct has_begin : std::disjunction<has_free_begin<T>, has_member_begin<T>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_begin_v = has_begin<T>::value;
+ } // namespace iterable_begin
+
+ inline namespace iterable_cbegin
+ {
+ template<typename T, typename = void>
+ struct has_free_cbegin : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_free_cbegin<T, std::void_t<decltype(cbegin(std::declval<T const &>()))>>
+ : std::is_same<typename T::const_iterator, std::remove_cvref_t<decltype(cbegin(std::declval<T const &>()))>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_free_cbegin_v = has_free_cbegin<T>::value;
+
+ template<typename T, typename = void>
+ struct has_member_cbegin : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_member_cbegin<T, std::void_t<decltype(std::declval<T const &>().cbegin())>>
+ : std::is_same<typename T::const_iterator, decltype(std::declval<T const &>().cbegin())>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_member_cbegin_v = has_member_cbegin<T>::value;
+
+ template<typename T>
+ struct has_cbegin : std::disjunction<has_free_cbegin<T>, has_member_cbegin<T>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_cbegin_v = has_cbegin<T>::value;
+ } // namespace iterable_cbegin
+
+ inline namespace iterable_rbegin
+ {
+ template<typename T, typename = void>
+ struct has_free_rbegin : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_free_rbegin<T, std::void_t<decltype(rbegin(std::declval<T &>()))>>
+ : std::is_same<typename T::reverse_iterator, std::remove_cvref_t<decltype(rbegin(std::declval<T &>()))>>
+ {
+ };
+
+ template<typename T>
+ struct has_free_rbegin<T const, std::void_t<decltype(rbegin(std::declval<T const &>()))>>
+ : std::is_same<typename T::const_reverse_iterator, std::remove_cvref_t<decltype(rbegin(std::declval<T const &>()))>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_free_rbegin_v = has_free_rbegin<T>::value;
+
+ template<typename T, typename = void>
+ struct has_member_rbegin : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_member_rbegin<T, std::void_t<decltype(std::declval<T &>().rbegin())>>
+ : std::is_same<typename T::reverse_iterator, std::remove_cvref_t<decltype(std::declval<T &>().rbegin())>>
+ {
+ };
+
+ template<typename T>
+ struct has_member_rbegin<T const, std::void_t<decltype(std::declval<T const &>().rbegin())>>
+ : std::is_same<typename T::const_reverse_iterator, std::remove_cvref_t<decltype(std::declval<T const &>().rbegin())>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_member_rbegin_v = has_member_rbegin<T>::value;
+
+ template<typename T>
+ struct has_rbegin : std::disjunction<has_free_rbegin<T>, has_member_rbegin<T>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_rbegin_v = has_rbegin<T>::value;
+ } // namespace iterable_rbegin
+
+ inline namespace iterable_crbegin
+ {
+ template<typename T, typename = void>
+ struct has_free_crbegin : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_free_crbegin<T, std::void_t<decltype(crbegin(std::declval<T const &>()))>>
+ : std::is_same<typename T::const_reverse_iterator, std::remove_cvref_t<decltype(crbegin(std::declval<T const &>()))>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_free_crbegin_v = has_free_crbegin<T>::value;
+
+ template<typename T, typename = void>
+ struct has_member_crbegin : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_member_crbegin<T, std::void_t<decltype(std::declval<T const &>().crbegin())>>
+ : std::is_same<typename T::const_reverse_iterator, std::remove_cvref_t<decltype(std::declval<T const &>().crbegin())>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_member_crbegin_v = has_member_crbegin<T>::value;
+
+ template<typename T>
+ struct has_crbegin : std::disjunction<has_free_crbegin<T>, has_member_crbegin<T>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_crbegin_v = has_crbegin<T>::value;
+ } // namespace iterable_crbegin
+
+ inline namespace iterable_end
+ {
+ template<typename T, typename = void>
+ struct has_free_end : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_free_end<T, std::void_t<decltype(end(std::declval<T &>()))>>
+ : std::is_same<typename T::iterator, std::remove_cvref_t<decltype(end(std::declval<T &>()))>>
+ {
+ };
+
+ template<typename T>
+ struct has_free_end<T const, std::void_t<decltype(end(std::declval<T const &>()))>>
+ : std::is_same<typename T::const_iterator, std::remove_cvref_t<decltype(end(std::declval<T const &>()))>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_free_end_v = has_free_end<T>::value;
+
+ template<typename T, typename = void>
+ struct has_member_end : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_member_end<T, std::void_t<decltype(std::declval<T &>().end())>>
+ : std::is_same<typename T::iterator, std::remove_cvref_t<decltype(std::declval<T &>().end())>>
+ {
+ };
+
+ template<typename T>
+ struct has_member_end<T const, std::void_t<decltype(std::declval<T const &>().end())>>
+ : std::is_same<typename T::const_iterator, std::remove_cvref_t<decltype(std::declval<T const &>().end())>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_member_end_v = has_member_end<T>::value;
+
+ template<typename T>
+ struct has_end : std::disjunction<has_free_end<T>, has_member_end<T>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_end_v = has_end<T>::value;
+ } // namespace iterable_end
+
+ inline namespace iterable_cend
+ {
+ template<typename T, typename = void>
+ struct has_free_cend : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_free_cend<T, std::void_t<decltype(cend(std::declval<T const &>()))>>
+ : std::is_same<typename T::const_iterator, std::remove_cvref_t<decltype(cend(std::declval<T const &>()))>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_free_cend_v = has_free_cend<T>::value;
+
+ template<typename T, typename = void>
+ struct has_member_cend : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_member_cend<T, std::void_t<decltype(std::declval<T const &>().cend())>>
+ : std::is_same<typename T::const_iterator, decltype(std::declval<T const &>().cend())>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_member_cend_v = has_member_cend<T>::value;
+
+ template<typename T>
+ struct has_cend : std::disjunction<has_free_cend<T>, has_member_cend<T>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_cend_v = has_cend<T>::value;
+ } // namespace iterable_cend
+
+ inline namespace iterable_rend
+ {
+ template<typename T, typename = void>
+ struct has_free_rend : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_free_rend<T, std::void_t<decltype(rend(std::declval<T &>()))>>
+ : std::is_same<typename T::reverse_iterator, std::remove_cvref_t<decltype(rend(std::declval<T &>()))>>
+ {
+ };
+
+ template<typename T>
+ struct has_free_rend<T const, std::void_t<decltype(rend(std::declval<T const &>()))>>
+ : std::is_same<typename T::const_reverse_iterator, std::remove_cvref_t<decltype(rend(std::declval<T const &>()))>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_free_rend_v = has_free_rend<T>::value;
+
+ template<typename T, typename = void>
+ struct has_member_rend : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_member_rend<T, std::void_t<decltype(std::declval<T &>().rend())>>
+ : std::is_same<typename T::reverse_iterator, std::remove_cvref_t<decltype(std::declval<T &>().rend())>>
+ {
+ };
+
+ template<typename T>
+ struct has_member_rend<T const, std::void_t<decltype(std::declval<T const &>().rend())>>
+ : std::is_same<typename T::const_reverse_iterator, std::remove_cvref_t<decltype(std::declval<T const &>().rend())>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_member_rend_v = has_member_rend<T>::value;
+
+ template<typename T>
+ struct has_rend : std::disjunction<has_free_rend<T>, has_member_rend<T>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_rend_v = has_rend<T>::value;
+ } // namespace iterable_rend
+
+ inline namespace iterable_crend
+ {
+ template<typename T, typename = void>
+ struct has_free_crend : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_free_crend<T, std::void_t<decltype(crend(std::declval<T const &>()))>>
+ : std::is_same<typename T::const_reverse_iterator, std::remove_cvref_t<decltype(crend(std::declval<T const &>()))>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_free_crend_v = has_free_crend<T>::value;
+
+ template<typename T, typename = void>
+ struct has_member_crend : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_member_crend<T, std::void_t<decltype(std::declval<T const &>().crend())>>
+ : std::is_same<typename T::const_reverse_iterator, std::remove_cvref_t<decltype(std::declval<T const &>().crend())>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_member_crend_v = has_member_crend<T>::value;
+
+ template<typename T>
+ struct has_crend : std::disjunction<has_free_crend<T>, has_member_crend<T>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_crend_v = has_crend<T>::value;
+ } // namespace iterable_crend
+
} // 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 ed1de44..66ff332 100644
--- a/include/newtype/new_type.hpp
+++ b/include/newtype/new_type.hpp
@@ -3,6 +3,7 @@
#include "newtype/derivable.hpp"
#include "newtype/deriving.hpp"
+#include "newtype/impl/new_type_iterator_types.hpp"
#include "newtype/impl/new_type_storage.hpp"
#include "newtype/impl/type_traits_extensions.hpp"
#include "newtype/version.hpp"
@@ -15,18 +16,10 @@
namespace nt
{
- /**
- * @brief Create a new type based on an existing one
- *
- * The class template nt::new_type is designed to allow the creation of new types based on existing types. Similarly to the Haskell newtype,
- * this class template creates a new type that is layout equivalent to the underlying type.
- *
- * @tparam BaseType An existing type that shall aliased
- * @tparam TagType A unique type to identify this nt::new_type
- * @tparam DervivationClause An nt::derivation_clause describing which features shall be automatically derived for the new type alias
- */
template<typename BaseType, typename TagType, auto DerivationClause = deriving()>
- class new_type : impl::new_type_move_assignment<BaseType, TagType>
+ class new_type
+ : impl::new_type_move_assignment<BaseType, TagType>
+ , public impl::new_type_iterator_types<BaseType, DerivationClause(nt::Iterable)>
{
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");
@@ -65,161 +58,198 @@ namespace nt
-> std::enable_if_t<DerivationClauseV(nt::Arithmetic) && impl::is_divide_assignable_v<BaseTypeT>,
new_type<BaseTypeT, TagTypeT, DerivationClauseV> &>;
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend begin(new_type<BaseTypeT, TagTypeT, DerivationClauseV> & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_begin_v<BaseTypeT>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend begin(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_begin_v<BaseTypeT const>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend cbegin(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_cbegin_v<BaseTypeT const>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend rbegin(new_type<BaseTypeT, TagTypeT, DerivationClauseV> & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_rbegin_v<BaseTypeT>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::reverse_iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend rbegin(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_rbegin_v<BaseTypeT const>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_reverse_iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend crbegin(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_crbegin_v<BaseTypeT const>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_reverse_iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend end(new_type<BaseTypeT, TagTypeT, DerivationClauseV> & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_end_v<BaseTypeT>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend end(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_end_v<BaseTypeT const>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend cend(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_cend_v<BaseTypeT const>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend rend(new_type<BaseTypeT, TagTypeT, DerivationClauseV> & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_rend_v<BaseTypeT>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::reverse_iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend rend(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_rend_v<BaseTypeT const>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_reverse_iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend crend(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_crend_v<BaseTypeT const>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_reverse_iterator>;
+
using super = impl::new_type_move_assignment<BaseType, TagType>;
public:
- /// @section Type aliases
-
- /**
- * @brief The base type of this nt::new_type
- *
- * This type alias provides convenient access to the contained objects type
- */
using base_type = BaseType;
-
- /**
- * @brief The tag type of this nt::new_type
- *
- * This type alias provides convenient access to the tag type of this nt::new_type instance
- */
using tag_type = TagType;
-
- /**
- * @brief The type of the derivation clause of this nt::newtype
- *
- * This type alias provides convenient access to the type of the derivation clause of this nt::new_type instance
- */
using derivation_clause_type = decltype(DerivationClause);
- /// @section Derivation clause access
-
- /**
- * @brief The derivation clause fo this nt::new_type
- *
- * This static data-member provides conevient access to the derivation clause of this nt::new_type instance
- */
auto constexpr static derivation_clause = DerivationClause;
- /// @section Constructors
-
using super::super;
- /**
- * @brief Construct an instance of this nt::new_type by default initializing the contained object
- *
- * @note This constructor is available iff. the base type is default-constructible. Otherwise is is defined as deleted.
- * @throw This constructor throws any exception thrown the base type constructor. It is noexcept iff. the base type constructor is noexcept
- */
constexpr new_type() noexcept(std::is_nothrow_default_constructible_v<BaseType>) = default;
-
- /**
- * @brief Copy-construct an instance of this nt::new_type from an existing one
- *
- * @note This constructor is available iff. the base type is copy-constructible. Otherwise is is defined as deleted.
- * @throw This constructor throws any exception thrown the base type copy-constructor. It is noexcept iff. the base type copy-constructor
- * is noexcept
- */
constexpr new_type(new_type const &) noexcept(std::is_nothrow_copy_constructible_v<BaseType>) = default;
-
- /**
- * @brief Move-construct an instance of this nt::new_type from an existing one
- *
- * @note This constructor is available iff. the base type is move-constructible. Otherwise is is defined as deleted.
- * @throw This constructor throws any exception thrown the base type move-constructor. It is noexcept iff. the base types move-constructor
- * is noexcept
- */
constexpr new_type(new_type &&) noexcept(std::is_nothrow_move_constructible_v<BaseType>) = default;
- /// @section Assignment operators
-
- /**
- * @brief Copy-assign the value of an existing instance of this nt::new_type to this instance
- *
- * @note This assignment operator is available iff. the base type is copy-assignable. Otherwise it is defined as deleted.
- * @throw This assignment operator throws any exception thrown by the base type copy-assignment operator. It is noexcept iff. the base type
- * copy-assignment operator is noexcept.
- * @return A reference to this instance
- */
auto constexpr operator=(new_type const &) noexcept(std::is_nothrow_copy_assignable_v<BaseType>) -> new_type & = default;
-
- /**
- * @brief Move-assign the value of an existing instance of this nt::new_type to this instance
- *
- * @note This assignment operator is available iff. the base type is move-assignable. Otherwise it is defined as deleted.
- * @throw This assignment operator throws any exception thrown by the base type move-assignment operator. It is noexcept iff. the base type
- * move-assignment operator is noexcept.
- * @return A reference to this instance
- */
auto constexpr operator=(new_type &&) noexcept(std::is_nothrow_move_assignable_v<BaseType>) -> new_type & = default;
- /// @section Accessors
-
- /**
- * @brief Obtain a copy of the contained base type object
- *
- * @return BaseType
- */
auto constexpr decay() const noexcept(std::is_nothrow_copy_constructible_v<BaseType>) -> BaseType
{
return this->m_value;
}
- /**
- * @brief Convert this instance into the equivalent base type value
- *
- * @note This is only available if the derivation clause of this nt::new_type contains nt::ImplicitConversion
- */
template<typename NewType = new_type, std::enable_if_t<NewType::derivation_clause(nt::ImplicitConversion)> * = nullptr>
constexpr operator base_type() const noexcept(std::is_nothrow_copy_constructible_v<base_type>)
{
return decay();
}
- /**
- * @brief Convert this instance into the equivalent base type value
- *
- * @note This overload is only avalaible if the derivation clause of this nt::new_type does not contain nt::ImplicitConversion
- */
template<typename NewType = new_type, std::enable_if_t<!NewType::derivation_clause(nt::ImplicitConversion)> * = nullptr>
explicit constexpr operator base_type() const noexcept(std::is_nothrow_copy_constructible_v<base_type>)
{
return decay();
}
- /// @section Indirection operators
-
- /**
- * @brief Perform an access to a member of the base type
- *
- * @return A pointer to the contained base type object
- */
template<typename NewType = new_type>
auto constexpr operator-> () noexcept -> std::enable_if_t<NewType::derivation_clause(nt::Indirection), BaseType *>
{
return std::addressof(this->m_value);
}
- /**
- * @brief Perform an access to a member of the base type
- *
- * @return A pointer to the contained base type object
- */
template<typename NewType = new_type>
auto constexpr operator-> () const noexcept -> std::enable_if_t<NewType::derivation_clause(nt::Indirection), BaseType const *>
{
return std::addressof(this->m_value);
}
- };
- /// @section Equality comparison operators
+ template<typename NewType = new_type, std::enable_if_t<NewType::derivation_clause(nt::Iterable)> * = nullptr>
+ auto constexpr begin()
+ -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_begin_v<BaseType>, typename NewType::iterator>
+ {
+ return this->m_value.begin();
+ }
+
+ template<typename NewType = new_type>
+ auto constexpr begin() const -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_begin_v<BaseType const>,
+ typename NewType::const_iterator>
+ {
+ return this->m_value.begin();
+ }
+
+ template<typename NewType = new_type>
+ auto constexpr cbegin() const -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_cbegin_v<BaseType const>,
+ typename NewType::const_iterator>
+ {
+ return this->m_value.cbegin();
+ }
+
+ template<typename NewType = new_type, std::enable_if_t<NewType::derivation_clause(nt::Iterable)> * = nullptr>
+ auto constexpr rbegin()
+ -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_rbegin_v<BaseType>, typename NewType::reverse_iterator>
+ {
+ return this->m_value.rbegin();
+ }
+
+ template<typename NewType = new_type>
+ auto constexpr rbegin() const -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_rbegin_v<BaseType const>,
+ typename NewType::const_reverse_iterator>
+ {
+ return this->m_value.rbegin();
+ }
+
+ template<typename NewType = new_type>
+ auto constexpr crbegin() const -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_crbegin_v<BaseType const>,
+ typename NewType::const_reverse_iterator>
+ {
+ return this->m_value.crbegin();
+ }
+
+ template<typename NewType = new_type, std::enable_if_t<NewType::derivation_clause(nt::Iterable)> * = nullptr>
+ auto constexpr end()
+ -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_end_v<BaseType>, typename NewType::iterator>
+ {
+ return this->m_value.end();
+ }
+
+ template<typename NewType = new_type>
+ auto constexpr end() const -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_end_v<BaseType const>,
+ typename NewType::const_iterator>
+ {
+ return this->m_value.end();
+ }
+
+ template<typename NewType = new_type>
+ auto constexpr cend() const -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_cend_v<BaseType const>,
+ typename NewType::const_iterator>
+ {
+ return this->m_value.cend();
+ }
+
+ template<typename NewType = new_type, std::enable_if_t<NewType::derivation_clause(nt::Iterable)> * = nullptr>
+ auto constexpr rend()
+ -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_rend_v<BaseType>, typename NewType::reverse_iterator>
+ {
+ return this->m_value.rend();
+ }
+
+ template<typename NewType = new_type>
+ auto constexpr rend() const -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_rend_v<BaseType const>,
+ typename NewType::const_reverse_iterator>
+ {
+ return this->m_value.rend();
+ }
+
+ template<typename NewType = new_type>
+ auto constexpr crend() const -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_crend_v<BaseType const>,
+ typename NewType::const_reverse_iterator>
+ {
+ return this->m_value.crend();
+ }
+ };
- /**
- * @brief Compare two objects for equality
- *
- * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type
- * comparison operator is noexcept.
- * @return true iff. the base type comparison operator returns true, false otherwise.
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr
operator==(new_type<BaseType, TagType, DerivationClause> const & lhs,
@@ -229,13 +259,6 @@ namespace nt
return lhs.decay() == rhs.decay();
}
- /**
- * @brief Compare an instance of a given nt::new_type with an object of its base type
- *
- * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type
- * comparison operator is noexcept.
- * @return true iff. the base type comparison operator returns true, false otherwise.
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr operator==(new_type<BaseType, TagType, DerivationClause> const & lhs,
BaseType const & rhs) noexcept(impl::is_nothrow_equality_comparable_v<BaseType>)
@@ -244,13 +267,6 @@ namespace nt
return lhs.decay() == rhs;
}
- /**
- * @brief Compare an instance of the base type with an instance of a given nt::new_type
- *
- * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type
- * comparison operator is noexcept.
- * @return true iff. the base type comparison operator returns true, false otherwise.
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr
operator==(BaseType const & lhs,
@@ -260,13 +276,6 @@ namespace nt
return lhs == rhs.decay();
}
- /**
- * @brief Compare two objects for non-equality
- *
- * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type
- * comparison operator is noexcept.
- * @return true iff. the base type comparison operator returns true, false otherwise.
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr
operator!=(new_type<BaseType, TagType, DerivationClause> const & lhs,
@@ -276,13 +285,6 @@ namespace nt
return lhs.decay() != rhs.decay();
}
- /**
- * @brief Compare an instance of a given nt::new_type with an object of its base type
- *
- * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type
- * comparison operator is noexcept.
- * @return true iff. the base type comparison operator returns true, false otherwise.
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr operator!=(new_type<BaseType, TagType, DerivationClause> const & lhs,
BaseType const & rhs) noexcept(impl::is_nothrow_inequality_comparable_v<BaseType>)
@@ -291,13 +293,6 @@ namespace nt
return lhs.decay() != rhs;
}
- /**
- * @brief Compare an instance of the base type with an instance of a given nt::new_type
- *
- * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type
- * comparison operator is noexcept.
- * @return true iff. the base type comparison operator returns true, false otherwise.
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr
operator!=(BaseType const & lhs,
@@ -307,17 +302,6 @@ namespace nt
return lhs != rhs.decay();
}
- /// @section Relational operators
-
- /**
- * @brief Check if one nt::new_type object is less-than an other
- *
- * @note This operator is only available if the the derivation clause of this nt::new_type does contains nt::Relational and the base type is
- * less-than comparable.
- * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type
- * comparison operator is noexcept.
- * @return true iff. the base type comparison operator returns true, false otherwise.
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr
operator<(new_type<BaseType, TagType, DerivationClause> const & lhs,
@@ -327,15 +311,6 @@ namespace nt
return lhs.decay() < rhs.decay();
}
- /**
- * Check if one nt::new_type object is greater-than an other
- *
- * @note This operator is only available if the the derivation clause of this nt::new_type does contains nt::Relational and the base type is
- * greater-than comparable.
- * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type
- * comparison operator is noexcept.
- * @return true iff. the base type comparison operator returns true, false otherwise.
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr
operator>(new_type<BaseType, TagType, DerivationClause> const & lhs,
@@ -345,15 +320,6 @@ namespace nt
return lhs.decay() > rhs.decay();
}
- /**
- * Check if one nt::new_type object is less-than or equal-to an other
- *
- * @note This operator is only available if the the derivation clause of this nt::new_type does contains nt::Relational and the base type is
- * less-than-or-equal-to comparable.
- * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type
- * comparison operator is noexcept.
- * @return true iff. the base type comparison operator returns true, false otherwise.
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr
operator<=(new_type<BaseType, TagType, DerivationClause> const & lhs,
@@ -363,15 +329,6 @@ namespace nt
return lhs.decay() <= rhs.decay();
}
- /**
- * Check if one nt::new_type object is greater-than or equal-to an other
- *
- * @note This operator is only available if the the derivation clause of this nt::new_type does contains nt::Relational and the base type is
- * greater-than-or-equal comparable
- * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type
- * comparison operator is noexcept.
- * @return true iff. the base type comparison operator returns true, false otherwise.
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr
operator>=(new_type<BaseType, TagType, DerivationClause> const & lhs,
@@ -381,16 +338,6 @@ namespace nt
return lhs.decay() >= rhs.decay();
}
- /// @section Stream input/output operators
-
- /**
- * @brief Write the contained base type object to a standard output stream
- *
- * @note This operator is only available if the derivation clause of the passed in nt::new_type object contains nt::Show.
- * @param output The output stream to write to
- * @param source An instance of an nt::new_type that shall be written to the stream
- * @return The a reference to the output stream
- */
template<typename BaseType, typename TagType, auto DerivationClause, typename CharType, typename StreamTraits>
auto operator<<(std::basic_ostream<CharType, StreamTraits> & output, new_type<BaseType, TagType, DerivationClause> const & source) noexcept(
impl::is_nothrow_output_streamable_v<std::basic_ostream<CharType, StreamTraits>, BaseType>)
@@ -400,14 +347,6 @@ namespace nt
return output << source.decay();
}
- /**
- * @brief Read an object of the base type from a standard input stream
- *
- * @note This operator is only available if the derivation clause of the passed in nt::new_type object contains nt::Read.
- * @param output The input stream to read from
- * @param source An instance of an nt::new_type that shall be read from the stream
- * @return The a reference to the input stream
- */
template<typename BaseType, typename TagType, auto DerivationClause, typename CharType, typename StreamTraits>
auto operator>>(std::basic_istream<CharType, StreamTraits> & input, new_type<BaseType, TagType, DerivationClause> & target) noexcept(
impl::is_nothrow_input_streamable_v<std::basic_istream<CharType, StreamTraits>, BaseType>)
@@ -417,17 +356,6 @@ namespace nt
return input >> target.m_value;
}
- /// @section Arithmetic operators
-
- /**
- * @brief Add two instances of the same nt::new_type
- *
- * @note This operator is only available if the derivation clause of the passed in nt::new_type objects contains nt::Arithmetic and the base
- * type is addable.
- * @param lhs The left-hand side of the addition
- * @param rhs The right-hand side of the addition
- * @return a new instance of the same nt::new_type
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr
operator+(new_type<BaseType, TagType, DerivationClause> const & lhs, new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(
@@ -437,15 +365,6 @@ namespace nt
return {lhs.decay() + rhs.decay()};
}
- /**
- * @brief Add two instances of the same nt::new_type, modifying the left-hand side
- *
- * @note This operator is only available if the derivation clause of the passed in nt::new_type objects contains nt::Arithmetic and the base
- * type is addable.
- * @param lhs The left-hand side of the addition
- * @param rhs The right-hand side of the addition
- * @return a reference to the the modified value
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr operator+=(new_type<BaseType, TagType, DerivationClause> & lhs,
new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(impl::is_nothrow_add_assignable_v<BaseType>)
@@ -456,15 +375,6 @@ namespace nt
return lhs;
}
- /**
- * @brief Subtract two instances of the same nt::new_type
- *
- * @note This operator is only available if the derivation clause of the passed in nt::new_type objects contains nt::Arithmetic and the base
- * type is subtractable.
- * @param lhs The left-hand side of the subtraction
- * @param rhs The right-hand side of the subtraction
- * @return a new instance of the same nt::new_type
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr
operator-(new_type<BaseType, TagType, DerivationClause> const & lhs, new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(
@@ -474,15 +384,6 @@ namespace nt
return {lhs.decay() - rhs.decay()};
}
- /**
- * @brief Subtract two instances of the same nt::new_type, modifying the left-hand side
- *
- * @note This operator is only available if the derivation clause of the passed in nt::new_type objects contains nt::Arithmetic and the base
- * type is subtractable.
- * @param lhs The left-hand side of the subtractition
- * @param rhs The right-hand side of the subtractition
- * @return a reference to the the modified value
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr
operator-=(new_type<BaseType, TagType, DerivationClause> & lhs,
@@ -494,15 +395,6 @@ namespace nt
return lhs;
}
- /**
- * @brief Multiply two instances of the same nt::new_type
- *
- * @note This operator is only available if the derivation clause of the passed in nt::new_type objects contains nt::Arithmetic and the base
- * type is multipliable.
- * @param lhs The left-hand side of the multiplication
- * @param rhs The right-hand side of the multiplication
- * @return a new instance of the same nt::new_type
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr
operator*(new_type<BaseType, TagType, DerivationClause> const & lhs, new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(
@@ -512,15 +404,6 @@ namespace nt
return {lhs.decay() * rhs.decay()};
}
- /**
- * @brief Multiply two instances of the same nt::new_type, modifying the left-hand side
- *
- * @note This operator is only available if the derivation clause of the passed in nt::new_type objects contains nt::Arithmetic and the base
- * type is multiplyable.
- * @param lhs The left-hand side of the multiplication
- * @param rhs The right-hand side of the multiplication
- * @return a reference to the the modified value
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr
operator*=(new_type<BaseType, TagType, DerivationClause> & lhs,
@@ -532,15 +415,6 @@ namespace nt
return lhs;
}
- /**
- * @brief Divide two instances of the same nt::new_type
- *
- * @note This operator is only available if the derivation clause of the passed in nt::new_type objects contains nt::Arithmetic and the base
- * type is dividable.
- * @param lhs The left-hand side of the division
- * @param rhs The right-hand side of the division
- * @return a new instance of the same nt::new_type
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr
operator/(new_type<BaseType, TagType, DerivationClause> const & lhs, new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(
@@ -550,15 +424,6 @@ namespace nt
return {lhs.decay() / rhs.decay()};
}
- /**
- * @brief Divide two instances of the same nt::new_type, modifying the left-hand side
- *
- * @note This operator is only available if the derivation clause of the passed in nt::new_type objects contains nt::Arithmetic and the base
- * type is dividable.
- * @param lhs The left-hand side of the division
- * @param rhs The right-hand side of the division
- * @return a reference to the the modified value
- */
template<typename BaseType, typename TagType, auto DerivationClause>
auto constexpr operator/=(new_type<BaseType, TagType, DerivationClause> & lhs,
new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(impl::is_nothrow_divide_assignable_v<BaseType>)
@@ -569,6 +434,102 @@ namespace nt
return lhs;
}
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr begin(new_type<BaseType, TagType, DerivationClause> & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_begin_v<BaseType>,
+ typename new_type<BaseType, TagType, DerivationClause>::iterator>
+ {
+ return begin(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr begin(new_type<BaseType, TagType, DerivationClause> const & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_begin_v<BaseType const>,
+ typename new_type<BaseType, TagType, DerivationClause>::const_iterator>
+ {
+ return begin(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr cbegin(new_type<BaseType, TagType, DerivationClause> const & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_cbegin_v<BaseType const>,
+ typename new_type<BaseType, TagType, DerivationClause>::const_iterator>
+ {
+ return cbegin(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr rbegin(new_type<BaseType, TagType, DerivationClause> & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_rbegin_v<BaseType>,
+ typename new_type<BaseType, TagType, DerivationClause>::reverse_iterator>
+ {
+ return rbegin(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr rbegin(new_type<BaseType, TagType, DerivationClause> const & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_rbegin_v<BaseType const>,
+ typename new_type<BaseType, TagType, DerivationClause>::const_reverse_iterator>
+ {
+ return rbegin(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr crbegin(new_type<BaseType, TagType, DerivationClause> const & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_crbegin_v<BaseType const>,
+ typename new_type<BaseType, TagType, DerivationClause>::const_reverse_iterator>
+ {
+ return crbegin(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr end(new_type<BaseType, TagType, DerivationClause> & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_end_v<BaseType>,
+ typename new_type<BaseType, TagType, DerivationClause>::iterator>
+ {
+ return end(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr end(new_type<BaseType, TagType, DerivationClause> const & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_end_v<BaseType const>,
+ typename new_type<BaseType, TagType, DerivationClause>::const_iterator>
+ {
+ return end(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr cend(new_type<BaseType, TagType, DerivationClause> const & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_cend_v<BaseType const>,
+ typename new_type<BaseType, TagType, DerivationClause>::const_iterator>
+ {
+ return cend(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr rend(new_type<BaseType, TagType, DerivationClause> & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_rend_v<BaseType>,
+ typename new_type<BaseType, TagType, DerivationClause>::reverse_iterator>
+ {
+ return rend(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr rend(new_type<BaseType, TagType, DerivationClause> const & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_rend_v<BaseType const>,
+ typename new_type<BaseType, TagType, DerivationClause>::const_reverse_iterator>
+ {
+ return rend(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr crend(new_type<BaseType, TagType, DerivationClause> const & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_crend_v<BaseType const>,
+ typename new_type<BaseType, TagType, DerivationClause>::const_reverse_iterator>
+ {
+ return crend(obj.m_value);
+ }
+
} // namespace nt
namespace std
diff --git a/include/newtype/version.hpp b/include/newtype/version.hpp
index b2dd19b..8678514 100644
--- a/include/newtype/version.hpp
+++ b/include/newtype/version.hpp
@@ -13,9 +13,9 @@ namespace nt
char const * const name;
} version{
.major = 1,
- .minor = 0,
- .patch = 2,
- .name = "Francesca",
+ .minor = 1,
+ .patch = 0,
+ .name = "Anastasia",
};
} // namespace nt