]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/contract/detail/condition/cond_subcontracting.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / contract / detail / condition / cond_subcontracting.hpp
1
2 #ifndef BOOST_CONTRACT_DETAIL_COND_SUBCONTRACTING_HPP_
3 #define BOOST_CONTRACT_DETAIL_COND_SUBCONTRACTING_HPP_
4
5 // Copyright (C) 2008-2018 Lorenzo Caminiti
6 // Distributed under the Boost Software License, Version 1.0 (see accompanying
7 // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
8 // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
9
10 #include <boost/contract/core/config.hpp>
11 #if !defined(BOOST_CONTRACT_NO_PRECONDITIONS) || \
12 !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \
13 !defined(BOOST_CONTRACT_NO_EXCEPTS)
14 #include <boost/contract/core/exception.hpp>
15 #endif
16 #include <boost/contract/detail/condition/cond_inv.hpp>
17 #include <boost/contract/detail/decl.hpp>
18 #include <boost/contract/detail/tvariadic.hpp>
19 #ifndef BOOST_CONTRACT_NO_CONDITIONS
20 #include <boost/contract/core/virtual.hpp>
21 #include <boost/contract/core/access.hpp>
22 #include <boost/contract/detail/type_traits/optional.hpp>
23 #include <boost/contract/detail/type_traits/member_function_types.hpp>
24 #include <boost/contract/detail/debug.hpp>
25 #include <boost/contract/detail/none.hpp>
26 #include <boost/contract/detail/name.hpp>
27 #include <boost/type_traits/add_pointer.hpp>
28 #include <boost/mpl/fold.hpp>
29 #include <boost/mpl/contains.hpp>
30 #include <boost/mpl/empty.hpp>
31 #include <boost/mpl/push_back.hpp>
32 #include <boost/mpl/eval_if.hpp>
33 #include <boost/mpl/identity.hpp>
34 #include <boost/mpl/placeholders.hpp>
35 #ifndef BOOST_CONTRACT_PERMISSIVE
36 #include <boost/type_traits/is_same.hpp>
37 #include <boost/mpl/or.hpp>
38 #include <boost/mpl/not.hpp>
39 #include <boost/static_assert.hpp>
40 #endif
41 #include <boost/preprocessor/punctuation/comma_if.hpp>
42 #include <boost/config.hpp>
43 #endif
44 #include <boost/mpl/vector.hpp>
45 #if !defined(BOOST_CONTRACT_NO_INVARIANTS) || \
46 !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \
47 !defined(BOOST_CONTRACT_NO_EXCEPTS)
48 #include <boost/mpl/for_each.hpp>
49 #endif
50 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
51 #include <boost/mpl/pop_front.hpp>
52 #include <boost/mpl/front.hpp>
53 #endif
54 #if !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \
55 !defined(BOSOT_CONTRACT_NO_EXCEPTS)
56 #include <boost/any.hpp>
57 #include <boost/optional.hpp>
58 #include <boost/type_traits/remove_reference.hpp>
59 #include <boost/utility/enable_if.hpp>
60 #include <typeinfo>
61 #endif
62
63 namespace boost { namespace contract { namespace detail {
64
65 namespace cond_subcontracting_ {
66 // Exception signals (must not inherit).
67 class signal_no_error {};
68 class signal_not_checked {};
69 }
70
71 // O, VR, F, and Args-i can be none types (but C cannot).
72 BOOST_CONTRACT_DETAIL_DECL_DETAIL_COND_SUBCONTRACTING_Z(1,
73 /* is_friend = */ 0, O, VR, F, C, Args) : public cond_inv<VR, C>
74 { // Non-copyable base.
75 #ifndef BOOST_CONTRACT_NO_CONDITIONS
76 template<class Class, typename Result = boost::mpl::vector<> >
77 class overridden_bases_of {
78 struct search_bases {
79 typedef typename boost::mpl::fold<
80 typename boost::contract::access::base_types_of<Class>::
81 type,
82 Result,
83 // Fold: _1 = result, _2 = current base from base_types.
84 boost::mpl::eval_if<boost::mpl::contains<boost::mpl::_1,
85 boost::add_pointer<boost::mpl::_2> >,
86 boost::mpl::_1 // Base in result, do not add it again.
87 ,
88 boost::mpl::eval_if<
89 typename O::template BOOST_CONTRACT_DETAIL_NAME1(
90 has_member_function)<
91 boost::mpl::_2,
92 typename member_function_types<C, F>::
93 result_type,
94 typename member_function_types<C, F>::
95 virtual_argument_types,
96 typename member_function_types<C, F>::
97 property_tag
98 >
99 ,
100 boost::mpl::push_back<
101 overridden_bases_of<boost::mpl::_2,
102 boost::mpl::_1>,
103 // Bases as * since for_each constructs them.
104 boost::add_pointer<boost::mpl::_2>
105 >
106 ,
107 overridden_bases_of<boost::mpl::_2, boost::mpl::_1>
108 >
109 >
110 >::type type;
111 };
112 public:
113 typedef typename boost::mpl::eval_if<
114 boost::contract::access::has_base_types<Class>,
115 search_bases
116 ,
117 boost::mpl::identity<Result> // Return result (stop recursion).
118 >::type type;
119 };
120
121 typedef typename boost::mpl::eval_if<boost::is_same<O, none>,
122 boost::mpl::vector<>
123 ,
124 overridden_bases_of<C>
125 >::type overridden_bases;
126
127 #ifndef BOOST_CONTRACT_PERMISSIVE
128 BOOST_STATIC_ASSERT_MSG(
129 (boost::mpl::or_<
130 boost::is_same<O, none>,
131 boost::mpl::not_<boost::mpl::empty<overridden_bases> >
132 >::value),
133 "subcontracting function specified as 'override' but does not "
134 "override any contracted member function"
135 );
136 #endif
137 #else
138 typedef boost::mpl::vector<> overridden_bases;
139 #endif
140
141 public:
142 explicit cond_subcontracting(
143 boost::contract::from from,
144 boost::contract::virtual_* v,
145 C* obj,
146 VR&
147 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS // Avoid unused param warning.
148 r
149 #endif
150 BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(BOOST_CONTRACT_MAX_ARGS)
151 BOOST_CONTRACT_DETAIL_TVARIADIC_FPARAMS_Z(1,
152 BOOST_CONTRACT_MAX_ARGS, Args, &, args)
153 ) :
154 cond_inv<VR, C>(from, obj)
155 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
156 , r_(r)
157 #endif
158 #ifndef BOOST_CONTRACT_NO_CONDITIONS
159 BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(BOOST_CONTRACT_MAX_ARGS)
160 BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INIT_Z(1,
161 BOOST_CONTRACT_MAX_ARGS, args_, args)
162 #endif
163 {
164 #ifndef BOOST_CONTRACT_NO_CONDITIONS
165 if(v) {
166 base_call_ = true;
167 v_ = v; // Invariant: v_ never null if base_call_.
168 BOOST_CONTRACT_DETAIL_DEBUG(v_);
169 } else {
170 base_call_ = false;
171 if(!boost::mpl::empty<overridden_bases>::value) {
172 v_ = new boost::contract::virtual_(
173 boost::contract::virtual_::no_action);
174 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
175 v_->result_ptr_ = &r_;
176 v_->result_type_name_ = typeid(VR).name();
177 v_->result_optional_ = is_optional<VR>::value;
178 #endif
179 } else v_ = 0;
180 }
181 #endif
182 }
183
184 #ifndef BOOST_CONTRACT_NO_CONDITIONS
185 virtual ~cond_subcontracting() BOOST_NOEXCEPT_IF(false) {
186 if(!base_call_) delete v_;
187 }
188 #endif
189
190 protected:
191 #ifndef BOOST_CONTRACT_NO_OLDS
192 void init_subcontracted_old() {
193 // Old values of overloaded func on stack (so no `f` param here).
194 exec_and(boost::contract::virtual_::push_old_init_copy);
195 }
196 #endif
197
198 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
199 void check_subcontracted_entry_inv() {
200 exec_and(boost::contract::virtual_::check_entry_inv,
201 &cond_subcontracting::check_entry_inv);
202 }
203 #endif
204
205 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
206 void check_subcontracted_pre() {
207 exec_or(
208 boost::contract::virtual_::check_pre,
209 &cond_subcontracting::check_pre,
210 &boost::contract::precondition_failure
211 );
212 }
213 #endif
214
215 #ifndef BOOST_CONTRACT_NO_OLDS
216 void copy_subcontracted_old() {
217 exec_and(boost::contract::virtual_::call_old_ftor,
218 &cond_subcontracting::copy_virtual_old);
219 }
220 #endif
221
222 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
223 void check_subcontracted_exit_inv() {
224 exec_and(boost::contract::virtual_::check_exit_inv,
225 &cond_subcontracting::check_exit_inv);
226 }
227 #endif
228
229 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
230 void check_subcontracted_post() {
231 exec_and(boost::contract::virtual_::check_post,
232 &cond_subcontracting::check_virtual_post);
233 }
234 #endif
235
236 #ifndef BOOST_CONTRACT_NO_EXCEPTS
237 void check_subcontracted_except() {
238 exec_and(boost::contract::virtual_::check_except,
239 &cond_subcontracting::check_virtual_except);
240 }
241 #endif
242
243 #ifndef BOOST_CONTRACT_NO_CONDITIONS
244 bool base_call() const { return base_call_; }
245
246 bool failed() const /* override */ {
247 if(v_) return v_->failed_;
248 else return cond_base::failed();
249 }
250
251 void failed(bool value) /* override */ {
252 if(v_) v_->failed_ = value;
253 else cond_base::failed(value);
254 }
255 #endif
256
257 private:
258 #ifndef BOOST_CONTRACT_NO_OLDS
259 void copy_virtual_old() {
260 boost::contract::virtual_::action_enum a;
261 if(base_call_) {
262 a = v_->action_;
263 v_->action_ = boost::contract::virtual_::push_old_ftor_copy;
264 }
265 this->copy_old();
266 if(base_call_) v_->action_ = a;
267 }
268
269 void pop_base_old() {
270 if(base_call_) {
271 boost::contract::virtual_::action_enum a = v_->action_;
272 v_->action_ = boost::contract::virtual_::pop_old_ftor_copy;
273 this->copy_old();
274 v_->action_ = a;
275 } // Else, do nothing (for base calls only).
276 }
277 #endif
278
279 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
280 void check_virtual_post() {
281 pop_base_old();
282 typedef typename boost::remove_reference<typename
283 optional_value_type<VR>::type>::type r_type;
284 boost::optional<r_type const&> r; // No result copy in this code.
285 if(!base_call_) r = optional_get(r_);
286 else if(v_->result_optional_) {
287 try {
288 r = **boost::any_cast<boost::optional<r_type>*>(
289 v_->result_ptr_);
290 } catch(boost::bad_any_cast const&) {
291 try { // Handle optional<...&>.
292 r = **boost::any_cast<boost::optional<r_type&>*>(
293 v_->result_ptr_);
294 } catch(boost::bad_any_cast const&) {
295 try {
296 throw boost::contract::bad_virtual_result_cast(v_->
297 result_type_name_, typeid(r_type).name());
298 } catch(...) {
299 this->fail(&boost::contract::postcondition_failure);
300 }
301 }
302 }
303 } else {
304 try {
305 r = *boost::any_cast<r_type*>(v_->result_ptr_);
306 } catch(boost::bad_any_cast const&) {
307 try {
308 throw boost::contract::bad_virtual_result_cast(
309 v_->result_type_name_, typeid(r_type).name());
310 } catch(...) {
311 this->fail(&boost::contract::postcondition_failure);
312 }
313 }
314 }
315 check_virtual_post_with_result<VR>(r);
316 }
317
318 template<typename R_, typename Result>
319 typename boost::enable_if<is_optional<R_> >::type
320 check_virtual_post_with_result(Result const& r) {
321 this->check_post(r);
322 }
323
324 template<typename R_, typename Result>
325 typename boost::disable_if<is_optional<R_> >::type
326 check_virtual_post_with_result(Result const& r) {
327 BOOST_CONTRACT_DETAIL_DEBUG(r);
328 this->check_post(*r);
329 }
330 #endif
331
332 #ifndef BOOST_CONTRACT_NO_EXCEPTS
333 void check_virtual_except() {
334 pop_base_old();
335 this->check_except();
336 }
337 #endif
338
339 #if !defined(BOOST_CONTRACT_NO_INVARIANTS) || \
340 !defined(BOOST_CONTRACT_NO_POSTCONDITIONS) || \
341 !defined(BOOST_CONTRACT_NO_EXCEPTS)
342 void exec_and( // Execute action in short-circuit logic-and with bases.
343 boost::contract::virtual_::action_enum a,
344 void (cond_subcontracting::* f)() = 0
345 ) {
346 if(failed()) return;
347 if(!base_call_ || v_->action_ == a) {
348 if(!base_call_ && v_) {
349 v_->action_ = a;
350 boost::mpl::for_each<overridden_bases>(call_base(*this));
351 }
352 if(f) (this->*f)();
353 if(base_call_) {
354 throw cond_subcontracting_::signal_no_error();
355 }
356 }
357 }
358 #endif
359
360 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
361 void exec_or( // Execute action in short-circuit logic-or with bases.
362 boost::contract::virtual_::action_enum a,
363 bool (cond_subcontracting::* f)(bool) = 0,
364 void (*h)(boost::contract::from) = 0
365 ) {
366 if(failed()) return;
367 if(!base_call_ || v_->action_ == a) {
368 if(!base_call_ && v_) {
369 v_->action_ = a;
370 try {
371 exec_or_bases<overridden_bases>();
372 return; // A base checked with no error (done).
373 } catch(...) {
374 bool checked = f ? (this->*f)(
375 /* throw_on_failure = */ false) : false;
376 if(!checked) {
377 try { throw; } // Report latest exception found.
378 catch(...) { this->fail(h); }
379 }
380 return; // Checked and no exception (done).
381 }
382 }
383 bool checked = f ?
384 (this->*f)(/* throw_on_failure = */ base_call_) : false;
385 if(base_call_) {
386 if(!checked) {
387 throw cond_subcontracting_::signal_not_checked();
388 }
389 throw cond_subcontracting_::signal_no_error();
390 }
391 }
392 }
393
394 template<typename Bases>
395 typename boost::enable_if<boost::mpl::empty<Bases>, bool>::type
396 exec_or_bases() { return false; }
397
398 template<typename Bases>
399 typename boost::disable_if<boost::mpl::empty<Bases>, bool>::type
400 exec_or_bases() {
401 if(boost::mpl::empty<Bases>::value) return false;
402 try {
403 call_base(*this)(typename boost::mpl::front<Bases>::type());
404 } catch(cond_subcontracting_::signal_not_checked const&) {
405 return exec_or_bases<
406 typename boost::mpl::pop_front<Bases>::type>();
407 } catch(...) {
408 bool checked = false;
409 try {
410 checked = exec_or_bases<
411 typename boost::mpl::pop_front<Bases>::type>();
412 } catch(...) { checked = false; }
413 if(!checked) throw;
414 }
415 return true;
416 }
417 #endif
418
419 #ifndef BOOST_CONTRACT_NO_CONDITIONS
420 class call_base { // Copyable (as &).
421 public:
422 explicit call_base(cond_subcontracting& me) : me_(me) {}
423
424 template<class B>
425 void operator()(B*) {
426 BOOST_CONTRACT_DETAIL_DEBUG(me_.object());
427 BOOST_CONTRACT_DETAIL_DEBUG(me_.v_);
428 BOOST_CONTRACT_DETAIL_DEBUG(me_.v_->action_ !=
429 boost::contract::virtual_::no_action);
430 try {
431 call<B>(BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INDEXES_OF(
432 Args));
433 } catch(cond_subcontracting_::signal_no_error const&) {
434 // No error (do not throw).
435 }
436 }
437
438 private:
439 template<
440 class B
441 // Can't use TVARIADIC_COMMA here.
442 BOOST_PP_COMMA_IF(BOOST_CONTRACT_DETAIL_TVARIADIC)
443 BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INDEXES_TPARAM(I)
444 >
445 void call(
446 BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_INDEXES_FPARAM(I)) {
447 O::template BOOST_CONTRACT_DETAIL_NAME1(call_base)<B>(
448 me_.v_,
449 me_.object()
450 BOOST_CONTRACT_DETAIL_TVARIADIC_COMMA(
451 BOOST_CONTRACT_MAX_ARGS)
452 BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_ELEMS_Z(1,
453 BOOST_CONTRACT_MAX_ARGS, I, me_.args_)
454 );
455 }
456
457 cond_subcontracting& me_;
458 };
459 #endif
460
461 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
462 VR& r_;
463 #endif
464 #ifndef BOOST_CONTRACT_NO_CONDITIONS
465 boost::contract::virtual_* v_;
466 bool base_call_;
467 BOOST_CONTRACT_DETAIL_TVARIADIC_TUPLE_Z(1,
468 BOOST_CONTRACT_MAX_ARGS, Args, &, args_)
469 #endif
470 };
471
472 } } } // namespace
473
474 #endif // #include guard
475