ZeroErr
载入中...
搜索中...
未找到
decomposition.h
浏览该文件的文档.
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_DIAGNOSTIC_NOINLINE ZEROERR_SFINAE_OP(Expression<R>, op) operator op(R&& rhs) { \
39 zeroerr::String text = \
40 detail::comparisonText(decomp, detail::makeDiagnosticValue(lhs), " " #op " ", \
41 detail::makeDiagnosticValue(rhs), res); \
42 return Expression<R>(static_cast<R&&>(rhs), res && (lhs op rhs), std::move(text)); \
43 } \
44 template <typename R, \
45 typename std::enable_if<!std::is_rvalue_reference<R>::value, void>::type* = nullptr> \
46 ZEROERR_DIAGNOSTIC_NOINLINE ZEROERR_SFINAE_OP(Expression<const R&>, op) operator op( \
47 const R& rhs) { \
48 zeroerr::String text = \
49 detail::comparisonText(decomp, detail::makeDiagnosticValue(lhs), " " #op " ", \
50 detail::makeDiagnosticValue(rhs), res); \
51 return Expression<const R&>(rhs, res && (lhs op rhs), std::move(text)); \
52 }
53
54
55#define ZEROERR_EXPRESSION_ANDOR(op, op_name) \
56 ExprResult operator op(ExprResult rhs) { \
57 return ExprResult(res op rhs.res, \
58 detail::joinDiagnostic(decomp, " " #op " ", rhs.decomp)); \
59 }
60
61
62#define ZEROERR_FORBIT_EXPRESSION(rt, op) \
63 template <typename R> \
64 rt& operator op(const R&) { \
65 static_assert(deferred_false<R>::value, \
66 "Please Rewrite Expression As Binary Comparison!"); \
67 return *this; \
68 }
69
99
100namespace details {
101// Detect whether a type can be explicitly converted to bool. This covers
102// explicit operator bool (std::unique_ptr/std::shared_ptr), which
103// std::is_convertible would miss. Scoped enums are excluded so that a bare
104// CHECK(enum) does not silently turn into "value != 0"; unscoped enums keep
105// their historical implicit-conversion behavior.
106template <typename T, typename = void>
107struct has_bool_conversion : std::false_type {};
108
109template <typename T>
110struct has_bool_conversion<T, decltype(static_cast<bool>(std::declval<T>()), void())>
111 : std::integral_constant<
112 bool, !(std::is_enum<typename std::decay<T>::type>::value &&
113 !std::is_convertible<typename std::decay<T>::type, int>::value)> {};
114
115template <typename T>
116typename std::enable_if<has_bool_conversion<T>::value, bool>::type getBool(T&& lhs) {
117 return static_cast<bool>(lhs);
118}
119
120template <typename T>
121typename std::enable_if<!has_bool_conversion<T>::value, bool>::type getBool(T&&) {
122 return true;
123}
124} // namespace details
125
126template <typename L>
129 bool res = true;
131
132 explicit Expression(L&& in) : lhs(static_cast<L&&>(in)) { res = details::getBool(lhs); }
133 explicit Expression(L&& in, bool res, zeroerr::String&& decomp)
134 : lhs(static_cast<L&&>(in)), res(res), decomp(static_cast<zeroerr::String&&>(decomp)) {}
135
136 operator ExprResult() {
137 if (decomp.empty()) {
138 decomp = detail::valueText(detail::makeDiagnosticValue(lhs));
139 }
140 return ExprResult(res, decomp);
141 }
142
143 operator L() const { return lhs; }
144
151
154
171};
172
173#undef ZEROERR_EXPRESSION_COMPARISON
174#undef ZEROERR_EXPRESSION_ANDOR
175#undef ZEROERR_FORBIT_EXPRESSION
176
178 // The right operator for capturing expressions is "<=" instead of "<<" (based on the
179 // operator precedence table) but then there will be warnings from GCC about "-Wparentheses"
180 // and since "_Pragma()" is problematic this will stay for now...
181 // https://github.com/catchorg/Catch2/issues/870
182 // https://github.com/catchorg/Catch2/issues/565
183
184 // For temporary objects, we need to use rvalue reference to avoid copy
185 template <typename L>
186 Expression<L> operator<<(L&& operand) {
187 return Expression<L>(static_cast<L&&>(operand));
188 }
189
190 // For other objects, we will store the reference
191 template <typename L,
192 typename std::enable_if<!std::is_rvalue_reference<L>::value, void>::type* = nullptr>
193 Expression<const L&> operator<<(const L& operand) {
194 return Expression<const L&>(operand);
195 }
196};
197
198
199template <typename T>
200class IMatcher {
201public:
202 virtual ~IMatcher() = default;
203
204
205 virtual bool match(const T&) const = 0;
206};
207
208template <typename T>
210public:
211 IMatcherRef(const IMatcher<T>* ptr) : p(ptr) {}
212 IMatcherRef(const IMatcherRef&) = delete;
213
215 p = std::move(other.p);
216 other.p = nullptr;
217 }
218 void operator=(IMatcherRef&& other) {
219 p = std::move(other.p);
220 other.p = nullptr;
221 }
224 if (p) delete p;
225 }
226
227 IMatcherRef operator&&(IMatcherRef&& other);
228 IMatcherRef operator||(IMatcherRef&& other);
229 IMatcherRef operator!();
230
231 const IMatcher<T>* operator->() const { return p; }
232
233protected:
234 const IMatcher<T>* p = nullptr;
235};
236
237
238template <typename T>
239class CombinedMatcher : public IMatcher<T> {
240public:
242 : lhs(std::move(lhs)), rhs(std::move(rhs)), is_and(is_and) {}
243
246 bool is_and;
247
248 virtual bool match(const T& t) const override {
249 if (is_and) {
250 return lhs->match(t) && rhs->match(t);
251 } else {
252 return lhs->match(t) || rhs->match(t);
253 }
254 }
255};
256
257template <typename T>
258class NotMatcher : public IMatcher<T> {
259public:
260 NotMatcher(IMatcherRef<T>&& matcher) : matcher(std::move(matcher)) {}
262
263 virtual bool match(const T& t) const override { return !matcher->match(t); }
264};
265
266template <typename T>
268 return new CombinedMatcher<T>(std::move(*this), std::move(other), true);
269}
270
271template <typename T>
273 return new CombinedMatcher<T>(std::move(*this), std::move(other), false);
274}
275
276template <typename T>
278 return new NotMatcher<T>(std::move(*this));
279}
280
281
282template <typename T>
283struct StartWithMatcher : public IMatcher<T> {
284 StartWithMatcher(const T& s) : start(s) {}
286
287 virtual bool match(const T& t) const override {
288 bool result = true;
289 for (auto i = start.begin(), j = t.begin(); i != start.end(); ++i, ++j) {
290 if (j == t.end() || *i != *j) {
291 result = false;
292 break;
293 }
294 }
295 return result;
296 }
297};
298
299template <typename T>
300typename std::enable_if<std::is_constructible<zeroerr::String, T>::value,
301 IMatcherRef<zeroerr::String>>::type
305
306} // namespace zeroerr
307
Definition decomposition.h:239
IMatcherRef< T > lhs
Definition decomposition.h:244
IMatcherRef< T > rhs
Definition decomposition.h:245
virtual bool match(const T &t) const override
Definition decomposition.h:248
bool is_and
Definition decomposition.h:246
CombinedMatcher(IMatcherRef< T > &&lhs, IMatcherRef< T > &&rhs, bool is_and)
Definition decomposition.h:241
Definition decomposition.h:209
IMatcherRef(IMatcherRef &&other)
Definition decomposition.h:214
IMatcherRef(const IMatcher< T > *ptr)
Definition decomposition.h:211
void operator=(IMatcherRef &&other)
Definition decomposition.h:218
IMatcherRef(const IMatcherRef &)=delete
IMatcherRef & operator=(const IMatcherRef &)=delete
const IMatcher< T > * operator->() const
Definition decomposition.h:231
~IMatcherRef()
Definition decomposition.h:223
Definition decomposition.h:200
virtual bool match(const T &) const =0
virtual ~IMatcher()=default
Definition decomposition.h:258
IMatcherRef< T > matcher
Definition decomposition.h:261
NotMatcher(IMatcherRef< T > &&matcher)
Definition decomposition.h:260
virtual bool match(const T &t) const override
Definition decomposition.h:263
Definition string.h:41
bool empty() const noexcept
Definition string.h:80
#define ZEROERR_SUPPRESS_COMPARE
Definition config.h:318
#define ZEROERR_SUPPRESS_COMMON_WARNINGS_POP
Definition config.h:283
#define ZEROERR_SUPPRESS_COMPARE_POP
Definition config.h:331
#define ZEROERR_SUPPRESS_COMMON_WARNINGS_PUSH
Definition config.h:235
#define ZEROERR_FORBIT_EXPRESSION(rt, op)
Definition decomposition.h:62
#define ZEROERR_EXPRESSION_ANDOR(op, op_name)
Definition decomposition.h:55
#define ZEROERR_EXPRESSION_COMPARISON(op, op_name)
Definition decomposition.h:36
STL namespace
std::enable_if< has_bool_conversion< T >::value, bool >::type getBool(T &&lhs)
Definition decomposition.h:116
Definition assert_text.cpp:5
std::enable_if< std::is_constructible< zeroerr::String, T >::value, IMatcherRef< zeroerr::String > >::type start_with(T &&s)
Definition decomposition.h:302
Definition decomposition.h:70
bool res
Definition decomposition.h:71
zeroerr::String decomp
Definition decomposition.h:72
ExprResult(bool res, zeroerr::String decomposition="")
Definition decomposition.h:74
Definition decomposition.h:177
Definition decomposition.h:127
zeroerr::String decomp
Definition decomposition.h:130
L lhs
Definition decomposition.h:128
Expression(L &&in)
Definition decomposition.h:132
Expression(L &&in, bool res, zeroerr::String &&decomp)
Definition decomposition.h:133
Definition decomposition.h:283
StartWithMatcher(const T &s)
Definition decomposition.h:284
virtual bool match(const T &t) const override
Definition decomposition.h:287
T start
Definition decomposition.h:285
Definition decomposition.h:32
static const bool value
Definition decomposition.h:33
Definition decomposition.h:107