1 /*********************************************************************************** 2 test_insert.h 3 4 * Copyright (c) 1997 5 * Mark of the Unicorn, Inc. 6 * 7 * Permission to use, copy, modify, distribute and sell this software 8 * and its documentation for any purpose is hereby granted without fee, 9 * provided that the above copyright notice appear in all copies and 10 * that both that copyright notice and this permission notice appear 11 * in supporting documentation. Mark of the Unicorn makes no 12 * representations about the suitability of this software for any 13 * purpose. It is provided "as is" without express or implied warranty. 14 15 ***********************************************************************************/ 16 #ifndef test_insert_H_ 17 #define test_insert_H_ 18 19 # include "Prefix.h" 20 # if defined (EH_NEW_HEADERS) 21 # include <utility> 22 # include <vector> 23 # include <cassert> 24 # include <climits> 25 # else 26 # include <vector.h> 27 # include <assert.h> 28 # include <limits.h> 29 # endif 30 #include "random_number.h" 31 #include "nc_alloc.h" 32 #include "ThrowCompare.h" 33 34 // A classification system for containers, for verification 35 struct container_tag {}; 36 struct sequence_container_tag {}; 37 struct associative_container_tag {}; 38 39 struct set_tag {}; 40 struct multiset_tag {}; 41 struct map_tag {}; 42 struct multimap_tag {}; 43 44 template <class C, class Iter> 45 size_t CountNewItems( const C&, const Iter& firstNew, 46 const Iter& lastNew, sequence_container_tag ) 47 { 48 size_t dist = 0; 49 #if 0 //def __SUNPRO_CC 50 EH_DISTANCE( firstNew, lastNew, dist ); 51 #else 52 EH_DISTANCE( Iter(firstNew), Iter(lastNew), dist ); 53 #endif 54 return dist; 55 } 56 57 template <class C, class Iter> 58 size_t CountNewItems( const C& c, const Iter& firstNew, 59 const Iter& lastNew, multimap_tag ) 60 { 61 return CountNewItems( c, firstNew, lastNew, sequence_container_tag() ); 62 } 63 64 template <class C, class Iter> 65 size_t CountNewItems( const C& c, const Iter& firstNew, 66 const Iter& lastNew, multiset_tag ) 67 { 68 return CountNewItems( c, firstNew, lastNew, sequence_container_tag() ); 69 } 70 71 72 template <class C, class Iter, class KeyOfValue> 73 #ifdef __BORLANDC__ 74 size_t CountUniqueItems_Aux( const C& original, const Iter& firstNew, 75 #else 76 size_t CountUniqueItems_Aux( const C& original, Iter firstNew, 77 #endif 78 Iter lastNew, const KeyOfValue& keyOfValue ) 79 { 80 typedef typename C::key_type key; 81 typedef typename C::const_iterator const_iter; 82 typedef EH_STD::vector<key> key_list; 83 typedef typename key_list::iterator key_iterator; 84 key_list keys; 85 size_t dist = 0; 86 #ifdef __SUNPRO_CC 87 EH_DISTANCE( firstNew, lastNew, dist ); 88 #else 89 EH_DISTANCE( Iter(firstNew), Iter(lastNew), dist ); 90 #endif 91 keys.reserve( dist ); 92 for ( Iter x = firstNew; x != lastNew; ++x ) 93 keys.push_back( keyOfValue(*x) ); 94 95 EH_STD::sort( keys.begin(), keys.end() ); 96 key_iterator last = EH_STD::unique( keys.begin(), keys.end() ); 97 98 size_t cnt = 0; 99 for ( key_iterator tmp = keys.begin(); tmp != last; ++tmp ) 100 { 101 if ( const_iter(original.find( *tmp )) == const_iter(original.end()) ) 102 ++cnt; 103 } 104 return cnt; 105 } 106 107 #if ! defined (__SGI_STL) 108 EH_BEGIN_NAMESPACE 109 template <class T> 110 struct identity 111 { 112 const T& operator()( const T& x ) const { return x; } 113 }; 114 # if ! defined (__KCC) 115 template <class _Pair> 116 struct select1st : public unary_function<_Pair, typename _Pair::first_type> { 117 const typename _Pair::first_type& operator()(const _Pair& __x) const { 118 return __x.first; 119 } 120 }; 121 # endif 122 EH_END_NAMESPACE 123 #endif 124 125 template <class C, class Iter> 126 size_t CountUniqueItems( const C& original, const Iter& firstNew, 127 const Iter& lastNew, set_tag ) 128 { 129 typedef typename C::value_type value_type; 130 return CountUniqueItems_Aux( original, firstNew, lastNew, 131 EH_STD::identity<value_type>() ); 132 } 133 134 template <class C, class Iter> 135 size_t CountUniqueItems( const C& original, const Iter& firstNew, 136 const Iter& lastNew, map_tag ) 137 { 138 #ifdef EH_MULTI_CONST_TEMPLATE_ARG_BUG 139 return CountUniqueItems_Aux( original, firstNew, lastNew, 140 EH_SELECT1ST_HINT<C::value_type, C::key_type>() ); 141 #else 142 typedef typename C::value_type value_type; 143 return CountUniqueItems_Aux( original, firstNew, lastNew, 144 EH_STD::select1st<value_type>() ); 145 #endif 146 } 147 148 template <class C, class Iter> 149 size_t CountNewItems( const C& original, const Iter& firstNew, 150 const Iter& lastNew, map_tag ) 151 { 152 return CountUniqueItems( original, firstNew, lastNew, 153 container_category( original ) ); 154 } 155 156 template <class C, class Iter> 157 size_t CountNewItems( const C& original, const Iter& firstNew, 158 const Iter& lastNew, set_tag ) 159 { 160 return CountUniqueItems( original, firstNew, lastNew, 161 container_category( original ) ); 162 } 163 164 template <class C, class SrcIter> 165 inline void VerifyInsertion( const C& original, const C& result, 166 const SrcIter& firstNew, const SrcIter& lastNew, 167 size_t, associative_container_tag ) 168 { 169 typedef typename C::const_iterator DstIter; 170 DstIter first1 = original.begin(); 171 DstIter first2 = result.begin(); 172 173 DstIter* from_orig = new DstIter[original.size()]; 174 DstIter* last_from_orig = from_orig; 175 176 // fbp : for hashed containers, the following is needed : 177 while ( first2 != result.end() ) 178 { 179 EH_STD::pair<DstIter, DstIter> p = EH_STD::mismatch( first1, original.end(), first2 ); 180 if ( p.second != result.end() ) 181 { 182 SrcIter srcItem = EH_STD::find( SrcIter(firstNew), SrcIter(lastNew), *p.second ); 183 184 if (srcItem == lastNew) 185 { 186 // not found in input range, probably re-ordered from the orig 187 DstIter* tmp; 188 tmp = EH_STD::find( from_orig, last_from_orig, p.first ); 189 190 // if already here, exclude 191 if (tmp != last_from_orig) 192 { 193 EH_STD::copy(tmp+1, last_from_orig, tmp); 194 last_from_orig--; 195 } 196 else 197 { 198 // register re-ordered element 199 DstIter dstItem; 200 dstItem = EH_STD::find( first1, original.end(), *p.first ); 201 EH_ASSERT( dstItem != original.end() ); 202 *last_from_orig = dstItem; 203 last_from_orig++; 204 ++p.first; 205 } 206 } 207 ++p.second; 208 } 209 first1 = p.first; 210 first2 = p.second; 211 } 212 213 delete [] from_orig; 214 } 215 216 // VC++ 217 template <class C, class SrcIter> 218 inline void VerifyInsertion( 219 const C& original, const C& result, const SrcIter& firstNew, 220 const SrcIter& lastNew, size_t, set_tag ) 221 { 222 VerifyInsertion( original, result, firstNew, lastNew, 223 size_t(0), associative_container_tag() ); 224 } 225 226 template <class C, class SrcIter> 227 inline void VerifyInsertion(const C& original, const C& result, 228 const SrcIter& firstNew, const SrcIter& lastNew, 229 size_t, multiset_tag ) 230 { 231 VerifyInsertion( original, result, firstNew, lastNew, 232 size_t(0), associative_container_tag() ); 233 } 234 235 template <class C, class SrcIter> 236 inline void VerifyInsertion( 237 const C& original, const C& result, const SrcIter& firstNew, 238 const SrcIter& lastNew, size_t, map_tag ) 239 { 240 VerifyInsertion( original, result, firstNew, lastNew, 241 size_t(0), associative_container_tag() ); 242 } 243 244 template <class C, class SrcIter> 245 inline void VerifyInsertion( 246 const C& original, const C& result, const SrcIter& firstNew, 247 const SrcIter& lastNew, size_t, multimap_tag ) 248 { 249 VerifyInsertion( original, result, firstNew, lastNew, 250 size_t(0), associative_container_tag() ); 251 } 252 253 template <class C, class SrcIter> 254 void VerifyInsertion( 255 # ifdef _MSC_VER 256 const C& original, const C& result, SrcIter firstNew, 257 SrcIter lastNew, size_t insPos, sequence_container_tag ) 258 # else 259 const C& original, const C& result, const SrcIter& firstNew, 260 const SrcIter& lastNew, size_t insPos, sequence_container_tag ) 261 # endif 262 { 263 typename C::const_iterator p1 = original.begin(); 264 typename C::const_iterator p2 = result.begin(); 265 SrcIter tmp(firstNew); 266 267 for ( size_t n = 0; n < insPos; n++, ++p1, ++p2) 268 EH_ASSERT( *p1 == *p2 ); 269 270 for (; tmp != lastNew; ++p2, ++tmp ) { 271 EH_ASSERT(p2 != result.end()); 272 EH_ASSERT(*p2 == *tmp); 273 } 274 275 for (; p2 != result.end(); ++p1, ++p2 ) 276 EH_ASSERT( *p1 == *p2 ); 277 EH_ASSERT( p1 == original.end() ); 278 } 279 280 template <class C, class SrcIter> 281 inline void VerifyInsertion( const C& original, const C& result, 282 const SrcIter& firstNew, 283 const SrcIter& lastNew, size_t insPos ) 284 { 285 EH_ASSERT( result.size() == original.size() + 286 CountNewItems( original, firstNew, lastNew, 287 container_category(original) ) ); 288 VerifyInsertion( original, result, firstNew, lastNew, insPos, 289 container_category(original) ); 290 } 291 292 template <class C, class Value> 293 void VerifyInsertN( const C& original, const C& result, size_t insCnt, 294 const Value& val, size_t insPos ) 295 { 296 typename C::const_iterator p1 = original.begin(); 297 typename C::const_iterator p2 = result.begin(); 298 (void)val; //*TY 02/06/2000 - to suppress unused variable warning under nondebug build 299 300 for ( size_t n = 0; n < insPos; n++ ) 301 EH_ASSERT( *p1++ == *p2++ ); 302 303 while ( insCnt-- > 0 ) 304 { 305 EH_ASSERT(p2 != result.end()); 306 EH_ASSERT(*p2 == val ); 307 ++p2; 308 } 309 310 while ( p2 != result.end() ) { 311 EH_ASSERT( *p1 == *p2 ); 312 ++p1; ++p2; 313 } 314 EH_ASSERT( p1 == original.end() ); 315 } 316 317 template <class C> 318 void prepare_insert_n( C&, size_t ) {} 319 320 // Metrowerks 1.8 compiler requires that specializations appear first (!!) 321 // or it won't call them. Fixed in 1.9, though. 322 inline void MakeRandomValue(bool& b) { b = bool(random_number(2) != 0); } 323 324 template<class T> 325 inline void MakeRandomValue(T&) {} 326 327 template <class C> 328 struct test_insert_one 329 { 330 test_insert_one( const C& orig, int pos =-1 ) 331 : original( orig ), fPos( random_number( orig.size() )) 332 { 333 MakeRandomValue( fInsVal ); 334 if ( pos != -1 ) 335 { 336 fPos = size_t(pos); 337 if ( pos == 0 ) 338 gTestController.SetCurrentTestName("single insertion at begin()"); 339 else 340 gTestController.SetCurrentTestName("single insertion at end()"); 341 } 342 else 343 gTestController.SetCurrentTestName("single insertion at random position"); 344 } 345 346 void operator()( C& c ) const 347 { 348 prepare_insert_n( c, (size_t)1 ); 349 typename C::iterator pos = c.begin(); 350 EH_STD::advance( pos, size_t(fPos) ); 351 c.insert( pos, fInsVal ); 352 353 // Prevent simulated failures during verification 354 gTestController.CancelFailureCountdown(); 355 // Success. Check results. 356 VerifyInsertion( original, c, &fInsVal, 1+&fInsVal, fPos ); 357 } 358 private: 359 typename C::value_type fInsVal; 360 const C& original; 361 size_t fPos; 362 }; 363 364 template <class C> 365 struct test_insert_n 366 { 367 test_insert_n( const C& orig, size_t insCnt, int pos =-1 ) 368 : original( orig ), fPos( random_number( orig.size() )), fInsCnt(insCnt) 369 { 370 MakeRandomValue( fInsVal ); 371 if (pos!=-1) 372 { 373 fPos=size_t(pos); 374 if (pos==0) 375 gTestController.SetCurrentTestName("n-ary insertion at begin()"); 376 else 377 gTestController.SetCurrentTestName("n-ary insertion at end()"); 378 } 379 else 380 gTestController.SetCurrentTestName("n-ary insertion at random position"); 381 } 382 383 void operator()( C& c ) const 384 { 385 prepare_insert_n( c, fInsCnt ); 386 typename C::iterator pos = c.begin(); 387 EH_STD::advance( pos, fPos ); 388 c.insert( pos, fInsCnt, fInsVal ); 389 390 // Prevent simulated failures during verification 391 gTestController.CancelFailureCountdown(); 392 // Success. Check results. 393 VerifyInsertN( original, c, fInsCnt, fInsVal, fPos ); 394 } 395 private: 396 typename C::value_type fInsVal; 397 const C& original; 398 size_t fPos; 399 size_t fInsCnt; 400 }; 401 402 template <class C> 403 struct test_insert_value 404 { 405 test_insert_value( const C& orig ) 406 : original( orig ) 407 { 408 MakeRandomValue( fInsVal ); 409 gTestController.SetCurrentTestName("insertion of random value"); 410 } 411 412 void operator()( C& c ) const 413 { 414 c.insert( fInsVal ); 415 416 // Prevent simulated failures during verification 417 gTestController.CancelFailureCountdown(); 418 // Success. Check results. 419 VerifyInsertion( original, c, &fInsVal, 1+&fInsVal, size_t(0) ); 420 } 421 private: 422 typename C::value_type fInsVal; 423 const C& original; 424 }; 425 426 template <class C> 427 struct test_insert_noresize 428 { 429 test_insert_noresize( const C& orig ) 430 : original( orig ) 431 { 432 MakeRandomValue( fInsVal ); 433 gTestController.SetCurrentTestName("insertion of random value without resize"); 434 } 435 436 void operator()( C& c ) const 437 { 438 c.insert_noresize( fInsVal ); 439 440 // Prevent simulated failures during verification 441 gTestController.CancelFailureCountdown(); 442 // Success. Check results. 443 VerifyInsertion( original, c, &fInsVal, 1+&fInsVal, size_t(0) ); 444 } 445 private: 446 typename C::value_type fInsVal; 447 const C& original; 448 }; 449 450 template <class C, class Position, class Iter> 451 void do_insert_range( C& c_inst, Position offset, 452 Iter first, Iter last, sequence_container_tag ) 453 { 454 typedef typename C::iterator CIter; 455 CIter pos = c_inst.begin(); 456 EH_STD::advance( pos, offset ); 457 c_inst.insert( pos, first, last ); 458 } 459 460 template <class C, class Position, class Iter> 461 void do_insert_range( C& c, Position, 462 Iter first, Iter last, associative_container_tag ) 463 { 464 c.insert( first, last ); 465 } 466 467 template <class C, class Position, class Iter> 468 void do_insert_range( C& c, Position, Iter first, Iter last, multiset_tag ) 469 { 470 c.insert( first, last ); 471 } 472 473 template <class C, class Position, class Iter> 474 void do_insert_range( C& c, Position, Iter first, Iter last, multimap_tag ) 475 { 476 c.insert( first, last ); 477 } 478 479 template <class C, class Position, class Iter> 480 void do_insert_range( C& c, Position, Iter first, Iter last, set_tag ) 481 { 482 c.insert( first, last ); 483 } 484 485 template <class C, class Position, class Iter> 486 void do_insert_range( C& c, Position, Iter first, Iter last, map_tag ) 487 { 488 c.insert( first, last ); 489 } 490 491 /* 492 template <class C, class Iter> 493 void prepare_insert_range( C&, size_t, Iter, Iter) {} 494 */ 495 496 template <class C, class Iter> 497 struct test_insert_range 498 { 499 test_insert_range( const C& orig, Iter first, Iter last, int pos=-1 ) 500 : fFirst( first ), 501 fLast( last ), 502 original( orig ), 503 fPos( random_number( orig.size() )) 504 { 505 gTestController.SetCurrentTestName("range insertion"); 506 if ( pos != -1 ) 507 { 508 fPos = size_t(pos); 509 if ( pos == 0 ) 510 gTestController.SetCurrentTestName("range insertion at begin()"); 511 else 512 gTestController.SetCurrentTestName("range insertion at end()"); 513 } 514 else 515 gTestController.SetCurrentTestName("range insertion at random position"); 516 } 517 518 void operator()( C& c ) const 519 { 520 // prepare_insert_range( c, fPos, fFirst, fLast ); 521 do_insert_range( c, fPos, fFirst, fLast, container_category(c) ); 522 523 // Prevent simulated failures during verification 524 gTestController.CancelFailureCountdown(); 525 // Success. Check results. 526 VerifyInsertion( original, c, fFirst, fLast, fPos ); 527 } 528 private: 529 Iter fFirst, fLast; 530 const C& original; 531 size_t fPos; 532 }; 533 534 template <class C, class Iter> 535 test_insert_range<C, Iter> insert_range_tester( const C& orig, const Iter& first, const Iter& last ) 536 { 537 return test_insert_range<C, Iter>( orig, first, last ); 538 } 539 540 template <class C, class Iter> 541 test_insert_range<C, Iter> insert_range_at_begin_tester( const C& orig, const Iter& first, const Iter& last ) 542 { 543 return test_insert_range<C, Iter>( orig, first, last , 0); 544 } 545 546 template <class C, class Iter> 547 test_insert_range<C, Iter> insert_range_at_end_tester( const C& orig, const Iter& first, const Iter& last ) 548 { 549 return test_insert_range<C, Iter>( orig, first, last , (int)orig.size()); 550 } 551 552 #endif // test_insert_H_ 553