jubilant-funicular
Wrapper.h
1 #ifndef UTILS_WRAPPER_H_INCLUDED
2 #define UTILS_WRAPPER_H_INCLUDED
3 
4 #include <type_traits>
5 
6 #define UTILS_OP_CHECKER(name, op) \
7  template<typename T, typename U> Nop operator op(const T&, const U&); \
8  template<typename T, typename U=T> \
9  struct name##Exists { \
10  enum { value = !::std::is_same<decltype(std::declval<T>() op std::declval<U>()), Nop>::value }; \
11  };
12 
13 #define UTILS_UNARY_OP_CHECKER(name, op) \
14  template<typename T> Nop operator op(T&); \
15  template<typename T> \
16  struct name##Exists { \
17  enum { value = !::std::is_same<decltype(op *std::declval<T*>()), Nop>::value }; \
18  };
19 
20 #define UTILS_IMPL_WRAPPER_OP(name, op) \
21  template<typename U, typename std::enable_if_t<check:: name##Exists<T, U>::value>* = nullptr> \
22  Wrapper operator op(const U& rhs) const { \
23  return Wrapper(m_data op rhs); \
24  } \
25  template<typename U, typename std::enable_if_t<check:: name##Exists<T, U>::value>* = nullptr> \
26  Wrapper& operator op##=(const U& rhs) { \
27  m_data = m_data op rhs; \
28  return *this; \
29  }
30 
31 #define UTILS_IMPL_WRAPPER_SELF_OP(name, op) \
32  template<typename T, typename TAG, typename std::enable_if_t<check:: name##Exists<T>::value>* = nullptr> \
33  Wrapper<T, TAG> operator op(const Wrapper<T, TAG>& lhs, const Wrapper<T, TAG>& rhs) { \
34  return Wrapper<T, TAG>(lhs.to_inner() op rhs.to_inner()); \
35  } \
36  template<typename T, typename TAG, typename std::enable_if_t<check:: name##Exists<T>::value>* = nullptr> \
37  Wrapper<T, TAG>& operator op##=(Wrapper<T, TAG>& lhs, const Wrapper<T, TAG>& rhs) { \
38  lhs.to_inner() = lhs.to_inner() op rhs.to_inner(); \
39  return Wrapper<T, TAG>(lhs); \
40  }
41 
42 #define UTILS_IMPL_WRAPPER_UNARY_OP(name, op, c) \
43  template<typename T, typename TAG, typename std::enable_if_t<check:: name##Exists<T>::value>* = nullptr> \
44  Wrapper<T, TAG> operator op(c Wrapper<T, TAG>& w) { \
45  return Wrapper<T, TAG>(op w.to_inner()); \
46  }
47 
48 #define UTILS_IMPL_WRAPPER_COMP(name, op) \
49  template<typename U, typename std::enable_if_t<check:: name##Exists<T, U>::value>* = nullptr> \
50  bool operator op(const U& rhs) const { \
51  return m_data op rhs; \
52  } \
53  template<typename U, typename std::enable_if_t<check:: name##Exists<T, U>::value && check::EqualsExists<T, U>::value>* = nullptr> \
54  bool operator op##=(const U& rhs) const { \
55  return m_data op rhs || m_data == rhs; \
56  }
57 
58 #define UTILS_IMPL_WRAPPER_SELF_COMP(name, op) \
59  template<typename T, typename TAG, typename std::enable_if_t<check:: name##Exists<T>::value>* = nullptr> \
60  bool operator op(const Wrapper<T, TAG>& lhs, const Wrapper<T, TAG>& rhs) { \
61  return lhs.to_inner() op rhs.to_inner(); \
62  } \
63  template<typename T, typename TAG, typename std::enable_if_t<check:: name##Exists<T>::value && check::EqualsExists<T>::value>* = nullptr> \
64  bool operator op##=(const Wrapper<T, TAG>& lhs, const Wrapper<T, TAG>& rhs) { \
65  return lhs.to_inner() op rhs.to_inner() || lhs.to_inner() == rhs.to_inner(); \
66  }
67 
68 namespace utils {
70  namespace check {
71  struct Nop {};
72  UTILS_OP_CHECKER(Equals, ==)
73  UTILS_OP_CHECKER(Add, +)
74  UTILS_OP_CHECKER(Sub, -)
75  UTILS_UNARY_OP_CHECKER(Neg, -)
76  UTILS_OP_CHECKER(Div, /)
77  UTILS_OP_CHECKER(Mul, *)
78  UTILS_OP_CHECKER(And, &)
79  UTILS_OP_CHECKER(Or, |)
80  UTILS_UNARY_OP_CHECKER(Not, ~)
81  UTILS_UNARY_OP_CHECKER(Incr, ++)
82  UTILS_UNARY_OP_CHECKER(Decr, --)
83  UTILS_OP_CHECKER(LShift, <<)
84  UTILS_OP_CHECKER(RShift, >>)
85  UTILS_OP_CHECKER(Mod, %)
86  UTILS_OP_CHECKER(Greater, >)
87  UTILS_OP_CHECKER(Lesser, <)
88  }
95  template<typename T, typename TAG>
96  class Wrapper {
97  public:
98  typedef T inner;
99  private:
100  T m_data;
101  public:
102  Wrapper(T data = T()) : m_data(data) {}
103  const T& to_inner() const { return m_data; }
104  T& to_inner() { return m_data; }
105  explicit operator T() const { return to_inner(); }
106  template<typename U>
107  auto operator==(const U& rhs) const -> decltype(std::enable_if_t<check::EqualsExists<T, U>::value, bool>{}) {
108  return m_data == rhs;
109  }
110  template<typename std::enable_if_t<check::EqualsExists<T>::value>* = nullptr>
111  bool operator==(const Wrapper& rhs) const {
112  return m_data == rhs.m_data;
113  }
114  template<typename U>
115  auto operator!=(const U& rhs) const -> decltype(std::enable_if_t<check::EqualsExists<T, U>::value, bool>{}) {
116  return m_data != rhs;
117  }
118  template<typename std::enable_if_t<check::EqualsExists<T>::value>* = nullptr>
119  bool operator!=(const Wrapper& rhs) const {
120  return !(m_data == rhs.m_data);
121  }
122  UTILS_IMPL_WRAPPER_OP(Add, +)
123  UTILS_IMPL_WRAPPER_OP(Sub, -)
124  UTILS_IMPL_WRAPPER_OP(Div, /)
125  UTILS_IMPL_WRAPPER_OP(Mul, *)
126  UTILS_IMPL_WRAPPER_OP(And, &)
127  UTILS_IMPL_WRAPPER_OP(Or, |)
128  UTILS_IMPL_WRAPPER_OP(LShift, <<)
129  UTILS_IMPL_WRAPPER_OP(RShift, >>)
130  UTILS_IMPL_WRAPPER_OP(Mod, %)
131  UTILS_IMPL_WRAPPER_COMP(Greater, >)
132  UTILS_IMPL_WRAPPER_COMP(Lesser, <)
133  };
134  UTILS_IMPL_WRAPPER_SELF_OP(Add, +)
135  UTILS_IMPL_WRAPPER_SELF_OP(Sub, -)
136  UTILS_IMPL_WRAPPER_SELF_OP(Div, /)
137  UTILS_IMPL_WRAPPER_SELF_OP(Mul, *)
138  UTILS_IMPL_WRAPPER_SELF_OP(And, &)
139  UTILS_IMPL_WRAPPER_SELF_OP(Or, |)
140  UTILS_IMPL_WRAPPER_SELF_OP(LShift, <<)
141  UTILS_IMPL_WRAPPER_SELF_OP(RShift, >>)
142  UTILS_IMPL_WRAPPER_SELF_OP(Mod, %)
143  UTILS_IMPL_WRAPPER_SELF_COMP(Greater, >)
144  UTILS_IMPL_WRAPPER_SELF_COMP(Lesser, <)
145  UTILS_IMPL_WRAPPER_UNARY_OP(Neg, -, const)
146  UTILS_IMPL_WRAPPER_UNARY_OP(Not, ~, const)
147  UTILS_IMPL_WRAPPER_UNARY_OP(Incr, ++,) // pre-incrementation
148  template<typename T, typename TAG, typename std::enable_if_t<check::IncrExists<T>::value>* = nullptr>
149  Wrapper<T, TAG> operator++(Wrapper<T, TAG>& lhs, int) {
150  auto ret = lhs;
151  ++lhs;
152  return ret;
153  }
154  UTILS_IMPL_WRAPPER_UNARY_OP(Decr, --,) // pre-decrementation
155  template<typename T, typename TAG, typename std::enable_if_t<check::DecrExists<T>::value>* = nullptr>
156  Wrapper<T, TAG> operator--(Wrapper<T, TAG>& lhs, int) {
157  auto ret = lhs;
158  --lhs;
159  return ret;
160  }
161  template<typename T, typename TAG, typename std::enable_if_t<check::LShiftExists<std::ostream, T>::value>* = nullptr>
162  std::ostream& operator<<(std::ostream& lhs, const Wrapper<T, TAG>& w) {
163  return lhs<<w.to_inner();
164  }
165 
174  template<typename T, typename TAG>
175  class StrongWrapper : public Wrapper<T, TAG> {
176  public:
177  explicit StrongWrapper(T data) : Wrapper<T, TAG>(data) {}
178  };
179 }
180 
181 namespace std {
183  template<typename T, typename TAG>
184  struct hash<utils::Wrapper<T, TAG>> {
185  std::size_t operator()(const utils::Wrapper<T, TAG>& w) const {
186  return std::hash<T>()(w.to_inner());
187  }
188  };
189  template<typename T, typename TAG>
190  struct hash<utils::StrongWrapper<T, TAG>> {
191  std::size_t operator()(const utils::StrongWrapper<T, TAG>& w) const {
192  return std::hash<T>()(w.to_inner());
193  }
194  };
195 }
196 
197 #endif // UTILS_WRAPPER_H_INCLUDED
utils::Wrapper
Definition: Wrapper.h:96
utils::StrongWrapper
Definition: Wrapper.h:175
utils::check::Nop
Definition: Wrapper.h:71
utils::check::EqualsExists
Definition: Wrapper.h:72