ZeroErr
Loading...
Searching...
No Matches
decomposition.h
Go to the documentation of this file.
1#pragma once
2
4
5#include "zeroerr/dbg.h"
6#include "zeroerr/print.h"
7
10
11#ifndef ZEROERR_DISABLE_COMPLEX_AND_OR
20#define AND &&zeroerr::ExpressionDecomposer() <<
21#define OR || zeroerr::ExpressionDecomposer() <<
22#endif
23
24namespace zeroerr {
25
26
27// SFINAE helper used to check L op R is supported, but the result type is `ret`
28#define ZEROERR_SFINAE_OP(ret, op) \
29 typename std::decay<decltype(std::declval<L>() op std::declval<R>(), std::declval<ret>())>::type
30
31template <typename T>
33 static const bool value = false;
34};
35
36#define ZEROERR_EXPRESSION_COMPARISON(op, op_name) \
37 template <typename R> \
38 ZEROERR_SFINAE_OP(Expression<R>, op) \
39 operator op(R && rhs) { \
40 std::stringstream ss; \
41 Printer print(ss); \
42 print.isCompact = true; \
43 print.line_break = ""; \
44 if (decomp.empty()) { \
45 print(lhs); \
46 res = true; \
47 } else \
48 ss << decomp; \
49 ss << " " #op " "; \
50 print(rhs); \
51 return Expression<R>(static_cast<R&&>(rhs), res && (lhs op rhs), ss.str()); \
52 } \
53 template <typename R, \
54 typename std::enable_if<!std::is_rvalue_reference<R>::value, void>::type* = nullptr> \
55 ZEROERR_SFINAE_OP(Expression<const R&>, op) \
56 operator op(const R & rhs) { \
57 std::stringstream ss; \
58 Printer print(ss); \
59 print.isCompact = true; \
60 print.line_break = ""; \
61 if (decomp.empty()) { \
62 print(lhs); \
63 res = true; \
64 } else \
65 ss << decomp; \
66 ss << " " #op " "; \
67 print(rhs); \
68 return Expression<const R&>(rhs, res && (lhs op rhs), ss.str()); \
69 }
70
71#define ZEROERR_EXPRESSION_ANDOR(op, op_name) \
72 ExprResult operator op(ExprResult rhs) { \
73 std::stringstream ss; \
74 ss << decomp << " " #op " " << rhs.decomp; \
75 return ExprResult(res op rhs.res, ss.str()); \
76 }
77
78
79#define ZEROERR_FORBIT_EXPRESSION(rt, op) \
80 template <typename R> \
81 rt& operator op(const R&) { \
82 static_assert(deferred_false<R>::value, \
83 "Please Rewrite Expression As Binary Comparison!"); \
84 return *this; \
85 }
86
116
117namespace details {
118template <typename T>
119typename std::enable_if<std::is_convertible<T, bool>::value, bool>::type getBool(T&& lhs) {
120 return static_cast<bool>(lhs);
121}
122
123template <typename T>
124typename std::enable_if<!std::is_convertible<T, bool>::value, bool>::type getBool(T&&) {
125 return true;
126}
127} // namespace details
128
129template <typename L>
132 bool res = true;
133 std::string decomp;
134
135 explicit Expression(L&& in) : lhs(static_cast<L&&>(in)) { res = details::getBool(lhs); }
136 explicit Expression(L&& in, bool res, std::string&& decomp)
137 : lhs(static_cast<L&&>(in)), res(res), decomp(static_cast<std::string&&>(decomp)) {}
138
139 operator ExprResult() {
140 if (decomp.empty()) {
141 Printer print;
142 print.isCompact = true;
143 print.line_break = "";
144 decomp = print(lhs).str();
145 }
146 return ExprResult(res, decomp);
147 }
148
149 operator L() const { return lhs; }
150
157
160
177};
178
179#undef ZEROERR_EXPRESSION_COMPARISON
180#undef ZEROERR_EXPRESSION_ANDOR
181#undef ZEROERR_FORBIT_EXPRESSION
182
184 // The right operator for capturing expressions is "<=" instead of "<<" (based on the
185 // operator precedence table) but then there will be warnings from GCC about "-Wparentheses"
186 // and since "_Pragma()" is problematic this will stay for now...
187 // https://github.com/catchorg/Catch2/issues/870
188 // https://github.com/catchorg/Catch2/issues/565
189
190 // For temporary objects, we need to use rvalue reference to avoid copy
191 template <typename L>
192 Expression<L> operator<<(L&& operand) {
193 return Expression<L>(static_cast<L&&>(operand));
194 }
195
196 // For other objects, we will store the reference
197 template <typename L,
198 typename std::enable_if<!std::is_rvalue_reference<L>::value, void>::type* = nullptr>
199 Expression<const L&> operator<<(const L& operand) {
200 return Expression<const L&>(operand);
201 }
202};
203
204
205template <typename T>
206class IMatcher {
207public:
208 virtual ~IMatcher() = default;
209
210
211 virtual bool match(const T&) const = 0;
212};
213
214template <typename T>
216public:
217 IMatcherRef(const IMatcher<T>* ptr) : p(ptr) {}
218 IMatcherRef(const IMatcherRef&) = delete;
219
221 p = std::move(other.p);
222 other.p = nullptr;
223 }
224 void operator=(IMatcherRef&& other) {
225 p = std::move(other.p);
226 other.p = nullptr;
227 }
230 if (p) delete p;
231 }
232
233 IMatcherRef operator&&(IMatcherRef&& other);
234 IMatcherRef operator||(IMatcherRef&& other);
235 IMatcherRef operator!();
236
237 const IMatcher<T>* operator->() const { return p; }
238
239protected:
240 const IMatcher<T>* p = nullptr;
241};
242
243
244template <typename T>
245class CombinedMatcher : public IMatcher<T> {
246public:
248 : lhs(std::move(lhs)), rhs(std::move(rhs)), is_and(is_and) {}
249
252 bool is_and;
253
254 virtual bool match(const T& t) const override {
255 if (is_and) {
256 return lhs->match(t) && rhs->match(t);
257 } else {
258 return lhs->match(t) || rhs->match(t);
259 }
260 }
261};
262
263template <typename T>
264class NotMatcher : public IMatcher<T> {
265public:
266 NotMatcher(IMatcherRef<T>&& matcher) : matcher(std::move(matcher)) {}
268
269 virtual bool match(const T& t) const override { return !matcher->match(t); }
270};
271
272template <typename T>
274 return new CombinedMatcher<T>(std::move(*this), std::move(other), true);
275}
276
277template <typename T>
279 return new CombinedMatcher<T>(std::move(*this), std::move(other), false);
280}
281
282template <typename T>
284 return new NotMatcher<T>(std::move(*this));
285}
286
287
288template <typename T>
289struct StartWithMatcher : public IMatcher<T> {
290 StartWithMatcher(const T& s) : start(s) {}
292
293 virtual bool match(const T& t) const override {
294 bool result = true;
295 for (auto i = start.begin(), j = t.begin(); i != start.end(); ++i, ++j) {
296 if (j == t.end() || *i != *j) {
297 result = false;
298 break;
299 }
300 }
301 return result;
302 }
303};
304
305template <typename T>
306typename std::enable_if<std::is_constructible<std::string, T>::value,
307 IMatcherRef<std::string>>::type
309 return new StartWithMatcher<std::string>(std::string(s));
310}
311
312} // namespace zeroerr
313
Definition decomposition.h:245
IMatcherRef< T > lhs
Definition decomposition.h:250
IMatcherRef< T > rhs
Definition decomposition.h:251
virtual bool match(const T &t) const override
Definition decomposition.h:254
bool is_and
Definition decomposition.h:252
CombinedMatcher(IMatcherRef< T > &&lhs, IMatcherRef< T > &&rhs, bool is_and)
Definition decomposition.h:247
Definition decomposition.h:215
IMatcherRef(IMatcherRef &&other)
Definition decomposition.h:220
IMatcherRef(const IMatcher< T > *ptr)
Definition decomposition.h:217
void operator=(IMatcherRef &&other)
Definition decomposition.h:224
IMatcherRef(const IMatcherRef &)=delete
IMatcherRef & operator=(const IMatcherRef &)=delete
const IMatcher< T > * operator->() const
Definition decomposition.h:237
~IMatcherRef()
Definition decomposition.h:229
Definition decomposition.h:206
virtual bool match(const T &) const =0
virtual ~IMatcher()=default
Definition decomposition.h:264
IMatcherRef< T > matcher
Definition decomposition.h:267
NotMatcher(IMatcherRef< T > &&matcher)
Definition decomposition.h:266
virtual bool match(const T &t) const override
Definition decomposition.h:269
#define ZEROERR_SUPPRESS_COMPARE
Definition config.h:299
#define ZEROERR_SUPPRESS_COMMON_WARNINGS_POP
Definition config.h:265
#define ZEROERR_SUPPRESS_COMPARE_POP
Definition config.h:312
#define ZEROERR_SUPPRESS_COMMON_WARNINGS_PUSH
Definition config.h:218
#define ZEROERR_FORBIT_EXPRESSION(rt, op)
Definition decomposition.h:79
#define ZEROERR_EXPRESSION_ANDOR(op, op_name)
Definition decomposition.h:71
#define ZEROERR_EXPRESSION_COMPARISON(op, op_name)
Definition decomposition.h:36
STL namespace.
std::enable_if< std::is_convertible< T, bool >::value, bool >::type getBool(T &&lhs)
Definition decomposition.h:119
Definition benchmark.cpp:17
std::enable_if< std::is_constructible< std::string, T >::value, IMatcherRef< std::string > >::type start_with(T &&s)
Definition decomposition.h:308
Definition decomposition.h:87
std::string decomp
Definition decomposition.h:89
bool res
Definition decomposition.h:88
ExprResult(bool res, std::string decomposition="")
Definition decomposition.h:91
Definition decomposition.h:183
Definition decomposition.h:130
Expression(L &&in, bool res, std::string &&decomp)
Definition decomposition.h:136
std::string decomp
Definition decomposition.h:133
L lhs
Definition decomposition.h:131
Expression(L &&in)
Definition decomposition.h:135
A functor class Printer for printing a value of any type.
Definition print.h:63
std::string str() const
Definition print.h:253
bool isCompact
Definition print.h:105
const char * line_break
Definition print.h:108
Definition decomposition.h:289
StartWithMatcher(const T &s)
Definition decomposition.h:290
virtual bool match(const T &t) const override
Definition decomposition.h:293
T start
Definition decomposition.h:291
Definition decomposition.h:32
static const bool value
Definition decomposition.h:33