1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 ==============================================================================*/ 15 16 #include "tensorflow/core/lib/gtl/inlined_vector.h" 17 18 #include <list> 19 #include <memory> 20 #include <string> 21 #include <vector> 22 23 #include "tensorflow/core/platform/logging.h" 24 #include "tensorflow/core/platform/macros.h" 25 #include "tensorflow/core/platform/test.h" 26 #include "tensorflow/core/platform/test_benchmark.h" 27 #include "tensorflow/core/platform/types.h" 28 29 namespace tensorflow { 30 31 typedef tensorflow::gtl::InlinedVector<int, 8> IntVec; 32 33 // A type that counts number of live occurrences of the type 34 static int64 instances = 0; 35 class Instance { 36 public: 37 int value_; 38 explicit Instance(int x) : value_(x) { instances++; } 39 Instance(const Instance& x) : value_(x.value_) { instances++; } 40 ~Instance() { instances--; } 41 42 friend inline void swap(Instance& a, Instance& b) { 43 using std::swap; 44 swap(a.value_, b.value_); 45 } 46 47 friend std::ostream& operator<<(std::ostream& o, const Instance& v) { 48 return o << "[value:" << v.value_ << "]"; 49 } 50 }; 51 52 typedef tensorflow::gtl::InlinedVector<Instance, 8> InstanceVec; 53 54 // A simple reference counted class to make sure that the proper elements are 55 // destroyed in the erase(begin, end) test. 56 class RefCounted { 57 public: 58 RefCounted(int value, int* count) : value_(value), count_(count) { Ref(); } 59 60 RefCounted(const RefCounted& v) : value_(v.value_), count_(v.count_) { 61 VLOG(5) << "[RefCounted: copy" 62 << " from count @" << v.count_ << "]"; 63 Ref(); 64 } 65 66 ~RefCounted() { 67 Unref(); 68 count_ = nullptr; 69 } 70 71 friend void swap(RefCounted& a, RefCounted& b) { 72 using std::swap; 73 swap(a.value_, b.value_); 74 swap(a.count_, b.count_); 75 } 76 77 RefCounted& operator=(RefCounted v) { 78 using std::swap; 79 swap(*this, v); 80 return *this; 81 } 82 83 void Ref() const { 84 CHECK(count_ != nullptr); 85 ++(*count_); 86 VLOG(5) << "[Ref: refcount " << *count_ << " on count @" << count_ << "]"; 87 } 88 89 void Unref() const { 90 --(*count_); 91 CHECK_GE(*count_, 0); 92 VLOG(5) << "[Unref: refcount " << *count_ << " on count @" << count_ << "]"; 93 } 94 95 int count() const { return *count_; } 96 97 friend std::ostream& operator<<(std::ostream& o, const RefCounted& v) { 98 return o << "[value:" << v.value_ << ", count:" << *v.count_ << "]"; 99 } 100 101 int value_; 102 int* count_; 103 }; 104 105 typedef tensorflow::gtl::InlinedVector<RefCounted, 8> RefCountedVec; 106 107 // A class with a vtable pointer 108 class Dynamic { 109 public: 110 virtual ~Dynamic() {} 111 112 friend std::ostream& operator<<(std::ostream& o, const Dynamic& v) { 113 return o << "[Dynamic]"; 114 } 115 }; 116 117 typedef tensorflow::gtl::InlinedVector<Dynamic, 8> DynamicVec; 118 119 // Append 0..len-1 to *v 120 static void Fill(IntVec* v, int len, int offset = 0) { 121 for (int i = 0; i < len; i++) { 122 v->push_back(i + offset); 123 } 124 } 125 126 static IntVec Fill(int len, int offset = 0) { 127 IntVec v; 128 Fill(&v, len, offset); 129 return v; 130 } 131 132 TEST(IntVec, SimpleOps) { 133 for (int len = 0; len < 20; len++) { 134 IntVec v; 135 const IntVec& cv = v; // const alias 136 137 Fill(&v, len); 138 EXPECT_EQ(len, v.size()); 139 EXPECT_LE(len, v.capacity()); 140 141 for (int i = 0; i < len; i++) { 142 EXPECT_EQ(i, v[i]); 143 } 144 EXPECT_EQ(v.begin(), v.data()); 145 EXPECT_EQ(cv.begin(), cv.data()); 146 147 int counter = 0; 148 for (IntVec::iterator iter = v.begin(); iter != v.end(); ++iter) { 149 EXPECT_EQ(counter, *iter); 150 counter++; 151 } 152 EXPECT_EQ(counter, len); 153 154 counter = 0; 155 for (IntVec::const_iterator iter = v.begin(); iter != v.end(); ++iter) { 156 EXPECT_EQ(counter, *iter); 157 counter++; 158 } 159 EXPECT_EQ(counter, len); 160 161 if (len > 0) { 162 EXPECT_EQ(0, v.front()); 163 EXPECT_EQ(len - 1, v.back()); 164 v.pop_back(); 165 EXPECT_EQ(len - 1, v.size()); 166 for (size_t i = 0; i < v.size(); ++i) { 167 EXPECT_EQ(i, v[i]); 168 } 169 } 170 } 171 } 172 173 TEST(IntVec, Erase) { 174 for (int len = 1; len < 20; len++) { 175 for (int i = 0; i < len; ++i) { 176 IntVec v; 177 Fill(&v, len); 178 v.erase(v.begin() + i); 179 EXPECT_EQ(len - 1, v.size()); 180 for (int j = 0; j < i; ++j) { 181 EXPECT_EQ(j, v[j]); 182 } 183 for (int j = i; j < len - 1; ++j) { 184 EXPECT_EQ(j + 1, v[j]); 185 } 186 } 187 } 188 } 189 190 // At the end of this test loop, the elements between [erase_begin, erase_end) 191 // should have reference counts == 0, and all others elements should have 192 // reference counts == 1. 193 TEST(RefCountedVec, EraseBeginEnd) { 194 for (int len = 1; len < 20; ++len) { 195 for (int erase_begin = 0; erase_begin < len; ++erase_begin) { 196 for (int erase_end = erase_begin; erase_end <= len; ++erase_end) { 197 std::vector<int> counts(len, 0); 198 RefCountedVec v; 199 for (int i = 0; i < len; ++i) { 200 v.push_back(RefCounted(i, &counts[i])); 201 } 202 203 int erase_len = erase_end - erase_begin; 204 205 v.erase(v.begin() + erase_begin, v.begin() + erase_end); 206 207 EXPECT_EQ(len - erase_len, v.size()); 208 209 // Check the elements before the first element erased. 210 for (int i = 0; i < erase_begin; ++i) { 211 EXPECT_EQ(i, v[i].value_); 212 } 213 214 // Check the elements after the first element erased. 215 for (size_t i = erase_begin; i < v.size(); ++i) { 216 EXPECT_EQ(i + erase_len, v[i].value_); 217 } 218 219 // Check that the elements at the beginning are preserved. 220 for (int i = 0; i < erase_begin; ++i) { 221 EXPECT_EQ(1, counts[i]); 222 } 223 224 // Check that the erased elements are destroyed 225 for (int i = erase_begin; i < erase_end; ++i) { 226 EXPECT_EQ(0, counts[i]); 227 } 228 229 // Check that the elements at the end are preserved. 230 for (int i = erase_end; i < len; ++i) { 231 EXPECT_EQ(1, counts[i]); 232 } 233 } 234 } 235 } 236 } 237 238 struct NoDefaultCtor { 239 explicit NoDefaultCtor(int) {} 240 }; 241 struct NoCopy { 242 NoCopy() {} 243 NoCopy(const NoCopy&) = delete; 244 }; 245 struct NoAssign { 246 NoAssign() {} 247 NoAssign& operator=(const NoAssign&) = delete; 248 }; 249 struct MoveOnly { 250 MoveOnly() {} 251 MoveOnly(MoveOnly&&) = default; 252 MoveOnly& operator=(MoveOnly&&) = default; 253 }; 254 TEST(InlinedVectorTest, NoDefaultCtor) { 255 tensorflow::gtl::InlinedVector<NoDefaultCtor, 1> v(10, NoDefaultCtor(2)); 256 (void)v; 257 } 258 TEST(InlinedVectorTest, NoCopy) { 259 tensorflow::gtl::InlinedVector<NoCopy, 1> v(10); 260 (void)v; 261 } 262 TEST(InlinedVectorTest, NoAssign) { 263 tensorflow::gtl::InlinedVector<NoAssign, 1> v(10); 264 (void)v; 265 } 266 TEST(InlinedVectorTest, MoveOnly) { 267 gtl::InlinedVector<MoveOnly, 2> v; 268 v.push_back(MoveOnly{}); 269 v.push_back(MoveOnly{}); 270 v.push_back(MoveOnly{}); 271 } 272 273 TEST(IntVec, Insert) { 274 for (int len = 0; len < 20; len++) { 275 for (int pos = 0; pos <= len; pos++) { 276 IntVec v; 277 Fill(&v, len); 278 v.insert(v.begin() + pos, 9999); 279 EXPECT_EQ(v.size(), len + 1); 280 for (int i = 0; i < pos; i++) { 281 EXPECT_EQ(v[i], i); 282 } 283 EXPECT_EQ(v[pos], 9999); 284 for (size_t i = pos + 1; i < v.size(); i++) { 285 EXPECT_EQ(v[i], i - 1); 286 } 287 } 288 } 289 } 290 291 TEST(RefCountedVec, InsertConstructorDestructor) { 292 // Make sure the proper construction/destruction happen during insert 293 // operations. 294 for (int len = 0; len < 20; len++) { 295 SCOPED_TRACE(len); 296 for (int pos = 0; pos <= len; pos++) { 297 SCOPED_TRACE(pos); 298 std::vector<int> counts(len, 0); 299 int inserted_count = 0; 300 RefCountedVec v; 301 for (int i = 0; i < len; ++i) { 302 SCOPED_TRACE(i); 303 v.push_back(RefCounted(i, &counts[i])); 304 } 305 306 for (auto elem : counts) { 307 EXPECT_EQ(1, elem); 308 } 309 310 RefCounted insert_element(9999, &inserted_count); 311 EXPECT_EQ(1, inserted_count); 312 v.insert(v.begin() + pos, insert_element); 313 EXPECT_EQ(2, inserted_count); 314 // Check that the elements at the end are preserved. 315 for (auto elem : counts) { 316 EXPECT_EQ(1, elem); 317 } 318 EXPECT_EQ(2, inserted_count); 319 } 320 } 321 } 322 323 TEST(IntVec, Resize) { 324 for (int len = 0; len < 20; len++) { 325 IntVec v; 326 Fill(&v, len); 327 328 // Try resizing up and down by k elements 329 static const int kResizeElem = 1000000; 330 for (int k = 0; k < 10; k++) { 331 // Enlarging resize 332 v.resize(len + k, kResizeElem); 333 EXPECT_EQ(len + k, v.size()); 334 EXPECT_LE(len + k, v.capacity()); 335 for (int i = 0; i < len + k; i++) { 336 if (i < len) { 337 EXPECT_EQ(i, v[i]); 338 } else { 339 EXPECT_EQ(kResizeElem, v[i]); 340 } 341 } 342 343 // Shrinking resize 344 v.resize(len, kResizeElem); 345 EXPECT_EQ(len, v.size()); 346 EXPECT_LE(len, v.capacity()); 347 for (int i = 0; i < len; i++) { 348 EXPECT_EQ(i, v[i]); 349 } 350 } 351 } 352 } 353 354 TEST(IntVec, InitWithLength) { 355 for (int len = 0; len < 20; len++) { 356 IntVec v(len, 7); 357 EXPECT_EQ(len, v.size()); 358 EXPECT_LE(len, v.capacity()); 359 for (int i = 0; i < len; i++) { 360 EXPECT_EQ(7, v[i]); 361 } 362 } 363 } 364 365 TEST(IntVec, CopyConstructorAndAssignment) { 366 for (int len = 0; len < 20; len++) { 367 IntVec v; 368 Fill(&v, len); 369 EXPECT_EQ(len, v.size()); 370 EXPECT_LE(len, v.capacity()); 371 372 IntVec v2(v); 373 EXPECT_EQ(v, v2); 374 375 for (int start_len = 0; start_len < 20; start_len++) { 376 IntVec v3; 377 Fill(&v3, start_len, 99); // Add dummy elements that should go away 378 v3 = v; 379 EXPECT_EQ(v, v3); 380 } 381 } 382 } 383 384 TEST(OverheadTest, Storage) { 385 // Check for size overhead. 386 using tensorflow::gtl::InlinedVector; 387 EXPECT_EQ(2 * sizeof(int*), sizeof(InlinedVector<int*, 1>)); 388 EXPECT_EQ(4 * sizeof(int*), sizeof(InlinedVector<int*, 2>)); 389 EXPECT_EQ(4 * sizeof(int*), sizeof(InlinedVector<int*, 3>)); 390 EXPECT_EQ(6 * sizeof(int*), sizeof(InlinedVector<int*, 4>)); 391 392 EXPECT_EQ(2 * sizeof(char*), sizeof(InlinedVector<char, 1>)); 393 EXPECT_EQ(2 * sizeof(char*), sizeof(InlinedVector<char, 2>)); 394 EXPECT_EQ(2 * sizeof(char*), sizeof(InlinedVector<char, 3>)); 395 EXPECT_EQ(2 * sizeof(char*), 396 sizeof(InlinedVector<char, 2 * sizeof(char*) - 1>)); 397 EXPECT_EQ(4 * sizeof(char*), sizeof(InlinedVector<char, 2 * sizeof(char*)>)); 398 } 399 400 TEST(IntVec, Clear) { 401 for (int len = 0; len < 20; len++) { 402 SCOPED_TRACE(len); 403 IntVec v; 404 Fill(&v, len); 405 v.clear(); 406 EXPECT_EQ(0, v.size()); 407 EXPECT_EQ(v.begin(), v.end()); 408 } 409 } 410 411 TEST(IntVec, Reserve) { 412 for (size_t len = 0; len < 20; len++) { 413 IntVec v; 414 Fill(&v, len); 415 416 for (size_t newlen = 0; newlen < 100; newlen++) { 417 const int* start_rep = v.data(); 418 v.reserve(newlen); 419 const int* final_rep = v.data(); 420 if (newlen <= len) { 421 EXPECT_EQ(start_rep, final_rep); 422 } 423 EXPECT_LE(newlen, v.capacity()); 424 425 // Filling up to newlen should not change rep 426 while (v.size() < newlen) { 427 v.push_back(0); 428 } 429 EXPECT_EQ(final_rep, v.data()); 430 } 431 } 432 } 433 434 template <typename T> 435 static std::vector<typename T::value_type> Vec(const T& src) { 436 std::vector<typename T::value_type> result; 437 for (const auto& elem : src) { 438 result.push_back(elem); 439 } 440 return result; 441 } 442 443 TEST(IntVec, SelfRefPushBack) { 444 std::vector<string> std_v; 445 tensorflow::gtl::InlinedVector<string, 4> v; 446 const string s = "A quite long string to ensure heap."; 447 std_v.push_back(s); 448 v.push_back(s); 449 for (int i = 0; i < 20; ++i) { 450 EXPECT_EQ(std_v, Vec(v)); 451 452 v.push_back(v.back()); 453 std_v.push_back(std_v.back()); 454 } 455 EXPECT_EQ(std_v, Vec(v)); 456 } 457 458 TEST(IntVec, SelfRefPushBackWithMove) { 459 std::vector<string> std_v; 460 gtl::InlinedVector<string, 4> v; 461 const string s = "A quite long string to ensure heap."; 462 std_v.push_back(s); 463 v.push_back(s); 464 for (int i = 0; i < 20; ++i) { 465 EXPECT_EQ(v.back(), std_v.back()); 466 467 v.push_back(std::move(v.back())); 468 std_v.push_back(std::move(std_v.back())); 469 } 470 EXPECT_EQ(v.back(), std_v.back()); 471 } 472 473 TEST(IntVec, Swap) { 474 for (int l1 = 0; l1 < 20; l1++) { 475 SCOPED_TRACE(l1); 476 for (int l2 = 0; l2 < 20; l2++) { 477 SCOPED_TRACE(l2); 478 IntVec a = Fill(l1, 0); 479 IntVec b = Fill(l2, 100); 480 { 481 using std::swap; 482 swap(a, b); 483 } 484 EXPECT_EQ(l1, b.size()); 485 EXPECT_EQ(l2, a.size()); 486 for (int i = 0; i < l1; i++) { 487 SCOPED_TRACE(i); 488 EXPECT_EQ(i, b[i]); 489 } 490 for (int i = 0; i < l2; i++) { 491 SCOPED_TRACE(i); 492 EXPECT_EQ(100 + i, a[i]); 493 } 494 } 495 } 496 } 497 498 TEST(InstanceVec, Swap) { 499 for (int l1 = 0; l1 < 20; l1++) { 500 for (int l2 = 0; l2 < 20; l2++) { 501 InstanceVec a, b; 502 for (int i = 0; i < l1; i++) a.push_back(Instance(i)); 503 for (int i = 0; i < l2; i++) b.push_back(Instance(100 + i)); 504 EXPECT_EQ(l1 + l2, instances); 505 { 506 using std::swap; 507 swap(a, b); 508 } 509 EXPECT_EQ(l1 + l2, instances); 510 EXPECT_EQ(l1, b.size()); 511 EXPECT_EQ(l2, a.size()); 512 for (int i = 0; i < l1; i++) { 513 EXPECT_EQ(i, b[i].value_); 514 } 515 for (int i = 0; i < l2; i++) { 516 EXPECT_EQ(100 + i, a[i].value_); 517 } 518 } 519 } 520 } 521 522 TEST(IntVec, EqualAndNotEqual) { 523 IntVec a, b; 524 EXPECT_TRUE(a == b); 525 EXPECT_FALSE(a != b); 526 527 a.push_back(3); 528 EXPECT_FALSE(a == b); 529 EXPECT_TRUE(a != b); 530 531 b.push_back(3); 532 EXPECT_TRUE(a == b); 533 EXPECT_FALSE(a != b); 534 535 b.push_back(7); 536 EXPECT_FALSE(a == b); 537 EXPECT_TRUE(a != b); 538 539 a.push_back(6); 540 EXPECT_FALSE(a == b); 541 EXPECT_TRUE(a != b); 542 543 a.clear(); 544 b.clear(); 545 for (int i = 0; i < 100; i++) { 546 a.push_back(i); 547 b.push_back(i); 548 EXPECT_TRUE(a == b); 549 EXPECT_FALSE(a != b); 550 551 b[i] = b[i] + 1; 552 EXPECT_FALSE(a == b); 553 EXPECT_TRUE(a != b); 554 555 b[i] = b[i] - 1; // Back to before 556 EXPECT_TRUE(a == b); 557 EXPECT_FALSE(a != b); 558 } 559 } 560 561 TEST(IntVec, RelationalOps) { 562 IntVec a, b; 563 EXPECT_FALSE(a < b); 564 EXPECT_FALSE(b < a); 565 EXPECT_FALSE(a > b); 566 EXPECT_FALSE(b > a); 567 EXPECT_TRUE(a <= b); 568 EXPECT_TRUE(b <= a); 569 EXPECT_TRUE(a >= b); 570 EXPECT_TRUE(b >= a); 571 b.push_back(3); 572 EXPECT_TRUE(a < b); 573 EXPECT_FALSE(b < a); 574 EXPECT_FALSE(a > b); 575 EXPECT_TRUE(b > a); 576 EXPECT_TRUE(a <= b); 577 EXPECT_FALSE(b <= a); 578 EXPECT_FALSE(a >= b); 579 EXPECT_TRUE(b >= a); 580 } 581 582 TEST(InstanceVec, CountConstructorsDestructors) { 583 const int start = instances; 584 for (int len = 0; len < 20; len++) { 585 InstanceVec v; 586 for (int i = 0; i < len; i++) { 587 v.push_back(Instance(i)); 588 } 589 EXPECT_EQ(start + len, instances); 590 591 { // Copy constructor should create 'len' more instances. 592 InstanceVec v_copy(v); 593 EXPECT_EQ(start + len + len, instances); 594 } 595 EXPECT_EQ(start + len, instances); 596 597 // Enlarging resize() must construct some objects 598 v.resize(len + 10, Instance(100)); 599 EXPECT_EQ(start + len + 10, instances); 600 601 // Shrinking resize() must destroy some objects 602 v.resize(len, Instance(100)); 603 EXPECT_EQ(start + len, instances); 604 605 // reserve() must not increase the number of initialized objects 606 v.reserve(len + 1000); 607 EXPECT_EQ(start + len, instances); 608 609 // pop_back() and erase() must destroy one object 610 if (len > 0) { 611 v.pop_back(); 612 EXPECT_EQ(start + len - 1, instances); 613 if (!v.empty()) { 614 v.erase(v.begin()); 615 EXPECT_EQ(start + len - 2, instances); 616 } 617 } 618 } 619 EXPECT_EQ(start, instances); 620 } 621 622 TEST(InstanceVec, CountConstructorsDestructorsOnAssignment) { 623 const int start = instances; 624 for (int len = 0; len < 20; len++) { 625 for (int longorshort = 0; longorshort <= 1; ++longorshort) { 626 InstanceVec longer, shorter; 627 for (int i = 0; i < len; i++) { 628 longer.push_back(Instance(i)); 629 shorter.push_back(Instance(i)); 630 } 631 longer.push_back(Instance(len)); 632 EXPECT_EQ(start + len + len + 1, instances); 633 634 if (longorshort) { 635 shorter = longer; 636 EXPECT_EQ(start + (len + 1) + (len + 1), instances); 637 } else { 638 longer = shorter; 639 EXPECT_EQ(start + len + len, instances); 640 } 641 } 642 } 643 EXPECT_EQ(start, instances); 644 } 645 646 TEST(RangedConstructor, SimpleType) { 647 std::vector<int> source_v = {4, 5, 6, 7}; 648 // First try to fit in inline backing 649 tensorflow::gtl::InlinedVector<int, 4> v(source_v.begin(), source_v.end()); 650 tensorflow::gtl::InlinedVector<int, 4> empty4; 651 EXPECT_EQ(4, v.size()); 652 EXPECT_EQ(empty4.capacity(), v.capacity()); // Must still be inline 653 EXPECT_EQ(4, v[0]); 654 EXPECT_EQ(5, v[1]); 655 EXPECT_EQ(6, v[2]); 656 EXPECT_EQ(7, v[3]); 657 658 // Now, force a re-allocate 659 tensorflow::gtl::InlinedVector<int, 2> realloc_v(source_v.begin(), 660 source_v.end()); 661 tensorflow::gtl::InlinedVector<int, 2> empty2; 662 EXPECT_EQ(4, realloc_v.size()); 663 EXPECT_LT(empty2.capacity(), realloc_v.capacity()); 664 EXPECT_EQ(4, realloc_v[0]); 665 EXPECT_EQ(5, realloc_v[1]); 666 EXPECT_EQ(6, realloc_v[2]); 667 EXPECT_EQ(7, realloc_v[3]); 668 } 669 670 TEST(RangedConstructor, ComplexType) { 671 // We also use a list here to pass a different flavor of iterator (e.g. not 672 // random-access). 673 std::list<Instance> source_v = {Instance(0)}; 674 675 // First try to fit in inline backing 676 tensorflow::gtl::InlinedVector<Instance, 1> v(source_v.begin(), 677 source_v.end()); 678 tensorflow::gtl::InlinedVector<Instance, 1> empty1; 679 EXPECT_EQ(1, v.size()); 680 EXPECT_EQ(empty1.capacity(), v.capacity()); // Must still be inline 681 EXPECT_EQ(0, v[0].value_); 682 683 std::list<Instance> source_v2 = {Instance(0), Instance(1), Instance(2), 684 Instance(3)}; 685 // Now, force a re-allocate 686 tensorflow::gtl::InlinedVector<Instance, 1> realloc_v(source_v2.begin(), 687 source_v2.end()); 688 EXPECT_EQ(4, realloc_v.size()); 689 EXPECT_LT(empty1.capacity(), realloc_v.capacity()); 690 EXPECT_EQ(0, realloc_v[0].value_); 691 EXPECT_EQ(1, realloc_v[1].value_); 692 EXPECT_EQ(2, realloc_v[2].value_); 693 EXPECT_EQ(3, realloc_v[3].value_); 694 } 695 696 TEST(RangedConstructor, ElementsAreConstructed) { 697 std::vector<string> source_v = {"cat", "dog"}; 698 699 // Force expansion and re-allocation of v. Ensures that when the vector is 700 // expanded that new elements are constructed. 701 tensorflow::gtl::InlinedVector<string, 1> v(source_v.begin(), source_v.end()); 702 EXPECT_EQ("cat", v[0]); 703 EXPECT_EQ("dog", v[1]); 704 } 705 706 TEST(InitializerListConstructor, SimpleTypeWithInlineBacking) { 707 auto vec = tensorflow::gtl::InlinedVector<int, 3>{4, 5, 6}; 708 EXPECT_EQ(3, vec.size()); 709 EXPECT_EQ(3, vec.capacity()); 710 EXPECT_EQ(4, vec[0]); 711 EXPECT_EQ(5, vec[1]); 712 EXPECT_EQ(6, vec[2]); 713 } 714 715 TEST(InitializerListConstructor, SimpleTypeWithReallocationRequired) { 716 auto vec = tensorflow::gtl::InlinedVector<int, 2>{4, 5, 6}; 717 EXPECT_EQ(3, vec.size()); 718 EXPECT_LE(3, vec.capacity()); 719 EXPECT_EQ(4, vec[0]); 720 EXPECT_EQ(5, vec[1]); 721 EXPECT_EQ(6, vec[2]); 722 } 723 724 TEST(InitializerListConstructor, DisparateTypesInList) { 725 EXPECT_EQ((std::vector<int>{-7, 8}), 726 Vec(tensorflow::gtl::InlinedVector<int, 2>{-7, 8ULL})); 727 728 EXPECT_EQ( 729 (std::vector<string>{"foo", "bar"}), 730 Vec(tensorflow::gtl::InlinedVector<string, 2>{"foo", string("bar")})); 731 } 732 733 TEST(InitializerListConstructor, ComplexTypeWithInlineBacking) { 734 tensorflow::gtl::InlinedVector<Instance, 1> empty; 735 auto vec = tensorflow::gtl::InlinedVector<Instance, 1>{Instance(0)}; 736 EXPECT_EQ(1, vec.size()); 737 EXPECT_EQ(empty.capacity(), vec.capacity()); 738 EXPECT_EQ(0, vec[0].value_); 739 } 740 741 TEST(InitializerListConstructor, ComplexTypeWithReallocationRequired) { 742 auto vec = 743 tensorflow::gtl::InlinedVector<Instance, 1>{Instance(0), Instance(1)}; 744 EXPECT_EQ(2, vec.size()); 745 EXPECT_LE(2, vec.capacity()); 746 EXPECT_EQ(0, vec[0].value_); 747 EXPECT_EQ(1, vec[1].value_); 748 } 749 750 TEST(DynamicVec, DynamicVecCompiles) { 751 DynamicVec v; 752 (void)v; 753 } 754 755 static void BM_InlinedVectorFill(int iters, int len) { 756 for (int i = 0; i < iters; i++) { 757 IntVec v; 758 for (int j = 0; j < len; j++) { 759 v.push_back(j); 760 } 761 } 762 testing::BytesProcessed((int64{iters} * len) * sizeof(int)); 763 } 764 BENCHMARK(BM_InlinedVectorFill)->Range(0, 1024); 765 766 static void BM_InlinedVectorFillRange(int iters, int len) { 767 std::unique_ptr<int[]> ia(new int[len]); 768 for (int j = 0; j < len; j++) { 769 ia[j] = j; 770 } 771 for (int i = 0; i < iters; i++) { 772 IntVec TF_ATTRIBUTE_UNUSED v(ia.get(), ia.get() + len); 773 } 774 testing::BytesProcessed((int64{iters} * len) * sizeof(int)); 775 } 776 BENCHMARK(BM_InlinedVectorFillRange)->Range(0, 1024); 777 778 static void BM_StdVectorFill(int iters, int len) { 779 for (int i = 0; i < iters; i++) { 780 std::vector<int> v; 781 v.reserve(len); 782 for (int j = 0; j < len; j++) { 783 v.push_back(j); 784 } 785 } 786 testing::BytesProcessed((int64{iters} * len) * sizeof(int)); 787 } 788 BENCHMARK(BM_StdVectorFill)->Range(0, 1024); 789 790 bool StringRepresentedInline(string s) { 791 const char* chars = s.data(); 792 string s1 = std::move(s); 793 return s1.data() != chars; 794 } 795 796 static void BM_InlinedVectorFillString(int iters, int len) { 797 string strings[4] = {"a quite long string", "another long string", 798 "012345678901234567", "to cause allocation"}; 799 for (int i = 0; i < iters; i++) { 800 gtl::InlinedVector<string, 8> v; 801 for (int j = 0; j < len; j++) { 802 v.push_back(strings[j & 3]); 803 } 804 } 805 testing::ItemsProcessed(int64{iters} * len); 806 } 807 BENCHMARK(BM_InlinedVectorFillString)->Range(0, 1024); 808 809 static void BM_StdVectorFillString(int iters, int len) { 810 string strings[4] = {"a quite long string", "another long string", 811 "012345678901234567", "to cause allocation"}; 812 for (int i = 0; i < iters; i++) { 813 std::vector<string> v; 814 v.reserve(len); 815 for (int j = 0; j < len; j++) { 816 v.push_back(strings[j & 3]); 817 } 818 } 819 testing::ItemsProcessed(int64{iters} * len); 820 // The purpose of the benchmark is to verify that inlined vector is 821 // efficient when moving is more efficient than copying. To do so, we 822 // use strings that are larger than the small string optimization. 823 CHECK(!StringRepresentedInline(strings[0])); 824 } 825 BENCHMARK(BM_StdVectorFillString)->Range(0, 1024); 826 827 namespace { 828 struct Buffer { // some arbitrary structure for benchmarking. 829 char* base; 830 int length; 831 int capacity; 832 void* user_data; 833 }; 834 } // anonymous namespace 835 836 static void BM_InlinedVectorTenAssignments(int iters, int len) { 837 typedef tensorflow::gtl::InlinedVector<Buffer, 2> BufferVec; 838 839 BufferVec src; 840 src.resize(len); 841 842 iters *= 10; 843 BufferVec dst; 844 for (int i = 0; i < iters; i++) { 845 dst = src; 846 } 847 } 848 BENCHMARK(BM_InlinedVectorTenAssignments) 849 ->Arg(0) 850 ->Arg(1) 851 ->Arg(2) 852 ->Arg(3) 853 ->Arg(4) 854 ->Arg(20); 855 856 static void BM_CreateFromInitializerList(int iters) { 857 for (; iters > 0; iters--) { 858 tensorflow::gtl::InlinedVector<int, 4> x{1, 2, 3}; 859 (void)x[0]; 860 } 861 } 862 BENCHMARK(BM_CreateFromInitializerList); 863 864 namespace { 865 866 struct LargeSwappable { 867 LargeSwappable() : d_(1024, 17) {} 868 ~LargeSwappable() {} 869 LargeSwappable(const LargeSwappable& o) : d_(o.d_) {} 870 871 friend void swap(LargeSwappable& a, LargeSwappable& b) { 872 using std::swap; 873 swap(a.d_, b.d_); 874 } 875 876 LargeSwappable& operator=(LargeSwappable o) { 877 using std::swap; 878 swap(*this, o); 879 return *this; 880 } 881 882 std::vector<int> d_; 883 }; 884 885 } // namespace 886 887 static void BM_LargeSwappableElements(int iters, int len) { 888 typedef tensorflow::gtl::InlinedVector<LargeSwappable, 32> Vec; 889 Vec a(len); 890 Vec b; 891 while (--iters >= 0) { 892 using std::swap; 893 swap(a, b); 894 } 895 } 896 BENCHMARK(BM_LargeSwappableElements)->Range(0, 1024); 897 898 } // namespace tensorflow 899