]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | |
2 | // Copyright (C) 2008-2018 Lorenzo Caminiti | |
3 | // Distributed under the Boost Software License, Version 1.0 (see accompanying | |
4 | // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). | |
5 | // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html | |
6 | ||
7 | #include <boost/contract.hpp> | |
8 | #include <boost/type_traits.hpp> | |
9 | #include <boost/noncopyable.hpp> | |
10 | #include <cassert> | |
11 | ||
12 | //[old_if_copyable_offset | |
13 | template<typename T> // T might or might not be copyable. | |
14 | void offset(T& x, int count) { | |
15 | // No compiler error if T has no copy constructor... | |
16 | boost::contract::old_ptr_if_copyable<T> old_x = BOOST_CONTRACT_OLDOF(x); | |
17 | boost::contract::check c = boost::contract::function() | |
18 | .postcondition([&] { | |
19 | // ...but old value null if T has no copy constructor. | |
20 | if(old_x) BOOST_CONTRACT_ASSERT(x == *old_x + count); | |
21 | }) | |
22 | ; | |
23 | ||
24 | x += count; | |
25 | } | |
26 | //] | |
27 | ||
28 | //[old_if_copyable_w_decl | |
29 | // Copyable type but... | |
30 | class w { | |
31 | public: | |
92f5a8d4 | 32 | w(w const&) { /* Some very expensive copy operation here... */ } |
11fdf7f2 TL |
33 | |
34 | /* ... */ | |
35 | //] | |
36 | w() : num_(0) {} | |
37 | int operator+(int i) const { return num_ + i; } | |
38 | w& operator+=(int i) { num_ += i; return *this; } | |
39 | bool operator==(int i) const { return long(num_) == i; } | |
40 | private: | |
41 | unsigned long num_; | |
42 | }; | |
43 | ||
44 | //[old_if_copyable_w_spec | |
45 | // ...never copy old values for type `w` (because its copy is too expensive). | |
46 | namespace boost { namespace contract { | |
47 | template<> | |
48 | struct is_old_value_copyable<w> : boost::false_type {}; | |
49 | } } | |
50 | //] | |
51 | ||
52 | //[old_if_copyable_p_decl | |
53 | // Non-copyable type but... | |
54 | class p : private boost::noncopyable { | |
55 | int* num_; | |
56 | ||
57 | friend struct boost::contract::old_value_copy<p>; | |
58 | ||
59 | /* ... */ | |
60 | //] | |
61 | public: | |
62 | p() : num_(new int(0)) {} | |
63 | ~p() { delete num_; } | |
64 | int operator+(int i) const { return *num_ + i; } | |
65 | p& operator+=(int i) { *num_ += i; return *this; } | |
66 | bool operator==(int i) const { return *num_ == i; } | |
67 | }; | |
68 | ||
69 | //[old_if_copyable_p_spec | |
70 | // ...still copy old values for type `p` (using a deep copy). | |
71 | namespace boost { namespace contract { | |
72 | template<> | |
73 | struct old_value_copy<p> { | |
74 | explicit old_value_copy(p const& old) { | |
75 | *old_.num_ = *old.num_; // Deep copy pointed value. | |
76 | } | |
77 | ||
78 | p const& old() const { return old_; } | |
79 | ||
80 | private: | |
81 | p old_; | |
82 | }; | |
83 | ||
84 | template<> | |
85 | struct is_old_value_copyable<p> : boost::true_type {}; | |
86 | } } | |
87 | //] | |
88 | ||
89 | //[old_if_copyable_n_decl | |
90 | class n { // Do not want to use boost::noncopyable but... | |
91 | int num_; | |
92 | ||
93 | private: | |
94 | n(n const&); // ...unimplemented private copy constructor (so non-copyable). | |
95 | ||
96 | /* ... */ | |
97 | //] | |
98 | ||
99 | public: | |
100 | n() : num_(0) {} | |
101 | int operator+(int i) const { return num_ + i; } | |
102 | n& operator+=(int i) { num_ += i; return *this; } | |
103 | bool operator==(int i) const { return num_ == i; } | |
104 | }; | |
105 | ||
106 | //[old_if_copyable_n_spec | |
107 | // Specialize `boost::is_copy_constructible` (no need for this on C++11). | |
108 | namespace boost { namespace contract { | |
109 | template<> | |
110 | struct is_old_value_copyable<n> : boost::false_type {}; | |
111 | } } | |
112 | //] | |
113 | ||
114 | int main() { | |
115 | int i = 0; // Copy constructor, copy and check old values. | |
116 | offset(i, 3); | |
117 | assert(i == 3); | |
118 | ||
119 | w j; // Expensive copy constructor, so never copy or check old values. | |
120 | offset(j, 3); | |
121 | assert(j == 3); | |
122 | ||
123 | p k; // No copy constructor, but still copy and check old values. | |
124 | offset(k, 3); | |
125 | assert(k == 3); | |
126 | ||
127 | n h; // No copy constructor, no compiler error but no old value checks. | |
128 | offset(h, 3); | |
129 | assert(h == 3); | |
130 | ||
131 | return 0; | |
132 | } | |
133 |