old.hpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  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 to
  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,
  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 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.
  109. namespace boost { namespace contract {
  110. template<> // Specialization.
  111. struct is_old_value_copyable<u> : boost::false_type {};
  112. } } // namespace
  113. @endcode
  114. In summary, 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. Copyable old value types are always copied using
  117. @c boost::contract::old_value_copy<T>.
  118. Non-copyable old value types generate a compile-time error when
  119. @c boost::contract::old_ptr<T> is dereferenced, but instead leave
  120. @c boost::contract::old_ptr_if_copyable<T> 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 @p 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_(value) // 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 old values (if they
  164. actually need to be copied).
  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 is set to point to 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 =
  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> is @c true),
  202. otherwise this pointer will always be null and this library will
  203. 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. constant pointer to a constant object (see
  242. @RefSect{contract_programming_overview.constant_correctness,
  243. Constant Correctness}).
  244. */
  245. T const* 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. Check if this old value pointer is null or not.
  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 is 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. This constructor is implicitly called by this library when assigning an
  315. object of this type using @RefMacro{BOOST_CONTRACT_OLDOF} (this constructor
  316. is usually not explicitly called by user code).
  317. @param other Old value pointer that requires the old value type to be
  318. copyable.
  319. */
  320. /* implicit */ old_ptr_if_copyable(old_ptr<T> const& other) :
  321. typed_copy_(other.typed_copy_) {}
  322. /**
  323. Dereference this old value pointer.
  324. This will generate a run-time error if this pointer is null, but no
  325. compile-time error is generated if the pointed type @c T is not copyable
  326. (i.e., if @c boost::contract::is_old_value_copyable<T>::value is @c false).
  327. @return The pointed old value.
  328. Contract assertions should not change the state of the program so
  329. this member function is @c const and it returns the old value as a
  330. reference to a constant object (see
  331. @RefSect{contract_programming_overview.constant_correctness,
  332. Constant Correctness}).
  333. */
  334. T const& operator*() const {
  335. BOOST_CONTRACT_DETAIL_DEBUG(typed_copy_);
  336. return typed_copy_->old();
  337. }
  338. /**
  339. Structure-dereference this old value pointer.
  340. This will return null but will not generate a compile-time error if the
  341. pointed type @c T is not copyable (i.e., if
  342. @c boost::contract::is_old_value_copyable<T>::value is @c false).
  343. @return A pointer to the old value (null if this old value pointer is null).
  344. Contract assertions should not change the state of the program so
  345. this member function is @c const and it returns the old value as a
  346. constant pointer to a constant object (see
  347. @RefSect{contract_programming_overview.constant_correctness,
  348. Constant Correctness}).
  349. */
  350. T const* const operator->() const {
  351. if(typed_copy_) return &typed_copy_->old();
  352. return 0;
  353. }
  354. #ifndef BOOST_CONTRACT_DETAIL_DOXYGEN
  355. BOOST_CONTRACT_DETAIL_OPERATOR_SAFE_BOOL(old_ptr_if_copyable<T>,
  356. !!typed_copy_)
  357. #else
  358. /**
  359. Check if this old value pointer is null or not (safe-bool operator).
  360. (This is implemented using safe-bool emulation on compilers that do not
  361. support C++11 explicit type conversion operators.)
  362. @return True if this pointer is not null, false otherwise.
  363. */
  364. explicit operator bool() const;
  365. #endif
  366. /** @cond */
  367. private:
  368. #ifndef BOOST_CONTRACT_NO_OLDS
  369. explicit old_ptr_if_copyable(boost::shared_ptr<old_value_copy<T> > old)
  370. : typed_copy_(old) {}
  371. #endif
  372. boost::shared_ptr<old_value_copy<T> > typed_copy_;
  373. friend class old_pointer;
  374. /** @endcond */
  375. };
  376. /**
  377. Convert user-specified expressions to old values.
  378. This class is often only implicitly used by this library and it does not
  379. explicitly appear in user code.
  380. On older compilers that cannot correctly deduce the
  381. @c boost::contract::is_old_value_copyable trait, programmers can manually
  382. specialize that trait to make sure that only old value types that are copyable
  383. are actually copied.
  384. @see @RefSect{extras.old_value_requirements__templates_,
  385. Old Value Requirements}
  386. */
  387. class old_value { // Copyable (as *).
  388. public:
  389. // Following implicitly called by ternary operator `... ? ... : null_old()`.
  390. /**
  391. Construct this object from the specified old value when the old value type
  392. is copy constructible.
  393. The specified old value is copied (one time only) using
  394. @c boost::contract::old_value_copy, in which case related old value pointer
  395. will not be null (no copy is made if postconditions and exception guarantees
  396. are not being checked, see @RefMacro{BOOST_CONTRACT_NO_OLDS}).
  397. @param old Old value to be copied.
  398. @tparam T Old value type.
  399. */
  400. template<typename T>
  401. /* implicit */ old_value(
  402. T const& old,
  403. typename boost::enable_if<boost::contract::is_old_value_copyable<T>
  404. >::type* = 0
  405. )
  406. #ifndef BOOST_CONTRACT_NO_OLDS
  407. : untyped_copy_(new old_value_copy<T>(old))
  408. #endif // Else, leave ptr_ null (thus no copy of T).
  409. {}
  410. /**
  411. Construct this object from the specified old value when the old value type
  412. is not copyable.
  413. The specified old value cannot be copied in this case so it is not copied
  414. and the related old value pointer will always be null (thus a call to this
  415. constructor has no effect and it will likely be optimized away by most
  416. compilers).
  417. @param old Old value (that will not be copied in this case).
  418. @tparam T Old value type.
  419. */
  420. template<typename T>
  421. /* implicit */ old_value(
  422. T const& old,
  423. typename boost::disable_if<boost::contract::is_old_value_copyable<T>
  424. >::type* = 0
  425. ) {} // Leave ptr_ null (thus no copy of T).
  426. /** @cond */
  427. private:
  428. explicit old_value() {}
  429. #ifndef BOOST_CONTRACT_NO_OLDS
  430. boost::shared_ptr<void> untyped_copy_; // Type erasure.
  431. #endif
  432. friend class old_pointer;
  433. friend BOOST_CONTRACT_DETAIL_DECLSPEC old_value null_old();
  434. /** @endcond */
  435. };
  436. /**
  437. Convert old value copies to old value pointers.
  438. This class is often only implicitly used by this library and it does not
  439. explicitly appear in user code (that is why this class does not have public
  440. constructors, etc.).
  441. */
  442. class old_pointer { // Copyable (as *).
  443. public:
  444. /**
  445. Convert this object to an actual old value pointer for which the old value
  446. type @c T might or not be copyable.
  447. For example, this is implicitly called when assigning or initializing old
  448. value pointers.
  449. @tparam T Type of the pointed old value.
  450. The old value pointer will always be null if this type is not
  451. copyable (see
  452. @c boost::contract::is_old_value_copyable), but this library
  453. will not generate a compile-time error.
  454. */
  455. template<typename T>
  456. /* implicit */ operator old_ptr_if_copyable<T>() {
  457. return get<old_ptr_if_copyable<T> >();
  458. }
  459. /**
  460. Convert this object to an actual old value pointer for which the old value
  461. type @c T must be copyable.
  462. For example, this is implicitly called when assigning or initializing old
  463. value pointers.
  464. @tparam T Type of the pointed old value. This type must be copyable
  465. (see @c boost::contract::is_old_value_copyable),
  466. otherwise this library will generate a compile-time error when
  467. the old value pointer is dereferenced.
  468. */
  469. template<typename T>
  470. /* implicit */ operator old_ptr<T>() {
  471. return get<old_ptr<T> >();
  472. }
  473. /** @cond */
  474. private:
  475. explicit old_pointer(virtual_* v, old_value const& old)
  476. #ifndef BOOST_CONTRACT_NO_OLDS
  477. : v_(v), untyped_copy_(old.untyped_copy_)
  478. #endif
  479. {}
  480. template<typename Ptr>
  481. Ptr get() {
  482. #ifndef BOOST_CONTRACT_NO_OLDS
  483. if(!boost::contract::is_old_value_copyable<typename
  484. Ptr::element_type>::value) {
  485. BOOST_CONTRACT_DETAIL_DEBUG(!untyped_copy_);
  486. return Ptr(); // Non-copyable so no old value and return null.
  487. #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION
  488. } else if(!v_ && boost::contract::detail::checking::already()) {
  489. return Ptr(); // Not checking (so return null).
  490. #endif
  491. } else if(!v_) {
  492. BOOST_CONTRACT_DETAIL_DEBUG(untyped_copy_);
  493. typedef old_value_copy<typename Ptr::element_type> copied_type;
  494. boost::shared_ptr<copied_type> typed_copy = // Un-erase type.
  495. boost::static_pointer_cast<copied_type>(untyped_copy_);
  496. BOOST_CONTRACT_DETAIL_DEBUG(typed_copy);
  497. return Ptr(typed_copy);
  498. } else if(
  499. v_->action_ == boost::contract::virtual_::push_old_init_copy ||
  500. v_->action_ == boost::contract::virtual_::push_old_ftor_copy
  501. ) {
  502. BOOST_CONTRACT_DETAIL_DEBUG(untyped_copy_);
  503. std::queue<boost::shared_ptr<void> >& copies = v_->action_ ==
  504. boost::contract::virtual_::push_old_ftor_copy ?
  505. v_->old_ftor_copies_
  506. :
  507. v_->old_init_copies_
  508. ;
  509. copies.push(untyped_copy_);
  510. return Ptr(); // Pushed (so return null).
  511. } else if(
  512. boost::contract::virtual_::pop_old_init_copy(v_->action_) ||
  513. v_->action_ == boost::contract::virtual_::pop_old_ftor_copy
  514. ) {
  515. // Copy not null, but still pop it from the queue.
  516. BOOST_CONTRACT_DETAIL_DEBUG(!untyped_copy_);
  517. std::queue<boost::shared_ptr<void> >& copies = v_->action_ ==
  518. boost::contract::virtual_::pop_old_ftor_copy ?
  519. v_->old_ftor_copies_
  520. :
  521. v_->old_init_copies_
  522. ;
  523. boost::shared_ptr<void> untyped_copy = copies.front();
  524. BOOST_CONTRACT_DETAIL_DEBUG(untyped_copy);
  525. copies.pop();
  526. typedef old_value_copy<typename Ptr::element_type> copied_type;
  527. boost::shared_ptr<copied_type> typed_copy = // Un-erase type.
  528. boost::static_pointer_cast<copied_type>(untyped_copy);
  529. BOOST_CONTRACT_DETAIL_DEBUG(typed_copy);
  530. return Ptr(typed_copy);
  531. }
  532. BOOST_CONTRACT_DETAIL_DEBUG(!untyped_copy_);
  533. #endif
  534. return Ptr();
  535. }
  536. #ifndef BOOST_CONTRACT_NO_OLDS
  537. virtual_* v_;
  538. boost::shared_ptr<void> untyped_copy_; // Type erasure.
  539. #endif
  540. friend BOOST_CONTRACT_DETAIL_DECLSPEC
  541. old_pointer make_old(old_value const&);
  542. friend BOOST_CONTRACT_DETAIL_DECLSPEC
  543. old_pointer make_old(virtual_*, old_value const&);
  544. /** @endcond */
  545. };
  546. /**
  547. Return a null old value.
  548. The related old value pointer will also be null.
  549. This function is often only used by the code expanded by
  550. @RefMacro{BOOST_CONTRACT_OLDOF}.
  551. @see @RefSect{extras.no_macros__and_no_variadic_macros_, No Macros}
  552. @return Null old value.
  553. */
  554. /** @cond */ BOOST_CONTRACT_DETAIL_DECLSPEC /** @endcond */
  555. old_value null_old();
  556. /**
  557. Make an old value pointer (but not for virtual public functions and public
  558. functions overrides).
  559. The related old value pointer will not be null if the specified old value was
  560. actually copied.
  561. This function is often only used by code expanded by
  562. @c BOOST_CONTRACT_OLDOF(old_expr):
  563. @code
  564. boost::contract::make_old(boost::contract::copy_old() ? old_expr :
  565. boost::contract::null_old())
  566. @endcode
  567. @see @RefSect{extras.no_macros__and_no_variadic_macros_, No Macros}
  568. @param old Old value which is usually implicitly constructed from the user old
  569. value expression to be copied (use the ternary operator <c>?:</c>
  570. to avoid evaluating the old value expression all together when
  571. @c boost::contract::copy_old() is @c false).
  572. @return Old value pointer (usually implicitly converted to either
  573. @RefClass{boost::contract::old_ptr} or
  574. @RefClass{boost::contract::old_ptr_if_copyable} in user code).
  575. */
  576. /** @cond */ BOOST_CONTRACT_DETAIL_DECLSPEC /** @endcond */
  577. old_pointer make_old(old_value const& old);
  578. /**
  579. Make an old value pointer (for virtual public functions and public functions
  580. overrides).
  581. The related old value pointer will not be null if the specified old value was
  582. actually copied.
  583. This function is often only used by code expanded by
  584. @c BOOST_CONTRACT_OLDOF(v, old_expr):
  585. @code
  586. boost::contract::make_old(v, boost::contract::copy_old(v) ? old_expr :
  587. boost::contract::null_old())
  588. @endcode
  589. @see @RefSect{extras.no_macros__and_no_variadic_macros_, No Macros}
  590. @param v The trailing parameter of type
  591. @RefClass{boost::contract::virtual_}<c>*</c> and default value @c 0
  592. from the enclosing virtual or overriding public function declaring
  593. the contract.
  594. @param old Old value which is usually implicitly constructed from the user old
  595. value expression to be copied (use the ternary operator <c>?:</c>
  596. to avoid evaluating the old value expression all together when
  597. @c boost::contract::copy_old(v) is @c false).
  598. @return Old value pointer (usually implicitly converted to either
  599. @RefClass{boost::contract::old_ptr} or
  600. @RefClass{boost::contract::old_ptr_if_copyable} in user code).
  601. */
  602. /** @cond */ BOOST_CONTRACT_DETAIL_DECLSPEC /** @endcond */
  603. old_pointer make_old(virtual_* v, old_value const& old);
  604. /**
  605. Check if old values need to be copied (but not for virtual public functions and
  606. public function overrides).
  607. For example, this function always returns false when both postconditions and
  608. exception guarantees are not being checked (see
  609. @RefMacro{BOOST_CONTRACT_NO_OLDS}).
  610. This function is often only used by the code expanded by
  611. @RefMacro{BOOST_CONTRACT_OLDOF}.
  612. @see @RefSect{extras.no_macros__and_no_variadic_macros_, No Macros}
  613. @return True if old values need to be copied, false otherwise.
  614. */
  615. inline bool copy_old() {
  616. #ifndef BOOST_CONTRACT_NO_OLDS
  617. #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION
  618. return !boost::contract::detail::checking::already();
  619. #else
  620. return true;
  621. #endif
  622. #else
  623. return false; // No post checking, so never copy old values.
  624. #endif
  625. }
  626. /**
  627. Check if old values need to be copied (for virtual public functions and public
  628. function overrides).
  629. For example, this function always returns false when both postconditions and
  630. exception guarantees are not being checked (see
  631. @RefMacro{BOOST_CONTRACT_NO_OLDS}).
  632. In addition, this function returns false when overridden functions are being
  633. called subsequent times by this library to support subcontracting.
  634. This function is often only used by the code expanded by
  635. @RefMacro{BOOST_CONTRACT_OLDOF}.
  636. @see @RefSect{extras.no_macros__and_no_variadic_macros_, No Macros}
  637. @param v The trailing parameter of type
  638. @RefClass{boost::contract::virtual_}<c>*</c> and default value @c 0
  639. from the enclosing virtual or overriding public function declaring
  640. the contract.
  641. @return True if old values need to be copied, false otherwise.
  642. */
  643. inline bool copy_old(virtual_* v) {
  644. #ifndef BOOST_CONTRACT_NO_OLDS
  645. if(!v) {
  646. #ifndef BOOST_CONTRACT_ALL_DISABLE_NO_ASSERTION
  647. return !boost::contract::detail::checking::already();
  648. #else
  649. return true;
  650. #endif
  651. }
  652. return v->action_ == boost::contract::virtual_::push_old_init_copy ||
  653. v->action_ == boost::contract::virtual_::push_old_ftor_copy;
  654. #else
  655. return false; // No post checking, so never copy old values.
  656. #endif
  657. }
  658. } } // namespace
  659. #ifdef BOOST_CONTRACT_HEADER_ONLY
  660. #include <boost/contract/detail/inlined/old.hpp>
  661. #endif
  662. #endif // #include guard