123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815 |
- // Copyright 2019 The Abseil Authors.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // https://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #include "absl/container/inlined_vector.h"
- #include <algorithm>
- #include <forward_list>
- #include <list>
- #include <memory>
- #include <scoped_allocator>
- #include <sstream>
- #include <stdexcept>
- #include <string>
- #include <vector>
- #include "gmock/gmock.h"
- #include "gtest/gtest.h"
- #include "absl/base/attributes.h"
- #include "absl/base/internal/exception_testing.h"
- #include "absl/base/internal/raw_logging.h"
- #include "absl/base/macros.h"
- #include "absl/base/options.h"
- #include "absl/container/internal/counting_allocator.h"
- #include "absl/container/internal/test_instance_tracker.h"
- #include "absl/hash/hash_testing.h"
- #include "absl/memory/memory.h"
- #include "absl/strings/str_cat.h"
- namespace {
- using absl::container_internal::CountingAllocator;
- using absl::test_internal::CopyableMovableInstance;
- using absl::test_internal::CopyableOnlyInstance;
- using absl::test_internal::InstanceTracker;
- using testing::AllOf;
- using testing::Each;
- using testing::ElementsAre;
- using testing::ElementsAreArray;
- using testing::Eq;
- using testing::Gt;
- using testing::PrintToString;
- using IntVec = absl::InlinedVector<int, 8>;
- MATCHER_P(SizeIs, n, "") {
- return testing::ExplainMatchResult(n, arg.size(), result_listener);
- }
- MATCHER_P(CapacityIs, n, "") {
- return testing::ExplainMatchResult(n, arg.capacity(), result_listener);
- }
- MATCHER_P(ValueIs, e, "") {
- return testing::ExplainMatchResult(e, arg.value(), result_listener);
- }
- // TODO(bsamwel): Add support for movable-only types.
- // Test fixture for typed tests on BaseCountedInstance derived classes, see
- // test_instance_tracker.h.
- template <typename T>
- class InstanceTest : public ::testing::Test {};
- TYPED_TEST_SUITE_P(InstanceTest);
- // A simple reference counted class to make sure that the proper elements are
- // destroyed in the erase(begin, end) test.
- class RefCounted {
- public:
- RefCounted(int value, int* count) : value_(value), count_(count) { Ref(); }
- RefCounted(const RefCounted& v) : value_(v.value_), count_(v.count_) {
- Ref();
- }
- ~RefCounted() {
- Unref();
- count_ = nullptr;
- }
- friend void swap(RefCounted& a, RefCounted& b) {
- using std::swap;
- swap(a.value_, b.value_);
- swap(a.count_, b.count_);
- }
- RefCounted& operator=(RefCounted v) {
- using std::swap;
- swap(*this, v);
- return *this;
- }
- void Ref() const {
- ABSL_RAW_CHECK(count_ != nullptr, "");
- ++(*count_);
- }
- void Unref() const {
- --(*count_);
- ABSL_RAW_CHECK(*count_ >= 0, "");
- }
- int value_;
- int* count_;
- };
- using RefCountedVec = absl::InlinedVector<RefCounted, 8>;
- // A class with a vtable pointer
- class Dynamic {
- public:
- virtual ~Dynamic() {}
- };
- using DynamicVec = absl::InlinedVector<Dynamic, 8>;
- // Append 0..len-1 to *v
- template <typename Container>
- static void Fill(Container* v, int len, int offset = 0) {
- for (int i = 0; i < len; i++) {
- v->push_back(i + offset);
- }
- }
- static IntVec Fill(int len, int offset = 0) {
- IntVec v;
- Fill(&v, len, offset);
- return v;
- }
- TEST(IntVec, SimpleOps) {
- for (int len = 0; len < 20; len++) {
- IntVec v;
- const IntVec& cv = v; // const alias
- Fill(&v, len);
- EXPECT_EQ(len, v.size());
- EXPECT_LE(len, v.capacity());
- for (int i = 0; i < len; i++) {
- EXPECT_EQ(i, v[i]);
- EXPECT_EQ(i, v.at(i));
- }
- EXPECT_EQ(v.begin(), v.data());
- EXPECT_EQ(cv.begin(), cv.data());
- int counter = 0;
- for (IntVec::iterator iter = v.begin(); iter != v.end(); ++iter) {
- EXPECT_EQ(counter, *iter);
- counter++;
- }
- EXPECT_EQ(counter, len);
- counter = 0;
- for (IntVec::const_iterator iter = v.begin(); iter != v.end(); ++iter) {
- EXPECT_EQ(counter, *iter);
- counter++;
- }
- EXPECT_EQ(counter, len);
- counter = 0;
- for (IntVec::const_iterator iter = v.cbegin(); iter != v.cend(); ++iter) {
- EXPECT_EQ(counter, *iter);
- counter++;
- }
- EXPECT_EQ(counter, len);
- if (len > 0) {
- EXPECT_EQ(0, v.front());
- EXPECT_EQ(len - 1, v.back());
- v.pop_back();
- EXPECT_EQ(len - 1, v.size());
- for (int i = 0; i < v.size(); ++i) {
- EXPECT_EQ(i, v[i]);
- EXPECT_EQ(i, v.at(i));
- }
- }
- }
- }
- TEST(IntVec, PopBackNoOverflow) {
- IntVec v = {1};
- v.pop_back();
- EXPECT_EQ(v.size(), 0);
- }
- TEST(IntVec, AtThrows) {
- IntVec v = {1, 2, 3};
- EXPECT_EQ(v.at(2), 3);
- ABSL_BASE_INTERNAL_EXPECT_FAIL(v.at(3), std::out_of_range,
- "failed bounds check");
- }
- TEST(IntVec, ReverseIterator) {
- for (int len = 0; len < 20; len++) {
- IntVec v;
- Fill(&v, len);
- int counter = len;
- for (IntVec::reverse_iterator iter = v.rbegin(); iter != v.rend(); ++iter) {
- counter--;
- EXPECT_EQ(counter, *iter);
- }
- EXPECT_EQ(counter, 0);
- counter = len;
- for (IntVec::const_reverse_iterator iter = v.rbegin(); iter != v.rend();
- ++iter) {
- counter--;
- EXPECT_EQ(counter, *iter);
- }
- EXPECT_EQ(counter, 0);
- counter = len;
- for (IntVec::const_reverse_iterator iter = v.crbegin(); iter != v.crend();
- ++iter) {
- counter--;
- EXPECT_EQ(counter, *iter);
- }
- EXPECT_EQ(counter, 0);
- }
- }
- TEST(IntVec, Erase) {
- for (int len = 1; len < 20; len++) {
- for (int i = 0; i < len; ++i) {
- IntVec v;
- Fill(&v, len);
- v.erase(v.begin() + i);
- EXPECT_EQ(len - 1, v.size());
- for (int j = 0; j < i; ++j) {
- EXPECT_EQ(j, v[j]);
- }
- for (int j = i; j < len - 1; ++j) {
- EXPECT_EQ(j + 1, v[j]);
- }
- }
- }
- }
- TEST(IntVec, Hardened) {
- IntVec v;
- Fill(&v, 10);
- EXPECT_EQ(v[9], 9);
- #if !defined(NDEBUG) || ABSL_OPTION_HARDENED
- EXPECT_DEATH_IF_SUPPORTED(v[10], "");
- EXPECT_DEATH_IF_SUPPORTED(v[-1], "");
- #endif
- }
- // At the end of this test loop, the elements between [erase_begin, erase_end)
- // should have reference counts == 0, and all others elements should have
- // reference counts == 1.
- TEST(RefCountedVec, EraseBeginEnd) {
- for (int len = 1; len < 20; ++len) {
- for (int erase_begin = 0; erase_begin < len; ++erase_begin) {
- for (int erase_end = erase_begin; erase_end <= len; ++erase_end) {
- std::vector<int> counts(len, 0);
- RefCountedVec v;
- for (int i = 0; i < len; ++i) {
- v.push_back(RefCounted(i, &counts[i]));
- }
- int erase_len = erase_end - erase_begin;
- v.erase(v.begin() + erase_begin, v.begin() + erase_end);
- EXPECT_EQ(len - erase_len, v.size());
- // Check the elements before the first element erased.
- for (int i = 0; i < erase_begin; ++i) {
- EXPECT_EQ(i, v[i].value_);
- }
- // Check the elements after the first element erased.
- for (int i = erase_begin; i < v.size(); ++i) {
- EXPECT_EQ(i + erase_len, v[i].value_);
- }
- // Check that the elements at the beginning are preserved.
- for (int i = 0; i < erase_begin; ++i) {
- EXPECT_EQ(1, counts[i]);
- }
- // Check that the erased elements are destroyed
- for (int i = erase_begin; i < erase_end; ++i) {
- EXPECT_EQ(0, counts[i]);
- }
- // Check that the elements at the end are preserved.
- for (int i = erase_end; i < len; ++i) {
- EXPECT_EQ(1, counts[i]);
- }
- }
- }
- }
- }
- struct NoDefaultCtor {
- explicit NoDefaultCtor(int) {}
- };
- struct NoCopy {
- NoCopy() {}
- NoCopy(const NoCopy&) = delete;
- };
- struct NoAssign {
- NoAssign() {}
- NoAssign& operator=(const NoAssign&) = delete;
- };
- struct MoveOnly {
- MoveOnly() {}
- MoveOnly(MoveOnly&&) = default;
- MoveOnly& operator=(MoveOnly&&) = default;
- };
- TEST(InlinedVectorTest, NoDefaultCtor) {
- absl::InlinedVector<NoDefaultCtor, 1> v(10, NoDefaultCtor(2));
- (void)v;
- }
- TEST(InlinedVectorTest, NoCopy) {
- absl::InlinedVector<NoCopy, 1> v(10);
- (void)v;
- }
- TEST(InlinedVectorTest, NoAssign) {
- absl::InlinedVector<NoAssign, 1> v(10);
- (void)v;
- }
- TEST(InlinedVectorTest, MoveOnly) {
- absl::InlinedVector<MoveOnly, 2> v;
- v.push_back(MoveOnly{});
- v.push_back(MoveOnly{});
- v.push_back(MoveOnly{});
- v.erase(v.begin());
- v.push_back(MoveOnly{});
- v.erase(v.begin(), v.begin() + 1);
- v.insert(v.begin(), MoveOnly{});
- v.emplace(v.begin());
- v.emplace(v.begin(), MoveOnly{});
- }
- TEST(InlinedVectorTest, Noexcept) {
- EXPECT_TRUE(std::is_nothrow_move_constructible<IntVec>::value);
- EXPECT_TRUE((std::is_nothrow_move_constructible<
- absl::InlinedVector<MoveOnly, 2>>::value));
- struct MoveCanThrow {
- MoveCanThrow(MoveCanThrow&&) {}
- };
- EXPECT_EQ(absl::default_allocator_is_nothrow::value,
- (std::is_nothrow_move_constructible<
- absl::InlinedVector<MoveCanThrow, 2>>::value));
- }
- TEST(InlinedVectorTest, EmplaceBack) {
- absl::InlinedVector<std::pair<std::string, int>, 1> v;
- auto& inlined_element = v.emplace_back("answer", 42);
- EXPECT_EQ(&inlined_element, &v[0]);
- EXPECT_EQ(inlined_element.first, "answer");
- EXPECT_EQ(inlined_element.second, 42);
- auto& allocated_element = v.emplace_back("taxicab", 1729);
- EXPECT_EQ(&allocated_element, &v[1]);
- EXPECT_EQ(allocated_element.first, "taxicab");
- EXPECT_EQ(allocated_element.second, 1729);
- }
- TEST(InlinedVectorTest, ShrinkToFitGrowingVector) {
- absl::InlinedVector<std::pair<std::string, int>, 1> v;
- v.shrink_to_fit();
- EXPECT_EQ(v.capacity(), 1);
- v.emplace_back("answer", 42);
- v.shrink_to_fit();
- EXPECT_EQ(v.capacity(), 1);
- v.emplace_back("taxicab", 1729);
- EXPECT_GE(v.capacity(), 2);
- v.shrink_to_fit();
- EXPECT_EQ(v.capacity(), 2);
- v.reserve(100);
- EXPECT_GE(v.capacity(), 100);
- v.shrink_to_fit();
- EXPECT_EQ(v.capacity(), 2);
- }
- TEST(InlinedVectorTest, ShrinkToFitEdgeCases) {
- {
- absl::InlinedVector<std::pair<std::string, int>, 1> v;
- v.emplace_back("answer", 42);
- v.emplace_back("taxicab", 1729);
- EXPECT_GE(v.capacity(), 2);
- v.pop_back();
- v.shrink_to_fit();
- EXPECT_EQ(v.capacity(), 1);
- EXPECT_EQ(v[0].first, "answer");
- EXPECT_EQ(v[0].second, 42);
- }
- {
- absl::InlinedVector<std::string, 2> v(100);
- v.resize(0);
- v.shrink_to_fit();
- EXPECT_EQ(v.capacity(), 2); // inlined capacity
- }
- {
- absl::InlinedVector<std::string, 2> v(100);
- v.resize(1);
- v.shrink_to_fit();
- EXPECT_EQ(v.capacity(), 2); // inlined capacity
- }
- {
- absl::InlinedVector<std::string, 2> v(100);
- v.resize(2);
- v.shrink_to_fit();
- EXPECT_EQ(v.capacity(), 2);
- }
- {
- absl::InlinedVector<std::string, 2> v(100);
- v.resize(3);
- v.shrink_to_fit();
- EXPECT_EQ(v.capacity(), 3);
- }
- }
- TEST(IntVec, Insert) {
- for (int len = 0; len < 20; len++) {
- for (int pos = 0; pos <= len; pos++) {
- {
- // Single element
- std::vector<int> std_v;
- Fill(&std_v, len);
- IntVec v;
- Fill(&v, len);
- std_v.insert(std_v.begin() + pos, 9999);
- IntVec::iterator it = v.insert(v.cbegin() + pos, 9999);
- EXPECT_THAT(v, ElementsAreArray(std_v));
- EXPECT_EQ(it, v.cbegin() + pos);
- }
- {
- // n elements
- std::vector<int> std_v;
- Fill(&std_v, len);
- IntVec v;
- Fill(&v, len);
- IntVec::size_type n = 5;
- std_v.insert(std_v.begin() + pos, n, 9999);
- IntVec::iterator it = v.insert(v.cbegin() + pos, n, 9999);
- EXPECT_THAT(v, ElementsAreArray(std_v));
- EXPECT_EQ(it, v.cbegin() + pos);
- }
- {
- // Iterator range (random access iterator)
- std::vector<int> std_v;
- Fill(&std_v, len);
- IntVec v;
- Fill(&v, len);
- const std::vector<int> input = {9999, 8888, 7777};
- std_v.insert(std_v.begin() + pos, input.cbegin(), input.cend());
- IntVec::iterator it =
- v.insert(v.cbegin() + pos, input.cbegin(), input.cend());
- EXPECT_THAT(v, ElementsAreArray(std_v));
- EXPECT_EQ(it, v.cbegin() + pos);
- }
- {
- // Iterator range (forward iterator)
- std::vector<int> std_v;
- Fill(&std_v, len);
- IntVec v;
- Fill(&v, len);
- const std::forward_list<int> input = {9999, 8888, 7777};
- std_v.insert(std_v.begin() + pos, input.cbegin(), input.cend());
- IntVec::iterator it =
- v.insert(v.cbegin() + pos, input.cbegin(), input.cend());
- EXPECT_THAT(v, ElementsAreArray(std_v));
- EXPECT_EQ(it, v.cbegin() + pos);
- }
- {
- // Iterator range (input iterator)
- std::vector<int> std_v;
- Fill(&std_v, len);
- IntVec v;
- Fill(&v, len);
- std_v.insert(std_v.begin() + pos, {9999, 8888, 7777});
- std::istringstream input("9999 8888 7777");
- IntVec::iterator it =
- v.insert(v.cbegin() + pos, std::istream_iterator<int>(input),
- std::istream_iterator<int>());
- EXPECT_THAT(v, ElementsAreArray(std_v));
- EXPECT_EQ(it, v.cbegin() + pos);
- }
- {
- // Initializer list
- std::vector<int> std_v;
- Fill(&std_v, len);
- IntVec v;
- Fill(&v, len);
- std_v.insert(std_v.begin() + pos, {9999, 8888});
- IntVec::iterator it = v.insert(v.cbegin() + pos, {9999, 8888});
- EXPECT_THAT(v, ElementsAreArray(std_v));
- EXPECT_EQ(it, v.cbegin() + pos);
- }
- }
- }
- }
- TEST(RefCountedVec, InsertConstructorDestructor) {
- // Make sure the proper construction/destruction happen during insert
- // operations.
- for (int len = 0; len < 20; len++) {
- SCOPED_TRACE(len);
- for (int pos = 0; pos <= len; pos++) {
- SCOPED_TRACE(pos);
- std::vector<int> counts(len, 0);
- int inserted_count = 0;
- RefCountedVec v;
- for (int i = 0; i < len; ++i) {
- SCOPED_TRACE(i);
- v.push_back(RefCounted(i, &counts[i]));
- }
- EXPECT_THAT(counts, Each(Eq(1)));
- RefCounted insert_element(9999, &inserted_count);
- EXPECT_EQ(1, inserted_count);
- v.insert(v.begin() + pos, insert_element);
- EXPECT_EQ(2, inserted_count);
- // Check that the elements at the end are preserved.
- EXPECT_THAT(counts, Each(Eq(1)));
- EXPECT_EQ(2, inserted_count);
- }
- }
- }
- TEST(IntVec, Resize) {
- for (int len = 0; len < 20; len++) {
- IntVec v;
- Fill(&v, len);
- // Try resizing up and down by k elements
- static const int kResizeElem = 1000000;
- for (int k = 0; k < 10; k++) {
- // Enlarging resize
- v.resize(len + k, kResizeElem);
- EXPECT_EQ(len + k, v.size());
- EXPECT_LE(len + k, v.capacity());
- for (int i = 0; i < len + k; i++) {
- if (i < len) {
- EXPECT_EQ(i, v[i]);
- } else {
- EXPECT_EQ(kResizeElem, v[i]);
- }
- }
- // Shrinking resize
- v.resize(len, kResizeElem);
- EXPECT_EQ(len, v.size());
- EXPECT_LE(len, v.capacity());
- for (int i = 0; i < len; i++) {
- EXPECT_EQ(i, v[i]);
- }
- }
- }
- }
- TEST(IntVec, InitWithLength) {
- for (int len = 0; len < 20; len++) {
- IntVec v(len, 7);
- EXPECT_EQ(len, v.size());
- EXPECT_LE(len, v.capacity());
- for (int i = 0; i < len; i++) {
- EXPECT_EQ(7, v[i]);
- }
- }
- }
- TEST(IntVec, CopyConstructorAndAssignment) {
- for (int len = 0; len < 20; len++) {
- IntVec v;
- Fill(&v, len);
- EXPECT_EQ(len, v.size());
- EXPECT_LE(len, v.capacity());
- IntVec v2(v);
- EXPECT_TRUE(v == v2) << PrintToString(v) << PrintToString(v2);
- for (int start_len = 0; start_len < 20; start_len++) {
- IntVec v3;
- Fill(&v3, start_len, 99); // Add dummy elements that should go away
- v3 = v;
- EXPECT_TRUE(v == v3) << PrintToString(v) << PrintToString(v3);
- }
- }
- }
- TEST(IntVec, AliasingCopyAssignment) {
- for (int len = 0; len < 20; ++len) {
- IntVec original;
- Fill(&original, len);
- IntVec dup = original;
- dup = *&dup;
- EXPECT_EQ(dup, original);
- }
- }
- TEST(IntVec, MoveConstructorAndAssignment) {
- for (int len = 0; len < 20; len++) {
- IntVec v_in;
- const int inlined_capacity = v_in.capacity();
- Fill(&v_in, len);
- EXPECT_EQ(len, v_in.size());
- EXPECT_LE(len, v_in.capacity());
- {
- IntVec v_temp(v_in);
- auto* old_data = v_temp.data();
- IntVec v_out(std::move(v_temp));
- EXPECT_TRUE(v_in == v_out) << PrintToString(v_in) << PrintToString(v_out);
- if (v_in.size() > inlined_capacity) {
- // Allocation is moved as a whole, data stays in place.
- EXPECT_TRUE(v_out.data() == old_data);
- } else {
- EXPECT_FALSE(v_out.data() == old_data);
- }
- }
- for (int start_len = 0; start_len < 20; start_len++) {
- IntVec v_out;
- Fill(&v_out, start_len, 99); // Add dummy elements that should go away
- IntVec v_temp(v_in);
- auto* old_data = v_temp.data();
- v_out = std::move(v_temp);
- EXPECT_TRUE(v_in == v_out) << PrintToString(v_in) << PrintToString(v_out);
- if (v_in.size() > inlined_capacity) {
- // Allocation is moved as a whole, data stays in place.
- EXPECT_TRUE(v_out.data() == old_data);
- } else {
- EXPECT_FALSE(v_out.data() == old_data);
- }
- }
- }
- }
- class NotTriviallyDestructible {
- public:
- NotTriviallyDestructible() : p_(new int(1)) {}
- explicit NotTriviallyDestructible(int i) : p_(new int(i)) {}
- NotTriviallyDestructible(const NotTriviallyDestructible& other)
- : p_(new int(*other.p_)) {}
- NotTriviallyDestructible& operator=(const NotTriviallyDestructible& other) {
- p_ = absl::make_unique<int>(*other.p_);
- return *this;
- }
- bool operator==(const NotTriviallyDestructible& other) const {
- return *p_ == *other.p_;
- }
- private:
- std::unique_ptr<int> p_;
- };
- TEST(AliasingTest, Emplace) {
- for (int i = 2; i < 20; ++i) {
- absl::InlinedVector<NotTriviallyDestructible, 10> vec;
- for (int j = 0; j < i; ++j) {
- vec.push_back(NotTriviallyDestructible(j));
- }
- vec.emplace(vec.begin(), vec[0]);
- EXPECT_EQ(vec[0], vec[1]);
- vec.emplace(vec.begin() + i / 2, vec[i / 2]);
- EXPECT_EQ(vec[i / 2], vec[i / 2 + 1]);
- vec.emplace(vec.end() - 1, vec.back());
- EXPECT_EQ(vec[vec.size() - 2], vec.back());
- }
- }
- TEST(AliasingTest, InsertWithCount) {
- for (int i = 1; i < 20; ++i) {
- absl::InlinedVector<NotTriviallyDestructible, 10> vec;
- for (int j = 0; j < i; ++j) {
- vec.push_back(NotTriviallyDestructible(j));
- }
- for (int n = 0; n < 5; ++n) {
- // We use back where we can because it's guaranteed to become invalidated
- vec.insert(vec.begin(), n, vec.back());
- auto b = vec.begin();
- EXPECT_TRUE(
- std::all_of(b, b + n, [&vec](const NotTriviallyDestructible& x) {
- return x == vec.back();
- }));
- auto m_idx = vec.size() / 2;
- vec.insert(vec.begin() + m_idx, n, vec.back());
- auto m = vec.begin() + m_idx;
- EXPECT_TRUE(
- std::all_of(m, m + n, [&vec](const NotTriviallyDestructible& x) {
- return x == vec.back();
- }));
- // We want distinct values so the equality test is meaningful,
- // vec[vec.size() - 1] is also almost always invalidated.
- auto old_e = vec.size() - 1;
- auto val = vec[old_e];
- vec.insert(vec.end(), n, vec[old_e]);
- auto e = vec.begin() + old_e;
- EXPECT_TRUE(std::all_of(
- e, e + n,
- [&val](const NotTriviallyDestructible& x) { return x == val; }));
- }
- }
- }
- TEST(OverheadTest, Storage) {
- // Check for size overhead.
- // In particular, ensure that std::allocator doesn't cost anything to store.
- // The union should be absorbing some of the allocation bookkeeping overhead
- // in the larger vectors, leaving only the size_ field as overhead.
- struct T { void* val; };
- size_t expected_overhead = sizeof(T);
- EXPECT_EQ((2 * expected_overhead),
- sizeof(absl::InlinedVector<T, 1>) - sizeof(T[1]));
- EXPECT_EQ(expected_overhead,
- sizeof(absl::InlinedVector<T, 2>) - sizeof(T[2]));
- EXPECT_EQ(expected_overhead,
- sizeof(absl::InlinedVector<T, 3>) - sizeof(T[3]));
- EXPECT_EQ(expected_overhead,
- sizeof(absl::InlinedVector<T, 4>) - sizeof(T[4]));
- EXPECT_EQ(expected_overhead,
- sizeof(absl::InlinedVector<T, 5>) - sizeof(T[5]));
- EXPECT_EQ(expected_overhead,
- sizeof(absl::InlinedVector<T, 6>) - sizeof(T[6]));
- EXPECT_EQ(expected_overhead,
- sizeof(absl::InlinedVector<T, 7>) - sizeof(T[7]));
- EXPECT_EQ(expected_overhead,
- sizeof(absl::InlinedVector<T, 8>) - sizeof(T[8]));
- }
- TEST(IntVec, Clear) {
- for (int len = 0; len < 20; len++) {
- SCOPED_TRACE(len);
- IntVec v;
- Fill(&v, len);
- v.clear();
- EXPECT_EQ(0, v.size());
- EXPECT_EQ(v.begin(), v.end());
- }
- }
- TEST(IntVec, Reserve) {
- for (int len = 0; len < 20; len++) {
- IntVec v;
- Fill(&v, len);
- for (int newlen = 0; newlen < 100; newlen++) {
- const int* start_rep = v.data();
- v.reserve(newlen);
- const int* final_rep = v.data();
- if (newlen <= len) {
- EXPECT_EQ(start_rep, final_rep);
- }
- EXPECT_LE(newlen, v.capacity());
- // Filling up to newlen should not change rep
- while (v.size() < newlen) {
- v.push_back(0);
- }
- EXPECT_EQ(final_rep, v.data());
- }
- }
- }
- TEST(StringVec, SelfRefPushBack) {
- std::vector<std::string> std_v;
- absl::InlinedVector<std::string, 4> v;
- const std::string s = "A quite long string to ensure heap.";
- std_v.push_back(s);
- v.push_back(s);
- for (int i = 0; i < 20; ++i) {
- EXPECT_THAT(v, ElementsAreArray(std_v));
- v.push_back(v.back());
- std_v.push_back(std_v.back());
- }
- EXPECT_THAT(v, ElementsAreArray(std_v));
- }
- TEST(StringVec, SelfRefPushBackWithMove) {
- std::vector<std::string> std_v;
- absl::InlinedVector<std::string, 4> v;
- const std::string s = "A quite long string to ensure heap.";
- std_v.push_back(s);
- v.push_back(s);
- for (int i = 0; i < 20; ++i) {
- EXPECT_EQ(v.back(), std_v.back());
- v.push_back(std::move(v.back()));
- std_v.push_back(std::move(std_v.back()));
- }
- EXPECT_EQ(v.back(), std_v.back());
- }
- TEST(StringVec, SelfMove) {
- const std::string s = "A quite long string to ensure heap.";
- for (int len = 0; len < 20; len++) {
- SCOPED_TRACE(len);
- absl::InlinedVector<std::string, 8> v;
- for (int i = 0; i < len; ++i) {
- SCOPED_TRACE(i);
- v.push_back(s);
- }
- // Indirection necessary to avoid compiler warning.
- v = std::move(*(&v));
- // Ensure that the inlined vector is still in a valid state by copying it.
- // We don't expect specific contents since a self-move results in an
- // unspecified valid state.
- std::vector<std::string> copy(v.begin(), v.end());
- }
- }
- TEST(IntVec, Swap) {
- for (int l1 = 0; l1 < 20; l1++) {
- SCOPED_TRACE(l1);
- for (int l2 = 0; l2 < 20; l2++) {
- SCOPED_TRACE(l2);
- IntVec a = Fill(l1, 0);
- IntVec b = Fill(l2, 100);
- {
- using std::swap;
- swap(a, b);
- }
- EXPECT_EQ(l1, b.size());
- EXPECT_EQ(l2, a.size());
- for (int i = 0; i < l1; i++) {
- SCOPED_TRACE(i);
- EXPECT_EQ(i, b[i]);
- }
- for (int i = 0; i < l2; i++) {
- SCOPED_TRACE(i);
- EXPECT_EQ(100 + i, a[i]);
- }
- }
- }
- }
- TYPED_TEST_P(InstanceTest, Swap) {
- using Instance = TypeParam;
- using InstanceVec = absl::InlinedVector<Instance, 8>;
- for (int l1 = 0; l1 < 20; l1++) {
- SCOPED_TRACE(l1);
- for (int l2 = 0; l2 < 20; l2++) {
- SCOPED_TRACE(l2);
- InstanceTracker tracker;
- InstanceVec a, b;
- const size_t inlined_capacity = a.capacity();
- auto min_len = std::min(l1, l2);
- auto max_len = std::max(l1, l2);
- for (int i = 0; i < l1; i++) a.push_back(Instance(i));
- for (int i = 0; i < l2; i++) b.push_back(Instance(100 + i));
- EXPECT_EQ(tracker.instances(), l1 + l2);
- tracker.ResetCopiesMovesSwaps();
- {
- using std::swap;
- swap(a, b);
- }
- EXPECT_EQ(tracker.instances(), l1 + l2);
- if (a.size() > inlined_capacity && b.size() > inlined_capacity) {
- EXPECT_EQ(tracker.swaps(), 0); // Allocations are swapped.
- EXPECT_EQ(tracker.moves(), 0);
- } else if (a.size() <= inlined_capacity && b.size() <= inlined_capacity) {
- EXPECT_EQ(tracker.swaps(), min_len);
- EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()),
- max_len - min_len);
- } else {
- // One is allocated and the other isn't. The allocation is transferred
- // without copying elements, and the inlined instances are copied/moved.
- EXPECT_EQ(tracker.swaps(), 0);
- EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()),
- min_len);
- }
- EXPECT_EQ(l1, b.size());
- EXPECT_EQ(l2, a.size());
- for (int i = 0; i < l1; i++) {
- EXPECT_EQ(i, b[i].value());
- }
- for (int i = 0; i < l2; i++) {
- EXPECT_EQ(100 + i, a[i].value());
- }
- }
- }
- }
- TEST(IntVec, EqualAndNotEqual) {
- IntVec a, b;
- EXPECT_TRUE(a == b);
- EXPECT_FALSE(a != b);
- a.push_back(3);
- EXPECT_FALSE(a == b);
- EXPECT_TRUE(a != b);
- b.push_back(3);
- EXPECT_TRUE(a == b);
- EXPECT_FALSE(a != b);
- b.push_back(7);
- EXPECT_FALSE(a == b);
- EXPECT_TRUE(a != b);
- a.push_back(6);
- EXPECT_FALSE(a == b);
- EXPECT_TRUE(a != b);
- a.clear();
- b.clear();
- for (int i = 0; i < 100; i++) {
- a.push_back(i);
- b.push_back(i);
- EXPECT_TRUE(a == b);
- EXPECT_FALSE(a != b);
- b[i] = b[i] + 1;
- EXPECT_FALSE(a == b);
- EXPECT_TRUE(a != b);
- b[i] = b[i] - 1; // Back to before
- EXPECT_TRUE(a == b);
- EXPECT_FALSE(a != b);
- }
- }
- TEST(IntVec, RelationalOps) {
- IntVec a, b;
- EXPECT_FALSE(a < b);
- EXPECT_FALSE(b < a);
- EXPECT_FALSE(a > b);
- EXPECT_FALSE(b > a);
- EXPECT_TRUE(a <= b);
- EXPECT_TRUE(b <= a);
- EXPECT_TRUE(a >= b);
- EXPECT_TRUE(b >= a);
- b.push_back(3);
- EXPECT_TRUE(a < b);
- EXPECT_FALSE(b < a);
- EXPECT_FALSE(a > b);
- EXPECT_TRUE(b > a);
- EXPECT_TRUE(a <= b);
- EXPECT_FALSE(b <= a);
- EXPECT_FALSE(a >= b);
- EXPECT_TRUE(b >= a);
- }
- TYPED_TEST_P(InstanceTest, CountConstructorsDestructors) {
- using Instance = TypeParam;
- using InstanceVec = absl::InlinedVector<Instance, 8>;
- InstanceTracker tracker;
- for (int len = 0; len < 20; len++) {
- SCOPED_TRACE(len);
- tracker.ResetCopiesMovesSwaps();
- InstanceVec v;
- const size_t inlined_capacity = v.capacity();
- for (int i = 0; i < len; i++) {
- v.push_back(Instance(i));
- }
- EXPECT_EQ(tracker.instances(), len);
- EXPECT_GE(tracker.copies() + tracker.moves(),
- len); // More due to reallocation.
- tracker.ResetCopiesMovesSwaps();
- // Enlarging resize() must construct some objects
- tracker.ResetCopiesMovesSwaps();
- v.resize(len + 10, Instance(100));
- EXPECT_EQ(tracker.instances(), len + 10);
- if (len <= inlined_capacity && len + 10 > inlined_capacity) {
- EXPECT_EQ(tracker.copies() + tracker.moves(), 10 + len);
- } else {
- // Only specify a minimum number of copies + moves. We don't want to
- // depend on the reallocation policy here.
- EXPECT_GE(tracker.copies() + tracker.moves(),
- 10); // More due to reallocation.
- }
- // Shrinking resize() must destroy some objects
- tracker.ResetCopiesMovesSwaps();
- v.resize(len, Instance(100));
- EXPECT_EQ(tracker.instances(), len);
- EXPECT_EQ(tracker.copies(), 0);
- EXPECT_EQ(tracker.moves(), 0);
- // reserve() must not increase the number of initialized objects
- SCOPED_TRACE("reserve");
- v.reserve(len + 1000);
- EXPECT_EQ(tracker.instances(), len);
- EXPECT_EQ(tracker.copies() + tracker.moves(), len);
- // pop_back() and erase() must destroy one object
- if (len > 0) {
- tracker.ResetCopiesMovesSwaps();
- v.pop_back();
- EXPECT_EQ(tracker.instances(), len - 1);
- EXPECT_EQ(tracker.copies(), 0);
- EXPECT_EQ(tracker.moves(), 0);
- if (!v.empty()) {
- tracker.ResetCopiesMovesSwaps();
- v.erase(v.begin());
- EXPECT_EQ(tracker.instances(), len - 2);
- EXPECT_EQ(tracker.copies() + tracker.moves(), len - 2);
- }
- }
- tracker.ResetCopiesMovesSwaps();
- int instances_before_empty_erase = tracker.instances();
- v.erase(v.begin(), v.begin());
- EXPECT_EQ(tracker.instances(), instances_before_empty_erase);
- EXPECT_EQ(tracker.copies() + tracker.moves(), 0);
- }
- }
- TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnCopyConstruction) {
- using Instance = TypeParam;
- using InstanceVec = absl::InlinedVector<Instance, 8>;
- InstanceTracker tracker;
- for (int len = 0; len < 20; len++) {
- SCOPED_TRACE(len);
- tracker.ResetCopiesMovesSwaps();
- InstanceVec v;
- for (int i = 0; i < len; i++) {
- v.push_back(Instance(i));
- }
- EXPECT_EQ(tracker.instances(), len);
- EXPECT_GE(tracker.copies() + tracker.moves(),
- len); // More due to reallocation.
- tracker.ResetCopiesMovesSwaps();
- { // Copy constructor should create 'len' more instances.
- InstanceVec v_copy(v);
- EXPECT_EQ(tracker.instances(), len + len);
- EXPECT_EQ(tracker.copies(), len);
- EXPECT_EQ(tracker.moves(), 0);
- }
- EXPECT_EQ(tracker.instances(), len);
- }
- }
- TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveConstruction) {
- using Instance = TypeParam;
- using InstanceVec = absl::InlinedVector<Instance, 8>;
- InstanceTracker tracker;
- for (int len = 0; len < 20; len++) {
- SCOPED_TRACE(len);
- tracker.ResetCopiesMovesSwaps();
- InstanceVec v;
- const size_t inlined_capacity = v.capacity();
- for (int i = 0; i < len; i++) {
- v.push_back(Instance(i));
- }
- EXPECT_EQ(tracker.instances(), len);
- EXPECT_GE(tracker.copies() + tracker.moves(),
- len); // More due to reallocation.
- tracker.ResetCopiesMovesSwaps();
- {
- InstanceVec v_copy(std::move(v));
- if (len > inlined_capacity) {
- // Allocation is moved as a whole.
- EXPECT_EQ(tracker.instances(), len);
- EXPECT_EQ(tracker.live_instances(), len);
- // Tests an implementation detail, don't rely on this in your code.
- EXPECT_EQ(v.size(), 0); // NOLINT misc-use-after-move
- EXPECT_EQ(tracker.copies(), 0);
- EXPECT_EQ(tracker.moves(), 0);
- } else {
- EXPECT_EQ(tracker.instances(), len + len);
- if (Instance::supports_move()) {
- EXPECT_EQ(tracker.live_instances(), len);
- EXPECT_EQ(tracker.copies(), 0);
- EXPECT_EQ(tracker.moves(), len);
- } else {
- EXPECT_EQ(tracker.live_instances(), len + len);
- EXPECT_EQ(tracker.copies(), len);
- EXPECT_EQ(tracker.moves(), 0);
- }
- }
- EXPECT_EQ(tracker.swaps(), 0);
- }
- }
- }
- TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnAssignment) {
- using Instance = TypeParam;
- using InstanceVec = absl::InlinedVector<Instance, 8>;
- InstanceTracker tracker;
- for (int len = 0; len < 20; len++) {
- SCOPED_TRACE(len);
- for (int longorshort = 0; longorshort <= 1; ++longorshort) {
- SCOPED_TRACE(longorshort);
- tracker.ResetCopiesMovesSwaps();
- InstanceVec longer, shorter;
- for (int i = 0; i < len; i++) {
- longer.push_back(Instance(i));
- shorter.push_back(Instance(i));
- }
- longer.push_back(Instance(len));
- EXPECT_EQ(tracker.instances(), len + len + 1);
- EXPECT_GE(tracker.copies() + tracker.moves(),
- len + len + 1); // More due to reallocation.
- tracker.ResetCopiesMovesSwaps();
- if (longorshort) {
- shorter = longer;
- EXPECT_EQ(tracker.instances(), (len + 1) + (len + 1));
- EXPECT_GE(tracker.copies() + tracker.moves(),
- len + 1); // More due to reallocation.
- } else {
- longer = shorter;
- EXPECT_EQ(tracker.instances(), len + len);
- EXPECT_EQ(tracker.copies() + tracker.moves(), len);
- }
- }
- }
- }
- TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveAssignment) {
- using Instance = TypeParam;
- using InstanceVec = absl::InlinedVector<Instance, 8>;
- InstanceTracker tracker;
- for (int len = 0; len < 20; len++) {
- SCOPED_TRACE(len);
- for (int longorshort = 0; longorshort <= 1; ++longorshort) {
- SCOPED_TRACE(longorshort);
- tracker.ResetCopiesMovesSwaps();
- InstanceVec longer, shorter;
- const int inlined_capacity = longer.capacity();
- for (int i = 0; i < len; i++) {
- longer.push_back(Instance(i));
- shorter.push_back(Instance(i));
- }
- longer.push_back(Instance(len));
- EXPECT_EQ(tracker.instances(), len + len + 1);
- EXPECT_GE(tracker.copies() + tracker.moves(),
- len + len + 1); // More due to reallocation.
- tracker.ResetCopiesMovesSwaps();
- int src_len;
- if (longorshort) {
- src_len = len + 1;
- shorter = std::move(longer);
- } else {
- src_len = len;
- longer = std::move(shorter);
- }
- if (src_len > inlined_capacity) {
- // Allocation moved as a whole.
- EXPECT_EQ(tracker.instances(), src_len);
- EXPECT_EQ(tracker.live_instances(), src_len);
- EXPECT_EQ(tracker.copies(), 0);
- EXPECT_EQ(tracker.moves(), 0);
- } else {
- // Elements are all copied.
- EXPECT_EQ(tracker.instances(), src_len + src_len);
- if (Instance::supports_move()) {
- EXPECT_EQ(tracker.copies(), 0);
- EXPECT_EQ(tracker.moves(), src_len);
- EXPECT_EQ(tracker.live_instances(), src_len);
- } else {
- EXPECT_EQ(tracker.copies(), src_len);
- EXPECT_EQ(tracker.moves(), 0);
- EXPECT_EQ(tracker.live_instances(), src_len + src_len);
- }
- }
- EXPECT_EQ(tracker.swaps(), 0);
- }
- }
- }
- TEST(CountElemAssign, SimpleTypeWithInlineBacking) {
- for (size_t original_size = 0; original_size <= 5; ++original_size) {
- SCOPED_TRACE(original_size);
- // Original contents are [12345, 12345, ...]
- std::vector<int> original_contents(original_size, 12345);
- absl::InlinedVector<int, 2> v(original_contents.begin(),
- original_contents.end());
- v.assign(2, 123);
- EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(123, 123)));
- if (original_size <= 2) {
- // If the original had inline backing, it should stay inline.
- EXPECT_EQ(2, v.capacity());
- }
- }
- }
- TEST(CountElemAssign, SimpleTypeWithAllocation) {
- for (size_t original_size = 0; original_size <= 5; ++original_size) {
- SCOPED_TRACE(original_size);
- // Original contents are [12345, 12345, ...]
- std::vector<int> original_contents(original_size, 12345);
- absl::InlinedVector<int, 2> v(original_contents.begin(),
- original_contents.end());
- v.assign(3, 123);
- EXPECT_THAT(v, AllOf(SizeIs(3), ElementsAre(123, 123, 123)));
- EXPECT_LE(v.size(), v.capacity());
- }
- }
- TYPED_TEST_P(InstanceTest, CountElemAssignInlineBacking) {
- using Instance = TypeParam;
- for (size_t original_size = 0; original_size <= 5; ++original_size) {
- SCOPED_TRACE(original_size);
- // Original contents are [12345, 12345, ...]
- std::vector<Instance> original_contents(original_size, Instance(12345));
- absl::InlinedVector<Instance, 2> v(original_contents.begin(),
- original_contents.end());
- v.assign(2, Instance(123));
- EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(ValueIs(123), ValueIs(123))));
- if (original_size <= 2) {
- // If the original had inline backing, it should stay inline.
- EXPECT_EQ(2, v.capacity());
- }
- }
- }
- template <typename Instance>
- void InstanceCountElemAssignWithAllocationTest() {
- for (size_t original_size = 0; original_size <= 5; ++original_size) {
- SCOPED_TRACE(original_size);
- // Original contents are [12345, 12345, ...]
- std::vector<Instance> original_contents(original_size, Instance(12345));
- absl::InlinedVector<Instance, 2> v(original_contents.begin(),
- original_contents.end());
- v.assign(3, Instance(123));
- EXPECT_THAT(v, AllOf(SizeIs(3), ElementsAre(ValueIs(123), ValueIs(123),
- ValueIs(123))));
- EXPECT_LE(v.size(), v.capacity());
- }
- }
- TEST(CountElemAssign, WithAllocationCopyableInstance) {
- InstanceCountElemAssignWithAllocationTest<CopyableOnlyInstance>();
- }
- TEST(CountElemAssign, WithAllocationCopyableMovableInstance) {
- InstanceCountElemAssignWithAllocationTest<CopyableMovableInstance>();
- }
- TEST(RangedConstructor, SimpleType) {
- std::vector<int> source_v = {4, 5, 6};
- // First try to fit in inline backing
- absl::InlinedVector<int, 4> v(source_v.begin(), source_v.end());
- EXPECT_EQ(3, v.size());
- EXPECT_EQ(4, v.capacity()); // Indication that we're still on inlined storage
- EXPECT_EQ(4, v[0]);
- EXPECT_EQ(5, v[1]);
- EXPECT_EQ(6, v[2]);
- // Now, force a re-allocate
- absl::InlinedVector<int, 2> realloc_v(source_v.begin(), source_v.end());
- EXPECT_EQ(3, realloc_v.size());
- EXPECT_LT(2, realloc_v.capacity());
- EXPECT_EQ(4, realloc_v[0]);
- EXPECT_EQ(5, realloc_v[1]);
- EXPECT_EQ(6, realloc_v[2]);
- }
- // Test for ranged constructors using Instance as the element type and
- // SourceContainer as the source container type.
- template <typename Instance, typename SourceContainer, int inlined_capacity>
- void InstanceRangedConstructorTestForContainer() {
- InstanceTracker tracker;
- SourceContainer source_v = {Instance(0), Instance(1)};
- tracker.ResetCopiesMovesSwaps();
- absl::InlinedVector<Instance, inlined_capacity> v(source_v.begin(),
- source_v.end());
- EXPECT_EQ(2, v.size());
- EXPECT_LT(1, v.capacity());
- EXPECT_EQ(0, v[0].value());
- EXPECT_EQ(1, v[1].value());
- EXPECT_EQ(tracker.copies(), 2);
- EXPECT_EQ(tracker.moves(), 0);
- }
- template <typename Instance, int inlined_capacity>
- void InstanceRangedConstructorTestWithCapacity() {
- // Test with const and non-const, random access and non-random-access sources.
- // TODO(bsamwel): Test with an input iterator source.
- {
- SCOPED_TRACE("std::list");
- InstanceRangedConstructorTestForContainer<Instance, std::list<Instance>,
- inlined_capacity>();
- {
- SCOPED_TRACE("const std::list");
- InstanceRangedConstructorTestForContainer<
- Instance, const std::list<Instance>, inlined_capacity>();
- }
- {
- SCOPED_TRACE("std::vector");
- InstanceRangedConstructorTestForContainer<Instance, std::vector<Instance>,
- inlined_capacity>();
- }
- {
- SCOPED_TRACE("const std::vector");
- InstanceRangedConstructorTestForContainer<
- Instance, const std::vector<Instance>, inlined_capacity>();
- }
- }
- }
- TYPED_TEST_P(InstanceTest, RangedConstructor) {
- using Instance = TypeParam;
- SCOPED_TRACE("capacity=1");
- InstanceRangedConstructorTestWithCapacity<Instance, 1>();
- SCOPED_TRACE("capacity=2");
- InstanceRangedConstructorTestWithCapacity<Instance, 2>();
- }
- TEST(RangedConstructor, ElementsAreConstructed) {
- std::vector<std::string> source_v = {"cat", "dog"};
- // Force expansion and re-allocation of v. Ensures that when the vector is
- // expanded that new elements are constructed.
- absl::InlinedVector<std::string, 1> v(source_v.begin(), source_v.end());
- EXPECT_EQ("cat", v[0]);
- EXPECT_EQ("dog", v[1]);
- }
- TEST(RangedAssign, SimpleType) {
- // Test for all combinations of original sizes (empty and non-empty inline,
- // and out of line) and target sizes.
- for (size_t original_size = 0; original_size <= 5; ++original_size) {
- SCOPED_TRACE(original_size);
- // Original contents are [12345, 12345, ...]
- std::vector<int> original_contents(original_size, 12345);
- for (size_t target_size = 0; target_size <= 5; ++target_size) {
- SCOPED_TRACE(target_size);
- // New contents are [3, 4, ...]
- std::vector<int> new_contents;
- for (size_t i = 0; i < target_size; ++i) {
- new_contents.push_back(i + 3);
- }
- absl::InlinedVector<int, 3> v(original_contents.begin(),
- original_contents.end());
- v.assign(new_contents.begin(), new_contents.end());
- EXPECT_EQ(new_contents.size(), v.size());
- EXPECT_LE(new_contents.size(), v.capacity());
- if (target_size <= 3 && original_size <= 3) {
- // Storage should stay inline when target size is small.
- EXPECT_EQ(3, v.capacity());
- }
- EXPECT_THAT(v, ElementsAreArray(new_contents));
- }
- }
- }
- // Returns true if lhs and rhs have the same value.
- template <typename Instance>
- static bool InstanceValuesEqual(const Instance& lhs, const Instance& rhs) {
- return lhs.value() == rhs.value();
- }
- // Test for ranged assign() using Instance as the element type and
- // SourceContainer as the source container type.
- template <typename Instance, typename SourceContainer>
- void InstanceRangedAssignTestForContainer() {
- // Test for all combinations of original sizes (empty and non-empty inline,
- // and out of line) and target sizes.
- for (size_t original_size = 0; original_size <= 5; ++original_size) {
- SCOPED_TRACE(original_size);
- // Original contents are [12345, 12345, ...]
- std::vector<Instance> original_contents(original_size, Instance(12345));
- for (size_t target_size = 0; target_size <= 5; ++target_size) {
- SCOPED_TRACE(target_size);
- // New contents are [3, 4, ...]
- // Generate data using a non-const container, because SourceContainer
- // itself may be const.
- // TODO(bsamwel): Test with an input iterator.
- std::vector<Instance> new_contents_in;
- for (size_t i = 0; i < target_size; ++i) {
- new_contents_in.push_back(Instance(i + 3));
- }
- SourceContainer new_contents(new_contents_in.begin(),
- new_contents_in.end());
- absl::InlinedVector<Instance, 3> v(original_contents.begin(),
- original_contents.end());
- v.assign(new_contents.begin(), new_contents.end());
- EXPECT_EQ(new_contents.size(), v.size());
- EXPECT_LE(new_contents.size(), v.capacity());
- if (target_size <= 3 && original_size <= 3) {
- // Storage should stay inline when target size is small.
- EXPECT_EQ(3, v.capacity());
- }
- EXPECT_TRUE(std::equal(v.begin(), v.end(), new_contents.begin(),
- InstanceValuesEqual<Instance>));
- }
- }
- }
- TYPED_TEST_P(InstanceTest, RangedAssign) {
- using Instance = TypeParam;
- // Test with const and non-const, random access and non-random-access sources.
- // TODO(bsamwel): Test with an input iterator source.
- SCOPED_TRACE("std::list");
- InstanceRangedAssignTestForContainer<Instance, std::list<Instance>>();
- SCOPED_TRACE("const std::list");
- InstanceRangedAssignTestForContainer<Instance, const std::list<Instance>>();
- SCOPED_TRACE("std::vector");
- InstanceRangedAssignTestForContainer<Instance, std::vector<Instance>>();
- SCOPED_TRACE("const std::vector");
- InstanceRangedAssignTestForContainer<Instance, const std::vector<Instance>>();
- }
- TEST(InitializerListConstructor, SimpleTypeWithInlineBacking) {
- EXPECT_THAT((absl::InlinedVector<int, 4>{4, 5, 6}),
- AllOf(SizeIs(3), CapacityIs(4), ElementsAre(4, 5, 6)));
- }
- TEST(InitializerListConstructor, SimpleTypeWithReallocationRequired) {
- EXPECT_THAT((absl::InlinedVector<int, 2>{4, 5, 6}),
- AllOf(SizeIs(3), CapacityIs(Gt(2)), ElementsAre(4, 5, 6)));
- }
- TEST(InitializerListConstructor, DisparateTypesInList) {
- EXPECT_THAT((absl::InlinedVector<int, 2>{-7, 8ULL}), ElementsAre(-7, 8));
- EXPECT_THAT((absl::InlinedVector<std::string, 2>{"foo", std::string("bar")}),
- ElementsAre("foo", "bar"));
- }
- TEST(InitializerListConstructor, ComplexTypeWithInlineBacking) {
- EXPECT_THAT((absl::InlinedVector<CopyableMovableInstance, 1>{
- CopyableMovableInstance(0)}),
- AllOf(SizeIs(1), CapacityIs(1), ElementsAre(ValueIs(0))));
- }
- TEST(InitializerListConstructor, ComplexTypeWithReallocationRequired) {
- EXPECT_THAT(
- (absl::InlinedVector<CopyableMovableInstance, 1>{
- CopyableMovableInstance(0), CopyableMovableInstance(1)}),
- AllOf(SizeIs(2), CapacityIs(Gt(1)), ElementsAre(ValueIs(0), ValueIs(1))));
- }
- TEST(InitializerListAssign, SimpleTypeFitsInlineBacking) {
- for (size_t original_size = 0; original_size <= 4; ++original_size) {
- SCOPED_TRACE(original_size);
- absl::InlinedVector<int, 2> v1(original_size, 12345);
- const size_t original_capacity_v1 = v1.capacity();
- v1.assign({3});
- EXPECT_THAT(
- v1, AllOf(SizeIs(1), CapacityIs(original_capacity_v1), ElementsAre(3)));
- absl::InlinedVector<int, 2> v2(original_size, 12345);
- const size_t original_capacity_v2 = v2.capacity();
- v2 = {3};
- EXPECT_THAT(
- v2, AllOf(SizeIs(1), CapacityIs(original_capacity_v2), ElementsAre(3)));
- }
- }
- TEST(InitializerListAssign, SimpleTypeDoesNotFitInlineBacking) {
- for (size_t original_size = 0; original_size <= 4; ++original_size) {
- SCOPED_TRACE(original_size);
- absl::InlinedVector<int, 2> v1(original_size, 12345);
- v1.assign({3, 4, 5});
- EXPECT_THAT(v1, AllOf(SizeIs(3), ElementsAre(3, 4, 5)));
- EXPECT_LE(3, v1.capacity());
- absl::InlinedVector<int, 2> v2(original_size, 12345);
- v2 = {3, 4, 5};
- EXPECT_THAT(v2, AllOf(SizeIs(3), ElementsAre(3, 4, 5)));
- EXPECT_LE(3, v2.capacity());
- }
- }
- TEST(InitializerListAssign, DisparateTypesInList) {
- absl::InlinedVector<int, 2> v_int1;
- v_int1.assign({-7, 8ULL});
- EXPECT_THAT(v_int1, ElementsAre(-7, 8));
- absl::InlinedVector<int, 2> v_int2;
- v_int2 = {-7, 8ULL};
- EXPECT_THAT(v_int2, ElementsAre(-7, 8));
- absl::InlinedVector<std::string, 2> v_string1;
- v_string1.assign({"foo", std::string("bar")});
- EXPECT_THAT(v_string1, ElementsAre("foo", "bar"));
- absl::InlinedVector<std::string, 2> v_string2;
- v_string2 = {"foo", std::string("bar")};
- EXPECT_THAT(v_string2, ElementsAre("foo", "bar"));
- }
- TYPED_TEST_P(InstanceTest, InitializerListAssign) {
- using Instance = TypeParam;
- for (size_t original_size = 0; original_size <= 4; ++original_size) {
- SCOPED_TRACE(original_size);
- absl::InlinedVector<Instance, 2> v(original_size, Instance(12345));
- const size_t original_capacity = v.capacity();
- v.assign({Instance(3)});
- EXPECT_THAT(v, AllOf(SizeIs(1), CapacityIs(original_capacity),
- ElementsAre(ValueIs(3))));
- }
- for (size_t original_size = 0; original_size <= 4; ++original_size) {
- SCOPED_TRACE(original_size);
- absl::InlinedVector<Instance, 2> v(original_size, Instance(12345));
- v.assign({Instance(3), Instance(4), Instance(5)});
- EXPECT_THAT(
- v, AllOf(SizeIs(3), ElementsAre(ValueIs(3), ValueIs(4), ValueIs(5))));
- EXPECT_LE(3, v.capacity());
- }
- }
- REGISTER_TYPED_TEST_CASE_P(InstanceTest, Swap, CountConstructorsDestructors,
- CountConstructorsDestructorsOnCopyConstruction,
- CountConstructorsDestructorsOnMoveConstruction,
- CountConstructorsDestructorsOnAssignment,
- CountConstructorsDestructorsOnMoveAssignment,
- CountElemAssignInlineBacking, RangedConstructor,
- RangedAssign, InitializerListAssign);
- using InstanceTypes =
- ::testing::Types<CopyableOnlyInstance, CopyableMovableInstance>;
- INSTANTIATE_TYPED_TEST_CASE_P(InstanceTestOnTypes, InstanceTest, InstanceTypes);
- TEST(DynamicVec, DynamicVecCompiles) {
- DynamicVec v;
- (void)v;
- }
- TEST(AllocatorSupportTest, Constructors) {
- using MyAlloc = CountingAllocator<int>;
- using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
- const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
- int64_t allocated = 0;
- MyAlloc alloc(&allocated);
- { AllocVec ABSL_ATTRIBUTE_UNUSED v; }
- { AllocVec ABSL_ATTRIBUTE_UNUSED v(alloc); }
- { AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc); }
- { AllocVec ABSL_ATTRIBUTE_UNUSED v({1, 2, 3}, alloc); }
- AllocVec v2;
- { AllocVec ABSL_ATTRIBUTE_UNUSED v(v2, alloc); }
- { AllocVec ABSL_ATTRIBUTE_UNUSED v(std::move(v2), alloc); }
- }
- TEST(AllocatorSupportTest, CountAllocations) {
- using MyAlloc = CountingAllocator<int>;
- using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
- const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
- int64_t allocated = 0;
- MyAlloc alloc(&allocated);
- {
- AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + 4, alloc);
- EXPECT_THAT(allocated, 0);
- }
- EXPECT_THAT(allocated, 0);
- {
- AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc);
- EXPECT_THAT(allocated, v.size() * sizeof(int));
- }
- EXPECT_THAT(allocated, 0);
- {
- AllocVec v(4, 1, alloc);
- EXPECT_THAT(allocated, 0);
- int64_t allocated2 = 0;
- MyAlloc alloc2(&allocated2);
- AllocVec v2(v, alloc2);
- EXPECT_THAT(allocated2, 0);
- int64_t allocated3 = 0;
- MyAlloc alloc3(&allocated3);
- AllocVec v3(std::move(v), alloc3);
- EXPECT_THAT(allocated3, 0);
- }
- EXPECT_THAT(allocated, 0);
- {
- AllocVec v(8, 2, alloc);
- EXPECT_THAT(allocated, v.size() * sizeof(int));
- int64_t allocated2 = 0;
- MyAlloc alloc2(&allocated2);
- AllocVec v2(v, alloc2);
- EXPECT_THAT(allocated2, v2.size() * sizeof(int));
- int64_t allocated3 = 0;
- MyAlloc alloc3(&allocated3);
- AllocVec v3(std::move(v), alloc3);
- EXPECT_THAT(allocated3, v3.size() * sizeof(int));
- }
- EXPECT_EQ(allocated, 0);
- {
- // Test shrink_to_fit deallocations.
- AllocVec v(8, 2, alloc);
- EXPECT_EQ(allocated, 8 * sizeof(int));
- v.resize(5);
- EXPECT_EQ(allocated, 8 * sizeof(int));
- v.shrink_to_fit();
- EXPECT_EQ(allocated, 5 * sizeof(int));
- v.resize(4);
- EXPECT_EQ(allocated, 5 * sizeof(int));
- v.shrink_to_fit();
- EXPECT_EQ(allocated, 0);
- }
- }
- TEST(AllocatorSupportTest, SwapBothAllocated) {
- using MyAlloc = CountingAllocator<int>;
- using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
- int64_t allocated1 = 0;
- int64_t allocated2 = 0;
- {
- const int ia1[] = {0, 1, 2, 3, 4, 5, 6, 7};
- const int ia2[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
- MyAlloc a1(&allocated1);
- MyAlloc a2(&allocated2);
- AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1);
- AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2);
- EXPECT_LT(v1.capacity(), v2.capacity());
- EXPECT_THAT(allocated1, v1.capacity() * sizeof(int));
- EXPECT_THAT(allocated2, v2.capacity() * sizeof(int));
- v1.swap(v2);
- EXPECT_THAT(v1, ElementsAreArray(ia2));
- EXPECT_THAT(v2, ElementsAreArray(ia1));
- EXPECT_THAT(allocated1, v2.capacity() * sizeof(int));
- EXPECT_THAT(allocated2, v1.capacity() * sizeof(int));
- }
- EXPECT_THAT(allocated1, 0);
- EXPECT_THAT(allocated2, 0);
- }
- TEST(AllocatorSupportTest, SwapOneAllocated) {
- using MyAlloc = CountingAllocator<int>;
- using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
- int64_t allocated1 = 0;
- int64_t allocated2 = 0;
- {
- const int ia1[] = {0, 1, 2, 3, 4, 5, 6, 7};
- const int ia2[] = {0, 1, 2, 3};
- MyAlloc a1(&allocated1);
- MyAlloc a2(&allocated2);
- AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1);
- AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2);
- EXPECT_THAT(allocated1, v1.capacity() * sizeof(int));
- EXPECT_THAT(allocated2, 0);
- v1.swap(v2);
- EXPECT_THAT(v1, ElementsAreArray(ia2));
- EXPECT_THAT(v2, ElementsAreArray(ia1));
- EXPECT_THAT(allocated1, v2.capacity() * sizeof(int));
- EXPECT_THAT(allocated2, 0);
- EXPECT_TRUE(v2.get_allocator() == a1);
- EXPECT_TRUE(v1.get_allocator() == a2);
- }
- EXPECT_THAT(allocated1, 0);
- EXPECT_THAT(allocated2, 0);
- }
- TEST(AllocatorSupportTest, ScopedAllocatorWorksInlined) {
- using StdVector = std::vector<int, CountingAllocator<int>>;
- using Alloc = CountingAllocator<StdVector>;
- using ScopedAlloc = std::scoped_allocator_adaptor<Alloc>;
- using AllocVec = absl::InlinedVector<StdVector, 1, ScopedAlloc>;
- int64_t total_allocated_byte_count = 0;
- AllocVec inlined_case(ScopedAlloc(Alloc(+&total_allocated_byte_count)));
- // Called only once to remain inlined
- inlined_case.emplace_back();
- int64_t absl_responsible_for_count = total_allocated_byte_count;
- // MSVC's allocator preemptively allocates in debug mode
- #if !defined(_MSC_VER)
- EXPECT_EQ(absl_responsible_for_count, 0);
- #endif // !defined(_MSC_VER)
- inlined_case[0].emplace_back();
- EXPECT_GT(total_allocated_byte_count, absl_responsible_for_count);
- inlined_case.clear();
- inlined_case.shrink_to_fit();
- EXPECT_EQ(total_allocated_byte_count, 0);
- }
- TEST(AllocatorSupportTest, ScopedAllocatorWorksAllocated) {
- using StdVector = std::vector<int, CountingAllocator<int>>;
- using Alloc = CountingAllocator<StdVector>;
- using ScopedAlloc = std::scoped_allocator_adaptor<Alloc>;
- using AllocVec = absl::InlinedVector<StdVector, 1, ScopedAlloc>;
- int64_t total_allocated_byte_count = 0;
- AllocVec allocated_case(ScopedAlloc(Alloc(+&total_allocated_byte_count)));
- // Called twice to force into being allocated
- allocated_case.emplace_back();
- allocated_case.emplace_back();
- int64_t absl_responsible_for_count = total_allocated_byte_count;
- EXPECT_GT(absl_responsible_for_count, 0);
- allocated_case[1].emplace_back();
- EXPECT_GT(total_allocated_byte_count, absl_responsible_for_count);
- allocated_case.clear();
- allocated_case.shrink_to_fit();
- EXPECT_EQ(total_allocated_byte_count, 0);
- }
- TEST(AllocatorSupportTest, SizeAllocConstructor) {
- constexpr int inlined_size = 4;
- using Alloc = CountingAllocator<int>;
- using AllocVec = absl::InlinedVector<int, inlined_size, Alloc>;
- {
- auto len = inlined_size / 2;
- int64_t allocated = 0;
- auto v = AllocVec(len, Alloc(&allocated));
- // Inline storage used; allocator should not be invoked
- EXPECT_THAT(allocated, 0);
- EXPECT_THAT(v, AllOf(SizeIs(len), Each(0)));
- }
- {
- auto len = inlined_size * 2;
- int64_t allocated = 0;
- auto v = AllocVec(len, Alloc(&allocated));
- // Out of line storage used; allocation of 8 elements expected
- EXPECT_THAT(allocated, len * sizeof(int));
- EXPECT_THAT(v, AllOf(SizeIs(len), Each(0)));
- }
- }
- TEST(InlinedVectorTest, MinimumAllocatorCompilesUsingTraits) {
- using T = int;
- using A = std::allocator<T>;
- using ATraits = absl::allocator_traits<A>;
- struct MinimumAllocator {
- using value_type = T;
- value_type* allocate(size_t n) {
- A a;
- return ATraits::allocate(a, n);
- }
- void deallocate(value_type* p, size_t n) {
- A a;
- ATraits::deallocate(a, p, n);
- }
- };
- absl::InlinedVector<T, 1, MinimumAllocator> vec;
- vec.emplace_back();
- vec.resize(0);
- }
- TEST(InlinedVectorTest, AbslHashValueWorks) {
- using V = absl::InlinedVector<int, 4>;
- std::vector<V> cases;
- // Generate a variety of vectors some of these are small enough for the inline
- // space but are stored out of line.
- for (int i = 0; i < 10; ++i) {
- V v;
- for (int j = 0; j < i; ++j) {
- v.push_back(j);
- }
- cases.push_back(v);
- v.resize(i % 4);
- cases.push_back(v);
- }
- EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases));
- }
- } // anonymous namespace
|