]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/contract/example/features/move.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / contract / example / features / move.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 <vector>
9 #include <utility>
10 #include <cassert>
11
12 //[move
13 class circular_buffer :
14 private boost::contract::constructor_precondition<circular_buffer> {
15 public:
16 void invariant() const {
17 if(!moved()) { // Do not check (some) invariants for moved-from objects.
18 BOOST_CONTRACT_ASSERT(index() < size());
19 }
20 // More invariants here that hold also for moved-from objects (e.g.,
21 // all assertions necessary to successfully destroy moved-from objects).
22 }
23
24 // Move constructor.
25 circular_buffer(circular_buffer&& other) :
26 boost::contract::constructor_precondition<circular_buffer>([&] {
27 BOOST_CONTRACT_ASSERT(!other.moved());
28 })
29 {
30 boost::contract::check c = boost::contract::constructor(this)
31 .postcondition([&] {
32 BOOST_CONTRACT_ASSERT(!moved());
33 BOOST_CONTRACT_ASSERT(other.moved());
34 })
35 ;
36
37 move(std::forward<circular_buffer>(other));
38 }
39
40 // Move assignment.
41 circular_buffer& operator=(circular_buffer&& other) {
42 // Moved-from can be (move) assigned (so no pre `!moved()` here).
43 boost::contract::check c = boost::contract::public_function(this)
44 .precondition([&] {
45 BOOST_CONTRACT_ASSERT(!other.moved());
46 })
47 .postcondition([&] {
48 BOOST_CONTRACT_ASSERT(!moved());
49 BOOST_CONTRACT_ASSERT(other.moved());
50 })
51 ;
52
53 return move(std::forward<circular_buffer>(other));
54 }
55
56 ~circular_buffer() {
57 // Moved-from can always be destroyed (in fact no preconditions).
58 boost::contract::check c = boost::contract::destructor(this);
59 }
60
61 bool moved() const {
62 boost::contract::check c = boost::contract::public_function(this);
63 return moved_;
64 }
65
66 private:
67 bool moved_;
68
69 /* ... */
70 //]
71
72 public:
73 explicit circular_buffer(std::vector<char> const& data,
74 unsigned start = 0) :
75 boost::contract::constructor_precondition<circular_buffer>([&] {
76 BOOST_CONTRACT_ASSERT(start < data.size());
77 }),
78 moved_(false),
79 data_(data),
80 index_(start)
81 {
82 boost::contract::check c = boost::contract::constructor(this)
83 .postcondition([&] {
84 BOOST_CONTRACT_ASSERT(!moved());
85 })
86 ;
87 }
88
89 // Copy constructor.
90 circular_buffer(circular_buffer const& other) :
91 boost::contract::constructor_precondition<circular_buffer>([&] {
92 BOOST_CONTRACT_ASSERT(!other.moved());
93 })
94 {
95 boost::contract::check c = boost::contract::constructor(this)
96 .postcondition([&] {
97 BOOST_CONTRACT_ASSERT(!moved());
98 })
99 ;
100
101 copy(other);
102 }
103
104 // Copy assignment.
105 circular_buffer& operator=(circular_buffer const& other) {
106 // Moved-from can be (copy) assigned (so no pre `!moved()` here).
107 boost::contract::check c = boost::contract::public_function(this)
108 .precondition([&] {
109 BOOST_CONTRACT_ASSERT(!other.moved());
110 })
111 .postcondition([&] {
112 BOOST_CONTRACT_ASSERT(!moved());
113 })
114 ;
115
116 return copy(other);
117 }
118
119 char read() {
120 boost::contract::check c = boost::contract::public_function(this)
121 .precondition([&] {
122 BOOST_CONTRACT_ASSERT(!moved());
123 })
124 ;
125
126 unsigned i = index_++;
127 if(index_ == data_.size()) index_ = 0; // Circular.
128 return data_.at(i);
129 }
130
131 private:
132 circular_buffer& copy(circular_buffer const& other) {
133 data_ = other.data_;
134 index_ = other.index_;
135 moved_ = false;
136 return *this;
137 }
138
139 circular_buffer& move(circular_buffer&& other) {
140 data_ = std::move(other.data_);
141 index_ = std::move(other.index_);
142 moved_ = false;
143 other.moved_ = true; // Mark moved-from object.
144 return *this;
145 }
146
147 std::vector<char> data_;
148 unsigned index_;
149
150 public:
151 unsigned index() const {
152 boost::contract::check c = boost::contract::public_function(this);
153 return index_;
154 }
155
156 unsigned size() const {
157 boost::contract::check c = boost::contract::public_function(this);
158 return data_.size();
159 }
160 };
161
162 int main() {
163 struct err {};
164 boost::contract::set_precondition_failure(
165 [] (boost::contract::from) { throw err(); });
166
167 {
168 circular_buffer x({'a', 'b', 'c', 'd'}, 2);
169 assert(x.read() == 'c');
170
171 circular_buffer y1 = x; // Copy constructor.
172 assert(y1.read() == 'd');
173 assert(x.read() == 'd');
174
175 circular_buffer y2({'h'});
176 y2 = x; // Copy assignment.
177 assert(y2.read() == 'a');
178 assert(x.read() == 'a');
179
180 circular_buffer z1 = std::move(x); // Move constructor.
181 assert(z1.read() == 'b');
182 // Calling `x.read()` would fail `!moved()` precondition.
183
184 x = y1; // Moved-from `x` can be copy assigned.
185 assert(x.read() == 'a');
186 assert(y1.read() == 'a');
187
188 circular_buffer z2({'k'});
189 z2 = std::move(x); // Move assignment.
190 assert(z2.read() == 'b');
191 // Calling `x.read()` would fail `!moved()` precondition.
192
193 x = std::move(y2); // Moved-from `x` can be move assigned.
194 assert(x.read() == 'b');
195 // Calling `y2.read()` would fail `!moved()` precondition.
196
197 } // Moved-from `y2` can be destroyed.
198
199 return 0;
200 }
201