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/optional.hpp>
9 #include <string>
10 #include <sstream>
11 #include <cassert>
12
13 class lines {
14 public:
15 virtual std::string str(boost::contract::virtual_* v = 0) const = 0;
16 virtual std::string& str(boost::contract::virtual_* v = 0) = 0;
17
18 virtual void put(std::string const& x,
19 boost::contract::virtual_* v = 0) = 0;
20
21 virtual void put(char x, boost::contract::virtual_* v = 0) = 0;
22
23 virtual void put(int x, bool tab = false,
24 boost::contract::virtual_* v = 0) = 0;
25 };
26
str(boost::contract::virtual_ * v) const27 std::string lines::str(boost::contract::virtual_* v) const {
28 std::string result;
29 boost::contract::check c = boost::contract::public_function(v, result, this)
30 .postcondition([&] (std::string const& result) {
31 if(result != "") BOOST_CONTRACT_ASSERT(*result.rbegin() == '\n');
32 })
33 ;
34 assert(false);
35 return result;
36 }
37
str(boost::contract::virtual_ * v)38 std::string& lines::str(boost::contract::virtual_* v) {
39 boost::optional<std::string&> result;
40 boost::contract::check c = boost::contract::public_function(v, result, this)
41 .postcondition([&] (boost::optional<std::string const&> const& result) {
42 if(*result != "") BOOST_CONTRACT_ASSERT(*result->rbegin() == '\n');
43 })
44 ;
45 assert(false);
46 return *result;
47 }
48
put(std::string const & x,boost::contract::virtual_ * v)49 void lines::put(std::string const& x, boost::contract::virtual_* v) {
50 boost::contract::check c = boost::contract::public_function(v, this)
51 .precondition([&] {
52 BOOST_CONTRACT_ASSERT(*x.rbegin() != '\n');
53 })
54 ;
55 assert(false);
56 }
57
put(char x,boost::contract::virtual_ * v)58 void lines::put(char x, boost::contract::virtual_* v) {
59 boost::contract::check c = boost::contract::public_function(v, this)
60 .precondition([&] {
61 BOOST_CONTRACT_ASSERT(x != '\n');
62 })
63 ;
64 assert(false);
65 }
66
put(int x,bool tab,boost::contract::virtual_ * v)67 void lines::put(int x, bool tab,
68 boost::contract::virtual_* v) {
69 boost::contract::check c = boost::contract::public_function(v, this)
70 .precondition([&] {
71 BOOST_CONTRACT_ASSERT(x >= 0);
72 })
73 ;
74 assert(false);
75 }
76
77 //[overload
78 class string_lines
79 #define BASES public lines
80 : BASES
81 {
82 public:
83 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
84 #undef BASES
85
BOOST_CONTRACT_OVERRIDES(str)86 BOOST_CONTRACT_OVERRIDES(str) // Invoked only once for all `str` overloads.
87
88 std::string str(boost::contract::virtual_* v = 0) const /* override */ {
89 std::string result;
90 boost::contract::check c = boost::contract::public_function<
91 override_str>(
92 v, result,
93 // `static_cast` resolves overloaded function pointer ambiguities.
94 static_cast<std::string (string_lines::*)(
95 boost::contract::virtual_*) const>(&string_lines::str),
96 this
97 );
98
99 return result = str_;
100 }
101
102 // Overload on (absence of) `const` qualifier.
str(boost::contract::virtual_ * v=0)103 std::string& str(boost::contract::virtual_* v = 0) /* override */ {
104 boost::contract::check c = boost::contract::public_function<
105 override_str>(
106 v, str_,
107 // `static_cast` resolves overloaded function pointer ambiguities.
108 static_cast<std::string& (string_lines::*)(
109 boost::contract::virtual_*)>(&string_lines::str),
110 this
111 );
112
113 return str_;
114 }
115
BOOST_CONTRACT_OVERRIDES(put)116 BOOST_CONTRACT_OVERRIDES(put) // Invoked only once for all `put` overloads.
117
118 void put(std::string const& x,
119 boost::contract::virtual_* v = 0) /* override */ {
120 boost::contract::old_ptr<std::string> old_str =
121 BOOST_CONTRACT_OLDOF(v, str());
122 boost::contract::check c = boost::contract::public_function<
123 override_put>(
124 v,
125 // `static_cast` resolves overloaded function pointer ambiguities.
126 static_cast<void (string_lines::*)(std::string const&,
127 boost::contract::virtual_*)>(&string_lines::put),
128 this, x
129 )
130 .postcondition([&] {
131 BOOST_CONTRACT_ASSERT(str() == *old_str + x + '\n');
132 })
133 ;
134
135 str_ = str_ + x + '\n';
136 }
137
138 // Overload on argument type.
put(char x,boost::contract::virtual_ * v=0)139 void put(char x, boost::contract::virtual_* v = 0) /* override */ {
140 boost::contract::old_ptr<std::string> old_str =
141 BOOST_CONTRACT_OLDOF(v, str());
142 boost::contract::check c = boost::contract::public_function<
143 override_put>(
144 v,
145 // `static_cast` resolves overloaded function pointer ambiguities.
146 static_cast<void (string_lines::*)(char,
147 boost::contract::virtual_*)>(&string_lines::put),
148 this, x
149 )
150 .postcondition([&] {
151 BOOST_CONTRACT_ASSERT(str() == *old_str + x + '\n');
152 })
153 ;
154
155 str_ = str_ + x + '\n';
156 }
157
158 // Overload on argument type and arity (also with default parameter).
put(int x,bool tab=false,boost::contract::virtual_ * v=0)159 void put(int x, bool tab = false,
160 boost::contract::virtual_* v = 0) /* override */ {
161 boost::contract::old_ptr<std::string> old_str =
162 BOOST_CONTRACT_OLDOF(v, str());
163 boost::contract::check c = boost::contract::public_function<
164 override_put>(
165 v,
166 // `static_cast` resolves overloaded function pointer ambiguities.
167 static_cast<void (string_lines::*)(int, bool,
168 boost::contract::virtual_*)>(&string_lines::put),
169 this, x, tab
170 )
171 .postcondition([&] {
172 std::ostringstream s;
173 s << x;
174 BOOST_CONTRACT_ASSERT(
175 str() == *old_str + (tab ? "\t" : "") + s.str() + '\n');
176 })
177 ;
178
179 std::ostringstream s;
180 s << str_ << (tab ? "\t" : "") << x << '\n';
181 str_ = s.str();
182 }
183
184 private:
185 std::string str_;
186 };
187 //]
188
main()189 int main() {
190 string_lines s;
191 s.put("abc");
192 assert(s.str() == "abc\n");
193 s.put('x');
194 assert(s.str() == "abc\nx\n");
195 s.put(10);
196 assert(s.str() == "abc\nx\n10\n");
197 s.put(20, true);
198 lines const& l = s;
199 assert(l.str() == "abc\nx\n10\n\t20\n");
200 return 0;
201 }
202
203