Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | #pragma once |
19 | | |
20 | | #include <fmt/format.h> |
21 | | #include <glog/logging.h> |
22 | | |
23 | | #include <cstddef> |
24 | | #include <ios> |
25 | | #include <ostream> |
26 | | #include <sstream> |
27 | | #include <string> |
28 | | #include <string_view> |
29 | | #include <type_traits> |
30 | | #include <utility> |
31 | | |
32 | | namespace doris { |
33 | | |
34 | | [[noreturn]] void doris_check_fail(std::string_view message); |
35 | | |
36 | | namespace detail { |
37 | | template <typename T> |
38 | | concept OstreamPrintable = requires(std::ostream& os, const T& value) { os << value; }; |
39 | | |
40 | | class DorisCheckMessage { |
41 | | public: |
42 | 0 | explicit DorisCheckMessage(std::string_view message) { _stream << message; } |
43 | | |
44 | | template <typename T> |
45 | 0 | DorisCheckMessage& operator<<(const T& value) { |
46 | 0 | _stream << value; |
47 | 0 | return *this; |
48 | 0 | } Unexecuted instantiation: _ZN5doris6detail17DorisCheckMessagelsIA57_cEERS1_RKT_ Unexecuted instantiation: _ZN5doris6detail17DorisCheckMessagelsIA49_cEERS1_RKT_ Unexecuted instantiation: _ZN5doris6detail17DorisCheckMessagelsImEERS1_RKT_ |
49 | | |
50 | | DorisCheckMessage& operator<<(std::ostream& (*func)(std::ostream&)) { |
51 | | func(_stream); |
52 | | return *this; |
53 | | } |
54 | | |
55 | | DorisCheckMessage& operator<<(std::ios& (*func)(std::ios&)) { |
56 | | func(_stream); |
57 | | return *this; |
58 | | } |
59 | | |
60 | | DorisCheckMessage& operator<<(std::ios_base& (*func)(std::ios_base&)) { |
61 | | func(_stream); |
62 | | return *this; |
63 | | } |
64 | | |
65 | 0 | [[noreturn]] void fail() { doris_check_fail(_stream.str()); } |
66 | | |
67 | | private: |
68 | | std::ostringstream _stream; |
69 | | }; |
70 | | |
71 | | class DorisCheckMessageVoidify { |
72 | | public: |
73 | 0 | [[noreturn]] void operator&(DorisCheckMessage& message) const { message.fail(); } |
74 | 0 | [[noreturn]] void operator&(DorisCheckMessage&& message) const { message.fail(); } |
75 | | }; |
76 | | |
77 | | class DorisCheckResult { |
78 | | public: |
79 | | explicit DorisCheckResult(bool ok) : _ok(ok) {} |
80 | | explicit DorisCheckResult(std::string message) : _ok(false), _message(std::move(message)) {} |
81 | | |
82 | | bool ok() const { return _ok; } |
83 | | const std::string& message() const { return _message; } |
84 | | |
85 | | private: |
86 | | bool _ok; |
87 | | std::string _message; |
88 | | }; |
89 | | |
90 | | template <typename T> |
91 | | std::string doris_check_value_to_string(const T& value) { |
92 | | if constexpr (std::is_same_v<std::decay_t<T>, std::nullptr_t>) { |
93 | | return "nullptr"; |
94 | | } else if constexpr (std::is_same_v<std::decay_t<T>, bool>) { |
95 | | return value ? "true" : "false"; |
96 | | } else if constexpr (OstreamPrintable<T>) { |
97 | | std::ostringstream oss; |
98 | | oss << std::boolalpha << value; |
99 | | return oss.str(); |
100 | | } else { |
101 | | return "<unprintable>"; |
102 | | } |
103 | | } |
104 | | |
105 | | template <typename Lhs, typename Rhs, typename Comparator> |
106 | | DorisCheckResult doris_check_binary_op_result(const Lhs& lhs, const Rhs& rhs, |
107 | | std::string_view lhs_expr, std::string_view rhs_expr, |
108 | | std::string_view op_expr, Comparator comparator) { |
109 | | if (static_cast<bool>(comparator(lhs, rhs))) { |
110 | | return DorisCheckResult(true); |
111 | | } |
112 | | return DorisCheckResult(fmt::format("Check failed: {} {} {} ({} vs {})", lhs_expr, op_expr, |
113 | | rhs_expr, doris_check_value_to_string(lhs), |
114 | | doris_check_value_to_string(rhs))); |
115 | | } |
116 | | } // namespace detail |
117 | | |
118 | | } // namespace doris |
119 | | |
120 | | // core in Debug mode, exception in Release mode. |
121 | | #define DORIS_CHECK(stmt) \ |
122 | 40.0M | if (bool _doris_check_ok = static_cast<bool>(stmt); _doris_check_ok) { \ |
123 | 18.4E | } else [[unlikely]] \ |
124 | 18.4E | ::doris::detail::DorisCheckMessageVoidify() & \ |
125 | 18.4E | ::doris::detail::DorisCheckMessage("Check failed: " #stmt) |
126 | | |
127 | | // Use DORIS_CHECK_* only for invariants that must also be checked in Release builds. |
128 | | // Keep DCHECK_* in loops or other hot paths where Release checks would add overhead. |
129 | | #ifndef NDEBUG |
130 | 1.32k | #define DORIS_CHECK_EQ(val1, val2) DCHECK_EQ(val1, val2) |
131 | | #define DORIS_CHECK_NE(val1, val2) DCHECK_NE(val1, val2) |
132 | | #define DORIS_CHECK_LT(val1, val2) DCHECK_LT(val1, val2) |
133 | | #define DORIS_CHECK_LE(val1, val2) DCHECK_LE(val1, val2) |
134 | | #define DORIS_CHECK_GT(val1, val2) DCHECK_GT(val1, val2) |
135 | 13.6k | #define DORIS_CHECK_GE(val1, val2) DCHECK_GE(val1, val2) |
136 | | #else |
137 | | #define DORIS_CHECK_BINARY_OP(val1, val2, op, op_str) \ |
138 | | if (auto _doris_check_result = ::doris::detail::doris_check_binary_op_result( \ |
139 | | (val1), (val2), #val1, #val2, op_str, \ |
140 | | [](const auto& _doris_check_lhs, const auto& _doris_check_rhs) { \ |
141 | | return _doris_check_lhs op _doris_check_rhs; \ |
142 | | }); \ |
143 | | _doris_check_result.ok()) { \ |
144 | | } else [[unlikely]] \ |
145 | | ::doris::detail::DorisCheckMessageVoidify() & \ |
146 | | ::doris::detail::DorisCheckMessage(_doris_check_result.message()) |
147 | | |
148 | | #define DORIS_CHECK_EQ(val1, val2) DORIS_CHECK_BINARY_OP(val1, val2, ==, "==") |
149 | | #define DORIS_CHECK_NE(val1, val2) DORIS_CHECK_BINARY_OP(val1, val2, !=, "!=") |
150 | | #define DORIS_CHECK_LT(val1, val2) DORIS_CHECK_BINARY_OP(val1, val2, <, "<") |
151 | | #define DORIS_CHECK_LE(val1, val2) DORIS_CHECK_BINARY_OP(val1, val2, <=, "<=") |
152 | | #define DORIS_CHECK_GT(val1, val2) DORIS_CHECK_BINARY_OP(val1, val2, >, ">") |
153 | | #define DORIS_CHECK_GE(val1, val2) DORIS_CHECK_BINARY_OP(val1, val2, >=, ">=") |
154 | | #endif |