]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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(data, 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(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 = { 0.0f, '\0', 0 }; | |
301 | AggregatePODStruct nonZeroInitializedAggregatePODStruct = { 1.25f, 'a', -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(swapFunctionCallTester1).data = 1; | |
359 | get(swapFunctionCallTester2).data = 2; | |
360 | boost::swap(swapFunctionCallTester1, 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 |