1 | // Copyright 2002-2008, Fernando Luis Cacciola Carballal. |
2 | // |
3 | // Distributed under the Boost Software License, Version 1.0. (See |
4 | // accompanying file LICENSE_1_0.txt or copy at |
5 | // http://www.boost.org/LICENSE_1_0.txt) |
6 | // |
7 | // Test program for "boost/utility/value_init.hpp" |
8 | // |
9 | // 21 Ago 2002 (Created) Fernando Cacciola |
10 | // 15 Jan 2008 (Added tests regarding compiler issues) Fernando Cacciola, Niels Dekker |
11 | // 23 May 2008 (Added tests regarding initialized_value) Niels Dekker |
12 | // 21 Ago 2008 (Added swap test) Niels Dekker |
13 | |
14 | #include <cstring> // For memcmp. |
15 | #include <iostream> |
16 | #include <string> |
17 | |
18 | #include "boost/utility/value_init.hpp" |
19 | #include <boost/shared_ptr.hpp> |
20 | |
21 | #ifdef __BORLANDC__ |
22 | #pragma hdrstop |
23 | #endif |
24 | |
25 | #include <boost/detail/lightweight_test.hpp> |
26 | |
27 | // |
28 | // Sample POD type |
29 | // |
30 | struct POD |
31 | { |
32 | POD () : f(0), c(0), i(0){} |
33 | |
34 | POD ( char c_, int i_, float f_ ) : f(f_), c(c_), i(i_) {} |
35 | |
36 | friend std::ostream& operator << ( std::ostream& os, POD const& pod ) |
37 | { return os << '(' << pod.c << ',' << pod.i << ',' << pod.f << ')' ; } |
38 | |
39 | friend bool operator == ( POD const& lhs, POD const& rhs ) |
40 | { return lhs.f == rhs.f && lhs.c == rhs.c && lhs.i == rhs.i ; } |
41 | |
42 | float f; |
43 | char c; |
44 | int i; |
45 | } ; |
46 | |
47 | // |
48 | // Sample non POD type |
49 | // |
50 | struct NonPODBase |
51 | { |
52 | virtual ~NonPODBase() {} |
53 | } ; |
54 | struct NonPOD : NonPODBase |
55 | { |
56 | NonPOD () : id() {} |
57 | explicit NonPOD ( std::string const& id_) : id(id_) {} |
58 | |
59 | friend std::ostream& operator << ( std::ostream& os, NonPOD const& npod ) |
60 | { return os << '(' << npod.id << ')' ; } |
61 | |
62 | friend bool operator == ( NonPOD const& lhs, NonPOD const& rhs ) |
63 | { return lhs.id == rhs.id ; } |
64 | |
65 | std::string id ; |
66 | } ; |
67 | |
68 | // |
69 | // Sample aggregate POD struct type |
70 | // Some compilers do not correctly value-initialize such a struct, for example: |
71 | // Borland C++ Report #51854, "Value-initialization: POD struct should be zero-initialized " |
72 | // http://qc.codegear.com/wc/qcmain.aspx?d=51854 |
73 | // |
74 | struct AggregatePODStruct |
75 | { |
76 | float f; |
77 | char c; |
78 | int i; |
79 | }; |
80 | |
81 | bool operator == ( AggregatePODStruct const& lhs, AggregatePODStruct const& rhs ) |
82 | { return lhs.f == rhs.f && lhs.c == rhs.c && lhs.i == rhs.i ; } |
83 | |
84 | // |
85 | // An aggregate struct that contains an std::string and an int. |
86 | // Pavel Kuznetsov (MetaCommunications Engineering) used a struct like |
87 | // this to reproduce the Microsoft Visual C++ compiler bug, reported as |
88 | // Feedback ID 100744, "Value-initialization in new-expression" |
89 | // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100744 |
90 | // |
91 | struct StringAndInt |
92 | { |
93 | std::string s; |
94 | int i; |
95 | }; |
96 | |
97 | bool operator == ( StringAndInt const& lhs, StringAndInt const& rhs ) |
98 | { return lhs.s == rhs.s && lhs.i == rhs.i ; } |
99 | |
100 | |
101 | // |
102 | // A struct that has an explicit (user defined) destructor. |
103 | // Some compilers do not correctly value-initialize such a struct, for example: |
104 | // Microsoft Visual C++, Feedback ID 100744, "Value-initialization in new-expression" |
105 | // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100744 |
106 | // |
107 | struct StructWithDestructor |
108 | { |
109 | int i; |
110 | ~StructWithDestructor() {} |
111 | }; |
112 | |
113 | bool operator == ( StructWithDestructor const& lhs, StructWithDestructor const& rhs ) |
114 | { return lhs.i == rhs.i ; } |
115 | |
116 | |
117 | // |
118 | // A struct that has a virtual function. |
119 | // Some compilers do not correctly value-initialize such a struct either, for example: |
120 | // Microsoft Visual C++, Feedback ID 100744, "Value-initialization in new-expression" |
121 | // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100744 |
122 | // |
123 | struct StructWithVirtualFunction |
124 | { |
125 | int i; |
126 | virtual void VirtualFunction(); |
127 | }; |
128 | |
129 | void StructWithVirtualFunction::VirtualFunction() |
130 | { |
131 | } |
132 | |
133 | bool operator == ( StructWithVirtualFunction const& lhs, StructWithVirtualFunction const& rhs ) |
134 | { return lhs.i == rhs.i ; } |
135 | |
136 | |
137 | // |
138 | // A struct that is derived from an aggregate POD struct. |
139 | // Some compilers do not correctly value-initialize such a struct, for example: |
140 | // GCC Bugzilla Bug 30111, "Value-initialization of POD base class doesn't initialize members", |
141 | // reported by Jonathan Wakely, http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30111 |
142 | // |
143 | struct DerivedFromAggregatePODStruct : AggregatePODStruct |
144 | { |
145 | DerivedFromAggregatePODStruct() : AggregatePODStruct() {} |
146 | }; |
147 | |
148 | // |
149 | // A struct that wraps an aggregate POD struct as data member. |
150 | // |
151 | struct AggregatePODStructWrapper |
152 | { |
153 | AggregatePODStructWrapper() : dataMember() {} |
154 | AggregatePODStruct dataMember; |
155 | }; |
156 | |
157 | bool operator == ( AggregatePODStructWrapper const& lhs, AggregatePODStructWrapper const& rhs ) |
158 | { return lhs.dataMember == rhs.dataMember ; } |
159 | |
160 | typedef unsigned char ArrayOfBytes[256]; |
161 | |
162 | |
163 | // |
164 | // A struct that allows testing whether the appropriate copy functions are called. |
165 | // |
166 | struct CopyFunctionCallTester |
167 | { |
168 | bool is_copy_constructed; |
169 | bool is_assignment_called; |
170 | |
171 | CopyFunctionCallTester() |
172 | : is_copy_constructed(false), is_assignment_called(false) {} |
173 | |
174 | CopyFunctionCallTester(const CopyFunctionCallTester & ) |
175 | : is_copy_constructed(true), is_assignment_called(false) {} |
176 | |
177 | CopyFunctionCallTester & operator=(const CopyFunctionCallTester & ) |
178 | { |
179 | is_assignment_called = true ; |
180 | return *this ; |
181 | } |
182 | }; |
183 | |
184 | |
185 | // |
186 | // A struct that allows testing whether its customized swap function is called. |
187 | // |
188 | struct SwapFunctionCallTester |
189 | { |
190 | bool is_custom_swap_called; |
191 | int data; |
192 | |
193 | SwapFunctionCallTester() |
194 | : is_custom_swap_called(false), data(0) {} |
195 | |
196 | SwapFunctionCallTester(const SwapFunctionCallTester & arg) |
197 | : is_custom_swap_called(false), data(arg.data) {} |
198 | |
199 | void swap(SwapFunctionCallTester & arg) |
200 | { |
201 | std::swap(a&: data, b&: arg.data); |
202 | is_custom_swap_called = true; |
203 | arg.is_custom_swap_called = true; |
204 | } |
205 | }; |
206 | |
207 | void swap(SwapFunctionCallTester & lhs, SwapFunctionCallTester & rhs) |
208 | { |
209 | lhs.swap(arg&: rhs); |
210 | } |
211 | |
212 | |
213 | |
214 | template<class T> |
215 | void check_initialized_value ( T const& y ) |
216 | { |
217 | T initializedValue = boost::initialized_value ; |
218 | BOOST_TEST ( y == initializedValue ) ; |
219 | } |
220 | |
221 | #ifdef __BORLANDC__ |
222 | #if __BORLANDC__ == 0x582 |
223 | void check_initialized_value( NonPOD const& ) |
224 | { |
225 | // The initialized_value check is skipped for Borland 5.82 |
226 | // and this type (NonPOD), because the following statement |
227 | // won't compile on this particular compiler version: |
228 | // NonPOD initializedValue = boost::initialized_value() ; |
229 | // |
230 | // This is caused by a compiler bug, that is fixed with a newer version |
231 | // of the Borland compiler. The Release Notes for Delphi(R) 2007 for |
232 | // Win32(R) and C++Builder(R) 2007 (http://dn.codegear.com/article/36575) |
233 | // say about similar statements: |
234 | // both of these statements now compile but under 5.82 got the error: |
235 | // Error E2015: Ambiguity between 'V::V(const A &)' and 'V::V(const V &)' |
236 | } |
237 | #endif |
238 | #endif |
239 | |
240 | // |
241 | // This test function tests boost::value_initialized<T> for a specific type T. |
242 | // The first argument (y) is assumed have the value of a value-initialized object. |
243 | // Returns true on success. |
244 | // |
245 | template<class T> |
246 | bool test ( T const& y, T const& z ) |
247 | { |
248 | const int errors_before_test = boost::detail::test_errors(); |
249 | |
250 | check_initialized_value(y); |
251 | |
252 | boost::value_initialized<T> x ; |
253 | BOOST_TEST ( y == x ) ; |
254 | BOOST_TEST ( y == boost::get(x) ) ; |
255 | |
256 | static_cast<T&>(x) = z ; |
257 | boost::get(x) = z ; |
258 | BOOST_TEST ( x == z ) ; |
259 | |
260 | boost::value_initialized<T> const x_c ; |
261 | BOOST_TEST ( y == x_c ) ; |
262 | BOOST_TEST ( y == boost::get(x_c) ) ; |
263 | T& x_c_ref = const_cast<T&>( boost::get(x_c) ) ; |
264 | x_c_ref = z ; |
265 | BOOST_TEST ( x_c == z ) ; |
266 | |
267 | boost::value_initialized<T> const copy1 = x; |
268 | BOOST_TEST ( boost::get(copy1) == boost::get(x) ) ; |
269 | |
270 | boost::value_initialized<T> copy2; |
271 | copy2 = x; |
272 | BOOST_TEST ( boost::get(copy2) == boost::get(x) ) ; |
273 | |
274 | boost::shared_ptr<boost::value_initialized<T> > ptr( new boost::value_initialized<T> ); |
275 | BOOST_TEST ( y == *ptr ) ; |
276 | |
277 | #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) |
278 | boost::value_initialized<T const> cx ; |
279 | BOOST_TEST ( y == cx ) ; |
280 | BOOST_TEST ( y == boost::get(cx) ) ; |
281 | |
282 | boost::value_initialized<T const> const cx_c ; |
283 | BOOST_TEST ( y == cx_c ) ; |
284 | BOOST_TEST ( y == boost::get(cx_c) ) ; |
285 | #endif |
286 | |
287 | return boost::detail::test_errors() == errors_before_test ; |
288 | } |
289 | |
290 | int main(int, char **) |
291 | { |
292 | BOOST_TEST ( test( 0,1234 ) ) ; |
293 | BOOST_TEST ( test( 0.0,12.34 ) ) ; |
294 | BOOST_TEST ( test( POD(0,0,0.0), POD('a',1234,56.78f) ) ) ; |
295 | BOOST_TEST ( test( NonPOD( std::string() ), NonPOD( std::string("something" ) ) ) ) ; |
296 | |
297 | NonPOD NonPOD_object( std::string("NonPOD_object" ) ); |
298 | BOOST_TEST ( test<NonPOD *>( 0, &NonPOD_object ) ) ; |
299 | |
300 | AggregatePODStruct zeroInitializedAggregatePODStruct = { .f: 0.0f, .c: '\0', .i: 0 }; |
301 | AggregatePODStruct nonZeroInitializedAggregatePODStruct = { .f: 1.25f, .c: 'a', .i: -1 }; |
302 | BOOST_TEST ( test(zeroInitializedAggregatePODStruct, nonZeroInitializedAggregatePODStruct) ); |
303 | |
304 | StringAndInt stringAndInt0; |
305 | StringAndInt stringAndInt1; |
306 | stringAndInt0.i = 0; |
307 | stringAndInt1.i = 1; |
308 | stringAndInt1.s = std::string("1" ); |
309 | BOOST_TEST ( test(stringAndInt0, stringAndInt1) ); |
310 | |
311 | StructWithDestructor structWithDestructor0; |
312 | StructWithDestructor structWithDestructor1; |
313 | structWithDestructor0.i = 0; |
314 | structWithDestructor1.i = 1; |
315 | BOOST_TEST ( test(structWithDestructor0, structWithDestructor1) ); |
316 | |
317 | StructWithVirtualFunction structWithVirtualFunction0; |
318 | StructWithVirtualFunction structWithVirtualFunction1; |
319 | structWithVirtualFunction0.i = 0; |
320 | structWithVirtualFunction1.i = 1; |
321 | BOOST_TEST ( test(structWithVirtualFunction0, structWithVirtualFunction1) ); |
322 | |
323 | DerivedFromAggregatePODStruct derivedFromAggregatePODStruct0; |
324 | DerivedFromAggregatePODStruct derivedFromAggregatePODStruct1; |
325 | static_cast<AggregatePODStruct &>(derivedFromAggregatePODStruct0) = zeroInitializedAggregatePODStruct; |
326 | static_cast<AggregatePODStruct &>(derivedFromAggregatePODStruct1) = nonZeroInitializedAggregatePODStruct; |
327 | BOOST_TEST ( test(derivedFromAggregatePODStruct0, derivedFromAggregatePODStruct1) ); |
328 | |
329 | AggregatePODStructWrapper aggregatePODStructWrapper0; |
330 | AggregatePODStructWrapper aggregatePODStructWrapper1; |
331 | aggregatePODStructWrapper0.dataMember = zeroInitializedAggregatePODStruct; |
332 | aggregatePODStructWrapper1.dataMember = nonZeroInitializedAggregatePODStruct; |
333 | BOOST_TEST ( test(aggregatePODStructWrapper0, aggregatePODStructWrapper1) ); |
334 | |
335 | ArrayOfBytes zeroInitializedArrayOfBytes = { 0 }; |
336 | boost::value_initialized<ArrayOfBytes> valueInitializedArrayOfBytes; |
337 | BOOST_TEST (std::memcmp(get(valueInitializedArrayOfBytes), zeroInitializedArrayOfBytes, sizeof(ArrayOfBytes)) == 0); |
338 | |
339 | boost::value_initialized<ArrayOfBytes> valueInitializedArrayOfBytes2; |
340 | valueInitializedArrayOfBytes2 = valueInitializedArrayOfBytes; |
341 | BOOST_TEST (std::memcmp(get(valueInitializedArrayOfBytes), get(valueInitializedArrayOfBytes2), sizeof(ArrayOfBytes)) == 0); |
342 | |
343 | boost::value_initialized<CopyFunctionCallTester> copyFunctionCallTester1; |
344 | BOOST_TEST ( ! get(copyFunctionCallTester1).is_copy_constructed); |
345 | BOOST_TEST ( ! get(copyFunctionCallTester1).is_assignment_called); |
346 | |
347 | boost::value_initialized<CopyFunctionCallTester> copyFunctionCallTester2 = boost::value_initialized<CopyFunctionCallTester>(copyFunctionCallTester1); |
348 | BOOST_TEST ( get(copyFunctionCallTester2).is_copy_constructed); |
349 | BOOST_TEST ( ! get(copyFunctionCallTester2).is_assignment_called); |
350 | |
351 | boost::value_initialized<CopyFunctionCallTester> copyFunctionCallTester3; |
352 | copyFunctionCallTester3 = boost::value_initialized<CopyFunctionCallTester>(copyFunctionCallTester1); |
353 | BOOST_TEST ( ! get(copyFunctionCallTester3).is_copy_constructed); |
354 | BOOST_TEST ( get(copyFunctionCallTester3).is_assignment_called); |
355 | |
356 | boost::value_initialized<SwapFunctionCallTester> swapFunctionCallTester1; |
357 | boost::value_initialized<SwapFunctionCallTester> swapFunctionCallTester2; |
358 | get(x&: swapFunctionCallTester1).data = 1; |
359 | get(x&: swapFunctionCallTester2).data = 2; |
360 | boost::swap(lhs&: swapFunctionCallTester1, rhs&: swapFunctionCallTester2); |
361 | BOOST_TEST( get(swapFunctionCallTester1).data == 2 ); |
362 | BOOST_TEST( get(swapFunctionCallTester2).data == 1 ); |
363 | BOOST_TEST( get(swapFunctionCallTester1).is_custom_swap_called ); |
364 | BOOST_TEST( get(swapFunctionCallTester2).is_custom_swap_called ); |
365 | |
366 | return boost::report_errors(); |
367 | } |
368 | |
369 | |
370 | |