Home | History | Annotate | Download | only in gtl
      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