summaryrefslogtreecommitdiff
path: root/boost/contract/check.hpp
blob: e7423ce9a8f2b72615f22e7b59d11f46c79c65b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347

#ifndef BOOST_CONTRACT_CHECK_HPP_
#define BOOST_CONTRACT_CHECK_HPP_

// Copyright (C) 2008-2018 Lorenzo Caminiti
// Distributed under the Boost Software License, Version 1.0 (see accompanying
// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html

/** @file
RAII object that checks contracts.
*/

#include <boost/contract/core/config.hpp>
#include <boost/contract/core/check_macro.hpp>
#include <boost/contract/core/specify.hpp>
#include <boost/contract/core/exception.hpp> // For set_... (if always in code).
#if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \
        defined(BOOST_CONTRACT_STATIC_LINK)
    #include <boost/contract/detail/condition/cond_base.hpp>
    #include <boost/contract/detail/auto_ptr.hpp>
    #include <boost/contract/detail/debug.hpp>
#endif
#include <boost/contract/detail/check.hpp>
#include <boost/config.hpp>

/* PRIVATE */

/** @cond */

#if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \
        defined(BOOST_CONTRACT_STATIC_LINK)
    #define BOOST_CONTRACT_CHECK_CTOR_DEF_(contract_type) \
        : cond_(const_cast<contract_type&>(contract).cond_.release()) \
        { \
            BOOST_CONTRACT_DETAIL_DEBUG(cond_); \
            cond_->initialize(); \
        }
#else
    #define BOOST_CONTRACT_CHECK_CTOR_DEF_(contract_type) {}
#endif

/** @endcond */

/* CODE */

namespace boost { namespace contract {

/**
RAII object that checks the contracts.

In general, when this object is constructed it checks class invariants at entry,
preconditions, and makes old value copies at body.
When it is destructed, it checks class invariants at exist, postconditions, and
exception guarantees.
This object enforces the following (see
@RefSect{contract_programming_overview, Contract Programming Overview}):

@li Postconditions are checked only if the body does not throw an exception.
@li Exceptions guarantees are checked only if the body throws an exception.
@li Constructor entry never checks class invariants.
@li Destructor exit checks class invariants only if the body throws an
exception (even if destructors should usually not be programmed to throw
exceptions in C++).
@li Static invariants are always checked at entry and exit (and regardless of
the body throwing exceptions or not).

When used this way, this object is usually constructed and initialized to the
return value of one of the contract functions
@RefFunc{boost::contract::function}, @RefFunc{boost::contract::constructor},
@RefFunc{boost::contract::destructor}, or
@RefFunc{boost::contract::public_function}.
In addition, this object can be constructed from a nullary functor that is used
to program implementation checks.

@see    @RefSect{tutorial, Tutorial},
        @RefSect{advanced.implementation_checks, Implementation Checks}
*/
class check { // Copy ctor only (as move via ptr release).
public:
    // NOTE: Unfortunately, Apple compilers define a `check(...)` macro that
    // clashes with the name of this class. In the following code,
    // BOOST_PREVENT_MACRO_SUBSTITUTION is used to workaround these name
    // clashes. In user code, `check c = ...` syntax is typically used also
    // avoiding clashes.

    /**
    Construct this object for implementation checks.

    This can be used to program checks within implementation code (body, etc.).
    This constructor is not declared @c explicit so initializations can use
    assignment syntax @c =.
    
    @b Throws:  This can throw in case programmers specify contract failure
                handlers that throw exceptions instead of terminating the
                program (see
                @RefSect{advanced.throw_on_failures__and__noexcept__,
                Throw on Failure}).

    @param f    Nullary functor that asserts implementation checks. @c f() will
                be called as soon as this object is constructed at the point it
                is declared within the implementation code (see
                @RefSect{advanced.implementation_checks,
                Implementation Checks}).
    */
    template<typename F> // Cannot check `if(f) ...` as f can be a lambda.
    // f must be a valid callable object (not null func ptr, empty ftor, etc.
    /* implicit */ check
    /** @cond **/ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ (
            F const& f) {
        BOOST_CONTRACT_DETAIL_CHECK({ f(); })
    }

    /**
    Construct this object copying it from the specified one.

    This object will check the contract, the copied-from object will not (i.e.,
    contract check ownership is transferred from the copied object to the new
    object being created by this constructor).

    @param other    Copied-from object.
    */
    check /** @cond **/ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ (
            check const& other)
        #if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \
                defined(BOOST_CONTRACT_STATIC_LINK)
            // Copy ctor moves cond_ pointer to dest.
            : cond_(const_cast<check&>(other).cond_.release())
        #endif
    {}

    /**
    Construct this object to check the specified contract.

    This checks class invariants at entry (if those apply to the specified
    contract).
    This constructor is not declared @c explicit so initializations can use
    assignment syntax @c =.
    
    @b Throws:  This can throw in case programmers specify contract failure
                handlers that throw exceptions instead of terminating the
                program (see
                @RefSect{advanced.throw_on_failures__and__noexcept__,
                Throw on Failure}).

    @param contract Contract to be checked (usually the return value of
                    @RefFunc{boost::contract::function} or
                    @RefFunc{boost::contract::public_function}).

    @tparam VirtualResult   Return type of the enclosing function declaring the
                            contract if that is either a virtual or an
                            overriding public function.
                            Otherwise, this is always @c void.
    */
    template<typename VirtualResult>
    /* implicit */ check
    /** @cond */ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ (
        specify_precondition_old_postcondition_except<VirtualResult> const&
                contract
    )
    #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
        BOOST_CONTRACT_CHECK_CTOR_DEF_(
                specify_precondition_old_postcondition_except<VirtualResult>)
    #else
        ;
    #endif
    
    /**
    Construct this object to check the specified contract.

    This checks class invariants at entry and preconditions (if any of those
    apply to the specified contract).
    This constructor is not declared @c explicit so initializations can use
    assignment syntax @c =.
    
    @b Throws:  This can throw in case programmers specify contract failure
                handlers that throw exceptions instead of terminating the
                program (see
                @RefSect{advanced.throw_on_failures__and__noexcept__,
                Throw on Failure}).

    @param contract Contract to be checked (usually the return value of
                    @RefFunc{boost::contract::function},
                    @RefFunc{boost::contract::constructor},
                    @RefFunc{boost::contract::destructor}, or
                    @RefFunc{boost::contract::public_function}).

    @tparam VirtualResult   Return type of the enclosing function declaring the
                            contract if that is either a virtual or an
                            overriding public function.
                            Otherwise, this is always @c void.
    */
    template<typename VirtualResult>
    /* implicit */ check
    /** @cond */ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ (
            specify_old_postcondition_except<VirtualResult> const& contract)
    #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
        BOOST_CONTRACT_CHECK_CTOR_DEF_(
                specify_old_postcondition_except<VirtualResult>)
    #else
        ;
    #endif
    
    /**
    Construct this object to check the specified contract.

    This checks class invariants at entry and preconditions then it makes old
    value copies at body (if any of those apply to the specified contract).
    This constructor is not declared @c explicit so initializations can use
    assignment syntax @c =.
    
    @b Throws:  This can throw in case programmers specify contract failure
                handlers that throw exceptions instead of terminating te
                program (see
                @RefSect{advanced.throw_on_failures__and__noexcept__,
                Throw on Failure}).

    @param contract Contract to be checked (usually the return value of
                    @RefFunc{boost::contract::function},
                    @RefFunc{boost::contract::constructor},
                    @RefFunc{boost::contract::destructor}, or
                    @RefFunc{boost::contract::public_function}).

    @tparam VirtualResult   Return type of the enclosing function declaring the
                            contract if that is either a virtual or an
                            overriding public function.
                            Otherwise, this is always @c void.
    */
    template<typename VirtualResult>
    /* implicit */ check
    /** @cond */ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ (
            specify_postcondition_except<VirtualResult> const& contract)
    #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
        BOOST_CONTRACT_CHECK_CTOR_DEF_(
                specify_postcondition_except<VirtualResult>)
    #else
        ;
    #endif
    
    /**
    Construct this object to check the specified contract.

    This checks class invariants at entry and preconditions then it makes old
    value copies at body, plus the destructor of this object will check
    postconditions in this case (if any of those apply to the specified
    contract).
    This constructor is not declared @c explicit so initializations can use
    assignment syntax @c =.
    
    @b Throws:  This can throw in case programmers specify contract failure
                handlers that throw exceptions instead of terminating the
                program (see
                @RefSect{advanced.throw_on_failures__and__noexcept__,
                Throw on Failure}).

    @param contract Contract to be checked (usually the return value of
                    @RefFunc{boost::contract::function},
                    @RefFunc{boost::contract::constructor},
                    @RefFunc{boost::contract::destructor}, or
                    @RefFunc{boost::contract::public_function}).

    @tparam VirtualResult   Return type of the enclosing function declaring the
                            contract if that is either a virtual or an
                            overriding public function.
                            Otherwise, this is always @c void.
    */
    /* implicit */ check
    /** @cond */ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ (
            specify_except const& contract)
    #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
        BOOST_CONTRACT_CHECK_CTOR_DEF_(specify_except)
    #else
        ;
    #endif
    
    /**
    Construct this object to check the specified contract.

    This checks class invariants at entry and preconditions then it makes old
    value copies at body, plus the destructor of this object will check
    postconditions and exception guarantees in this case (if any of those apply
    to the specified contract).
    This constructor is not declared @c explicit so initializations can use
    assignment syntax @c =.
    
    @b Throws:  This can throw in case programmers specify contract failure
                handlers that throw exceptions instead of terminating the
                program (see
                @RefSect{advanced.throw_on_failures__and__noexcept__,
                Throw on Failure}).

    @param contract Contract to be checked (usually the return value of
                    @RefFunc{boost::contract::function},
                    @RefFunc{boost::contract::constructor},
                    @RefFunc{boost::contract::destructor}, or
                    @RefFunc{boost::contract::public_function}).

    @tparam VirtualResult   Return type of the enclosing function declaring the
                            contract if that is either a virtual or an
                            overriding public function.
                            Otherwise, this is always @c void.
    */
    /* implicit */ check
    /** @cond */ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ (
            specify_nothing const& contract)
    #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
        BOOST_CONTRACT_CHECK_CTOR_DEF_(specify_nothing)
    #else
        ;
    #endif

    /**
    Destruct this object.

    This checks class invariants at exit and either postconditions when the
    enclosing function body did not throw an exception, or exception guarantees
    when the function body threw an exception (that is if class invariants,
    postconditions, and exception guarantees respectively apply to the contract
    parameter specified when constructing this object).

    @b Throws:  This can throw in case programmers specify contract failure
                handlers that throw exceptions instead of terminating the
                program (see
                @RefSect{advanced.throw_on_failures__and__noexcept__,
                Throw on Failure}).
                (This is declared @c noexcept(false) since C++11.)
    */
    ~check /** @cond */ BOOST_PREVENT_MACRO_SUBSTITUTION /** @endcond */ ()
        BOOST_NOEXCEPT_IF(false) /* allow auto_ptr dtor to throw */
    {}

/** @cond */
private:
    check& operator=(check const&); // Cannot copy outside of `check c = ...`.

    #if !defined(BOOST_CONTRACT_NO_CONDITIONS) || \
            defined(BOOST_CONTRACT_STATIC_LINK)
        boost::contract::detail::auto_ptr<boost::contract::detail::cond_base>
                cond_;
    #endif
/** @endcond */
};

} } // namespace

#endif // #include guard