|
|
@@ -11,177 +11,65 @@
|
|
|
|
|
|
#include <type_traits>
|
|
|
|
|
|
-template <typename, typename> class opaque_typedef;
|
|
|
-
|
|
|
-template <typename Tag, typename T>
|
|
|
-T underlying_type_impl(opaque_typedef<Tag, T>);
|
|
|
-
|
|
|
-template <typename T>
|
|
|
-using underlying_type = decltype(underlying_type_impl(std::declval<T>()));
|
|
|
-
|
|
|
-#define OPAQUE_TYPE_ASSIGN_OPERATOR(name, op) \
|
|
|
- template <typename TDef> \
|
|
|
- struct name { \
|
|
|
- friend TDef & operator op##=(TDef & lhs, TDef const & rhs) { \
|
|
|
- using type = underlying_type<TDef>; \
|
|
|
- static_cast<type &>(lhs) op##= static_cast<type const &>(rhs); \
|
|
|
- return lhs; \
|
|
|
- } \
|
|
|
- \
|
|
|
- friend TDef operator op(TDef const & lhs, TDef const & rhs) { \
|
|
|
- using type = underlying_type<TDef>; \
|
|
|
- return TDef(static_cast<type const&>(lhs) op static_cast<type const&>(rhs)); \
|
|
|
- } \
|
|
|
- }
|
|
|
-
|
|
|
-#define OPAQUE_TYPE_BINARY_OPERATOR_T(name, op, Out) \
|
|
|
- template <typename TDef> \
|
|
|
- struct name { \
|
|
|
- friend Out operator op(TDef const & lhs, TDef const & rhs) { \
|
|
|
- using type = underlying_type<TDef>; \
|
|
|
- return Out(static_cast<type const&>(lhs) op static_cast<type const&>(rhs)); \
|
|
|
- } \
|
|
|
- }
|
|
|
-
|
|
|
-#define OPAQUE_TYPE_BINARY_OPERATOR(name, op) \
|
|
|
- OPAQUE_TYPE_BINARY_OPERATOR_T(name, op, TDef)
|
|
|
-
|
|
|
-#define OPAQUE_TYPE_MIXED_BINARY_OPERATOR(name, op) \
|
|
|
- template <typename TDef, typename RDef, typename Out> \
|
|
|
- struct name { \
|
|
|
- friend Out operator op(TDef const & lhs, RDef const & rhs) { \
|
|
|
- using type1 = underlying_type<TDef>; \
|
|
|
- using type2 = underlying_type<RDef>; \
|
|
|
- return Out(static_cast<type1 const&>(lhs) op static_cast<type2 const&>(rhs)); \
|
|
|
- } \
|
|
|
- }; \
|
|
|
- \
|
|
|
- template <typename TDef, typename RDef> \
|
|
|
- struct name<TDef, RDef, TDef> { \
|
|
|
- friend TDef operator op##=(TDef & lhs, RDef const & rhs) { \
|
|
|
- using type1 = underlying_type<TDef>; \
|
|
|
- using type2 = underlying_type<RDef>; \
|
|
|
- static_cast<type1 &>(lhs) op##= static_cast<type2 const&>(rhs); \
|
|
|
- return lhs; \
|
|
|
- } \
|
|
|
- \
|
|
|
- friend TDef operator op(TDef const & lhs, RDef const & rhs) { \
|
|
|
- using type1 = underlying_type<TDef>; \
|
|
|
- using type2 = underlying_type<RDef>; \
|
|
|
- return TDef(static_cast<type1 const&>(lhs) op static_cast<type2 const&>(rhs)); \
|
|
|
- } \
|
|
|
- }
|
|
|
-
|
|
|
-#define OPAQUE_TYPE_UNARY_OPERATOR(name, op) \
|
|
|
- template <typename TDef> \
|
|
|
- struct name { \
|
|
|
- friend TDef operator op(TDef const & val) { \
|
|
|
- using type = underlying_type<TDef>; \
|
|
|
- return TDef(op static_cast<type const&>(val)); \
|
|
|
- } \
|
|
|
- }
|
|
|
-
|
|
|
-OPAQUE_TYPE_UNARY_OPERATOR(unary_plus, +);
|
|
|
-OPAQUE_TYPE_UNARY_OPERATOR(unary_minus, -);
|
|
|
-
|
|
|
-OPAQUE_TYPE_ASSIGN_OPERATOR(addition, +);
|
|
|
-OPAQUE_TYPE_ASSIGN_OPERATOR(subtraction, -);
|
|
|
-OPAQUE_TYPE_ASSIGN_OPERATOR(multiplication, *);
|
|
|
-OPAQUE_TYPE_ASSIGN_OPERATOR(division, /);
|
|
|
-OPAQUE_TYPE_ASSIGN_OPERATOR(modulo, %);
|
|
|
-
|
|
|
-OPAQUE_TYPE_BINARY_OPERATOR_T(equals, ==, bool);
|
|
|
-OPAQUE_TYPE_BINARY_OPERATOR_T(not_equals, !=, bool);
|
|
|
-OPAQUE_TYPE_BINARY_OPERATOR_T(less_than, <, bool);
|
|
|
-OPAQUE_TYPE_BINARY_OPERATOR_T(less_equal, <=, bool);
|
|
|
-OPAQUE_TYPE_BINARY_OPERATOR_T(greater_than, >, bool);
|
|
|
-OPAQUE_TYPE_BINARY_OPERATOR_T(greater_equal, >=, bool);
|
|
|
-
|
|
|
-OPAQUE_TYPE_MIXED_BINARY_OPERATOR(mixed_addition, +);
|
|
|
-OPAQUE_TYPE_MIXED_BINARY_OPERATOR(mixed_subtraction, -);
|
|
|
-OPAQUE_TYPE_MIXED_BINARY_OPERATOR(mixed_multiplication, *);
|
|
|
-OPAQUE_TYPE_MIXED_BINARY_OPERATOR(mixed_division, /);
|
|
|
-
|
|
|
-OPAQUE_TYPE_ASSIGN_OPERATOR(bitwise_and, &);
|
|
|
-OPAQUE_TYPE_ASSIGN_OPERATOR(bitwise_or, |);
|
|
|
-OPAQUE_TYPE_ASSIGN_OPERATOR(exclusive_or, ^);
|
|
|
-
|
|
|
-#undef OPAQUE_TYPE_BINARY_OPERATOR_T
|
|
|
-#undef OPAQUE_TYPE_BINARY_OPERATOR
|
|
|
-#undef OPAQUE_TYPE_MIXED_BINARY_OPERATOR
|
|
|
-#undef OPAQUE_TYPE_UNARY_OPERATOR
|
|
|
-#undef OPAQUE_TYPE_ASSIGN_OPERATOR
|
|
|
-
|
|
|
-template <typename TDef>
|
|
|
-struct arithmetic : unary_plus<TDef>, unary_minus<TDef>, addition<TDef>, subtraction<TDef> {};
|
|
|
-
|
|
|
-template <typename TDef>
|
|
|
-struct numeric_arithmetic : arithmetic<TDef>, multiplication<TDef>, division<TDef> {};
|
|
|
-
|
|
|
-template <typename TDef>
|
|
|
-struct integer_arithmetic : numeric_arithmetic<TDef>, modulo<TDef> {};
|
|
|
-
|
|
|
-template <typename TDef, typename Base = underlying_type<TDef>>
|
|
|
-struct untyped_multiplication : mixed_multiplication<TDef, Base, TDef>
|
|
|
-, mixed_multiplication<Base, TDef, TDef> {};
|
|
|
-
|
|
|
-template <typename TDef, typename Base = underlying_type<TDef>>
|
|
|
-struct untyped_division : mixed_division<TDef, Base, TDef> {};
|
|
|
-
|
|
|
-template <typename TDef>
|
|
|
-struct equality_comparible : equals<TDef>, not_equals<TDef> {};
|
|
|
-
|
|
|
-template <typename TDef>
|
|
|
-struct orderable : equality_comparible<TDef>, less_than<TDef>, less_equal<TDef>, greater_than<TDef>, greater_equal<TDef> {};
|
|
|
-
|
|
|
-template <typename Self, typename T>
|
|
|
-class opaque_typedef {
|
|
|
-public:
|
|
|
- opaque_typedef() : _value() {}
|
|
|
- explicit opaque_typedef(T const & val) : _value(val) {}
|
|
|
- explicit opaque_typedef(T && val) noexcept(std::is_nothrow_move_constructible<T>::value) : _value(std::move(val)) {}
|
|
|
- explicit operator T &() noexcept { return _value; }
|
|
|
- explicit operator T const&() const noexcept { return _value; }
|
|
|
+namespace types { namespace detail {
|
|
|
+ template <typename FromOpaque>
|
|
|
+ struct is_a {
|
|
|
+ FromOpaque const & self() const {
|
|
|
+ return *(FromOpaque const *)(void const *)(this);
|
|
|
+ }
|
|
|
+ };
|
|
|
+}}
|
|
|
+
|
|
|
+namespace types {
|
|
|
+ template <typename Base, typename Tag, template <typename> class... Skills>
|
|
|
+ class opaque_typedef : public Skills<opaque_typedef<Base, Tag, Skills...>>... {
|
|
|
+ public:
|
|
|
+ using super = opaque_typedef;
|
|
|
+
|
|
|
+ private:
|
|
|
+ Base value_;
|
|
|
+
|
|
|
+ public:
|
|
|
+ opaque_typedef() = default;
|
|
|
+ explicit opaque_typedef(Base const & value) : value_(value) {};
|
|
|
+ explicit opaque_typedef(Base && value) : value_(std::forward<Base>(value)) {};
|
|
|
+
|
|
|
+ Base const & get() const { return value_; }
|
|
|
+ explicit operator Base const &() const { return value_; }
|
|
|
+ };
|
|
|
|
|
|
- friend void swap(opaque_typedef & lhs, opaque_typedef & rhs) {
|
|
|
- using std::swap;
|
|
|
- swap(lhs._value, rhs._value);
|
|
|
- }
|
|
|
-protected:
|
|
|
- T const & self() const { return _value; }
|
|
|
-private:
|
|
|
- T _value;
|
|
|
-};
|
|
|
-
|
|
|
-#include <boost/preprocessor/variadic/to_seq.hpp>
|
|
|
-#include <boost/preprocessor/tuple/to_seq.hpp>
|
|
|
-#include <boost/preprocessor/seq/for_each.hpp>
|
|
|
-
|
|
|
-#define OPAQUE_TYPEDEF_CONVERT(r, x, type) operator type() const;
|
|
|
-#define OPAQUE_TYPEDEF_CONVERSIONS(...) \
|
|
|
- BOOST_PP_SEQ_FOR_EACH(OPAQUE_TYPEDEF_CONVERT, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
|
|
|
- }
|
|
|
-
|
|
|
-#define CREATE_CONVERTABLE_OPAQUE_TYPEDEF(name, basetype, ...) \
|
|
|
- struct name##_base : opaque_typedef<name, basetype> \
|
|
|
- { \
|
|
|
- using opaque_typedef::opaque_typedef; \
|
|
|
- }; \
|
|
|
- struct name : name##_base \
|
|
|
- BOOST_PP_SEQ_FOR_EACH(OPAQUE_TYPEDEF_PARENT, name##_base, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
|
|
|
- { \
|
|
|
- using name##_base::name##_base; \
|
|
|
- OPAQUE_TYPEDEF_CONVERSIONS
|
|
|
-
|
|
|
-
|
|
|
-#define OPAQUE_TYPEDEF_PARENT(r, name, parent) , parent < name >
|
|
|
-#define CREATE_OPAQUE_TYPEDEF(name, basetype, ...) \
|
|
|
- struct name##_base : opaque_typedef<name, basetype> \
|
|
|
- { \
|
|
|
- using opaque_typedef::opaque_typedef; \
|
|
|
- }; \
|
|
|
- struct name : name##_base \
|
|
|
- BOOST_PP_SEQ_FOR_EACH(OPAQUE_TYPEDEF_PARENT, name##_base, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
|
|
|
- { \
|
|
|
- using name##_base::name##_base; \
|
|
|
- }
|
|
|
+ template <typename Opaque>
|
|
|
+ struct EqualityComparable {
|
|
|
+ friend bool operator==(Opaque const & lhs, Opaque const & rhs) {
|
|
|
+ return lhs.get() == rhs.get();
|
|
|
+ }
|
|
|
+ friend bool operator!=(Opaque const & lhs, Opaque const & rhs) {
|
|
|
+ return !(lhs == rhs);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ template <typename Opaque>
|
|
|
+ struct Comparable : EqualityComparable<Opaque> {
|
|
|
+ friend bool operator<(Opaque const & lhs, Opaque const & rhs) {
|
|
|
+ return lhs.get() < rhs.get();
|
|
|
+ }
|
|
|
+ friend bool operator>(Opaque const & lhs, Opaque const & rhs) {
|
|
|
+ return rhs.get() < lhs.get();
|
|
|
+ }
|
|
|
+ friend bool operator<=(Opaque const & lhs, Opaque const & rhs) {
|
|
|
+ return !(rhs.get() < lhs.get());
|
|
|
+ }
|
|
|
+ friend bool operator>=(Opaque const & lhs, Opaque const & rhs) {
|
|
|
+ return !(lhs.get() < rhs.get());
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ template <typename ToOpaque>
|
|
|
+ struct Convertable {
|
|
|
+ template <typename FromOpaque>
|
|
|
+ class type : detail::is_a<FromOpaque> {
|
|
|
+ public:
|
|
|
+ operator ToOpaque() const;
|
|
|
+ };
|
|
|
+ };
|
|
|
+}
|