16 template<
class operation_t>
22 static constexpr string_view symbol() noexcept
31 static constexpr string_view symbol() noexcept
40 static constexpr string_view symbol() noexcept
49 static constexpr string_view symbol() noexcept
58 static constexpr string_view symbol() noexcept
67 static constexpr string_view symbol() noexcept
73 constexpr string_view trim_assert_expression(string_view svExpression) noexcept
75 while (!svExpression.empty()
76 && (svExpression.front() == QXT(
' ') || svExpression.front() == QXT(
'\t')
77 || svExpression.front() == QXT(
'\r') || svExpression.front() == QXT(
'\n')))
79 svExpression.remove_prefix(1);
82 while (!svExpression.empty()
83 && (svExpression.back() == QXT(
' ') || svExpression.back() == QXT(
'\t') || svExpression.back() == QXT(
'\r')
84 || svExpression.back() == QXT(
'\n')))
86 svExpression.remove_suffix(1);
92 constexpr
bool is_space(char_type ch) noexcept
94 return ch == QXT(
' ') || ch == QXT(
'\t') || ch == QXT(
'\r') || ch == QXT(
'\n');
97 constexpr
bool is_char(char_type ch) noexcept
99 return ch == QXT(
'_') || ch >= QXT(
'0') && ch <= QXT(
'9') || ch >= QXT(
'a') && ch <= QXT(
'z')
100 || ch >= QXT(
'A') && ch <= QXT(
'Z');
103 constexpr
bool is_identifier_first_char(char_type ch) noexcept
105 return ch == QXT(
'_') || ch >= QXT(
'a') && ch <= QXT(
'z') || ch >= QXT(
'A') && ch <= QXT(
'Z');
108 constexpr
bool is_literal(string_view svExpression) noexcept
110 if (svExpression.empty())
113 if (svExpression == QXT(
"true") || svExpression == QXT(
"false") || svExpression == QXT(
"nullptr"))
116 const char_type chFirst = svExpression.front();
117 if (chFirst == QXT(
'"') || chFirst == QXT(
'\''))
120 if (chFirst >= QXT(
'0') && chFirst <= QXT(
'9'))
123 return (chFirst == QXT(
'+') || chFirst == QXT(
'-')) && svExpression.size() > 1 && svExpression[1] >= QXT(
'0')
124 && svExpression[1] <= QXT(
'9');
127 constexpr
bool is_temporary_value(string_view svExpression) noexcept
129 if (svExpression.starts_with(QXT(
"static_cast<")) || svExpression.starts_with(QXT(
"const_cast<"))
130 || svExpression.starts_with(QXT(
"dynamic_cast<")) || svExpression.starts_with(QXT(
"reinterpret_cast<")))
135 bool bQualified =
false;
137 while (nPos < svExpression.size() && is_char(svExpression[nPos]))
140 while (nPos + 1 < svExpression.size() && svExpression[nPos] == QXT(
':') && svExpression[nPos + 1] == QXT(
':'))
144 while (nPos < svExpression.size() && is_char(svExpression[nPos]))
148 if (nPos < svExpression.size() && svExpression[nPos] == QXT(
'<'))
153 while (nPos < svExpression.size() && nAngleDepth > 0)
155 if (svExpression[nPos] == QXT(
'<'))
157 else if (svExpression[nPos] == QXT(
'>'))
164 return bQualified && nPos < svExpression.size() && svExpression[nPos] == QXT(
'(');
167 constexpr
bool is_qualified_value(string_view svExpression) noexcept
170 if (svExpression.size() > 1 && svExpression[0] == QXT(
':') && svExpression[1] == QXT(
':'))
173 bool bQualified = nPos != 0;
174 while (nPos < svExpression.size())
176 if (!is_identifier_first_char(svExpression[nPos]))
179 while (nPos < svExpression.size() && is_char(svExpression[nPos]))
182 if (nPos < svExpression.size() && svExpression[nPos] == QXT(
'<'))
187 while (nPos < svExpression.size() && nAngleDepth > 0)
189 if (svExpression[nPos] == QXT(
'<'))
191 else if (svExpression[nPos] == QXT(
'>'))
197 if (nAngleDepth != 0)
201 if (nPos == svExpression.size())
204 if (nPos + 1 >= svExpression.size() || svExpression[nPos] != QXT(
':') || svExpression[nPos + 1] != QXT(
':'))
216 constexpr
bool should_show_assert_expression_for_rvalue(string_view svExpression) noexcept
218 return !is_literal(svExpression) && !is_temporary_value(svExpression) && !is_qualified_value(svExpression);
221 constexpr
bool is_identifier_open_angle_char(char_type ch) noexcept
223 return ch == QXT(
'_') || ch >= QXT(
'a') && ch <= QXT(
'z') || ch >= QXT(
'A') && ch <= QXT(
'Z');
226 constexpr
bool is_open_angle(string_view svExpression,
size_t nPos) noexcept
231 const char_type chPrev = svExpression[nPos - 1];
232 return is_identifier_open_angle_char(chPrev) || chPrev == QXT(
':') || chPrev == QXT(
'>') || chPrev == QXT(
'&')
233 || chPrev == QXT(
'*');
236 constexpr
bool is_close_angle(string_view svExpression,
size_t nPos) noexcept
238 if (nPos + 1 >= svExpression.size())
241 const char_type chNext = svExpression[nPos + 1];
242 return is_space(chNext) || chNext == QXT(
'(') || chNext == QXT(
')') || chNext == QXT(
',') || chNext == QXT(
':')
243 || chNext == QXT(
'&') || chNext == QXT(
'*') || chNext == QXT(
'>') || chNext == QXT(
'{')
244 || chNext == QXT(
'.');
247 constexpr std::pair<string_view, string_view> split_assert_arguments(string_view svCondition) noexcept
249 const size_t nArgsBegin = svCondition.find(QXT(
'('));
250 if (nArgsBegin == string_view::npos)
254 i32 nBracketDepth = 0;
257 size_t nCommaPos = string_view::npos;
258 size_t nArgsEnd = string_view::npos;
259 bool bInString =
false;
260 bool bInChar =
false;
261 bool bEscaped =
false;
263 for (
size_t nPos = nArgsBegin + 1; nPos < svCondition.size(); ++nPos)
265 if (bInString || bInChar)
271 else if (svCondition[nPos] == QXT(
'\\'))
275 else if (bInString && svCondition[nPos] == QXT(
'"'))
279 else if (bInChar && svCondition[nPos] == QXT(
'\''))
287 switch (svCondition[nPos])
302 if (nParenDepth == 0 && nBracketDepth == 0 && nBraceDepth == 0 && nAngleDepth == 0)
305 nPos = svCondition.size();
330 if (is_open_angle(svCondition, nPos))
335 if (nAngleDepth > 0 && is_close_angle(svCondition, nPos))
340 if (nParenDepth == 0 && nBracketDepth == 0 && nBraceDepth == 0 && nAngleDepth == 0
341 && nCommaPos == string_view::npos)
347 if (nCommaPos == string_view::npos || nArgsEnd == string_view::npos)
350 return { trim_assert_expression(svCondition.substr(nArgsBegin + 1, nCommaPos - nArgsBegin - 1)),
351 trim_assert_expression(svCondition.substr(nCommaPos + 1, nArgsEnd - nCommaPos - 1)) };
355 inline string assert_value_to_string(
const T& value) noexcept
357 if constexpr (std::is_convertible_v<const T&, string_view>)
358 return string(value);
363 inline void append_assert_expression(
string& sResult, string_view svExpression) noexcept
365 bool bPreviousWasSpace =
false;
367 for (
const char_type ch : svExpression)
371 bPreviousWasSpace = !sResult.empty();
375 if (bPreviousWasSpace)
377 sResult.append(QXT(
' '));
378 bPreviousWasSpace =
false;
386 template<
bool bCanHaveName,
class T>
387 inline string make_assert_operand_string(string_view svExpression,
const T& value) noexcept
389 if constexpr (bCanHaveName)
392 append_assert_expression(sResult, svExpression);
393 sResult.append(QXT(
" ["));
394 sResult.append(assert_value_to_string(value));
395 sResult.append(QXT(
"]"));
400 return assert_value_to_string(value);
404 template<
string_literal svCondition,
class condition_t>
405 constexpr string_view get_assert_condition_string(
const condition_t&) noexcept
407 return svCondition.view();
411 string_literal svCondition,
417 inline string get_assert_condition_string(
418 const assert_comparison<left_t, right_t, operation_t, bLeftIsLvalue, bRightIsLvalue>& condition) noexcept
420 constexpr
auto split = split_assert_arguments(svCondition.view());
421 constexpr
auto svLeftExpression = split.first;
422 constexpr
auto svRightExpression = split.second;
426 make_assert_operand_string < bLeftIsLvalue
427 || should_show_assert_expression_for_rvalue(svLeftExpression) > (svLeftExpression, condition.left()),
428 assert_operation_symbol<operation_t>::symbol(),
429 make_assert_operand_string < bRightIsLvalue
430 || should_show_assert_expression_for_rvalue(svRightExpression) > (svRightExpression, condition.right()));
433 template<
class left_t,
class right_t,
class operation_t,
bool bLeftIsLvalue,
bool bRightIsLvalue>
436 std::is_nothrow_constructible_v<left_t, left_t&&> && std::is_nothrow_constructible_v<right_t, right_t&&>)
437 : m_Left(std::forward<left_t>(left))
438 , m_Right(std::forward<right_t>(right))
442 template<
class left_t,
class right_t,
class operation_t,
bool bLeftIsLvalue,
bool bRightIsLvalue>
444 noexcept(noexcept(operation_t {}(left(), right())))
446 return operation_t {}(left(), right());
449 template<
class left_t,
class right_t,
class operation_t,
bool bLeftIsLvalue,
bool bRightIsLvalue>
451 noexcept(noexcept(result()))
456 template<
class left_t,
class right_t,
class operation_t,
bool bLeftIsLvalue,
bool bRightIsLvalue>
463 template<
class left_t,
class right_t,
class operation_t,
bool bLeftIsLvalue,
bool bRightIsLvalue>
472 template<
class left_t,
class right_t,
class operation_t,
bool bLeftIsLvalue,
bool bRightIsLvalue>
473 constexpr
bool predicates::
474 validator<details::assert_comparison<left_t, right_t, operation_t, bLeftIsLvalue, bRightIsLvalue>>::is_valid(
476 value) noexcept(noexcept(value.result()))
478 return value.result();
481 template<
class left_t,
class right_t>
482 constexpr
auto assert_eq(left_t&& left, right_t&& right) noexcept(
487 std::is_lvalue_reference_v<left_t>,
488 std::is_lvalue_reference_v<right_t>>(std::forward<left_t>(left), std::forward<right_t>(right))))
494 std::is_lvalue_reference_v<left_t>,
495 std::is_lvalue_reference_v<right_t>>(std::forward<left_t>(left), std::forward<right_t>(right));
498 template<
class left_t,
class right_t>
499 constexpr
auto assert_ne(left_t&& left, right_t&& right) noexcept(
504 std::is_lvalue_reference_v<left_t>,
505 std::is_lvalue_reference_v<right_t>>(std::forward<left_t>(left), std::forward<right_t>(right))))
511 std::is_lvalue_reference_v<left_t>,
512 std::is_lvalue_reference_v<right_t>>(std::forward<left_t>(left), std::forward<right_t>(right));
515 template<
class left_t,
class right_t>
516 constexpr
auto assert_lt(left_t&& left, right_t&& right) noexcept(
521 std::is_lvalue_reference_v<left_t>,
522 std::is_lvalue_reference_v<right_t>>(std::forward<left_t>(left), std::forward<right_t>(right))))
528 std::is_lvalue_reference_v<left_t>,
529 std::is_lvalue_reference_v<right_t>>(std::forward<left_t>(left), std::forward<right_t>(right));
532 template<
class left_t,
class right_t>
533 constexpr
auto assert_le(left_t&& left, right_t&& right) noexcept(
538 std::is_lvalue_reference_v<left_t>,
539 std::is_lvalue_reference_v<right_t>>(std::forward<left_t>(left), std::forward<right_t>(right))))
545 std::is_lvalue_reference_v<left_t>,
546 std::is_lvalue_reference_v<right_t>>(std::forward<left_t>(left), std::forward<right_t>(right));
549 template<
class left_t,
class right_t>
550 constexpr
auto assert_gt(left_t&& left, right_t&& right) noexcept(
555 std::is_lvalue_reference_v<left_t>,
556 std::is_lvalue_reference_v<right_t>>(std::forward<left_t>(left), std::forward<right_t>(right))))
562 std::is_lvalue_reference_v<left_t>,
563 std::is_lvalue_reference_v<right_t>>(std::forward<left_t>(left), std::forward<right_t>(right));
566 template<
class left_t,
class right_t>
567 constexpr
auto assert_ge(left_t&& left, right_t&& right) noexcept(
571 std::greater_equal<>,
572 std::is_lvalue_reference_v<left_t>,
573 std::is_lvalue_reference_v<right_t>>(std::forward<left_t>(left), std::forward<right_t>(right))))
578 std::greater_equal<>,
579 std::is_lvalue_reference_v<left_t>,
580 std::is_lvalue_reference_v<right_t>>(std::forward<left_t>(left), std::forward<right_t>(right));
constexpr auto assert_ge(left_t &&left, right_t &&right) noexcept(noexcept(details::assert_comparison< left_t, right_t, std::greater_equal<>, std::is_lvalue_reference_v< left_t >, std::is_lvalue_reference_v< right_t >>(std::forward< left_t >(left), std::forward< right_t >(right))))
Compare whether left value is greater than or equal to right value and preserve values for assertion ...
constexpr auto assert_le(left_t &&left, right_t &&right) noexcept(noexcept(details::assert_comparison< left_t, right_t, std::less_equal<>, std::is_lvalue_reference_v< left_t >, std::is_lvalue_reference_v< right_t >>(std::forward< left_t >(left), std::forward< right_t >(right))))
Compare whether left value is less than or equal to right value and preserve values for assertion dia...
constexpr auto assert_gt(left_t &&left, right_t &&right) noexcept(noexcept(details::assert_comparison< left_t, right_t, std::greater<>, std::is_lvalue_reference_v< left_t >, std::is_lvalue_reference_v< right_t >>(std::forward< left_t >(left), std::forward< right_t >(right))))
Compare whether left value is greater than right value and preserve values for assertion diagnostics.
constexpr auto assert_lt(left_t &&left, right_t &&right) noexcept(noexcept(details::assert_comparison< left_t, right_t, std::less<>, std::is_lvalue_reference_v< left_t >, std::is_lvalue_reference_v< right_t >>(std::forward< left_t >(left), std::forward< right_t >(right))))
Compare whether left value is less than right value and preserve values for assertion diagnostics.
constexpr auto assert_ne(left_t &&left, right_t &&right) noexcept(noexcept(details::assert_comparison< left_t, right_t, std::not_equal_to<>, std::is_lvalue_reference_v< left_t >, std::is_lvalue_reference_v< right_t >>(std::forward< left_t >(left), std::forward< right_t >(right))))
Compare two values for inequality and preserve values for assertion diagnostics.
constexpr auto assert_eq(left_t &&left, right_t &&right) noexcept(noexcept(details::assert_comparison< left_t, right_t, std::equal_to<>, std::is_lvalue_reference_v< left_t >, std::is_lvalue_reference_v< right_t >>(std::forward< left_t >(left), std::forward< right_t >(right))))
Compare two values for equality and preserve values for assertion diagnostics.
Lightweight assertion comparison object that preserves compared operand values for diagnostics.
constexpr const auto & left() const noexcept
Get left operand.
constexpr const auto & right() const noexcept
Get right operand.
constexpr bool result() const noexcept(noexcept(operation_t {}(left(), right())))
Evaluate comparison.
constexpr assert_comparison(left_t &&left, right_t &&right) noexcept(std::is_nothrow_constructible_v< left_t, left_t && > &&std::is_nothrow_constructible_v< right_t, right_t && >)
Construct comparison object from two operands.
std::int32_t i32
− 9 223 372 036 854 775 808 .. 9 223 372 036 854 775 807