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