1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #pragma once
32 
33 #include <boost/preprocessor/facilities/overload.hpp>
34 #include <string>
35 
36 #include "mongo/platform/compiler.h"
37 #include "mongo/util/debug_util.h"
38 
39 namespace mongo {
40 
41 /**
42  * This include exists so that mongo/base/status_with.h can use the invariant macro without causing
43  * a circular include chain. It should never be included directly in any other file other than that
44  * one (and assert_util.h).
45  */
46 
47 #if !defined(MONGO_INCLUDE_INVARIANT_H_WHITELISTED)
48 #error "Include assert_util.h instead of invariant.h."
49 #endif
50 
51 MONGO_COMPILER_NORETURN void invariantFailed(const char* expr,
52                                              const char* file,
53                                              unsigned line) noexcept;
54 
55 // This overload is our legacy invariant, which just takes a condition to test.
56 //
57 // ex)   invariant(!condition);
58 //
59 //       Invariant failure !condition some/file.cpp 528
60 //
61 #define MONGO_invariant_1(_Expression)                                  \
62     do {                                                                \
63         if (MONGO_unlikely(!(_Expression))) {                           \
64             ::mongo::invariantFailed(#_Expression, __FILE__, __LINE__); \
65         }                                                               \
66     } while (false)
67 
68 MONGO_COMPILER_NORETURN void invariantFailedWithMsg(const char* expr,
69                                                     const char* msg,
70                                                     const char* file,
71                                                     unsigned line) noexcept;
72 
73 MONGO_COMPILER_NORETURN void invariantFailedWithMsg(const char* expr,
74                                                     const std::string& msg,
75                                                     const char* file,
76                                                     unsigned line) noexcept;
77 
78 // This invariant overload accepts a condition and a message, to be logged if the condition is
79 // false.
80 //
81 // ex)   invariant(!condition, "hello!");
82 //
83 //       Invariant failure !condition "hello!" some/file.cpp 528
84 //
85 #define MONGO_invariant_2(_Expression, _Message)                                           \
86     do {                                                                                   \
87         if (MONGO_unlikely(!(_Expression))) {                                              \
88             ::mongo::invariantFailedWithMsg(#_Expression, (_Message), __FILE__, __LINE__); \
89         }                                                                                  \
90     } while (false)
91 
92 // This helper macro is necessary to make the __VAR_ARGS__ expansion work properly on MSVC.
93 #define MONGO_expand(x) x
94 
95 #define invariant(...) \
96     MONGO_expand(MONGO_expand(BOOST_PP_OVERLOAD(MONGO_invariant_, __VA_ARGS__))(__VA_ARGS__))
97 
98 // Behaves like invariant in debug builds and is compiled out in release. Use for checks, which can
99 // potentially be slow or on a critical path.
100 #define MONGO_dassert(...) \
101     if (kDebugBuild)       \
102     invariant(__VA_ARGS__)
103 
104 #define dassert MONGO_dassert
105 
106 }  // namespace mongo
107