old.hpp 28 KB

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