]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/utility/test/base_from_member_test.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / utility / test / base_from_member_test.cpp
1 // Boost test program for base-from-member class templates -----------------//
2
3 // Copyright 2001, 2003 Daryle Walker. Use, modification, and distribution are
4 // subject to the Boost Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)
6
7 // See <http://www.boost.org/libs/utility/> for the library's home page.
8
9 // Revision History
10 // 14 Jun 2003 Adjusted code for Boost.Test changes (Daryle Walker)
11 // 29 Aug 2001 Initial Version (Daryle Walker)
12
13 #include <boost/test/minimal.hpp> // for BOOST_CHECK, main
14
15 #include <boost/config.hpp> // for BOOST_NO_MEMBER_TEMPLATES
16 #include <boost/cstdlib.hpp> // for boost::exit_success
17 #include <boost/noncopyable.hpp> // for boost::noncopyable
18
19 #include <boost/utility/base_from_member.hpp> // for boost::base_from_member
20
21 #include <functional> // for std::less
22 #include <iostream> // for std::cout (std::ostream, std::endl indirectly)
23 #include <set> // for std::set
24 #include <typeinfo> // for std::type_info
25 #include <utility> // for std::pair, std::make_pair
26 #include <vector> // for std::vector
27
28
29 // Control if extra information is printed
30 #ifndef CONTROL_EXTRA_PRINTING
31 #define CONTROL_EXTRA_PRINTING 1
32 #endif
33
34
35 // A (sub)object can be identified by its memory location and its type.
36 // Both are needed since an object can start at the same place as its
37 // first base class subobject and/or contained subobject.
38 typedef std::pair< void *, std::type_info const * > object_id;
39
40 // Object IDs need to be printed
41 std::ostream & operator <<( std::ostream &os, object_id const &oi );
42
43 // A way to generate an object ID
44 template < typename T >
45 object_id identify( T &obj );
46
47 // A custom comparison type is needed
48 struct object_id_compare
49 {
50 bool operator ()( object_id const &a, object_id const &b ) const;
51
52 }; // object_id_compare
53
54 // A singleton of this type coordinates the acknowledgements
55 // of objects being created and used.
56 class object_registrar
57 : private boost::noncopyable
58 {
59 public:
60
61 #ifndef BOOST_NO_MEMBER_TEMPLATES
62 template < typename T >
63 void register_object( T &obj )
64 { this->register_object_imp( identify(obj) ); }
65 template < typename T, typename U >
66 void register_use( T &owner, U &owned )
67 { this->register_use_imp( identify(owner), identify(owned) ); }
68 template < typename T, typename U >
69 void unregister_use( T &owner, U &owned )
70 { this->unregister_use_imp( identify(owner), identify(owned) ); }
71 template < typename T >
72 void unregister_object( T &obj )
73 { this->unregister_object_imp( identify(obj) ); }
74 #endif
75
76 void register_object_imp( object_id obj );
77 void register_use_imp( object_id owner, object_id owned );
78 void unregister_use_imp( object_id owner, object_id owned );
79 void unregister_object_imp( object_id obj );
80
81 typedef std::set<object_id, object_id_compare> set_type;
82
83 typedef std::vector<object_id> error_record_type;
84 typedef std::vector< std::pair<object_id, object_id> > error_pair_type;
85
86 set_type db_;
87
88 error_pair_type defrauders_in_, defrauders_out_;
89 error_record_type overeager_, overkilled_;
90
91 }; // object_registrar
92
93 // A sample type to be used by containing types
94 class base_or_member
95 {
96 public:
97 explicit base_or_member( int x = 1, double y = -0.25 );
98 ~base_or_member();
99
100 }; // base_or_member
101
102 // A sample type that uses base_or_member, used
103 // as a base for the main demonstration classes
104 class base_class
105 {
106 public:
107 explicit base_class( base_or_member &x, base_or_member *y = 0,
108 base_or_member *z = 0 );
109
110 ~base_class();
111
112 private:
113 base_or_member *x_, *y_, *z_;
114
115 }; // base_class
116
117 // This bad class demonstrates the direct method of a base class needing
118 // to be initialized by a member. This is improper since the member
119 // isn't initialized until after the base class.
120 class bad_class
121 : public base_class
122 {
123 public:
124 bad_class();
125 ~bad_class();
126
127 private:
128 base_or_member x_;
129
130 }; // bad_class
131
132 // The first good class demonstrates the correct way to initialize a
133 // base class with a member. The member is changed to another base
134 // class, one that is initialized before the base that needs it.
135 class good_class_1
136 : private boost::base_from_member<base_or_member>
137 , public base_class
138 {
139 typedef boost::base_from_member<base_or_member> pbase_type;
140 typedef base_class base_type;
141
142 public:
143 good_class_1();
144 ~good_class_1();
145
146 }; // good_class_1
147
148 // The second good class also demonstrates the correct way to initialize
149 // base classes with other subobjects. This class uses the other helpers
150 // in the library, and shows the technique of using two base subobjects
151 // of the "same" type.
152 class good_class_2
153 : private boost::base_from_member<base_or_member, 0>
154 , private boost::base_from_member<base_or_member, 1>
155 , private boost::base_from_member<base_or_member, 2>
156 , public base_class
157 {
158 typedef boost::base_from_member<base_or_member, 0> pbase_type0;
159 typedef boost::base_from_member<base_or_member, 1> pbase_type1;
160 typedef boost::base_from_member<base_or_member, 2> pbase_type2;
161 typedef base_class base_type;
162
163 public:
164 good_class_2();
165 ~good_class_2();
166
167 }; // good_class_2
168
169 // Declare/define the single object registrar
170 object_registrar obj_reg;
171
172
173 // Main functionality
174 int
175 test_main( int , char * [] )
176 {
177 BOOST_CHECK( obj_reg.db_.empty() );
178 BOOST_CHECK( obj_reg.defrauders_in_.empty() );
179 BOOST_CHECK( obj_reg.defrauders_out_.empty() );
180 BOOST_CHECK( obj_reg.overeager_.empty() );
181 BOOST_CHECK( obj_reg.overkilled_.empty() );
182
183 // Make a separate block to examine pre- and post-effects
184 {
185 using std::cout;
186 using std::endl;
187
188 bad_class bc;
189 BOOST_CHECK( obj_reg.db_.size() == 3 );
190 BOOST_CHECK( obj_reg.defrauders_in_.size() == 1 );
191
192 good_class_1 gc1;
193 BOOST_CHECK( obj_reg.db_.size() == 6 );
194 BOOST_CHECK( obj_reg.defrauders_in_.size() == 1 );
195
196 good_class_2 gc2;
197 BOOST_CHECK( obj_reg.db_.size() == 11 );
198 BOOST_CHECK( obj_reg.defrauders_in_.size() == 1 );
199
200 BOOST_CHECK( obj_reg.defrauders_out_.empty() );
201 BOOST_CHECK( obj_reg.overeager_.empty() );
202 BOOST_CHECK( obj_reg.overkilled_.empty() );
203
204 // Getting the addresses of the objects ensure
205 // that they're used, and not optimized away.
206 cout << "Object 'bc' is at " << &bc << '.' << endl;
207 cout << "Object 'gc1' is at " << &gc1 << '.' << endl;
208 cout << "Object 'gc2' is at " << &gc2 << '.' << endl;
209 }
210
211 BOOST_CHECK( obj_reg.db_.empty() );
212 BOOST_CHECK( obj_reg.defrauders_in_.size() == 1 );
213 BOOST_CHECK( obj_reg.defrauders_out_.size() == 1 );
214 BOOST_CHECK( obj_reg.overeager_.empty() );
215 BOOST_CHECK( obj_reg.overkilled_.empty() );
216
217 return boost::exit_success;
218 }
219
220
221 // Print an object's ID
222 std::ostream &
223 operator <<
224 (
225 std::ostream & os,
226 object_id const & oi
227 )
228 {
229 // I had an std::ostringstream to help, but I did not need it since
230 // the program never screws around with formatting. Worse, using
231 // std::ostringstream is an issue with some compilers.
232
233 return os << '[' << ( oi.second ? oi.second->name() : "NOTHING" )
234 << " at " << oi.first << ']';
235 }
236
237 // Get an object ID given an object
238 template < typename T >
239 inline
240 object_id
241 identify
242 (
243 T & obj
244 )
245 {
246 return std::make_pair( static_cast<void *>(&obj), &(typeid( obj )) );
247 }
248
249 // Compare two object IDs
250 bool
251 object_id_compare::operator ()
252 (
253 object_id const & a,
254 object_id const & b
255 ) const
256 {
257 std::less<void *> vp_cmp;
258 if ( vp_cmp(a.first, b.first) )
259 {
260 return true;
261 }
262 else if ( vp_cmp(b.first, a.first) )
263 {
264 return false;
265 }
266 else
267 {
268 // object pointers are equal, compare the types
269 if ( a.second == b.second )
270 {
271 return false;
272 }
273 else if ( !a.second )
274 {
275 return true; // NULL preceeds anything else
276 }
277 else if ( !b.second )
278 {
279 return false; // NULL preceeds anything else
280 }
281 else
282 {
283 return a.second->before( *b.second ) != 0;
284 }
285 }
286 }
287
288 // Let an object register its existence
289 void
290 object_registrar::register_object_imp
291 (
292 object_id obj
293 )
294 {
295 if ( db_.count(obj) <= 0 )
296 {
297 db_.insert( obj );
298
299 #if CONTROL_EXTRA_PRINTING
300 std::cout << "Registered " << obj << '.' << std::endl;
301 #endif
302 }
303 else
304 {
305 overeager_.push_back( obj );
306
307 #if CONTROL_EXTRA_PRINTING
308 std::cout << "Attempted to register a non-existant " << obj
309 << '.' << std::endl;
310 #endif
311 }
312 }
313
314 // Let an object register its use of another object
315 void
316 object_registrar::register_use_imp
317 (
318 object_id owner,
319 object_id owned
320 )
321 {
322 if ( db_.count(owned) > 0 )
323 {
324 // We don't care to record usage registrations
325 }
326 else
327 {
328 defrauders_in_.push_back( std::make_pair(owner, owned) );
329
330 #if CONTROL_EXTRA_PRINTING
331 std::cout << "Attempted to own a non-existant " << owned
332 << " by " << owner << '.' << std::endl;
333 #endif
334 }
335 }
336
337 // Let an object un-register its use of another object
338 void
339 object_registrar::unregister_use_imp
340 (
341 object_id owner,
342 object_id owned
343 )
344 {
345 if ( db_.count(owned) > 0 )
346 {
347 // We don't care to record usage un-registrations
348 }
349 else
350 {
351 defrauders_out_.push_back( std::make_pair(owner, owned) );
352
353 #if CONTROL_EXTRA_PRINTING
354 std::cout << "Attempted to disown a non-existant " << owned
355 << " by " << owner << '.' << std::endl;
356 #endif
357 }
358 }
359
360 // Let an object un-register its existence
361 void
362 object_registrar::unregister_object_imp
363 (
364 object_id obj
365 )
366 {
367 set_type::iterator const i = db_.find( obj );
368
369 if ( i != db_.end() )
370 {
371 db_.erase( i );
372
373 #if CONTROL_EXTRA_PRINTING
374 std::cout << "Unregistered " << obj << '.' << std::endl;
375 #endif
376 }
377 else
378 {
379 overkilled_.push_back( obj );
380
381 #if CONTROL_EXTRA_PRINTING
382 std::cout << "Attempted to unregister a non-existant " << obj
383 << '.' << std::endl;
384 #endif
385 }
386 }
387
388 // Macros to abstract the registration of objects
389 #ifndef BOOST_NO_MEMBER_TEMPLATES
390 #define PRIVATE_REGISTER_BIRTH(o) obj_reg.register_object( (o) )
391 #define PRIVATE_REGISTER_DEATH(o) obj_reg.unregister_object( (o) )
392 #define PRIVATE_REGISTER_USE(o, w) obj_reg.register_use( (o), (w) )
393 #define PRIVATE_UNREGISTER_USE(o, w) obj_reg.unregister_use( (o), (w) )
394 #else
395 #define PRIVATE_REGISTER_BIRTH(o) obj_reg.register_object_imp( \
396 identify((o)) )
397 #define PRIVATE_REGISTER_DEATH(o) obj_reg.unregister_object_imp( \
398 identify((o)) )
399 #define PRIVATE_REGISTER_USE(o, w) obj_reg.register_use_imp( identify((o)), \
400 identify((w)) )
401 #define PRIVATE_UNREGISTER_USE(o, w) obj_reg.unregister_use_imp( \
402 identify((o)), identify((w)) )
403 #endif
404
405 // Create a base_or_member, with arguments to simulate member initializations
406 base_or_member::base_or_member
407 (
408 int x, // = 1
409 double y // = -0.25
410 )
411 {
412 PRIVATE_REGISTER_BIRTH( *this );
413
414 #if CONTROL_EXTRA_PRINTING
415 std::cout << "\tMy x-factor is " << x << " and my y-factor is " << y
416 << '.' << std::endl;
417 #endif
418 }
419
420 // Destroy a base_or_member
421 inline
422 base_or_member::~base_or_member
423 (
424 )
425 {
426 PRIVATE_REGISTER_DEATH( *this );
427 }
428
429 // Create a base_class, registering any objects used
430 base_class::base_class
431 (
432 base_or_member & x,
433 base_or_member * y, // = 0
434 base_or_member * z // = 0
435 )
436 : x_( &x ), y_( y ), z_( z )
437 {
438 PRIVATE_REGISTER_BIRTH( *this );
439
440 #if CONTROL_EXTRA_PRINTING
441 std::cout << "\tMy x-factor is " << x_;
442 #endif
443
444 PRIVATE_REGISTER_USE( *this, *x_ );
445
446 if ( y_ )
447 {
448 #if CONTROL_EXTRA_PRINTING
449 std::cout << ", my y-factor is " << y_;
450 #endif
451
452 PRIVATE_REGISTER_USE( *this, *y_ );
453 }
454
455 if ( z_ )
456 {
457 #if CONTROL_EXTRA_PRINTING
458 std::cout << ", my z-factor is " << z_;
459 #endif
460
461 PRIVATE_REGISTER_USE( *this, *z_ );
462 }
463
464 #if CONTROL_EXTRA_PRINTING
465 std::cout << '.' << std::endl;
466 #endif
467 }
468
469 // Destroy a base_class, unregistering the objects it uses
470 base_class::~base_class
471 (
472 )
473 {
474 PRIVATE_REGISTER_DEATH( *this );
475
476 #if CONTROL_EXTRA_PRINTING
477 std::cout << "\tMy x-factor was " << x_;
478 #endif
479
480 PRIVATE_UNREGISTER_USE( *this, *x_ );
481
482 if ( y_ )
483 {
484 #if CONTROL_EXTRA_PRINTING
485 std::cout << ", my y-factor was " << y_;
486 #endif
487
488 PRIVATE_UNREGISTER_USE( *this, *y_ );
489 }
490
491 if ( z_ )
492 {
493 #if CONTROL_EXTRA_PRINTING
494 std::cout << ", my z-factor was " << z_;
495 #endif
496
497 PRIVATE_UNREGISTER_USE( *this, *z_ );
498 }
499
500 #if CONTROL_EXTRA_PRINTING
501 std::cout << '.' << std::endl;
502 #endif
503 }
504
505 // Create a bad_class, noting the improper construction order
506 bad_class::bad_class
507 (
508 )
509 : x_( -7, 16.75 ), base_class( x_ ) // this order doesn't matter
510 {
511 PRIVATE_REGISTER_BIRTH( *this );
512
513 #if CONTROL_EXTRA_PRINTING
514 std::cout << "\tMy factor is at " << &x_
515 << " and my base is at " << static_cast<base_class *>(this) << '.'
516 << std::endl;
517 #endif
518 }
519
520 // Destroy a bad_class, noting the improper destruction order
521 bad_class::~bad_class
522 (
523 )
524 {
525 PRIVATE_REGISTER_DEATH( *this );
526
527 #if CONTROL_EXTRA_PRINTING
528 std::cout << "\tMy factor was at " << &x_
529 << " and my base was at " << static_cast<base_class *>(this)
530 << '.' << std::endl;
531 #endif
532 }
533
534 // Create a good_class_1, noting the proper construction order
535 good_class_1::good_class_1
536 (
537 )
538 : pbase_type( 8 ), base_type( member )
539 {
540 PRIVATE_REGISTER_BIRTH( *this );
541
542 #if CONTROL_EXTRA_PRINTING
543 std::cout << "\tMy factor is at " << &member
544 << " and my base is at " << static_cast<base_class *>(this) << '.'
545 << std::endl;
546 #endif
547 }
548
549 // Destroy a good_class_1, noting the proper destruction order
550 good_class_1::~good_class_1
551 (
552 )
553 {
554 PRIVATE_REGISTER_DEATH( *this );
555
556 #if CONTROL_EXTRA_PRINTING
557 std::cout << "\tMy factor was at " << &member
558 << " and my base was at " << static_cast<base_class *>(this)
559 << '.' << std::endl;
560 #endif
561 }
562
563 // Create a good_class_2, noting the proper construction order
564 good_class_2::good_class_2
565 (
566 )
567 : pbase_type0(), pbase_type1(-16, 0.125), pbase_type2(2, -3)
568 , base_type( pbase_type1::member, &this->pbase_type0::member,
569 &this->pbase_type2::member )
570 {
571 PRIVATE_REGISTER_BIRTH( *this );
572
573 #if CONTROL_EXTRA_PRINTING
574 std::cout << "\tMy factors are at " << &this->pbase_type0::member
575 << ", " << &this->pbase_type1::member << ", "
576 << &this->pbase_type2::member << ", and my base is at "
577 << static_cast<base_class *>(this) << '.' << std::endl;
578 #endif
579 }
580
581 // Destroy a good_class_2, noting the proper destruction order
582 good_class_2::~good_class_2
583 (
584 )
585 {
586 PRIVATE_REGISTER_DEATH( *this );
587
588 #if CONTROL_EXTRA_PRINTING
589 std::cout << "\tMy factors were at " << &this->pbase_type0::member
590 << ", " << &this->pbase_type1::member << ", "
591 << &this->pbase_type2::member << ", and my base was at "
592 << static_cast<base_class *>(this) << '.' << std::endl;
593 #endif
594 }