134 lines
3.4 KiB
C++
134 lines
3.4 KiB
C++
|
|
// Copyright (C) 2008-2018 Lorenzo Caminiti
|
|
// Distributed under the Boost Software License, Version 1.0 (see accompanying
|
|
// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
|
|
// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
|
|
|
|
#include <boost/contract.hpp>
|
|
#include <boost/type_traits.hpp>
|
|
#include <boost/noncopyable.hpp>
|
|
#include <cassert>
|
|
|
|
//[old_if_copyable_offset
|
|
template<typename T> // T might or might not be copyable.
|
|
void offset(T& x, int count) {
|
|
// No compiler error if T has no copy constructor...
|
|
boost::contract::old_ptr_if_copyable<T> old_x = BOOST_CONTRACT_OLDOF(x);
|
|
boost::contract::check c = boost::contract::function()
|
|
.postcondition([&] {
|
|
// ...but old value null if T has no copy constructor.
|
|
if(old_x) BOOST_CONTRACT_ASSERT(x == *old_x + count);
|
|
})
|
|
;
|
|
|
|
x += count;
|
|
}
|
|
//]
|
|
|
|
//[old_if_copyable_w_decl
|
|
// Copyable type but...
|
|
class w {
|
|
public:
|
|
w(w const&) { /* Some very expensive copy operation here... */ }
|
|
|
|
/* ... */
|
|
//]
|
|
w() : num_(0) {}
|
|
int operator+(int i) const { return num_ + i; }
|
|
w& operator+=(int i) { num_ += i; return *this; }
|
|
bool operator==(int i) const { return long(num_) == i; }
|
|
private:
|
|
unsigned long num_;
|
|
};
|
|
|
|
//[old_if_copyable_w_spec
|
|
// ...never copy old values for type `w` (because its copy is too expensive).
|
|
namespace boost { namespace contract {
|
|
template<>
|
|
struct is_old_value_copyable<w> : boost::false_type {};
|
|
} }
|
|
//]
|
|
|
|
//[old_if_copyable_p_decl
|
|
// Non-copyable type but...
|
|
class p : private boost::noncopyable {
|
|
int* num_;
|
|
|
|
friend struct boost::contract::old_value_copy<p>;
|
|
|
|
/* ... */
|
|
//]
|
|
public:
|
|
p() : num_(new int(0)) {}
|
|
~p() { delete num_; }
|
|
int operator+(int i) const { return *num_ + i; }
|
|
p& operator+=(int i) { *num_ += i; return *this; }
|
|
bool operator==(int i) const { return *num_ == i; }
|
|
};
|
|
|
|
//[old_if_copyable_p_spec
|
|
// ...still copy old values for type `p` (using a deep copy).
|
|
namespace boost { namespace contract {
|
|
template<>
|
|
struct old_value_copy<p> {
|
|
explicit old_value_copy(p const& old) {
|
|
*old_.num_ = *old.num_; // Deep copy pointed value.
|
|
}
|
|
|
|
p const& old() const { return old_; }
|
|
|
|
private:
|
|
p old_;
|
|
};
|
|
|
|
template<>
|
|
struct is_old_value_copyable<p> : boost::true_type {};
|
|
} }
|
|
//]
|
|
|
|
//[old_if_copyable_n_decl
|
|
class n { // Do not want to use boost::noncopyable but...
|
|
int num_;
|
|
|
|
private:
|
|
n(n const&); // ...unimplemented private copy constructor (so non-copyable).
|
|
|
|
/* ... */
|
|
//]
|
|
|
|
public:
|
|
n() : num_(0) {}
|
|
int operator+(int i) const { return num_ + i; }
|
|
n& operator+=(int i) { num_ += i; return *this; }
|
|
bool operator==(int i) const { return num_ == i; }
|
|
};
|
|
|
|
//[old_if_copyable_n_spec
|
|
// Specialize `boost::is_copy_constructible` (no need for this on C++11).
|
|
namespace boost { namespace contract {
|
|
template<>
|
|
struct is_old_value_copyable<n> : boost::false_type {};
|
|
} }
|
|
//]
|
|
|
|
int main() {
|
|
int i = 0; // Copy constructor, copy and check old values.
|
|
offset(i, 3);
|
|
assert(i == 3);
|
|
|
|
w j; // Expensive copy constructor, so never copy or check old values.
|
|
offset(j, 3);
|
|
assert(j == 3);
|
|
|
|
p k; // No copy constructor, but still copy and check old values.
|
|
offset(k, 3);
|
|
assert(k == 3);
|
|
|
|
n h; // No copy constructor, no compiler error but no old value checks.
|
|
offset(h, 3);
|
|
assert(h == 3);
|
|
|
|
return 0;
|
|
}
|
|
|