File: old_if_copyable.cpp

package info (click to toggle)
boost1.83 1.83.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 545,632 kB
  • sloc: cpp: 3,857,086; xml: 125,552; ansic: 34,414; python: 25,887; asm: 5,276; sh: 4,799; ada: 1,681; makefile: 1,629; perl: 1,212; pascal: 1,139; sql: 810; yacc: 478; ruby: 102; lisp: 24; csh: 6
file content (133 lines) | stat: -rw-r--r-- 3,509 bytes parent folder | download | duplicates (11)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

// 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;
}