diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/newtype/derivable.hpp | 63 | ||||
| -rw-r--r-- | include/newtype/deriving.hpp | 123 | ||||
| -rw-r--r-- | include/newtype/new_type.hpp | 124 | ||||
| -rw-r--r-- | include/newtype/type.hpp | 29 |
4 files changed, 339 insertions, 0 deletions
diff --git a/include/newtype/derivable.hpp b/include/newtype/derivable.hpp new file mode 100644 index 0000000..4fec2b7 --- /dev/null +++ b/include/newtype/derivable.hpp @@ -0,0 +1,63 @@ +#ifndef NEWTYPE_DERIVABLE_HPP +#define NEWTYPE_DERIVABLE_HPP + +#include "newtype/type.hpp" + +namespace nt +{ + + template<typename NameTag> + using derivable = type<NameTag>; + + /** + * A set of standard derivation tags + * + * This convenience namespace contains all standard derivation tags. + * + * @since 1.0.0 + */ + inline namespace derivables + { + + /** + * A tag to enable derivation of arithmetic operators + * + * @since 1.0.0 + */ + auto constexpr Arithmetic = derivable<struct arithmetic_tag>{}; + + /** + * A tag to enable derivation of equality comparison operators + * + * @since 1.0.0 + */ + auto constexpr EqBase = derivable<struct eq_tag>{}; + + /** + * 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>{}; + + /** + * A tag to enable derivation of the stream input operator + * + * @since 1.0.0 + */ + auto constexpr Read = derivable<struct read_tag>{}; + + /** + * A tag to enable derivation of the stream output operator + * + * @since 1.0.0 + */ + auto constexpr Show = derivable<struct show_tag>{}; + + } // namespace derivables + +} // namespace nt + +#endif
\ No newline at end of file diff --git a/include/newtype/deriving.hpp b/include/newtype/deriving.hpp new file mode 100644 index 0000000..431742f --- /dev/null +++ b/include/newtype/deriving.hpp @@ -0,0 +1,123 @@ +#ifndef NEWTYPE_DERIVING_HPP +#define NEWTYPE_DERIVING_HPP + +#include "newtype/derivable.hpp" + +#include <type_traits> + +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 + { + constexpr derivation_clause(derivable<DerivableTags>...) noexcept + { + } + + /** + * 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 + { + return *this > other || *this == other; + } + }; + + /** + * Create a new derivation clause with the given derivables + */ + template<typename... DerivableTags> + auto constexpr deriving(derivable<DerivableTags>... request) -> derivation_clause<DerivableTags...> + { + return {request...}; + } + +} // namespace nt + +#endif
\ No newline at end of file diff --git a/include/newtype/new_type.hpp b/include/newtype/new_type.hpp new file mode 100644 index 0000000..9c1074c --- /dev/null +++ b/include/newtype/new_type.hpp @@ -0,0 +1,124 @@ +#ifndef NEWTYPE_NEW_TYPE_HPP +#define NEWTYPE_NEW_TYPE_HPP + +#include "newtype/derivable.hpp" +#include "newtype/deriving.hpp" +#include "newtype/type.hpp" + +#include <type_traits> + +namespace nt +{ + + namespace impl + { + + /** + * This class forms the a base type of nt::new_type and provides its storage + * + * This specialization enables the default constructor for cases in which @p BaseType is default constructible + * + * @tparam BaseType An existing type that shall aliased + * @tparam TagType A unique type to identify this nt::new_type + */ + template<typename BaseType, typename TagType, bool = std::is_default_constructible_v<BaseType>> + struct new_type_storage + { + constexpr new_type_storage() noexcept(std::is_nothrow_default_constructible_v<BaseType>) = default; + + constexpr explicit new_type_storage(BaseType const & value) noexcept(std::is_nothrow_copy_constructible_v<BaseType>) + : m_value{value} + { + } + + constexpr explicit new_type_storage(BaseType && value) noexcept(std::is_nothrow_move_constructible_v<BaseType>) + : m_value{std::move(value)} + { + } + + protected: + BaseType m_value{}; + }; + + /** + * This class forms the a base type of nt::new_type and provides its storage + * + * This specialization explicitly deletes the default constructor for cases in which @p BaseType is not default + * constructible + * + * @tparam BaseType An existing type that shall aliased + * @tparam TagType A unique type to identify this nt::new_type + */ + template<typename BaseType, typename TagType> + struct new_type_storage<BaseType, TagType, false> + { + constexpr new_type_storage() = delete; + + constexpr explicit new_type_storage(BaseType const & value) noexcept(std::is_nothrow_copy_constructible_v<BaseType>) + : m_value{value} + { + } + + constexpr explicit new_type_storage(BaseType && value) noexcept(std::is_nothrow_move_constructible_v<BaseType>) + : m_value{std::move(value)} + { + } + + protected: + BaseType m_value; + }; + + } // namespace impl + + /** + * @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 : public impl::new_type_storage<BaseType, TagType> + { + using impl::new_type_storage<BaseType, TagType>::new_type_storage; + + using base_type = BaseType; + using tag_type = TagType; + + auto constexpr static derivations = DerivationClause; + + public: + /** + * Retrieve the base type value contained in this @p new_type + */ + auto constexpr decay() const noexcept -> BaseType + { + return this->m_value; + } + + /** + * Convert this instance into the equivalent base type value + * + * @note This overload participates only in overload resolution if the derication clause of this @p new_type contains + * nt::ImplicitConversion + */ + template<typename NewType = new_type, std::enable_if_t<NewType::derivations(nt::ImplicitConversion)> * = nullptr> + constexpr operator base_type() const noexcept(std::is_nothrow_copy_constructible_v<base_type>) + { + return decay(); + } + + /** + * Convert this instance into the equivalent base type value + * + * @note This overload participates only in overload resolution if the derication clause of this @p new_type does not contain + * nt::ImplicitConversion + */ + template<typename NewType = new_type, std::enable_if_t<!NewType::derivations(nt::ImplicitConversion)> * = nullptr> + explicit constexpr operator base_type() const noexcept(std::is_nothrow_copy_constructible_v<base_type>) + { + return decay(); + } + }; + +} // namespace nt + +#endif
\ No newline at end of file diff --git a/include/newtype/type.hpp b/include/newtype/type.hpp new file mode 100644 index 0000000..b1f8787 --- /dev/null +++ b/include/newtype/type.hpp @@ -0,0 +1,29 @@ +#ifndef NEWTYPE_TYPE_HPP +#define NEWTYPE_TYPE_HPP + +namespace nt +{ + + /** + * A convenience type to make values out of types + * + * @tparam Type The type to wrap + * @since 1.0.0 + */ + template<typename Type> + struct type final + { + }; + + /** + * A value to represent a type + * + * @tparam The type to represent + * @since 1.0.0 + */ + template<typename Type> + auto constexpr type_v = type<Type>{}; + +} // namespace nt + +#endif
\ No newline at end of file |
