From 6370b3fc6ffb973cc272f18d18db521c02fea0f1 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 22 Dec 2019 19:47:21 +0100 Subject: newtype: initial commit --- include/newtype/derivable.hpp | 63 +++++++++++++++++++++ include/newtype/deriving.hpp | 123 +++++++++++++++++++++++++++++++++++++++++ include/newtype/new_type.hpp | 124 ++++++++++++++++++++++++++++++++++++++++++ include/newtype/type.hpp | 29 ++++++++++ 4 files changed, 339 insertions(+) create mode 100644 include/newtype/derivable.hpp create mode 100644 include/newtype/deriving.hpp create mode 100644 include/newtype/new_type.hpp create mode 100644 include/newtype/type.hpp (limited to 'include') 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 + using derivable = type; + + /** + * 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{}; + + /** + * 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 + * + * @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{}; + + /** + * 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 stream output operator + * + * @since 1.0.0 + */ + auto constexpr Show = derivable{}; + + } // 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 + +namespace nt +{ + + /** + * A @p deriving clause type + * + * @tparam DerivableTags A list of tag types defining a set of derivable features + */ + template + struct derivation_clause + { + constexpr derivation_clause(derivable...) noexcept + { + } + + /** + * Check whether the derivation clause contains a given derivable + */ + template + auto constexpr operator()(derivable) const noexcept -> bool + { + return (std::is_same_v || ...); + } + + /** + * Check whether the derivation clause contains all derivables in a given lists + */ + template + auto constexpr operator()(derivable, derivable...) const noexcept -> bool + { + return (*this)(derivable{}) && (*this)(derivable{}...); + } + + /** + * 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 + auto constexpr operator<(derivation_clause other) const noexcept -> bool + { + return (sizeof...(DerivableTags) < sizeof...(OtherDerivableTags)) && other(derivable{}...); + } + + /** + * 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 + auto constexpr operator>(derivation_clause 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 + auto constexpr operator==(derivation_clause other) const noexcept -> bool + { + return sizeof...(DerivableTags) == sizeof...(OtherDerivableTags) && other(derivable{}...); + } + + /** + * 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 + auto constexpr operator!=(derivation_clause 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 + auto constexpr operator<=(derivation_clause 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 + auto constexpr operator>=(derivation_clause other) const noexcept -> bool + { + return *this > other || *this == other; + } + }; + + /** + * Create a new derivation clause with the given derivables + */ + template + auto constexpr deriving(derivable... request) -> derivation_clause + { + 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 + +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> + struct new_type_storage + { + constexpr new_type_storage() noexcept(std::is_nothrow_default_constructible_v) = default; + + constexpr explicit new_type_storage(BaseType const & value) noexcept(std::is_nothrow_copy_constructible_v) + : m_value{value} + { + } + + constexpr explicit new_type_storage(BaseType && value) noexcept(std::is_nothrow_move_constructible_v) + : 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 + struct new_type_storage + { + constexpr new_type_storage() = delete; + + constexpr explicit new_type_storage(BaseType const & value) noexcept(std::is_nothrow_copy_constructible_v) + : m_value{value} + { + } + + constexpr explicit new_type_storage(BaseType && value) noexcept(std::is_nothrow_move_constructible_v) + : 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 + class new_type : public impl::new_type_storage + { + using impl::new_type_storage::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 * = nullptr> + constexpr operator base_type() const noexcept(std::is_nothrow_copy_constructible_v) + { + 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 * = nullptr> + explicit constexpr operator base_type() const noexcept(std::is_nothrow_copy_constructible_v) + { + 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 + struct type final + { + }; + + /** + * A value to represent a type + * + * @tparam The type to represent + * @since 1.0.0 + */ + template + auto constexpr type_v = type{}; + +} // namespace nt + +#endif \ No newline at end of file -- cgit v1.2.3