Coverage Report

Created: 2026-05-31 02:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/common/check.h
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
44.7M
    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