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
7 #include <boost/contract.hpp>
13 class circular_buffer :
14 private boost::contract::constructor_precondition<circular_buffer> {
16 void invariant() const {
17 if(!moved()) { // Do not check (some) invariants for moved-from objects.
18 BOOST_CONTRACT_ASSERT(index() < size());
20 // More invariants here that hold also for moved-from objects (e.g.,
21 // all assertions necessary to successfully destroy moved-from objects).
25 circular_buffer(circular_buffer&& other) :
26 boost::contract::constructor_precondition<circular_buffer>([&] {
27 BOOST_CONTRACT_ASSERT(!other.moved());
30 boost::contract::check c = boost::contract::constructor(this)
32 BOOST_CONTRACT_ASSERT(!moved());
33 BOOST_CONTRACT_ASSERT(other.moved());
37 move(std::forward<circular_buffer>(other));
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)
45 BOOST_CONTRACT_ASSERT(!other.moved());
48 BOOST_CONTRACT_ASSERT(!moved());
49 BOOST_CONTRACT_ASSERT(other.moved());
53 return move(std::forward<circular_buffer>(other));
57 // Moved-from can always be destroyed (in fact no preconditions).
58 boost::contract::check c = boost::contract::destructor(this);
62 boost::contract::check c = boost::contract::public_function(this);
73 explicit circular_buffer(std::vector<char> const& data,
75 boost::contract::constructor_precondition<circular_buffer>([&] {
76 BOOST_CONTRACT_ASSERT(start < data.size());
82 boost::contract::check c = boost::contract::constructor(this)
84 BOOST_CONTRACT_ASSERT(!moved());
90 circular_buffer(circular_buffer const& other) :
91 boost::contract::constructor_precondition<circular_buffer>([&] {
92 BOOST_CONTRACT_ASSERT(!other.moved());
95 boost::contract::check c = boost::contract::constructor(this)
97 BOOST_CONTRACT_ASSERT(!moved());
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)
109 BOOST_CONTRACT_ASSERT(!other.moved());
112 BOOST_CONTRACT_ASSERT(!moved());
120 boost::contract::check c = boost::contract::public_function(this)
122 BOOST_CONTRACT_ASSERT(!moved());
126 unsigned i = index_++;
127 if(index_ == data_.size()) index_ = 0; // Circular.
132 circular_buffer& copy(circular_buffer const& other) {
134 index_ = other.index_;
139 circular_buffer& move(circular_buffer&& other) {
140 data_ = std::move(other.data_);
141 index_ = std::move(other.index_);
143 other.moved_ = true; // Mark moved-from object.
147 std::vector<char> data_;
151 unsigned index() const {
152 boost::contract::check c = boost::contract::public_function(this);
156 unsigned size() const {
157 boost::contract::check c = boost::contract::public_function(this);
164 boost::contract::set_precondition_failure(
165 [] (boost::contract::from) { throw err(); });
168 circular_buffer x({'a', 'b', 'c', 'd'}, 2);
169 assert(x.read() == 'c');
171 circular_buffer y1 = x; // Copy constructor.
172 assert(y1.read() == 'd');
173 assert(x.read() == 'd');
175 circular_buffer y2({'h'});
176 y2 = x; // Copy assignment.
177 assert(y2.read() == 'a');
178 assert(x.read() == 'a');
180 circular_buffer z1 = std::move(x); // Move constructor.
181 assert(z1.read() == 'b');
182 // Calling `x.read()` would fail `!moved()` precondition.
184 x = y1; // Moved-from `x` can be copy assigned.
185 assert(x.read() == 'a');
186 assert(y1.read() == 'a');
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.
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.
197 } // Moved-from `y2` can be destroyed.