aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/newtype/derivable.hpp63
-rw-r--r--include/newtype/deriving.hpp123
-rw-r--r--include/newtype/new_type.hpp124
-rw-r--r--include/newtype/type.hpp29
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