| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- //
- // opaque_typedef.hpp
- // opaque-type
- //
- // Inspired by https://foonathan.github.io/blog/2016/10/19/strong-typedefs.html and others
- //
- // Created by Sam Jaffe on 8/16/16.
- //
- #pragma once
- #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 = std::underlying_type<TDef>; \
- using type2 = std::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 numeric_arithmetic : unary_plus<TDef>, unary_minus<TDef>, addition<TDef>, subtraction<TDef>, multiplication<TDef>, division<TDef> {};
- template <typename TDef>
- struct integer_arithmetic : numeric_arithmetic<TDef>, modulo<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; }
-
- 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 : opaque_typedef<name, basetype> \
- BOOST_PP_SEQ_FOR_EACH(OPAQUE_TYPEDEF_PARENT, name, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
- { \
- using opaque_typedef::opaque_typedef; \
- OPAQUE_TYPEDEF_CONVERSIONS
- #define OPAQUE_TYPEDEF_PARENT(r, name, parent) , parent < name >
- #define CREATE_OPAQUE_TYPEDEF(name, basetype, ...) \
- struct name : opaque_typedef<name, basetype> \
- BOOST_PP_SEQ_FOR_EACH(OPAQUE_TYPEDEF_PARENT, name, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
- { \
- using opaque_typedef::opaque_typedef; \
- }
|