1 //Has to be first for StackAllocator swap overload to be taken 2 //into account (at least using GCC 4.0.1) 3 #include "stack_allocator.h" 4 5 #include <vector> 6 #include <algorithm> 7 #if !defined (STLPORT) || defined (_STLP_USE_EXCEPTIONS) 8 # include <stdexcept> 9 #endif 10 11 #include "cppunit/cppunit_proxy.h" 12 13 #if !defined (STLPORT) || defined(_STLP_USE_NAMESPACES) 14 using namespace std; 15 #endif 16 17 // 18 // TestCase class 19 // 20 class VectorTest : public CPPUNIT_NS::TestCase 21 { 22 CPPUNIT_TEST_SUITE(VectorTest); 23 CPPUNIT_TEST(vec_test_1); 24 CPPUNIT_TEST(vec_test_2); 25 CPPUNIT_TEST(vec_test_3); 26 CPPUNIT_TEST(vec_test_4); 27 CPPUNIT_TEST(vec_test_5); 28 CPPUNIT_TEST(vec_test_6); 29 CPPUNIT_TEST(vec_test_7); 30 CPPUNIT_TEST(capacity); 31 CPPUNIT_TEST(at); 32 CPPUNIT_TEST(pointer); 33 CPPUNIT_TEST(auto_ref); 34 CPPUNIT_TEST(allocator_with_state); 35 CPPUNIT_TEST(iterators); 36 #if defined (STLPORT) && defined (_STLP_NO_MEMBER_TEMPLATES) 37 CPPUNIT_IGNORE; 38 #endif 39 CPPUNIT_TEST(optimizations_check); 40 CPPUNIT_TEST(assign_check); 41 CPPUNIT_STOP_IGNORE; 42 CPPUNIT_TEST(ebo); 43 CPPUNIT_TEST_SUITE_END(); 44 45 protected: 46 void vec_test_1(); 47 void vec_test_2(); 48 void vec_test_3(); 49 void vec_test_4(); 50 void vec_test_5(); 51 void vec_test_6(); 52 void vec_test_7(); 53 void capacity(); 54 void at(); 55 void pointer(); 56 void auto_ref(); 57 void allocator_with_state(); 58 void iterators(); 59 void optimizations_check(); 60 void assign_check(); 61 void ebo(); 62 }; 63 64 CPPUNIT_TEST_SUITE_REGISTRATION(VectorTest); 65 66 // 67 // tests implementation 68 // 69 void VectorTest::vec_test_1() 70 { 71 vector<int> v1; // Empty vector of integers. 72 73 CPPUNIT_ASSERT( v1.empty() == true ); 74 CPPUNIT_ASSERT( v1.size() == 0 ); 75 76 // CPPUNIT_ASSERT( v1.max_size() == INT_MAX / sizeof(int) ); 77 // cout << "max_size = " << v1.max_size() << endl; 78 v1.push_back(42); // Add an integer to the vector. 79 80 CPPUNIT_ASSERT( v1.size() == 1 ); 81 82 CPPUNIT_ASSERT( v1[0] == 42 ); 83 84 { 85 vector<vector<int> > vect(10); 86 vector<vector<int> >::iterator it(vect.begin()), end(vect.end()); 87 for (; it != end; ++it) { 88 CPPUNIT_ASSERT( (*it).empty() ); 89 CPPUNIT_ASSERT( (*it).size() == 0 ); 90 CPPUNIT_ASSERT( (*it).capacity() == 0 ); 91 CPPUNIT_ASSERT( (*it).begin() == (*it).end() ); 92 } 93 } 94 } 95 96 void VectorTest::vec_test_2() 97 { 98 vector<double> v1; // Empty vector of doubles. 99 v1.push_back(32.1); 100 v1.push_back(40.5); 101 vector<double> v2; // Another empty vector of doubles. 102 v2.push_back(3.56); 103 104 CPPUNIT_ASSERT( v1.size() == 2 ); 105 CPPUNIT_ASSERT( v1[0] == 32.1 ); 106 CPPUNIT_ASSERT( v1[1] == 40.5 ); 107 108 CPPUNIT_ASSERT( v2.size() == 1 ); 109 CPPUNIT_ASSERT( v2[0] == 3.56 ); 110 size_t v1Cap = v1.capacity(); 111 size_t v2Cap = v2.capacity(); 112 113 v1.swap(v2); // Swap the vector's contents. 114 115 CPPUNIT_ASSERT( v1.size() == 1 ); 116 CPPUNIT_ASSERT( v1.capacity() == v2Cap ); 117 CPPUNIT_ASSERT( v1[0] == 3.56 ); 118 119 CPPUNIT_ASSERT( v2.size() == 2 ); 120 CPPUNIT_ASSERT( v2.capacity() == v1Cap ); 121 CPPUNIT_ASSERT( v2[0] == 32.1 ); 122 CPPUNIT_ASSERT( v2[1] == 40.5 ); 123 124 v2 = v1; // Assign one vector to another. 125 126 CPPUNIT_ASSERT( v2.size() == 1 ); 127 CPPUNIT_ASSERT( v2[0] == 3.56 ); 128 } 129 130 void VectorTest::vec_test_3() 131 { 132 typedef vector<char> vec_type; 133 134 vec_type v1; // Empty vector of characters. 135 v1.push_back('h'); 136 v1.push_back('i'); 137 138 CPPUNIT_ASSERT( v1.size() == 2 ); 139 CPPUNIT_ASSERT( v1[0] == 'h' ); 140 CPPUNIT_ASSERT( v1[1] == 'i' ); 141 142 vec_type v2(v1.begin(), v1.end()); 143 v2[1] = 'o'; // Replace second character. 144 145 CPPUNIT_ASSERT( v2.size() == 2 ); 146 CPPUNIT_ASSERT( v2[0] == 'h' ); 147 CPPUNIT_ASSERT( v2[1] == 'o' ); 148 149 CPPUNIT_ASSERT( (v1 == v2) == false ); 150 151 CPPUNIT_ASSERT( (v1 < v2) == true ); 152 } 153 154 void VectorTest::vec_test_4() 155 { 156 vector<int> v(4); 157 158 v[0] = 1; 159 v[1] = 4; 160 v[2] = 9; 161 v[3] = 16; 162 163 CPPUNIT_ASSERT( v.front() == 1 ); 164 CPPUNIT_ASSERT( v.back() == 16 ); 165 166 v.push_back(25); 167 168 CPPUNIT_ASSERT( v.back() == 25 ); 169 CPPUNIT_ASSERT( v.size() == 5 ); 170 171 v.pop_back(); 172 173 CPPUNIT_ASSERT( v.back() == 16 ); 174 CPPUNIT_ASSERT( v.size() == 4 ); 175 } 176 177 void VectorTest::vec_test_5() 178 { 179 int array [] = { 1, 4, 9, 16 }; 180 181 vector<int> v(array, array + 4); 182 183 CPPUNIT_ASSERT( v.size() == 4 ); 184 185 CPPUNIT_ASSERT( v[0] == 1 ); 186 CPPUNIT_ASSERT( v[1] == 4 ); 187 CPPUNIT_ASSERT( v[2] == 9 ); 188 CPPUNIT_ASSERT( v[3] == 16 ); 189 } 190 191 void VectorTest::vec_test_6() 192 { 193 int array [] = { 1, 4, 9, 16, 25, 36 }; 194 195 vector<int> v(array, array + 6); 196 vector<int>::iterator vit; 197 198 CPPUNIT_ASSERT( v.size() == 6 ); 199 CPPUNIT_ASSERT( v[0] == 1 ); 200 CPPUNIT_ASSERT( v[1] == 4 ); 201 CPPUNIT_ASSERT( v[2] == 9 ); 202 CPPUNIT_ASSERT( v[3] == 16 ); 203 CPPUNIT_ASSERT( v[4] == 25 ); 204 CPPUNIT_ASSERT( v[5] == 36 ); 205 206 vit = v.erase( v.begin() ); // Erase first element. 207 CPPUNIT_ASSERT( *vit == 4 ); 208 209 CPPUNIT_ASSERT( v.size() == 5 ); 210 CPPUNIT_ASSERT( v[0] == 4 ); 211 CPPUNIT_ASSERT( v[1] == 9 ); 212 CPPUNIT_ASSERT( v[2] == 16 ); 213 CPPUNIT_ASSERT( v[3] == 25 ); 214 CPPUNIT_ASSERT( v[4] == 36 ); 215 216 vit = v.erase(v.end() - 1); // Erase last element. 217 CPPUNIT_ASSERT( vit == v.end() ); 218 219 CPPUNIT_ASSERT( v.size() == 4 ); 220 CPPUNIT_ASSERT( v[0] == 4 ); 221 CPPUNIT_ASSERT( v[1] == 9 ); 222 CPPUNIT_ASSERT( v[2] == 16 ); 223 CPPUNIT_ASSERT( v[3] == 25 ); 224 225 226 v.erase(v.begin() + 1, v.end() - 1); // Erase all but first and last. 227 228 CPPUNIT_ASSERT( v.size() == 2 ); 229 CPPUNIT_ASSERT( v[0] == 4 ); 230 CPPUNIT_ASSERT( v[1] == 25 ); 231 232 } 233 234 void VectorTest::vec_test_7() 235 { 236 int array1 [] = { 1, 4, 25 }; 237 int array2 [] = { 9, 16 }; 238 239 vector<int> v(array1, array1 + 3); 240 vector<int>::iterator vit; 241 vit = v.insert(v.begin(), 0); // Insert before first element. 242 CPPUNIT_ASSERT( *vit == 0 ); 243 244 vit = v.insert(v.end(), 36); // Insert after last element. 245 CPPUNIT_ASSERT( *vit == 36 ); 246 247 CPPUNIT_ASSERT( v.size() == 5 ); 248 CPPUNIT_ASSERT( v[0] == 0 ); 249 CPPUNIT_ASSERT( v[1] == 1 ); 250 CPPUNIT_ASSERT( v[2] == 4 ); 251 CPPUNIT_ASSERT( v[3] == 25 ); 252 CPPUNIT_ASSERT( v[4] == 36 ); 253 254 // Insert contents of array2 before fourth element. 255 v.insert(v.begin() + 3, array2, array2 + 2); 256 257 CPPUNIT_ASSERT( v.size() == 7 ); 258 259 CPPUNIT_ASSERT( v[0] == 0 ); 260 CPPUNIT_ASSERT( v[1] == 1 ); 261 CPPUNIT_ASSERT( v[2] == 4 ); 262 CPPUNIT_ASSERT( v[3] == 9 ); 263 CPPUNIT_ASSERT( v[4] == 16 ); 264 CPPUNIT_ASSERT( v[5] == 25 ); 265 CPPUNIT_ASSERT( v[6] == 36 ); 266 267 v.clear(); 268 CPPUNIT_ASSERT( v.empty() ); 269 270 v.insert(v.begin(), 5, 10); 271 CPPUNIT_ASSERT( v.size() == 5 ); 272 CPPUNIT_ASSERT( v[0] == 10 ); 273 CPPUNIT_ASSERT( v[1] == 10 ); 274 CPPUNIT_ASSERT( v[2] == 10 ); 275 CPPUNIT_ASSERT( v[3] == 10 ); 276 CPPUNIT_ASSERT( v[4] == 10 ); 277 278 /* 279 { 280 vector<float> vf(2.0f, 3.0f); 281 CPPUNIT_ASSERT( vf.size() == 2 ); 282 CPPUNIT_ASSERT( vf.front() == 3.0f ); 283 CPPUNIT_ASSERT( vf.back() == 3.0f ); 284 } 285 */ 286 } 287 288 struct TestStruct 289 { 290 unsigned int a[3]; 291 }; 292 293 void VectorTest::capacity() 294 { 295 { 296 vector<int> v; 297 298 CPPUNIT_ASSERT( v.capacity() == 0 ); 299 v.push_back(42); 300 CPPUNIT_ASSERT( v.capacity() >= 1 ); 301 v.reserve(5000); 302 CPPUNIT_ASSERT( v.capacity() >= 5000 ); 303 } 304 305 { 306 //Test that used to generate an assertion when using __debug_alloc. 307 vector<TestStruct> va; 308 va.reserve(1); 309 va.reserve(2); 310 } 311 } 312 313 void VectorTest::at() { 314 vector<int> v; 315 vector<int> const& cv = v; 316 317 v.push_back(10); 318 CPPUNIT_ASSERT( v.at(0) == 10 ); 319 v.at(0) = 20; 320 CPPUNIT_ASSERT( cv.at(0) == 20 ); 321 322 #if !defined (STLPORT) || defined (_STLP_USE_EXCEPTIONS) 323 try { 324 v.at(1) = 20; 325 CPPUNIT_FAIL; 326 } 327 catch (out_of_range const&) { 328 } 329 catch (...) { 330 CPPUNIT_FAIL; 331 } 332 #endif 333 } 334 335 void VectorTest::pointer() 336 { 337 vector<int *> v1; 338 vector<int *> v2 = v1; 339 vector<int *> v3; 340 341 v3.insert( v3.end(), v1.begin(), v1.end() ); 342 } 343 344 void VectorTest::auto_ref() 345 { 346 vector<int> ref; 347 for (int i = 0; i < 5; ++i) { 348 ref.push_back(i); 349 } 350 351 vector<vector<int> > v_v_int(1, ref); 352 v_v_int.push_back(v_v_int[0]); 353 v_v_int.push_back(ref); 354 v_v_int.push_back(v_v_int[0]); 355 v_v_int.push_back(v_v_int[0]); 356 v_v_int.push_back(ref); 357 358 vector<vector<int> >::iterator vvit(v_v_int.begin()), vvitEnd(v_v_int.end()); 359 for (; vvit != vvitEnd; ++vvit) { 360 CPPUNIT_ASSERT( *vvit == ref ); 361 } 362 363 /* 364 * Forbidden by the Standard: 365 v_v_int.insert(v_v_int.end(), v_v_int.begin(), v_v_int.end()); 366 for (vvit = v_v_int.begin(), vvitEnd = v_v_int.end(); 367 vvit != vvitEnd; ++vvit) { 368 CPPUNIT_ASSERT( *vvit == ref ); 369 } 370 */ 371 } 372 373 void VectorTest::allocator_with_state() 374 { 375 char buf1[1024]; 376 StackAllocator<int> stack1(buf1, buf1 + sizeof(buf1)); 377 378 char buf2[1024]; 379 StackAllocator<int> stack2(buf2, buf2 + sizeof(buf2)); 380 381 { 382 typedef vector<int, StackAllocator<int> > VectorInt; 383 VectorInt vint1(10, 0, stack1); 384 VectorInt vint1Cpy(vint1); 385 386 VectorInt vint2(10, 1, stack2); 387 VectorInt vint2Cpy(vint2); 388 389 vint1.swap(vint2); 390 391 CPPUNIT_ASSERT( vint1.get_allocator().swaped() ); 392 CPPUNIT_ASSERT( vint2.get_allocator().swaped() ); 393 394 CPPUNIT_ASSERT( vint1 == vint2Cpy ); 395 CPPUNIT_ASSERT( vint2 == vint1Cpy ); 396 CPPUNIT_ASSERT( vint1.get_allocator() == stack2 ); 397 CPPUNIT_ASSERT( vint2.get_allocator() == stack1 ); 398 } 399 CPPUNIT_ASSERT( stack1.ok() ); 400 CPPUNIT_ASSERT( stack2.ok() ); 401 } 402 403 struct Point { 404 int x, y; 405 }; 406 407 struct PointEx : public Point { 408 PointEx() : builtFromBase(false) {} 409 PointEx(const Point&) : builtFromBase(true) {} 410 411 bool builtFromBase; 412 }; 413 414 #if defined (STLPORT) 415 # if defined (_STLP_USE_NAMESPACES) 416 namespace std { 417 # endif 418 _STLP_TEMPLATE_NULL 419 struct __type_traits<PointEx> { 420 typedef __false_type has_trivial_default_constructor; 421 typedef __true_type has_trivial_copy_constructor; 422 typedef __true_type has_trivial_assignment_operator; 423 typedef __true_type has_trivial_destructor; 424 typedef __true_type is_POD_type; 425 }; 426 # if defined (_STLP_USE_NAMESPACES) 427 } 428 # endif 429 #endif 430 431 //This test check that vector implementation do not over optimize 432 //operation as PointEx copy constructor is trivial 433 void VectorTest::optimizations_check() 434 { 435 #if !defined (STLPORT) || !defined (_STLP_NO_MEMBER_TEMPLATES) 436 vector<Point> v1(1); 437 CPPUNIT_ASSERT( v1.size() == 1 ); 438 439 vector<PointEx> v2(v1.begin(), v1.end()); 440 CPPUNIT_ASSERT( v2.size() == 1 ); 441 CPPUNIT_ASSERT( v2[0].builtFromBase == true ); 442 #endif 443 } 444 445 void VectorTest::assign_check() 446 { 447 #if !defined (STLPORT) || !defined (_STLP_NO_MEMBER_TEMPLATES) 448 vector<int> v(3,1); 449 int array[] = { 1, 2, 3, 4, 5 }; 450 451 v.assign( array, array + 5 ); 452 CPPUNIT_CHECK( v[4] == 5 ); 453 CPPUNIT_CHECK( v[0] == 1 ); 454 CPPUNIT_CHECK( v[1] == 2 ); 455 #endif 456 } 457 458 void VectorTest::iterators() 459 { 460 vector<int> vint(10, 0); 461 vector<int> const& crvint = vint; 462 463 CPPUNIT_ASSERT( vint.begin() == vint.begin() ); 464 CPPUNIT_ASSERT( crvint.begin() == vint.begin() ); 465 CPPUNIT_ASSERT( vint.begin() == crvint.begin() ); 466 CPPUNIT_ASSERT( crvint.begin() == crvint.begin() ); 467 468 CPPUNIT_ASSERT( vint.begin() != vint.end() ); 469 CPPUNIT_ASSERT( crvint.begin() != vint.end() ); 470 CPPUNIT_ASSERT( vint.begin() != crvint.end() ); 471 CPPUNIT_ASSERT( crvint.begin() != crvint.end() ); 472 473 CPPUNIT_ASSERT( vint.rbegin() == vint.rbegin() ); 474 // Not Standard: 475 //CPPUNIT_ASSERT( vint.rbegin() == crvint.rbegin() ); 476 //CPPUNIT_ASSERT( crvint.rbegin() == vint.rbegin() ); 477 CPPUNIT_ASSERT( crvint.rbegin() == crvint.rbegin() ); 478 479 CPPUNIT_ASSERT( vint.rbegin() != vint.rend() ); 480 // Not Standard: 481 //CPPUNIT_ASSERT( vint.rbegin() != crvint.rend() ); 482 //CPPUNIT_ASSERT( crvint.rbegin() != vint.rend() ); 483 CPPUNIT_ASSERT( crvint.rbegin() != crvint.rend() ); 484 } 485 486 487 #if !defined (STLPORT) || \ 488 !defined (_STLP_USE_PTR_SPECIALIZATIONS) || defined (_STLP_CLASS_PARTIAL_SPECIALIZATION) 489 /* Simple compilation test: Check that nested types like iterator 490 * can be access even if type used to instanciate container is not 491 * yet completely defined. 492 */ 493 class IncompleteClass 494 { 495 vector<IncompleteClass> instances; 496 typedef vector<IncompleteClass>::iterator it; 497 }; 498 #endif 499 500 #if defined (STLPORT) 501 # define NOTHROW _STLP_NOTHROW 502 #else 503 # define NOTHROW throw() 504 #endif 505 506 /* This allocator implementation purpose is simply to break some 507 * internal STLport mecanism specific to the STLport own allocator 508 * implementation. */ 509 template <class _Tp> 510 struct NotSTLportAllocator : public allocator<_Tp> { 511 #if !defined (STLPORT) || defined (_STLP_MEMBER_TEMPLATE_CLASSES) 512 template <class _Tp1> struct rebind { 513 typedef NotSTLportAllocator<_Tp1> other; 514 }; 515 #endif 516 NotSTLportAllocator() NOTHROW {} 517 #if !defined (STLPORT) || defined (_STLP_MEMBER_TEMPLATES) 518 template <class _Tp1> NotSTLportAllocator(const NotSTLportAllocator<_Tp1>&) NOTHROW {} 519 #endif 520 NotSTLportAllocator(const NotSTLportAllocator<_Tp>&) NOTHROW {} 521 ~NotSTLportAllocator() NOTHROW {} 522 }; 523 524 /* This test check a potential issue with empty base class 525 * optimization. Some compilers (VC6) do not implement it 526 * correctly resulting ina wrong behavior. */ 527 void VectorTest::ebo() 528 { 529 // We use heap memory as test failure can corrupt vector internal 530 // representation making executable crash on vector destructor invocation. 531 // We prefer a simple memory leak, internal corruption should be reveal 532 // by size or capacity checks. 533 typedef vector<int, NotSTLportAllocator<int> > V; 534 V *pv1 = new V(1, 1); 535 V *pv2 = new V(10, 2); 536 537 size_t v1Capacity = pv1->capacity(); 538 size_t v2Capacity = pv2->capacity(); 539 540 pv1->swap(*pv2); 541 542 CPPUNIT_ASSERT( pv1->size() == 10 ); 543 CPPUNIT_ASSERT( pv1->capacity() == v2Capacity ); 544 CPPUNIT_ASSERT( (*pv1)[5] == 2 ); 545 546 CPPUNIT_ASSERT( pv2->size() == 1 ); 547 CPPUNIT_ASSERT( pv2->capacity() == v1Capacity ); 548 CPPUNIT_ASSERT( (*pv2)[0] == 1 ); 549 550 delete pv2; 551 delete pv1; 552 } 553 554