• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
20 #ifdef BOOST_BORLANDC
21 #pragma hdrstop
22 #endif
23 
24 #include <boost/core/lightweight_test.hpp>
25 #include <boost/config/workaround.hpp>
26 
27 //
28 // Sample POD type
29 //
30 struct POD
31 {
PODPOD32   POD () : f(0), c(0), i(0){}
33 
PODPOD34   POD ( char c_, int i_, float f_ ) : f(f_), c(c_), i(i_) {}
35 
operator <<(std::ostream & os,POD const & pod)36   friend std::ostream& operator << ( std::ostream& os, POD const& pod )
37     { return os << '(' << pod.c << ',' << pod.i << ',' << pod.f << ')' ; }
38 
operator ==(POD const & lhs,POD const & rhs)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 {
~NonPODBaseNonPODBase52   virtual ~NonPODBase() {}
53 } ;
54 struct NonPOD : NonPODBase
55 {
NonPODNonPOD56   NonPOD () : id() {}
NonPODNonPOD57   explicit NonPOD ( std::string const& id_) : id(id_) {}
58 
operator <<(std::ostream & os,NonPOD const & npod)59   friend std::ostream& operator << ( std::ostream& os, NonPOD const& npod )
60     { return os << '(' << npod.id << ')' ; }
61 
operator ==(NonPOD const & lhs,NonPOD const & rhs)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 
operator ==(AggregatePODStruct const & lhs,AggregatePODStruct const & rhs)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 
operator ==(StringAndInt const & lhs,StringAndInt const & rhs)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;
~StructWithDestructorStructWithDestructor110   ~StructWithDestructor() {}
111 };
112 
operator ==(StructWithDestructor const & lhs,StructWithDestructor const & rhs)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 
VirtualFunction()129 void StructWithVirtualFunction::VirtualFunction()
130 {
131 }
132 
operator ==(StructWithVirtualFunction const & lhs,StructWithVirtualFunction const & rhs)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 {
DerivedFromAggregatePODStructDerivedFromAggregatePODStruct145   DerivedFromAggregatePODStruct() : AggregatePODStruct() {}
146 };
147 
148 //
149 // A struct that wraps an aggregate POD struct as data member.
150 //
151 struct AggregatePODStructWrapper
152 {
AggregatePODStructWrapperAggregatePODStructWrapper153   AggregatePODStructWrapper() : dataMember() {}
154   AggregatePODStruct dataMember;
155 };
156 
operator ==(AggregatePODStructWrapper const & lhs,AggregatePODStructWrapper const & rhs)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 
CopyFunctionCallTesterCopyFunctionCallTester171   CopyFunctionCallTester()
172   : is_copy_constructed(false), is_assignment_called(false) {}
173 
CopyFunctionCallTesterCopyFunctionCallTester174   CopyFunctionCallTester(const CopyFunctionCallTester & )
175   : is_copy_constructed(true), is_assignment_called(false) {}
176 
operator =CopyFunctionCallTester177   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 
SwapFunctionCallTesterSwapFunctionCallTester193   SwapFunctionCallTester()
194   : is_custom_swap_called(false), data(0) {}
195 
SwapFunctionCallTesterSwapFunctionCallTester196   SwapFunctionCallTester(const SwapFunctionCallTester & arg)
197   : is_custom_swap_called(false), data(arg.data) {}
198 
swapSwapFunctionCallTester199   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 
swap(SwapFunctionCallTester & lhs,SwapFunctionCallTester & rhs)207 void swap(SwapFunctionCallTester & lhs, SwapFunctionCallTester & rhs)
208 {
209   lhs.swap(rhs);
210 }
211 
212 
213 
214 template<class T>
check_initialized_value(T const & y)215 void check_initialized_value ( T const& y )
216 {
217   T initializedValue = boost::initialized_value ;
218   BOOST_TEST ( y == initializedValue ) ;
219 }
220 
221 #ifdef  BOOST_BORLANDC
222 #if BOOST_BORLANDC == 0x582
check_initialized_value(NonPOD const &)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>
test(T const & y,T const & z)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   {
275     boost::value_initialized<T> * ptr = new boost::value_initialized<T>;
276     BOOST_TEST ( y == *ptr ) ;
277     delete ptr;
278   }
279 
280 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
281   boost::value_initialized<T const> cx ;
282   BOOST_TEST ( y == cx ) ;
283   BOOST_TEST ( y == boost::get(cx) ) ;
284 
285   boost::value_initialized<T const> const cx_c ;
286   BOOST_TEST ( y == cx_c ) ;
287   BOOST_TEST ( y == boost::get(cx_c) ) ;
288 #endif
289 
290   return boost::detail::test_errors() == errors_before_test ;
291 }
292 
main()293 int main()
294 {
295   BOOST_TEST ( test( 0,1234 ) ) ;
296   BOOST_TEST ( test( 0.0,12.34 ) ) ;
297   BOOST_TEST ( test( POD(0,0,0.0), POD('a',1234,56.78f) ) ) ;
298   BOOST_TEST ( test( NonPOD( std::string() ), NonPOD( std::string("something") ) ) ) ;
299 
300   NonPOD NonPOD_object( std::string("NonPOD_object") );
301   BOOST_TEST ( test<NonPOD *>( 0, &NonPOD_object ) ) ;
302 
303   AggregatePODStruct zeroInitializedAggregatePODStruct = { 0.0f, '\0', 0 };
304   AggregatePODStruct nonZeroInitializedAggregatePODStruct = { 1.25f, 'a', -1 };
305   BOOST_TEST ( test(zeroInitializedAggregatePODStruct, nonZeroInitializedAggregatePODStruct) );
306 
307   StringAndInt stringAndInt0;
308   StringAndInt stringAndInt1;
309   stringAndInt0.i = 0;
310   stringAndInt1.i = 1;
311   stringAndInt1.s = std::string("1");
312   BOOST_TEST ( test(stringAndInt0, stringAndInt1) );
313 
314   StructWithDestructor structWithDestructor0;
315   StructWithDestructor structWithDestructor1;
316   structWithDestructor0.i = 0;
317   structWithDestructor1.i = 1;
318   BOOST_TEST ( test(structWithDestructor0, structWithDestructor1) );
319 
320   StructWithVirtualFunction structWithVirtualFunction0;
321   StructWithVirtualFunction structWithVirtualFunction1;
322   structWithVirtualFunction0.i = 0;
323   structWithVirtualFunction1.i = 1;
324   BOOST_TEST ( test(structWithVirtualFunction0, structWithVirtualFunction1) );
325 
326   DerivedFromAggregatePODStruct derivedFromAggregatePODStruct0;
327   DerivedFromAggregatePODStruct derivedFromAggregatePODStruct1;
328   static_cast<AggregatePODStruct &>(derivedFromAggregatePODStruct0) = zeroInitializedAggregatePODStruct;
329   static_cast<AggregatePODStruct &>(derivedFromAggregatePODStruct1) = nonZeroInitializedAggregatePODStruct;
330   BOOST_TEST ( test(derivedFromAggregatePODStruct0, derivedFromAggregatePODStruct1) );
331 
332   AggregatePODStructWrapper aggregatePODStructWrapper0;
333   AggregatePODStructWrapper aggregatePODStructWrapper1;
334   aggregatePODStructWrapper0.dataMember = zeroInitializedAggregatePODStruct;
335   aggregatePODStructWrapper1.dataMember = nonZeroInitializedAggregatePODStruct;
336   BOOST_TEST ( test(aggregatePODStructWrapper0, aggregatePODStructWrapper1) );
337 
338   ArrayOfBytes zeroInitializedArrayOfBytes = { 0 };
339   boost::value_initialized<ArrayOfBytes> valueInitializedArrayOfBytes;
340   BOOST_TEST (std::memcmp(get(valueInitializedArrayOfBytes), zeroInitializedArrayOfBytes, sizeof(ArrayOfBytes)) == 0);
341 
342   boost::value_initialized<ArrayOfBytes> valueInitializedArrayOfBytes2;
343   valueInitializedArrayOfBytes2 = valueInitializedArrayOfBytes;
344   BOOST_TEST (std::memcmp(get(valueInitializedArrayOfBytes), get(valueInitializedArrayOfBytes2), sizeof(ArrayOfBytes)) == 0);
345 
346   boost::value_initialized<CopyFunctionCallTester> copyFunctionCallTester1;
347   BOOST_TEST ( ! get(copyFunctionCallTester1).is_copy_constructed);
348   BOOST_TEST ( ! get(copyFunctionCallTester1).is_assignment_called);
349 
350   boost::value_initialized<CopyFunctionCallTester> copyFunctionCallTester2 = boost::value_initialized<CopyFunctionCallTester>(copyFunctionCallTester1);
351   BOOST_TEST ( get(copyFunctionCallTester2).is_copy_constructed);
352   BOOST_TEST ( ! get(copyFunctionCallTester2).is_assignment_called);
353 
354   boost::value_initialized<CopyFunctionCallTester> copyFunctionCallTester3;
355   copyFunctionCallTester3 = boost::value_initialized<CopyFunctionCallTester>(copyFunctionCallTester1);
356   BOOST_TEST ( ! get(copyFunctionCallTester3).is_copy_constructed);
357   BOOST_TEST ( get(copyFunctionCallTester3).is_assignment_called);
358 
359   boost::value_initialized<SwapFunctionCallTester> swapFunctionCallTester1;
360   boost::value_initialized<SwapFunctionCallTester> swapFunctionCallTester2;
361   get(swapFunctionCallTester1).data = 1;
362   get(swapFunctionCallTester2).data = 2;
363   boost::swap(swapFunctionCallTester1, swapFunctionCallTester2);
364   BOOST_TEST( get(swapFunctionCallTester1).data == 2 );
365   BOOST_TEST( get(swapFunctionCallTester2).data == 1 );
366   BOOST_TEST( get(swapFunctionCallTester1).is_custom_swap_called );
367   BOOST_TEST( get(swapFunctionCallTester2).is_custom_swap_called );
368 
369   return boost::report_errors();
370 }
371 
372 
373