Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / contract / example / features / old_if_copyable.cpp
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:
32     w(w const&) { /* Some very expensive copy operation here... */ }
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