From a8d181abe5a64def14b0f90f6149a67cca354a3a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 29 Dec 2019 15:08:44 +0100 Subject: new_type: cleanup implementation --- include/newtype/derivable.hpp | 21 +- include/newtype/impl/new_type_storage.hpp | 152 ++++++++++++ include/newtype/new_type.hpp | 375 ++++++++++++++---------------- 3 files changed, 343 insertions(+), 205 deletions(-) create mode 100644 include/newtype/impl/new_type_storage.hpp diff --git a/include/newtype/derivable.hpp b/include/newtype/derivable.hpp index 157bac7..1b6651f 100644 --- a/include/newtype/derivable.hpp +++ b/include/newtype/derivable.hpp @@ -10,7 +10,7 @@ namespace nt using derivable = type; /** - * A set of standard derivation tags + * @brief A set of standard derivation tags * * This convenience namespace contains all standard derivation tags. * @@ -20,21 +20,21 @@ namespace nt { /** - * A tag to enable derivation of arithmetic operators + * @brief A tag to enable derivation of arithmetic operators * * @since 1.0.0 */ auto constexpr Arithmetic = derivable{}; /** - * A tag to enable derivation of equality comparison operators + * @brief A tag to enable derivation of equality comparison operators * * @since 1.0.0 */ auto constexpr EqBase = derivable{}; /** - * A tag to enable derivation of the implicit "conversion to base type" operator + * @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" @@ -43,21 +43,28 @@ namespace nt auto constexpr ImplicitConversion = derivable{}; /** - * A tag to enable derivation of the stream input operator + * @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{}; + + /** + * @brief A tag to enable derivation of the stream input operator * * @since 1.0.0 */ auto constexpr Read = derivable{}; /** - * A tag to enable derivation of the relational operators + * @brief A tag to enable derivation of the relational operators * * @since 1.0.0 */ auto constexpr Relational = derivable{}; /** - * A tag to enable derivation of the stream output operator + * @brief A tag to enable derivation of the stream output operator * * @since 1.0.0 */ diff --git a/include/newtype/impl/new_type_storage.hpp b/include/newtype/impl/new_type_storage.hpp new file mode 100644 index 0000000..414eff4 --- /dev/null +++ b/include/newtype/impl/new_type_storage.hpp @@ -0,0 +1,152 @@ +#ifndef NEWTYPE_IMPL_NEW_TYPE_STORAGE_HPP +#define NEWTYPE_IMPL_NEW_TYPE_STORAGE_HPP + +#include + +namespace nt::impl +{ + + template + struct new_type_storage + { + constexpr new_type_storage() noexcept(std::is_nothrow_default_constructible_v) + : m_value{} + { + } + + template + constexpr explicit new_type_storage(ArgumentType && value) noexcept(std::is_nothrow_constructible_v) + : m_value{std::forward(value)} + { + } + + BaseType m_value; + }; + + template> + struct new_type_constructor : new_type_storage + { + using super = new_type_storage; + using super::super; + + constexpr new_type_constructor(BaseType const & value) + : super{value} + { + } + + constexpr new_type_constructor(BaseType && value) + : super{std::move(value)} + { + } + }; + + template + struct new_type_constructor : new_type_storage + { + using super = new_type_storage; + using super::super; + + constexpr new_type_constructor() = delete; + + constexpr new_type_constructor(BaseType const & value) + : super{value} + { + } + + constexpr new_type_constructor(BaseType && value) + : super{std::move(value)} + { + } + }; + + template> + struct new_type_copy_constructor : new_type_constructor + { + using new_type_constructor::new_type_constructor; + + constexpr new_type_copy_constructor(new_type_copy_constructor const &) = default; + constexpr new_type_copy_constructor(new_type_copy_constructor &&) = default; + auto constexpr operator=(new_type_copy_constructor &) -> new_type_copy_constructor & = default; + auto constexpr operator=(new_type_copy_constructor &&) -> new_type_copy_constructor & = default; + }; + + template + struct new_type_copy_constructor : new_type_constructor + { + using new_type_constructor::new_type_constructor; + + constexpr new_type_copy_constructor(new_type_copy_constructor const &) = delete; + constexpr new_type_copy_constructor(new_type_copy_constructor &&) = default; + auto constexpr operator=(new_type_copy_constructor &) -> new_type_copy_constructor & = default; + auto constexpr operator=(new_type_copy_constructor &&) -> new_type_copy_constructor & = default; + }; + + template> + struct new_type_move_constructor : new_type_copy_constructor + { + using new_type_copy_constructor::new_type_copy_constructor; + + constexpr new_type_move_constructor(new_type_move_constructor const &) = default; + constexpr new_type_move_constructor(new_type_move_constructor &&) = default; + auto constexpr operator=(new_type_move_constructor &) -> new_type_move_constructor & = default; + auto constexpr operator=(new_type_move_constructor &&) -> new_type_move_constructor & = default; + }; + + template + struct new_type_move_constructor : new_type_copy_constructor + { + using new_type_copy_constructor::new_type_copy_constructor; + + constexpr new_type_move_constructor(new_type_move_constructor const &) = default; + constexpr new_type_move_constructor(new_type_move_constructor &&) = delete; + auto constexpr operator=(new_type_move_constructor &) -> new_type_move_constructor & = default; + auto constexpr operator=(new_type_move_constructor &&) -> new_type_move_constructor & = default; + }; + + template> + struct new_type_copy_assignment : new_type_move_constructor + { + using new_type_move_constructor::new_type_move_constructor; + + constexpr new_type_copy_assignment(new_type_copy_assignment const &) = default; + constexpr new_type_copy_assignment(new_type_copy_assignment &&) = default; + auto constexpr operator=(new_type_copy_assignment &) -> new_type_copy_assignment & = default; + auto constexpr operator=(new_type_copy_assignment &&) -> new_type_copy_assignment & = default; + }; + + template + struct new_type_copy_assignment : new_type_move_constructor + { + using new_type_move_constructor::new_type_move_constructor; + + constexpr new_type_copy_assignment(new_type_copy_assignment const &) = default; + constexpr new_type_copy_assignment(new_type_copy_assignment &&) = default; + auto constexpr operator=(new_type_copy_assignment &) -> new_type_copy_assignment & = default; + auto constexpr operator=(new_type_copy_assignment &&) -> new_type_copy_assignment & = delete; + }; + + template> + struct new_type_move_assignment : new_type_copy_assignment + { + using new_type_copy_assignment::new_type_copy_assignment; + + constexpr new_type_move_assignment(new_type_move_assignment const &) = default; + constexpr new_type_move_assignment(new_type_move_assignment &&) = default; + auto constexpr operator=(new_type_move_assignment &) -> new_type_move_assignment & = default; + auto constexpr operator=(new_type_move_assignment &&) -> new_type_move_assignment & = default; + }; + + template + struct new_type_move_assignment : new_type_copy_assignment + { + using new_type_copy_assignment::new_type_copy_assignment; + + constexpr new_type_move_assignment(new_type_move_assignment const &) = default; + constexpr new_type_move_assignment(new_type_move_assignment &&) = default; + auto constexpr operator=(new_type_move_assignment &) -> new_type_move_assignment & = default; + auto constexpr operator=(new_type_move_assignment &&) -> new_type_move_assignment & = delete; + }; + +} // namespace nt::impl + +#endif diff --git a/include/newtype/new_type.hpp b/include/newtype/new_type.hpp index 57674cb..7f73daa 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_storage.hpp" #include "newtype/type.hpp" #include @@ -12,131 +13,9 @@ namespace nt { - namespace impl - { - - template - struct new_type_storage - { - constexpr new_type_storage() noexcept(std::is_nothrow_default_constructible_v) - : m_value{} - { - } - - template - constexpr explicit new_type_storage(ArgumentType && value) noexcept(std::is_nothrow_constructible_v) - : m_value{std::forward(value)} - { - } - - BaseType m_value; - }; - - template> - struct new_type_constructor : new_type_storage - { - using new_type_storage::new_type_storage; - }; - - template - struct new_type_constructor : new_type_storage - { - using new_type_storage::new_type_storage; - - new_type_constructor() = delete; - }; - - template> - struct new_type_copy_constructor : new_type_constructor - { - using new_type_constructor::new_type_constructor; - - constexpr new_type_copy_constructor(new_type_copy_constructor const &) = default; - constexpr new_type_copy_constructor(new_type_copy_constructor &&) = default; - auto constexpr operator=(new_type_copy_constructor &) -> new_type_copy_constructor & = default; - auto constexpr operator=(new_type_copy_constructor &&) -> new_type_copy_constructor & = default; - }; - - template - struct new_type_copy_constructor : new_type_constructor - { - using new_type_constructor::new_type_constructor; - - constexpr new_type_copy_constructor(new_type_copy_constructor const &) = delete; - constexpr new_type_copy_constructor(new_type_copy_constructor &&) = default; - auto constexpr operator=(new_type_copy_constructor &) -> new_type_copy_constructor & = default; - auto constexpr operator=(new_type_copy_constructor &&) -> new_type_copy_constructor & = default; - }; - - template> - struct new_type_move_constructor : new_type_copy_constructor - { - using new_type_copy_constructor::new_type_copy_constructor; - - constexpr new_type_move_constructor(new_type_move_constructor const &) = default; - constexpr new_type_move_constructor(new_type_move_constructor &&) = default; - auto constexpr operator=(new_type_move_constructor &) -> new_type_move_constructor & = default; - auto constexpr operator=(new_type_move_constructor &&) -> new_type_move_constructor & = default; - }; - - template - struct new_type_move_constructor : new_type_copy_constructor - { - using new_type_copy_constructor::new_type_copy_constructor; - - constexpr new_type_move_constructor(new_type_move_constructor const &) = default; - constexpr new_type_move_constructor(new_type_move_constructor &&) = delete; - auto constexpr operator=(new_type_move_constructor &) -> new_type_move_constructor & = default; - auto constexpr operator=(new_type_move_constructor &&) -> new_type_move_constructor & = default; - }; - - template> - struct new_type_copy_assignment : new_type_move_constructor - { - using new_type_move_constructor::new_type_move_constructor; - - constexpr new_type_copy_assignment(new_type_copy_assignment const &) = default; - constexpr new_type_copy_assignment(new_type_copy_assignment &&) = default; - auto constexpr operator=(new_type_copy_assignment &) -> new_type_copy_assignment & = default; - auto constexpr operator=(new_type_copy_assignment &&) -> new_type_copy_assignment & = default; - }; - - template - struct new_type_copy_assignment : new_type_move_constructor - { - using new_type_move_constructor::new_type_move_constructor; - - constexpr new_type_copy_assignment(new_type_copy_assignment const &) = default; - constexpr new_type_copy_assignment(new_type_copy_assignment &&) = default; - auto constexpr operator=(new_type_copy_assignment &) -> new_type_copy_assignment & = default; - auto constexpr operator=(new_type_copy_assignment &&) -> new_type_copy_assignment & = delete; - }; - - template> - struct new_type_move_assignment : new_type_copy_assignment - { - using new_type_copy_assignment::new_type_copy_assignment; - - constexpr new_type_move_assignment(new_type_move_assignment const &) = default; - constexpr new_type_move_assignment(new_type_move_assignment &&) = default; - auto constexpr operator=(new_type_move_assignment &) -> new_type_move_assignment & = default; - auto constexpr operator=(new_type_move_assignment &&) -> new_type_move_assignment & = default; - }; - - template - struct new_type_move_assignment : new_type_copy_assignment - { - using new_type_copy_assignment::new_type_copy_assignment; - - constexpr new_type_move_assignment(new_type_move_assignment const &) = default; - constexpr new_type_move_assignment(new_type_move_assignment &&) = default; - auto constexpr operator=(new_type_move_assignment &) -> new_type_move_assignment & = default; - auto constexpr operator=(new_type_move_assignment &&) -> new_type_move_assignment & = delete; - }; - - } // namespace impl - /** + * @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. * @@ -147,71 +26,108 @@ namespace nt template class new_type : impl::new_type_move_assignment { - using super = impl::new_type_move_assignment; + static_assert(!std::is_reference_v, "The base type must not be a reference type"); + static_assert(!std::is_void_v>, "The base type must not be possibly cv-qualified void"); + + template + auto friend + operator>>(std::basic_istream & input, new_type & target) noexcept( + noexcept(std::declval &>() >> std::declval())) + -> std::enable_if_t> &; - template - auto friend operator>>(std::basic_istream & input, - new_type & target) noexcept(noexcept(std::declval() >> - std::declval())) - -> std::basic_istream &; + using super = impl::new_type_move_assignment; public: /** - * The base type of this nt::new_type + * @brief The base type of this nt::new_type + * + * This type alias provides convenient access to the contained objects type */ using base_type = BaseType; /** - * The tag type of this nt::new_type + * @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; /** - * The type of the derivation clause of this nt::newtype + * @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); /** - * The derivation clause fo this nt::new_type + * @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; + 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) = 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) = 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) = default; - constexpr explicit new_type(BaseType const & value) noexcept(std::is_nothrow_copy_constructible_v) - : super{value} - { - } - - constexpr explicit new_type(BaseType const && value) noexcept(std::is_nothrow_move_constructible_v) - : super{std::move(value)} - { - } - + /** + * @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) -> 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) -> new_type & = default; + /** + * @brief Obtain a copy of the contained base type object + * + * @return BaseType + */ auto constexpr decay() const noexcept(std::is_nothrow_copy_constructible_v) -> BaseType { return this->m_value; } /** - * Convert this instance into the equivalent base type value + * @brief Convert this instance into the equivalent base type value * - * @note This overload participates only in overload resolution if the derivation clause of this @p new_type contains - * nt::ImplicitConversion + * @note This is only available if the derivation clause of this nt::new_type contains nt::ImplicitConversion */ template * = nullptr> constexpr operator base_type() const noexcept(std::is_nothrow_copy_constructible_v) @@ -220,20 +136,45 @@ namespace nt } /** - * Convert this instance into the equivalent base type value + * @brief Convert this instance into the equivalent base type value * - * @note This overload participates only in overload resolution if the derivation clause of this @p new_type does not contain - * nt::ImplicitConversion + * @note This overload is only avalaible if the derivation clause of this nt::new_type does not contain nt::ImplicitConversion */ template * = nullptr> explicit constexpr operator base_type() const noexcept(std::is_nothrow_copy_constructible_v) { return decay(); } + + /** + * @brief Perform an access to a member of the base type + * + * @return A pointer to the contained base type object + */ + template + auto constexpr operator-> () noexcept -> std::enable_if_t + { + 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 + auto constexpr operator-> () const noexcept -> std::enable_if_t + { + return std::addressof(this->m_value); + } }; /** - * Compare two objects for equality + * @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 auto constexpr operator==(new_type const & lhs, @@ -245,7 +186,11 @@ namespace nt } /** - * Compare two objects for non-equality + * @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 auto constexpr operator!=(new_type const & lhs, @@ -257,93 +202,127 @@ namespace nt } /** - * Check if one nt::new_type object is less-than an other + * @brief Check if one nt::new_type object is less-than an other * - * @note This overload participates only in overload resolution if the derivation clause of this @p new_type does contain - * nt::Relational - * @return true iff. the object contained by lhs is less-than the one contained by rhs + * @note This operator is only avalaible if the the derivation clause of this nt::new_type does contains nt::Relational. Otherwise is is + * defined as deleted. + * @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> + template auto constexpr operator<(new_type const & lhs, new_type const & rhs) noexcept(noexcept(std::declval() < std::declval())) - -> bool + -> std::enable_if_t { return lhs.decay() < rhs.decay(); } + template + auto constexpr operator<(new_type const & lhs, + new_type const & rhs) noexcept(noexcept(std::declval() < + std::declval())) + -> std::enable_if_t = delete; + /** * Check if one nt::new_type object is greater-than an other * - * @note This overload participates only in overload resolution if the derivation clause of this @p new_type does contain - * nt::Relational - * @return true iff. the object contained by lhs is greater-than the one contained by rhs + * @note This operator is only avalaible if the the derivation clause of this nt::new_type does contains nt::Relational. Otherwise is is + * defined as deleted. + * @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> + template auto constexpr operator>(new_type const & lhs, new_type const & rhs) noexcept(noexcept(std::declval() > std::declval())) - -> bool + -> std::enable_if_t { return lhs.decay() > rhs.decay(); } + template + auto constexpr operator>(new_type const & lhs, + new_type const & rhs) noexcept(noexcept(std::declval() > + std::declval())) + -> std::enable_if_t = delete; + /** * Check if one nt::new_type object is less-than or equal-to an other * - * @note This overload participates only in overload resolution if the derivation clause of this @p new_type does contain - * nt::Relational - * @return true iff. the object contained by lhs is less-than or equal-to the one contained by rhs + * @note This operator is only avalaible if the the derivation clause of this nt::new_type does contains nt::Relational + * @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> + template auto constexpr operator<=(new_type const & lhs, new_type const & rhs) noexcept(noexcept(std::declval() <= std::declval())) - -> bool + -> std::enable_if_t { return lhs.decay() <= rhs.decay(); } + template + auto constexpr operator<=(new_type const & lhs, + new_type const & rhs) noexcept(noexcept(std::declval() <= + std::declval())) + -> std::enable_if_t = delete; + /** * Check if one nt::new_type object is greater-than or equal-to an other * - * @note This overload participates only in overload resolution if the derivation clause of this @p new_type does contain - * nt::Relational - * @return true iff. the object contained by lhs is greater-than or equal-to the one contained by rhs + * @note This operator is only avalaible if the the derivation clause of this nt::new_type does contains nt::Relational + * @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> + template auto constexpr operator>=(new_type const & lhs, new_type const & rhs) noexcept(noexcept(std::declval() >= std::declval())) - -> bool + -> std::enable_if_t { return lhs.decay() >= rhs.decay(); } - template, - typename StreamType = std::basic_ostream> - auto operator<<(std::basic_ostream & output, - new_type const & source) noexcept(noexcept(std::declval() - << std::declval())) - -> std::basic_ostream & + template + auto constexpr operator>=(new_type const & lhs, + new_type const & rhs) noexcept(noexcept(std::declval() >= + std::declval())) + -> std::enable_if_t = delete; + + /** + * @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 + auto operator<<(std::basic_ostream & output, new_type const & source) noexcept( + noexcept(std::declval &>() << std::declval())) + -> std::enable_if_t> & { return output << source.decay(); } - template, - typename StreamType = std::basic_istream> + /** + * @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 auto operator>>(std::basic_istream & input, new_type & target) noexcept( - noexcept(std::declval() >> std::declval())) -> std::basic_istream & + noexcept(std::declval &>() >> std::declval())) + -> std::enable_if_t> & { return input >> target.m_value; } -- cgit v1.2.3