]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | |
2 | #ifndef BOOST_CONTRACT_OLD_HPP_ | |
3 | #define BOOST_CONTRACT_OLD_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 | /** @file | |
11 | Handle old values. | |
12 | */ | |
13 | ||
14 | #include <boost/contract/core/config.hpp> | |
15 | #include <boost/contract/core/virtual.hpp> | |
16 | #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION | |
17 | #include <boost/contract/detail/checking.hpp> | |
18 | #endif | |
19 | #include <boost/contract/detail/operator_safe_bool.hpp> | |
20 | #include <boost/contract/detail/declspec.hpp> | |
21 | #include <boost/contract/detail/debug.hpp> | |
22 | #include <boost/make_shared.hpp> | |
23 | #include <boost/shared_ptr.hpp> | |
24 | #include <boost/type_traits/is_copy_constructible.hpp> | |
25 | #include <boost/utility/enable_if.hpp> | |
26 | #include <boost/static_assert.hpp> | |
27 | #include <boost/preprocessor/control/expr_iif.hpp> | |
28 | #include <boost/preprocessor/config/config.hpp> | |
29 | #include <queue> | |
30 | ||
31 | #if !BOOST_PP_VARIADICS | |
32 | ||
33 | #define BOOST_CONTRACT_OLDOF \ | |
34 | BOOST_CONTRACT_ERROR_macro_OLDOF_requires_variadic_macros_otherwise_manually_program_old_values | |
35 | ||
36 | #else // variadics | |
37 | ||
38 | #include <boost/preprocessor/facilities/overload.hpp> | |
39 | #include <boost/preprocessor/facilities/empty.hpp> | |
40 | #include <boost/preprocessor/cat.hpp> | |
41 | #include <boost/config.hpp> | |
42 | ||
43 | /* PRIVATE */ | |
44 | ||
45 | /** @cond */ | |
46 | ||
47 | #ifdef BOOST_NO_CXX11_AUTO_DECLARATIONS | |
48 | #define BOOST_CONTRACT_OLDOF_AUTO_TYPEOF_(value) /* nothing */ | |
49 | #else | |
50 | #include <boost/typeof/typeof.hpp> | |
51 | // Explicitly force old_ptr<...> conversion to allow for C++11 auto decl. | |
52 | #define BOOST_CONTRACT_OLDOF_AUTO_TYPEOF_(value) \ | |
53 | boost::contract::old_ptr<BOOST_TYPEOF(value)> | |
54 | #endif | |
55 | ||
56 | #define BOOST_CONTRACT_ERROR_macro_OLDOF_has_invalid_number_of_arguments_2( \ | |
57 | v, value) \ | |
58 | BOOST_CONTRACT_OLDOF_AUTO_TYPEOF_(value)(boost::contract::make_old(v, \ | |
59 | boost::contract::copy_old(v) ? (value) : boost::contract::null_old() \ | |
60 | )) | |
61 | ||
62 | #define BOOST_CONTRACT_ERROR_macro_OLDOF_has_invalid_number_of_arguments_1( \ | |
63 | value) \ | |
64 | BOOST_CONTRACT_OLDOF_AUTO_TYPEOF_(value)(boost::contract::make_old( \ | |
65 | boost::contract::copy_old() ? (value) : boost::contract::null_old() \ | |
66 | )) | |
67 | ||
68 | /** @endcond */ | |
69 | ||
70 | /* PUBLIC */ | |
71 | ||
72 | // NOTE: Leave this #defined the same regardless of ..._NO_OLDS. | |
73 | /** | |
74 | Macro typically used to copy an old value expression and assign it to an old | |
75 | value pointer. | |
76 | ||
77 | The expression expanded by this macro should be assigned to an old value | |
78 | pointer of type @RefClass{boost::contract::old_ptr} or | |
79 | @RefClass{boost::contract::old_ptr_if_copyable}. | |
80 | This is an overloaded variadic macro and it can be used in the following | |
81 | different ways. | |
82 | ||
83 | 1\. From within virtual public functions and public functions overrides: | |
84 | ||
85 | @code | |
86 | BOOST_CONTRACT_OLDOF(v, old_expr) | |
87 | @endcode | |
88 | ||
89 | 2\. From all other operations: | |
90 | ||
91 | @code | |
92 | BOOST_CONTRACT_OLDOF(old_expr) | |
93 | @endcode | |
94 | ||
95 | Where: | |
96 | ||
97 | @arg <c><b>v</b></c> is the extra parameter of type | |
98 | @RefClass{boost::contract::virtual_}<c>*</c> and default value @c 0 | |
99 | from the enclosing virtual public function or public function | |
100 | overrides declaring the contract. | |
92f5a8d4 | 101 | @arg <c><b>old_expr</b></c> is the expression to be evaluated and copied into |
11fdf7f2 TL |
102 | the old value pointer. |
103 | (This is not a variadic macro parameter so any comma it might contain | |
92f5a8d4 | 104 | must be protected by round parenthesis and |
11fdf7f2 TL |
105 | <c>BOOST_CONTRACT_OLDOF(v, (old_expr))</c> will always work.) |
106 | ||
107 | On compilers that do not support variadic macros, programmers can manually copy | |
108 | old value expressions without using this macro (see | |
109 | @RefSect{extras.no_macros__and_no_variadic_macros_, No Macros}). | |
110 | ||
111 | @see @RefSect{tutorial.old_values, Old Values} | |
112 | */ | |
113 | #define BOOST_CONTRACT_OLDOF(...) \ | |
114 | BOOST_PP_CAT( /* CAT(..., EMTPY()) required on MSVC */ \ | |
115 | BOOST_PP_OVERLOAD( \ | |
116 | BOOST_CONTRACT_ERROR_macro_OLDOF_has_invalid_number_of_arguments_, \ | |
117 | __VA_ARGS__ \ | |
118 | )(__VA_ARGS__), \ | |
119 | BOOST_PP_EMPTY() \ | |
120 | ) | |
121 | ||
122 | #endif // variadics | |
123 | ||
124 | /* CODE */ | |
125 | ||
126 | namespace boost { namespace contract { | |
127 | ||
128 | /** | |
129 | Trait to check if an old value type can be copied or not. | |
130 | ||
131 | By default, this unary boolean meta-function is equivalent to | |
132 | @c boost::is_copy_constructible<T> but programmers can chose to specialize it | |
92f5a8d4 | 133 | for user-defined types (in general some kind of specialization is also needed on |
11fdf7f2 TL |
134 | compilers that do not support C++11, see |
135 | <a href="http://www.boost.org/doc/libs/release/libs/type_traits/doc/html/boost_typetraits/reference/is_copy_constructible.html"> | |
136 | <c>boost::is_copy_constructible</c></a>): | |
137 | ||
138 | @code | |
92f5a8d4 | 139 | class u; // Some user-defined type for which old values shall not be copied. |
11fdf7f2 TL |
140 | |
141 | namespace boost { namespace contract { | |
92f5a8d4 | 142 | template<> // Specialization to not copy old values of type `u`. |
11fdf7f2 TL |
143 | struct is_old_value_copyable<u> : boost::false_type {}; |
144 | } } // namespace | |
145 | @endcode | |
146 | ||
92f5a8d4 | 147 | A given old value type @c T is copied only if |
11fdf7f2 | 148 | @c boost::contract::is_old_value_copyable<T>::value is @c true. |
92f5a8d4 TL |
149 | A copyable old value type @c V is always copied using |
150 | @c boost::contract::old_value_copy<V>. | |
151 | A non-copyable old value type @c W generates a compile-time error when | |
152 | @c boost::contract::old_ptr<W> is dereferenced, but instead leaves | |
153 | @c boost::contract::old_ptr_if_copyable<W> always null (without generating | |
11fdf7f2 TL |
154 | compile-time errors). |
155 | ||
156 | @see @RefSect{extras.old_value_requirements__templates_, | |
157 | Old Value Requirements} | |
158 | */ | |
159 | template<typename T> | |
160 | struct is_old_value_copyable : boost::is_copy_constructible<T> {}; | |
161 | ||
162 | /** @cond */ | |
163 | class old_value; | |
164 | ||
165 | template<> // Needed because `old_value` incomplete type when trait first used. | |
166 | struct is_old_value_copyable<old_value> : boost::true_type {}; | |
167 | /** @endcond */ | |
168 | ||
169 | /** | |
170 | Trait to copy an old value. | |
171 | ||
172 | By default, the implementation of this trait uses @c T's copy constructor to | |
92f5a8d4 | 173 | make one single copy of the specified value. |
11fdf7f2 TL |
174 | However, programmers can specialize this trait to copy old values using |
175 | user-specific operations different from @c T's copy constructor. | |
176 | The default implementation of this trait is equivalent to: | |
177 | ||
178 | @code | |
179 | template<typename T> | |
180 | class old_value_copy { | |
181 | public: | |
182 | explicit old_value_copy(T const& old) : | |
92f5a8d4 | 183 | old_(old) // One single copy of value using T's copy constructor. |
11fdf7f2 TL |
184 | {} |
185 | ||
186 | T const& old() const { return old_; } | |
187 | ||
188 | private: | |
189 | T const old_; // The old value copy. | |
190 | }; | |
191 | @endcode | |
192 | ||
193 | This library will instantiate and use this trait only on old value types @c T | |
194 | that are copyable (i.e., for which | |
195 | <c>boost::contract::is_old_value_copyable<T>::value</c> is @c true). | |
196 | ||
197 | @see @RefSect{extras.old_value_requirements__templates_, | |
198 | Old Value Requirements} | |
199 | */ | |
200 | template<typename T> // Used only if is_old_value_copyable<T>. | |
201 | struct old_value_copy { | |
202 | /** | |
203 | Construct this object by making one single copy of the specified old value. | |
204 | ||
205 | This is the only operation within this library that actually copies old | |
206 | values. | |
92f5a8d4 TL |
207 | This ensures this library makes one and only one copy of an old value (if |
208 | they actually need to be copied, see @RefMacro{BOOST_CONTRACT_NO_OLDS}). | |
11fdf7f2 TL |
209 | |
210 | @param old The old value to copy. | |
211 | */ | |
212 | explicit old_value_copy(T const& old) : | |
213 | old_(old) {} // This makes the one single copy of T. | |
214 | ||
215 | /** | |
216 | Return a (constant) reference to the old value that was copied. | |
217 | ||
218 | Contract assertions should not change the state of the program so the old | |
219 | value copy is returned as @c const (see | |
220 | @RefSect{contract_programming_overview.constant_correctness, | |
221 | Constant Correctness}). | |
222 | */ | |
223 | T const& old() const { return old_; } | |
224 | ||
225 | private: | |
226 | T const old_; | |
227 | }; | |
228 | ||
229 | template<typename T> | |
230 | class old_ptr_if_copyable; | |
231 | ||
232 | /** | |
233 | Old value pointer that requires the pointed old value type to be copyable. | |
234 | ||
92f5a8d4 | 235 | This pointer can be set to point an actual old value copy using either |
11fdf7f2 TL |
236 | @RefMacro{BOOST_CONTRACT_OLDOF} or @RefFunc{boost::contract::make_old} (that is |
237 | why this class does not have public non-default constructors): | |
238 | ||
239 | @code | |
240 | class u { | |
241 | public: | |
242 | virtual void f(..., boost::contract::virtual_* v = 0) { | |
92f5a8d4 | 243 | boost::contract::old_ptr<old_type> old_var = // For copyable `old_type`. |
11fdf7f2 TL |
244 | BOOST_CONTRACT_OLDOF(v, old_expr); |
245 | ... | |
246 | } | |
247 | ||
248 | ... | |
249 | }; | |
250 | @endcode | |
251 | ||
252 | @see @RefSect{tutorial.old_values, Old Values} | |
253 | ||
254 | @tparam T Type of the pointed old value. | |
255 | This type must be copyable (i.e., | |
92f5a8d4 TL |
256 | <c>boost::contract::is_old_value_copyable<T>::value</c> must be |
257 | @c true), otherwise this pointer will always be null and this library | |
258 | will generate a compile-time error when the pointer is dereferenced. | |
11fdf7f2 TL |
259 | */ |
260 | template<typename T> | |
261 | class old_ptr { /* copyable (as *) */ | |
262 | public: | |
263 | /** Pointed old value type. */ | |
264 | typedef T element_type; | |
265 | ||
266 | /** Construct this old value pointer as null. */ | |
267 | old_ptr() {} | |
268 | ||
269 | /** | |
270 | Dereference this old value pointer. | |
271 | ||
272 | This will generate a run-time error if this pointer is null and a | |
273 | compile-time error if the pointed type @c T is not copyable (i.e., if | |
274 | @c boost::contract::is_old_value_copyable<T>::value is @c false). | |
275 | ||
276 | @return The pointed old value. | |
277 | Contract assertions should not change the state of the program so | |
278 | this member function is @c const and it returns the old value as a | |
279 | reference to a constant object (see | |
280 | @RefSect{contract_programming_overview.constant_correctness, | |
281 | Constant Correctness}). | |
282 | */ | |
283 | T const& operator*() const { | |
284 | BOOST_STATIC_ASSERT_MSG( | |
285 | boost::contract::is_old_value_copyable<T>::value, | |
286 | "old_ptr<T> requires T copyable (see is_old_value_copyable<T>), " | |
287 | "otherwise use old_ptr_if_copyable<T>" | |
288 | ); | |
289 | BOOST_CONTRACT_DETAIL_DEBUG(typed_copy_); | |
290 | return typed_copy_->old(); | |
291 | } | |
292 | ||
293 | /** | |
294 | Structure-dereference this old value pointer. | |
295 | ||
296 | This will generate a compile-time error if the pointed type @c T is not | |
297 | copyable (i.e., if @c boost::contract::is_old_value_copyable<T>::value is | |
298 | @c false). | |
299 | ||
300 | @return A pointer to the old value (null if this old value pointer is null). | |
301 | Contract assertions should not change the state of the program so | |
302 | this member function is @c const and it returns the old value as a | |
92f5a8d4 | 303 | pointer to a constant object (see |
11fdf7f2 TL |
304 | @RefSect{contract_programming_overview.constant_correctness, |
305 | Constant Correctness}). | |
306 | */ | |
92f5a8d4 | 307 | T const* operator->() const { |
11fdf7f2 TL |
308 | BOOST_STATIC_ASSERT_MSG( |
309 | boost::contract::is_old_value_copyable<T>::value, | |
310 | "old_ptr<T> requires T copyble (see is_old_value_copyable<T>), " | |
311 | "otherwise use old_ptr_if_copyable<T>" | |
312 | ); | |
313 | if(typed_copy_) return &typed_copy_->old(); | |
314 | return 0; | |
315 | } | |
316 | ||
317 | #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN | |
318 | BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL(old_ptr<T>, | |
319 | !!typed_copy_) | |
320 | #else | |
321 | /** | |
92f5a8d4 | 322 | Query if this old value pointer is null or not (safe-bool operator). |
11fdf7f2 TL |
323 | |
324 | (This is implemented using safe-bool emulation on compilers that do not | |
325 | support C++11 explicit type conversion operators.) | |
326 | ||
327 | @return True if this pointer is not null, false otherwise. | |
328 | */ | |
329 | explicit operator bool() const; | |
330 | #endif | |
331 | ||
332 | /** @cond */ | |
333 | private: | |
334 | #ifndef BOOST_CONTRACT_NO_OLDS | |
335 | explicit old_ptr(boost::shared_ptr<old_value_copy<T> > old) | |
336 | : typed_copy_(old) {} | |
337 | #endif | |
338 | ||
339 | boost::shared_ptr<old_value_copy<T> > typed_copy_; | |
340 | ||
341 | friend class old_pointer; | |
342 | friend class old_ptr_if_copyable<T>; | |
343 | /** @endcond */ | |
344 | }; | |
345 | ||
346 | /** | |
347 | Old value pointer that does not require the pointed old value type to be | |
348 | copyable. | |
349 | ||
92f5a8d4 | 350 | This pointer can be set to point to an actual old value copy using either |
11fdf7f2 TL |
351 | @RefMacro{BOOST_CONTRACT_OLDOF} or @RefFunc{boost::contract::make_old}: |
352 | ||
353 | @code | |
354 | template<typename T> // Type `T` might or not be copyable. | |
355 | class u { | |
356 | public: | |
357 | virtual void f(..., boost::contract::virtual_* v = 0) { | |
358 | boost::contract::old_ptr_if_copyable<T> old_var = | |
359 | BOOST_CONTRACT_OLDOF(v, old_expr); | |
360 | ... | |
361 | if(old_var) ... // Always null for non-copyable types. | |
362 | ... | |
363 | } | |
364 | ||
365 | ... | |
366 | }; | |
367 | @endcode | |
368 | ||
369 | @see @RefSect{extras.old_value_requirements__templates_, | |
370 | Old Value Requirements} | |
371 | ||
372 | @tparam T Type of the pointed old value. | |
373 | If this type is not copyable (i.e., | |
374 | <c>boost::contract::is_old_value_copyable<T>::value</c> is @c false), | |
375 | this pointer will always be null (but this library will not generate a | |
376 | compile-time error when this pointer is dereferenced). | |
377 | */ | |
378 | template<typename T> | |
379 | class old_ptr_if_copyable { /* copyable (as *) */ | |
380 | public: | |
381 | /** Pointed old value type. */ | |
382 | typedef T element_type; | |
383 | ||
384 | /** Construct this old value pointer as null. */ | |
385 | old_ptr_if_copyable() {} | |
386 | ||
387 | /** | |
388 | Construct this old value pointer from an old value pointer that requires | |
389 | the old value type to be copyable. | |
92f5a8d4 TL |
390 | |
391 | Ownership of the pointed value object is transferred to this pointer. | |
11fdf7f2 TL |
392 | This constructor is implicitly called by this library when assigning an |
393 | object of this type using @RefMacro{BOOST_CONTRACT_OLDOF} (this constructor | |
394 | is usually not explicitly called by user code). | |
395 | ||
396 | @param other Old value pointer that requires the old value type to be | |
397 | copyable. | |
398 | */ | |
399 | /* implicit */ old_ptr_if_copyable(old_ptr<T> const& other) : | |
400 | typed_copy_(other.typed_copy_) {} | |
401 | ||
402 | /** | |
403 | Dereference this old value pointer. | |
404 | ||
405 | This will generate a run-time error if this pointer is null, but no | |
406 | compile-time error is generated if the pointed type @c T is not copyable | |
407 | (i.e., if @c boost::contract::is_old_value_copyable<T>::value is @c false). | |
408 | ||
409 | @return The pointed old value. | |
410 | Contract assertions should not change the state of the program so | |
411 | this member function is @c const and it returns the old value as a | |
412 | reference to a constant object (see | |
413 | @RefSect{contract_programming_overview.constant_correctness, | |
414 | Constant Correctness}). | |
415 | */ | |
416 | T const& operator*() const { | |
417 | BOOST_CONTRACT_DETAIL_DEBUG(typed_copy_); | |
418 | return typed_copy_->old(); | |
419 | } | |
420 | ||
421 | /** | |
422 | Structure-dereference this old value pointer. | |
423 | ||
424 | This will return null but will not generate a compile-time error if the | |
425 | pointed type @c T is not copyable (i.e., if | |
426 | @c boost::contract::is_old_value_copyable<T>::value is @c false). | |
427 | ||
428 | @return A pointer to the old value (null if this old value pointer is null). | |
429 | Contract assertions should not change the state of the program so | |
430 | this member function is @c const and it returns the old value as a | |
92f5a8d4 | 431 | pointer to a constant object (see |
11fdf7f2 TL |
432 | @RefSect{contract_programming_overview.constant_correctness, |
433 | Constant Correctness}). | |
434 | */ | |
92f5a8d4 | 435 | T const* operator->() const { |
11fdf7f2 TL |
436 | if(typed_copy_) return &typed_copy_->old(); |
437 | return 0; | |
438 | } | |
439 | ||
440 | #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN | |
441 | BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL(old_ptr_if_copyable<T>, | |
442 | !!typed_copy_) | |
443 | #else | |
444 | /** | |
92f5a8d4 | 445 | Query if this old value pointer is null or not (safe-bool operator). |
11fdf7f2 TL |
446 | |
447 | (This is implemented using safe-bool emulation on compilers that do not | |
448 | support C++11 explicit type conversion operators.) | |
449 | ||
450 | @return True if this pointer is not null, false otherwise. | |
451 | */ | |
452 | explicit operator bool() const; | |
453 | #endif | |
454 | ||
455 | /** @cond */ | |
456 | private: | |
457 | #ifndef BOOST_CONTRACT_NO_OLDS | |
458 | explicit old_ptr_if_copyable(boost::shared_ptr<old_value_copy<T> > old) | |
459 | : typed_copy_(old) {} | |
460 | #endif | |
461 | ||
462 | boost::shared_ptr<old_value_copy<T> > typed_copy_; | |
463 | ||
464 | friend class old_pointer; | |
465 | /** @endcond */ | |
466 | }; | |
467 | ||
468 | /** | |
469 | Convert user-specified expressions to old values. | |
470 | ||
92f5a8d4 | 471 | This class is usually only implicitly used by this library and it does not |
11fdf7f2 TL |
472 | explicitly appear in user code. |
473 | ||
474 | On older compilers that cannot correctly deduce the | |
92f5a8d4 TL |
475 | @c boost::contract::is_old_value_copyable trait used in the declaration of this |
476 | class, programmers can manually specialize that trait to make sure that only old | |
477 | value types that are copyable are actually copied. | |
11fdf7f2 TL |
478 | |
479 | @see @RefSect{extras.old_value_requirements__templates_, | |
480 | Old Value Requirements} | |
481 | */ | |
482 | class old_value { // Copyable (as *). | |
483 | public: | |
484 | // Following implicitly called by ternary operator `... ? ... : null_old()`. | |
485 | ||
486 | /** | |
487 | Construct this object from the specified old value when the old value type | |
488 | is copy constructible. | |
489 | ||
92f5a8d4 TL |
490 | The specified old value @c old is copied (one time only) using |
491 | @c boost::contract::old_value_copy, in which case the related old value | |
492 | pointer will not be null (but no copy is made if postconditions and | |
493 | exception guarantees are not being checked, see | |
494 | @RefMacro{BOOST_CONTRACT_NO_OLDS}). | |
11fdf7f2 TL |
495 | |
496 | @param old Old value to be copied. | |
497 | ||
498 | @tparam T Old value type. | |
499 | */ | |
500 | template<typename T> | |
501 | /* implicit */ old_value( | |
92f5a8d4 TL |
502 | T const& |
503 | #if !defined(BOOST_CONTRACT_NO_OLDS) || \ | |
504 | defined(BOOST_CONTRACT_DETAIL_DOXYGEN) | |
505 | old | |
506 | #endif // Else, no name (avoid unused param warning). | |
507 | , | |
11fdf7f2 TL |
508 | typename boost::enable_if<boost::contract::is_old_value_copyable<T> |
509 | >::type* = 0 | |
510 | ) | |
511 | #ifndef BOOST_CONTRACT_NO_OLDS | |
512 | : untyped_copy_(new old_value_copy<T>(old)) | |
513 | #endif // Else, leave ptr_ null (thus no copy of T). | |
514 | {} | |
515 | ||
516 | /** | |
517 | Construct this object from the specified old value when the old value type | |
518 | is not copyable. | |
519 | ||
92f5a8d4 TL |
520 | The specified old value @c old cannot be copied in this case so it is not |
521 | copied and the related old value pointer will always be null (thus calls to | |
522 | this constructor have no effect and they will likely be optimized away by | |
523 | most compilers). | |
11fdf7f2 TL |
524 | |
525 | @param old Old value (that will not be copied in this case). | |
526 | ||
527 | @tparam T Old value type. | |
528 | */ | |
529 | template<typename T> | |
530 | /* implicit */ old_value( | |
92f5a8d4 TL |
531 | T const& |
532 | #ifdef BOOST_CONTRACT_DETAIL_DOXYGEN | |
533 | old | |
534 | #endif // Else, no name (avoid unused param warning). | |
535 | , | |
11fdf7f2 TL |
536 | typename boost::disable_if<boost::contract::is_old_value_copyable<T> |
537 | >::type* = 0 | |
538 | ) {} // Leave ptr_ null (thus no copy of T). | |
539 | ||
540 | /** @cond */ | |
541 | private: | |
542 | explicit old_value() {} | |
543 | ||
544 | #ifndef BOOST_CONTRACT_NO_OLDS | |
545 | boost::shared_ptr<void> untyped_copy_; // Type erasure. | |
546 | #endif | |
547 | ||
548 | friend class old_pointer; | |
549 | friend BOOST_CONTRACT_DETAIL_DECLSPEC old_value null_old(); | |
550 | /** @endcond */ | |
551 | }; | |
552 | ||
553 | /** | |
92f5a8d4 | 554 | Convert old value copies into old value pointers. |
11fdf7f2 | 555 | |
92f5a8d4 | 556 | This class is usually only implicitly used by this library and it does not |
11fdf7f2 TL |
557 | explicitly appear in user code (that is why this class does not have public |
558 | constructors, etc.). | |
559 | */ | |
560 | class old_pointer { // Copyable (as *). | |
561 | public: | |
562 | /** | |
563 | Convert this object to an actual old value pointer for which the old value | |
564 | type @c T might or not be copyable. | |
565 | ||
566 | For example, this is implicitly called when assigning or initializing old | |
92f5a8d4 | 567 | value pointers of type @c boost::contract::old_ptr_if_copyable. |
11fdf7f2 TL |
568 | |
569 | @tparam T Type of the pointed old value. | |
570 | The old value pointer will always be null if this type is not | |
571 | copyable (see | |
572 | @c boost::contract::is_old_value_copyable), but this library | |
573 | will not generate a compile-time error. | |
574 | */ | |
575 | template<typename T> | |
576 | /* implicit */ operator old_ptr_if_copyable<T>() { | |
577 | return get<old_ptr_if_copyable<T> >(); | |
578 | } | |
579 | ||
580 | /** | |
581 | Convert this object to an actual old value pointer for which the old value | |
582 | type @c T must be copyable. | |
583 | ||
584 | For example, this is implicitly called when assigning or initializing old | |
92f5a8d4 | 585 | value pointers of type @c boost::contract::old_ptr. |
11fdf7f2 TL |
586 | |
587 | @tparam T Type of the pointed old value. This type must be copyable | |
588 | (see @c boost::contract::is_old_value_copyable), | |
589 | otherwise this library will generate a compile-time error when | |
590 | the old value pointer is dereferenced. | |
591 | */ | |
592 | template<typename T> | |
593 | /* implicit */ operator old_ptr<T>() { | |
594 | return get<old_ptr<T> >(); | |
595 | } | |
596 | ||
597 | /** @cond */ | |
598 | private: | |
92f5a8d4 TL |
599 | #ifndef BOOST_CONTRACT_NO_OLDS |
600 | explicit old_pointer(virtual_* v, old_value const& old) | |
601 | : v_(v), untyped_copy_(old.untyped_copy_) {} | |
602 | #else | |
603 | explicit old_pointer(virtual_* /* v */, old_value const& /* old */) {} | |
604 | #endif | |
11fdf7f2 TL |
605 | |
606 | template<typename Ptr> | |
607 | Ptr get() { | |
608 | #ifndef BOOST_CONTRACT_NO_OLDS | |
609 | if(!boost::contract::is_old_value_copyable<typename | |
610 | Ptr::element_type>::value) { | |
611 | BOOST_CONTRACT_DETAIL_DEBUG(!untyped_copy_); | |
612 | return Ptr(); // Non-copyable so no old value and return null. | |
613 | #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION | |
614 | } else if(!v_ && boost::contract::detail::checking::already()) { | |
615 | return Ptr(); // Not checking (so return null). | |
616 | #endif | |
617 | } else if(!v_) { | |
618 | BOOST_CONTRACT_DETAIL_DEBUG(untyped_copy_); | |
619 | typedef old_value_copy<typename Ptr::element_type> copied_type; | |
620 | boost::shared_ptr<copied_type> typed_copy = // Un-erase type. | |
621 | boost::static_pointer_cast<copied_type>(untyped_copy_); | |
622 | BOOST_CONTRACT_DETAIL_DEBUG(typed_copy); | |
623 | return Ptr(typed_copy); | |
624 | } else if( | |
625 | v_->action_ == boost::contract::virtual_::push_old_init_copy || | |
626 | v_->action_ == boost::contract::virtual_::push_old_ftor_copy | |
627 | ) { | |
628 | BOOST_CONTRACT_DETAIL_DEBUG(untyped_copy_); | |
629 | std::queue<boost::shared_ptr<void> >& copies = v_->action_ == | |
630 | boost::contract::virtual_::push_old_ftor_copy ? | |
631 | v_->old_ftor_copies_ | |
632 | : | |
633 | v_->old_init_copies_ | |
634 | ; | |
635 | copies.push(untyped_copy_); | |
636 | return Ptr(); // Pushed (so return null). | |
637 | } else if( | |
638 | boost::contract::virtual_::pop_old_init_copy(v_->action_) || | |
639 | v_->action_ == boost::contract::virtual_::pop_old_ftor_copy | |
640 | ) { | |
641 | // Copy not null, but still pop it from the queue. | |
642 | BOOST_CONTRACT_DETAIL_DEBUG(!untyped_copy_); | |
643 | ||
644 | std::queue<boost::shared_ptr<void> >& copies = v_->action_ == | |
645 | boost::contract::virtual_::pop_old_ftor_copy ? | |
646 | v_->old_ftor_copies_ | |
647 | : | |
648 | v_->old_init_copies_ | |
649 | ; | |
650 | boost::shared_ptr<void> untyped_copy = copies.front(); | |
651 | BOOST_CONTRACT_DETAIL_DEBUG(untyped_copy); | |
652 | copies.pop(); | |
653 | ||
654 | typedef old_value_copy<typename Ptr::element_type> copied_type; | |
655 | boost::shared_ptr<copied_type> typed_copy = // Un-erase type. | |
656 | boost::static_pointer_cast<copied_type>(untyped_copy); | |
657 | BOOST_CONTRACT_DETAIL_DEBUG(typed_copy); | |
658 | return Ptr(typed_copy); | |
659 | } | |
660 | BOOST_CONTRACT_DETAIL_DEBUG(!untyped_copy_); | |
661 | #endif | |
662 | return Ptr(); | |
663 | } | |
664 | ||
665 | #ifndef BOOST_CONTRACT_NO_OLDS | |
666 | virtual_* v_; | |
667 | boost::shared_ptr<void> untyped_copy_; // Type erasure. | |
668 | #endif | |
669 | ||
670 | friend BOOST_CONTRACT_DETAIL_DECLSPEC | |
671 | old_pointer make_old(old_value const&); | |
672 | ||
673 | friend BOOST_CONTRACT_DETAIL_DECLSPEC | |
674 | old_pointer make_old(virtual_*, old_value const&); | |
675 | /** @endcond */ | |
676 | }; | |
677 | ||
678 | /** | |
92f5a8d4 | 679 | Return a "null" old value. |
11fdf7f2 TL |
680 | |
681 | The related old value pointer will also be null. | |
92f5a8d4 | 682 | This function is usually only called by the code expanded by |
11fdf7f2 TL |
683 | @RefMacro{BOOST_CONTRACT_OLDOF}. |
684 | ||
685 | @see @RefSect{extras.no_macros__and_no_variadic_macros_, No Macros} | |
686 | ||
687 | @return Null old value. | |
688 | */ | |
689 | /** @cond */ BOOST_CONTRACT_DETAIL_DECLSPEC /** @endcond */ | |
690 | old_value null_old(); | |
691 | ||
692 | /** | |
693 | Make an old value pointer (but not for virtual public functions and public | |
694 | functions overrides). | |
695 | ||
696 | The related old value pointer will not be null if the specified old value was | |
697 | actually copied. | |
92f5a8d4 TL |
698 | This function is usually only called by code expanded by |
699 | @c BOOST_CONTRACT_OLDOF(old_expr) as in: | |
11fdf7f2 TL |
700 | |
701 | @code | |
702 | boost::contract::make_old(boost::contract::copy_old() ? old_expr : | |
703 | boost::contract::null_old()) | |
704 | @endcode | |
705 | ||
706 | @see @RefSect{extras.no_macros__and_no_variadic_macros_, No Macros} | |
707 | ||
708 | @param old Old value which is usually implicitly constructed from the user old | |
709 | value expression to be copied (use the ternary operator <c>?:</c> | |
92f5a8d4 | 710 | to completely avoid to evaluate the old value expression when |
11fdf7f2 TL |
711 | @c boost::contract::copy_old() is @c false). |
712 | ||
713 | @return Old value pointer (usually implicitly converted to either | |
714 | @RefClass{boost::contract::old_ptr} or | |
715 | @RefClass{boost::contract::old_ptr_if_copyable} in user code). | |
716 | */ | |
717 | /** @cond */ BOOST_CONTRACT_DETAIL_DECLSPEC /** @endcond */ | |
718 | old_pointer make_old(old_value const& old); | |
719 | ||
720 | /** | |
721 | Make an old value pointer (for virtual public functions and public functions | |
722 | overrides). | |
723 | ||
724 | The related old value pointer will not be null if the specified old value was | |
725 | actually copied. | |
92f5a8d4 TL |
726 | This function is usually only called by code expanded by |
727 | @c BOOST_CONTRACT_OLDOF(v, old_expr) as in: | |
11fdf7f2 TL |
728 | |
729 | @code | |
730 | boost::contract::make_old(v, boost::contract::copy_old(v) ? old_expr : | |
731 | boost::contract::null_old()) | |
732 | @endcode | |
733 | ||
734 | @see @RefSect{extras.no_macros__and_no_variadic_macros_, No Macros} | |
735 | ||
736 | @param v The trailing parameter of type | |
737 | @RefClass{boost::contract::virtual_}<c>*</c> and default value @c 0 | |
738 | from the enclosing virtual or overriding public function declaring | |
739 | the contract. | |
740 | @param old Old value which is usually implicitly constructed from the user old | |
741 | value expression to be copied (use the ternary operator <c>?:</c> | |
92f5a8d4 | 742 | to completely avoid to evaluate the old value expression when |
11fdf7f2 TL |
743 | @c boost::contract::copy_old(v) is @c false). |
744 | ||
745 | @return Old value pointer (usually implicitly converted to either | |
746 | @RefClass{boost::contract::old_ptr} or | |
747 | @RefClass{boost::contract::old_ptr_if_copyable} in user code). | |
748 | */ | |
749 | /** @cond */ BOOST_CONTRACT_DETAIL_DECLSPEC /** @endcond */ | |
750 | old_pointer make_old(virtual_* v, old_value const& old); | |
751 | ||
752 | /** | |
92f5a8d4 | 753 | Query if old values need to be copied (but not for virtual public functions and |
11fdf7f2 TL |
754 | public function overrides). |
755 | ||
756 | For example, this function always returns false when both postconditions and | |
757 | exception guarantees are not being checked (see | |
758 | @RefMacro{BOOST_CONTRACT_NO_OLDS}). | |
92f5a8d4 | 759 | This function is usually only called by the code expanded by |
11fdf7f2 TL |
760 | @RefMacro{BOOST_CONTRACT_OLDOF}. |
761 | ||
762 | @see @RefSect{extras.no_macros__and_no_variadic_macros_, No Macros} | |
763 | ||
764 | @return True if old values need to be copied, false otherwise. | |
765 | */ | |
766 | inline bool copy_old() { | |
767 | #ifndef BOOST_CONTRACT_NO_OLDS | |
768 | #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION | |
769 | return !boost::contract::detail::checking::already(); | |
770 | #else | |
771 | return true; | |
772 | #endif | |
773 | #else | |
774 | return false; // No post checking, so never copy old values. | |
775 | #endif | |
776 | } | |
777 | ||
778 | /** | |
92f5a8d4 | 779 | Query if old values need to be copied (for virtual public functions and public |
11fdf7f2 TL |
780 | function overrides). |
781 | ||
782 | For example, this function always returns false when both postconditions and | |
783 | exception guarantees are not being checked (see | |
784 | @RefMacro{BOOST_CONTRACT_NO_OLDS}). | |
785 | In addition, this function returns false when overridden functions are being | |
786 | called subsequent times by this library to support subcontracting. | |
92f5a8d4 | 787 | This function is usually only called by the code expanded by |
11fdf7f2 TL |
788 | @RefMacro{BOOST_CONTRACT_OLDOF}. |
789 | ||
790 | @see @RefSect{extras.no_macros__and_no_variadic_macros_, No Macros} | |
791 | ||
792 | @param v The trailing parameter of type | |
793 | @RefClass{boost::contract::virtual_}<c>*</c> and default value @c 0 | |
794 | from the enclosing virtual or overriding public function declaring | |
795 | the contract. | |
796 | ||
797 | @return True if old values need to be copied, false otherwise. | |
798 | */ | |
92f5a8d4 TL |
799 | #ifndef BOOST_CONTRACT_NO_OLDS |
800 | inline bool copy_old(virtual_* v) { | |
11fdf7f2 TL |
801 | if(!v) { |
802 | #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION | |
803 | return !boost::contract::detail::checking::already(); | |
804 | #else | |
805 | return true; | |
806 | #endif | |
807 | } | |
808 | return v->action_ == boost::contract::virtual_::push_old_init_copy || | |
809 | v->action_ == boost::contract::virtual_::push_old_ftor_copy; | |
92f5a8d4 TL |
810 | } |
811 | #else | |
812 | inline bool copy_old(virtual_* | |
813 | #ifdef BOOST_CONTRACT_DETAIL_DOXYGEN | |
814 | v | |
815 | #endif | |
816 | ) { | |
11fdf7f2 | 817 | return false; // No post checking, so never copy old values. |
92f5a8d4 TL |
818 | } |
819 | #endif | |
11fdf7f2 TL |
820 | |
821 | } } // namespace | |
822 | ||
823 | #ifdef BOOST_CONTRACT_HEADER_ONLY | |
824 | #include <boost/contract/detail/inlined/old.hpp> | |
825 | #endif | |
826 | ||
827 | #endif // #include guard | |
828 |