compact_vector_ut.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  1. // Adapted from the following:
  2. //===- llvm/unittest/ADT/CompactVectorTest.cpp ------------------------------===//
  3. //
  4. // The LLVM Compiler Infrastructure
  5. //
  6. // This file is distributed under the University of Illinois Open Source
  7. // License. See LICENSE.TXT for details.
  8. //
  9. //===----------------------------------------------------------------------===//
  10. //
  11. // TCompactVector unit tests.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include <library/cpp/yt/small_containers/compact_vector.h>
  15. #include <library/cpp/testing/gtest/gtest.h>
  16. #include <util/string/cast.h>
  17. #include <algorithm>
  18. #include <list>
  19. #include <stdarg.h>
  20. namespace NYT {
  21. namespace {
  22. ////////////////////////////////////////////////////////////////////////////////
  23. /// A helper class that counts the total number of constructor and
  24. /// destructor calls.
  25. class Constructable {
  26. private:
  27. static int numConstructorCalls;
  28. static int numMoveConstructorCalls;
  29. static int numCopyConstructorCalls;
  30. static int numDestructorCalls;
  31. static int numAssignmentCalls;
  32. static int numMoveAssignmentCalls;
  33. static int numCopyAssignmentCalls;
  34. bool constructed;
  35. int value;
  36. public:
  37. Constructable() : constructed(true), value(0) {
  38. ++numConstructorCalls;
  39. }
  40. Constructable(int val) : constructed(true), value(val) {
  41. ++numConstructorCalls;
  42. }
  43. Constructable(const Constructable & src) : constructed(true) {
  44. value = src.value;
  45. ++numConstructorCalls;
  46. ++numCopyConstructorCalls;
  47. }
  48. Constructable(Constructable && src) : constructed(true) {
  49. value = src.value;
  50. ++numConstructorCalls;
  51. ++numMoveConstructorCalls;
  52. }
  53. ~Constructable() {
  54. EXPECT_TRUE(constructed);
  55. ++numDestructorCalls;
  56. constructed = false;
  57. }
  58. Constructable & operator=(const Constructable & src) {
  59. EXPECT_TRUE(constructed);
  60. value = src.value;
  61. ++numAssignmentCalls;
  62. ++numCopyAssignmentCalls;
  63. return *this;
  64. }
  65. Constructable & operator=(Constructable && src) {
  66. EXPECT_TRUE(constructed);
  67. value = src.value;
  68. ++numAssignmentCalls;
  69. ++numMoveAssignmentCalls;
  70. return *this;
  71. }
  72. int getValue() const {
  73. return abs(value);
  74. }
  75. static void reset() {
  76. numConstructorCalls = 0;
  77. numMoveConstructorCalls = 0;
  78. numCopyConstructorCalls = 0;
  79. numDestructorCalls = 0;
  80. numAssignmentCalls = 0;
  81. numMoveAssignmentCalls = 0;
  82. numCopyAssignmentCalls = 0;
  83. }
  84. static int getNumConstructorCalls() {
  85. return numConstructorCalls;
  86. }
  87. static int getNumMoveConstructorCalls() {
  88. return numMoveConstructorCalls;
  89. }
  90. static int getNumCopyConstructorCalls() {
  91. return numCopyConstructorCalls;
  92. }
  93. static int getNumDestructorCalls() {
  94. return numDestructorCalls;
  95. }
  96. static int getNumAssignmentCalls() {
  97. return numAssignmentCalls;
  98. }
  99. static int getNumMoveAssignmentCalls() {
  100. return numMoveAssignmentCalls;
  101. }
  102. static int getNumCopyAssignmentCalls() {
  103. return numCopyAssignmentCalls;
  104. }
  105. friend bool operator==(const Constructable & c0, const Constructable & c1) {
  106. return c0.getValue() == c1.getValue();
  107. }
  108. };
  109. int Constructable::numConstructorCalls;
  110. int Constructable::numCopyConstructorCalls;
  111. int Constructable::numMoveConstructorCalls;
  112. int Constructable::numDestructorCalls;
  113. int Constructable::numAssignmentCalls;
  114. int Constructable::numCopyAssignmentCalls;
  115. int Constructable::numMoveAssignmentCalls;
  116. struct NonCopyable {
  117. NonCopyable() {}
  118. NonCopyable(NonCopyable &&) {}
  119. NonCopyable &operator=(NonCopyable &&) { return *this; }
  120. private:
  121. NonCopyable(const NonCopyable &) = delete;
  122. NonCopyable &operator=(const NonCopyable &) = delete;
  123. };
  124. [[maybe_unused]] void CompileTest() {
  125. TCompactVector<NonCopyable, 0> V;
  126. V.resize(42);
  127. }
  128. class CompactVectorTestBase : public testing::Test {
  129. protected:
  130. void SetUp() override {
  131. Constructable::reset();
  132. }
  133. template <typename VectorT>
  134. void assertEmpty(VectorT & v) {
  135. // Size tests
  136. EXPECT_EQ(0u, v.size());
  137. EXPECT_TRUE(v.empty());
  138. // Iterator tests
  139. EXPECT_TRUE(v.begin() == v.end());
  140. }
  141. // Assert that v contains the specified values, in order.
  142. template <typename VectorT>
  143. void assertValuesInOrder(VectorT & v, size_t size, ...) {
  144. EXPECT_EQ(size, v.size());
  145. va_list ap;
  146. va_start(ap, size);
  147. for (size_t i = 0; i < size; ++i) {
  148. int value = va_arg(ap, int);
  149. EXPECT_EQ(value, v[i].getValue());
  150. }
  151. va_end(ap);
  152. }
  153. // Generate a sequence of values to initialize the vector.
  154. template <typename VectorT>
  155. void makeSequence(VectorT & v, int start, int end) {
  156. for (int i = start; i <= end; ++i) {
  157. v.push_back(Constructable(i));
  158. }
  159. }
  160. };
  161. // Test fixture class
  162. template <typename VectorT>
  163. class CompactVectorTest : public CompactVectorTestBase {
  164. protected:
  165. VectorT theVector;
  166. VectorT otherVector;
  167. };
  168. using CompactVectorTestTypes = ::testing::Types<TCompactVector<Constructable, 0>,
  169. TCompactVector<Constructable, 1>,
  170. TCompactVector<Constructable, 2>,
  171. TCompactVector<Constructable, 4>,
  172. TCompactVector<Constructable, 5>
  173. >;
  174. TYPED_TEST_SUITE(CompactVectorTest, CompactVectorTestTypes);
  175. // New vector test.
  176. TYPED_TEST(CompactVectorTest, EmptyVectorTest) {
  177. SCOPED_TRACE("EmptyVectorTest");
  178. this->assertEmpty(this->theVector);
  179. EXPECT_TRUE(this->theVector.rbegin() == this->theVector.rend());
  180. EXPECT_EQ(0, Constructable::getNumConstructorCalls());
  181. EXPECT_EQ(0, Constructable::getNumDestructorCalls());
  182. }
  183. // Simple insertions and deletions.
  184. TYPED_TEST(CompactVectorTest, PushPopTest) {
  185. SCOPED_TRACE("PushPopTest");
  186. // Track whether the vector will potentially have to grow.
  187. bool RequiresGrowth = this->theVector.capacity() < 3;
  188. // Push an element
  189. this->theVector.push_back(Constructable(1));
  190. // Size tests
  191. this->assertValuesInOrder(this->theVector, 1u, 1);
  192. EXPECT_FALSE(this->theVector.begin() == this->theVector.end());
  193. EXPECT_FALSE(this->theVector.empty());
  194. // Push another element
  195. this->theVector.push_back(Constructable(2));
  196. this->assertValuesInOrder(this->theVector, 2u, 1, 2);
  197. // Insert at beginning
  198. this->theVector.insert(this->theVector.begin(), this->theVector[1]);
  199. this->assertValuesInOrder(this->theVector, 3u, 2, 1, 2);
  200. // Pop one element
  201. this->theVector.pop_back();
  202. this->assertValuesInOrder(this->theVector, 2u, 2, 1);
  203. // Pop remaining elements
  204. this->theVector.pop_back();
  205. this->theVector.pop_back();
  206. this->assertEmpty(this->theVector);
  207. // Check number of constructor calls. Should be 2 for each list element,
  208. // one for the argument to push_back, one for the argument to insert,
  209. // and one for the list element itself.
  210. if (!RequiresGrowth) {
  211. EXPECT_EQ(5, Constructable::getNumConstructorCalls());
  212. EXPECT_EQ(5, Constructable::getNumDestructorCalls());
  213. } else {
  214. // If we had to grow the vector, these only have a lower bound, but should
  215. // always be equal.
  216. EXPECT_LE(5, Constructable::getNumConstructorCalls());
  217. EXPECT_EQ(Constructable::getNumConstructorCalls(),
  218. Constructable::getNumDestructorCalls());
  219. }
  220. }
  221. TYPED_TEST(CompactVectorTest, InsertEnd)
  222. {
  223. SCOPED_TRACE("InsertEnd");
  224. TCompactVector<TString, 5> vector;
  225. for (int index = 0; index < 10; ++index) {
  226. vector.insert(vector.end(), ToString(index));
  227. }
  228. for (int index = 0; index < 10; ++index) {
  229. EXPECT_EQ(vector[index], ToString(index));
  230. }
  231. }
  232. TYPED_TEST(CompactVectorTest, ShrinkToSmall)
  233. {
  234. SCOPED_TRACE("ShrinkToSmall");
  235. TCompactVector<TString, 5> vector;
  236. for (int index = 0; index < 10; ++index) {
  237. vector.shrink_to_small();
  238. vector.push_back(ToString(index));
  239. }
  240. for (int index = 0; index < 6; ++index) {
  241. vector.pop_back();
  242. }
  243. EXPECT_EQ(std::ssize(vector), 4);
  244. EXPECT_GE(static_cast<int>(vector.capacity()), 10);
  245. vector.shrink_to_small();
  246. EXPECT_EQ(std::ssize(vector), 4);
  247. EXPECT_EQ(static_cast<int>(vector.capacity()), 5);
  248. for (int index = 0; index < 4; ++index) {
  249. EXPECT_EQ(vector[index], ToString(index));
  250. }
  251. }
  252. // Clear test.
  253. TYPED_TEST(CompactVectorTest, ClearTest) {
  254. SCOPED_TRACE("ClearTest");
  255. this->theVector.reserve(2);
  256. this->makeSequence(this->theVector, 1, 2);
  257. this->theVector.clear();
  258. this->assertEmpty(this->theVector);
  259. EXPECT_EQ(4, Constructable::getNumConstructorCalls());
  260. EXPECT_EQ(4, Constructable::getNumDestructorCalls());
  261. }
  262. // Resize smaller test.
  263. TYPED_TEST(CompactVectorTest, ResizeShrinkTest) {
  264. SCOPED_TRACE("ResizeShrinkTest");
  265. this->theVector.reserve(3);
  266. this->makeSequence(this->theVector, 1, 3);
  267. this->theVector.resize(1);
  268. this->assertValuesInOrder(this->theVector, 1u, 1);
  269. EXPECT_EQ(6, Constructable::getNumConstructorCalls());
  270. EXPECT_EQ(5, Constructable::getNumDestructorCalls());
  271. }
  272. // Resize bigger test.
  273. TYPED_TEST(CompactVectorTest, ResizeGrowTest) {
  274. SCOPED_TRACE("ResizeGrowTest");
  275. this->theVector.resize(2);
  276. EXPECT_EQ(2, Constructable::getNumConstructorCalls());
  277. EXPECT_EQ(0, Constructable::getNumDestructorCalls());
  278. EXPECT_EQ(2u, this->theVector.size());
  279. }
  280. TYPED_TEST(CompactVectorTest, ResizeWithElementsTest) {
  281. this->theVector.resize(2);
  282. Constructable::reset();
  283. this->theVector.resize(4);
  284. size_t Ctors = Constructable::getNumConstructorCalls();
  285. EXPECT_TRUE(Ctors == 2 || Ctors == 4);
  286. size_t MoveCtors = Constructable::getNumMoveConstructorCalls();
  287. EXPECT_TRUE(MoveCtors == 0 || MoveCtors == 2);
  288. size_t Dtors = Constructable::getNumDestructorCalls();
  289. EXPECT_TRUE(Dtors == 0 || Dtors == 2);
  290. }
  291. // Resize with fill value.
  292. TYPED_TEST(CompactVectorTest, ResizeFillTest) {
  293. SCOPED_TRACE("ResizeFillTest");
  294. this->theVector.resize(3, Constructable(77));
  295. this->assertValuesInOrder(this->theVector, 3u, 77, 77, 77);
  296. }
  297. // Overflow past fixed size.
  298. TYPED_TEST(CompactVectorTest, OverflowTest) {
  299. SCOPED_TRACE("OverflowTest");
  300. // Push more elements than the fixed size.
  301. this->makeSequence(this->theVector, 1, 10);
  302. // Test size and values.
  303. EXPECT_EQ(10u, this->theVector.size());
  304. for (int i = 0; i < 10; ++i) {
  305. EXPECT_EQ(i+1, this->theVector[i].getValue());
  306. }
  307. // Now resize back to fixed size.
  308. this->theVector.resize(1);
  309. this->assertValuesInOrder(this->theVector, 1u, 1);
  310. }
  311. // Iteration tests.
  312. TYPED_TEST(CompactVectorTest, IterationTest) {
  313. this->makeSequence(this->theVector, 1, 2);
  314. // Forward Iteration
  315. typename TypeParam::iterator it = this->theVector.begin();
  316. EXPECT_TRUE(*it == this->theVector.front());
  317. EXPECT_TRUE(*it == this->theVector[0]);
  318. EXPECT_EQ(1, it->getValue());
  319. ++it;
  320. EXPECT_TRUE(*it == this->theVector[1]);
  321. EXPECT_TRUE(*it == this->theVector.back());
  322. EXPECT_EQ(2, it->getValue());
  323. ++it;
  324. EXPECT_TRUE(it == this->theVector.end());
  325. --it;
  326. EXPECT_TRUE(*it == this->theVector[1]);
  327. EXPECT_EQ(2, it->getValue());
  328. --it;
  329. EXPECT_TRUE(*it == this->theVector[0]);
  330. EXPECT_EQ(1, it->getValue());
  331. // Reverse Iteration
  332. typename TypeParam::reverse_iterator rit = this->theVector.rbegin();
  333. EXPECT_TRUE(*rit == this->theVector[1]);
  334. EXPECT_EQ(2, rit->getValue());
  335. ++rit;
  336. EXPECT_TRUE(*rit == this->theVector[0]);
  337. EXPECT_EQ(1, rit->getValue());
  338. ++rit;
  339. EXPECT_TRUE(rit == this->theVector.rend());
  340. --rit;
  341. EXPECT_TRUE(*rit == this->theVector[0]);
  342. EXPECT_EQ(1, rit->getValue());
  343. --rit;
  344. EXPECT_TRUE(*rit == this->theVector[1]);
  345. EXPECT_EQ(2, rit->getValue());
  346. }
  347. // Swap test.
  348. TYPED_TEST(CompactVectorTest, SwapTest) {
  349. SCOPED_TRACE("SwapTest");
  350. this->makeSequence(this->theVector, 1, 2);
  351. std::swap(this->theVector, this->otherVector);
  352. this->assertEmpty(this->theVector);
  353. this->assertValuesInOrder(this->otherVector, 2u, 1, 2);
  354. }
  355. // Append test
  356. TYPED_TEST(CompactVectorTest, AppendTest) {
  357. SCOPED_TRACE("AppendTest");
  358. this->makeSequence(this->otherVector, 2, 3);
  359. this->theVector.push_back(Constructable(1));
  360. this->theVector.insert(this->theVector.end(), this->otherVector.begin(), this->otherVector.end());
  361. this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3);
  362. }
  363. // Append repeated test
  364. TYPED_TEST(CompactVectorTest, AppendRepeatedTest) {
  365. SCOPED_TRACE("AppendRepeatedTest");
  366. this->theVector.push_back(Constructable(1));
  367. this->theVector.insert(this->theVector.end(), 2, Constructable(77));
  368. this->assertValuesInOrder(this->theVector, 3u, 1, 77, 77);
  369. }
  370. // Assign test
  371. TYPED_TEST(CompactVectorTest, AssignTest) {
  372. SCOPED_TRACE("AssignTest");
  373. this->theVector.push_back(Constructable(1));
  374. this->theVector.assign(2, Constructable(77));
  375. this->assertValuesInOrder(this->theVector, 2u, 77, 77);
  376. }
  377. // Move-assign test
  378. TYPED_TEST(CompactVectorTest, MoveAssignTest) {
  379. SCOPED_TRACE("MoveAssignTest");
  380. // Set up our vector with a single element, but enough capacity for 4.
  381. this->theVector.reserve(4);
  382. this->theVector.push_back(Constructable(1));
  383. // Set up the other vector with 2 elements.
  384. this->otherVector.push_back(Constructable(2));
  385. this->otherVector.push_back(Constructable(3));
  386. // Move-assign from the other vector.
  387. this->theVector = std::move(this->otherVector);
  388. // Make sure we have the right result.
  389. this->assertValuesInOrder(this->theVector, 2u, 2, 3);
  390. // Make sure the # of constructor/destructor calls line up. There
  391. // are two live objects after clearing the other vector.
  392. this->otherVector.clear();
  393. EXPECT_EQ(Constructable::getNumConstructorCalls()-2,
  394. Constructable::getNumDestructorCalls());
  395. // There shouldn't be any live objects any more.
  396. this->theVector.clear();
  397. EXPECT_EQ(Constructable::getNumConstructorCalls(),
  398. Constructable::getNumDestructorCalls());
  399. }
  400. // Erase a single element
  401. TYPED_TEST(CompactVectorTest, EraseTest) {
  402. SCOPED_TRACE("EraseTest");
  403. this->makeSequence(this->theVector, 1, 3);
  404. this->theVector.erase(this->theVector.begin());
  405. this->assertValuesInOrder(this->theVector, 2u, 2, 3);
  406. }
  407. // Erase a range of elements
  408. TYPED_TEST(CompactVectorTest, EraseRangeTest) {
  409. SCOPED_TRACE("EraseRangeTest");
  410. this->makeSequence(this->theVector, 1, 3);
  411. this->theVector.erase(this->theVector.begin(), this->theVector.begin() + 2);
  412. this->assertValuesInOrder(this->theVector, 1u, 3);
  413. }
  414. // Insert a single element.
  415. TYPED_TEST(CompactVectorTest, InsertTest) {
  416. SCOPED_TRACE("InsertTest");
  417. this->makeSequence(this->theVector, 1, 3);
  418. typename TypeParam::iterator I =
  419. this->theVector.insert(this->theVector.begin() + 1, Constructable(77));
  420. EXPECT_EQ(this->theVector.begin() + 1, I);
  421. this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3);
  422. }
  423. // Insert a copy of a single element.
  424. TYPED_TEST(CompactVectorTest, InsertCopy) {
  425. SCOPED_TRACE("InsertTest");
  426. this->makeSequence(this->theVector, 1, 3);
  427. Constructable C(77);
  428. typename TypeParam::iterator I =
  429. this->theVector.insert(this->theVector.begin() + 1, C);
  430. EXPECT_EQ(this->theVector.begin() + 1, I);
  431. this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3);
  432. }
  433. // Insert repeated elements.
  434. TYPED_TEST(CompactVectorTest, InsertRepeatedTest) {
  435. SCOPED_TRACE("InsertRepeatedTest");
  436. this->makeSequence(this->theVector, 1, 4);
  437. Constructable::reset();
  438. auto I =
  439. this->theVector.insert(this->theVector.begin() + 1, 2, Constructable(16));
  440. // Move construct the top element into newly allocated space, and optionally
  441. // reallocate the whole buffer, move constructing into it.
  442. // FIXME: This is inefficient, we shouldn't move things into newly allocated
  443. // space, then move them up/around, there should only be 2 or 4 move
  444. // constructions here.
  445. EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 ||
  446. Constructable::getNumMoveConstructorCalls() == 6);
  447. // Move assign the next two to shift them up and make a gap.
  448. EXPECT_EQ(1, Constructable::getNumMoveAssignmentCalls());
  449. // Copy construct the two new elements from the parameter.
  450. EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls());
  451. // All without any copy construction.
  452. EXPECT_EQ(0, Constructable::getNumCopyConstructorCalls());
  453. EXPECT_EQ(this->theVector.begin() + 1, I);
  454. this->assertValuesInOrder(this->theVector, 6u, 1, 16, 16, 2, 3, 4);
  455. }
  456. TYPED_TEST(CompactVectorTest, InsertRepeatedAtEndTest) {
  457. SCOPED_TRACE("InsertRepeatedTest");
  458. this->makeSequence(this->theVector, 1, 4);
  459. Constructable::reset();
  460. auto I = this->theVector.insert(this->theVector.end(), 2, Constructable(16));
  461. // Just copy construct them into newly allocated space
  462. EXPECT_EQ(2, Constructable::getNumCopyConstructorCalls());
  463. // Move everything across if reallocation is needed.
  464. EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 ||
  465. Constructable::getNumMoveConstructorCalls() == 4);
  466. // Without ever moving or copying anything else.
  467. EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls());
  468. EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls());
  469. EXPECT_EQ(this->theVector.begin() + 4, I);
  470. this->assertValuesInOrder(this->theVector, 6u, 1, 2, 3, 4, 16, 16);
  471. }
  472. TYPED_TEST(CompactVectorTest, InsertRepeatedEmptyTest) {
  473. SCOPED_TRACE("InsertRepeatedTest");
  474. this->makeSequence(this->theVector, 10, 15);
  475. // Empty insert.
  476. EXPECT_EQ(this->theVector.end(),
  477. this->theVector.insert(this->theVector.end(),
  478. 0, Constructable(42)));
  479. EXPECT_EQ(this->theVector.begin() + 1,
  480. this->theVector.insert(this->theVector.begin() + 1,
  481. 0, Constructable(42)));
  482. }
  483. // Insert range.
  484. TYPED_TEST(CompactVectorTest, InsertRangeTest) {
  485. SCOPED_TRACE("InsertRangeTest");
  486. Constructable Arr[3] =
  487. { Constructable(77), Constructable(77), Constructable(77) };
  488. this->makeSequence(this->theVector, 1, 3);
  489. Constructable::reset();
  490. auto I = this->theVector.insert(this->theVector.begin() + 1, Arr, Arr + 3);
  491. // Move construct the top 3 elements into newly allocated space.
  492. // Possibly move the whole sequence into new space first.
  493. // FIXME: This is inefficient, we shouldn't move things into newly allocated
  494. // space, then move them up/around, there should only be 2 or 3 move
  495. // constructions here.
  496. EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 ||
  497. Constructable::getNumMoveConstructorCalls() == 5);
  498. // Copy assign the lower 2 new elements into existing space.
  499. EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls());
  500. // Copy construct the third element into newly allocated space.
  501. EXPECT_EQ(1, Constructable::getNumCopyConstructorCalls());
  502. EXPECT_EQ(this->theVector.begin() + 1, I);
  503. this->assertValuesInOrder(this->theVector, 6u, 1, 77, 77, 77, 2, 3);
  504. }
  505. TYPED_TEST(CompactVectorTest, InsertRangeAtEndTest) {
  506. SCOPED_TRACE("InsertRangeTest");
  507. Constructable Arr[3] =
  508. { Constructable(77), Constructable(77), Constructable(77) };
  509. this->makeSequence(this->theVector, 1, 3);
  510. // Insert at end.
  511. Constructable::reset();
  512. auto I = this->theVector.insert(this->theVector.end(), Arr, Arr+3);
  513. // Copy construct the 3 elements into new space at the top.
  514. EXPECT_EQ(3, Constructable::getNumCopyConstructorCalls());
  515. // Don't copy/move anything else.
  516. EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls());
  517. // Reallocation might occur, causing all elements to be moved into the new
  518. // buffer.
  519. EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 ||
  520. Constructable::getNumMoveConstructorCalls() == 3);
  521. EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls());
  522. EXPECT_EQ(this->theVector.begin() + 3, I);
  523. this->assertValuesInOrder(this->theVector, 6u,
  524. 1, 2, 3, 77, 77, 77);
  525. }
  526. TYPED_TEST(CompactVectorTest, InsertEmptyRangeTest) {
  527. SCOPED_TRACE("InsertRangeTest");
  528. this->makeSequence(this->theVector, 1, 3);
  529. // Empty insert.
  530. EXPECT_EQ(this->theVector.end(),
  531. this->theVector.insert(this->theVector.end(),
  532. this->theVector.begin(),
  533. this->theVector.begin()));
  534. EXPECT_EQ(this->theVector.begin() + 1,
  535. this->theVector.insert(this->theVector.begin() + 1,
  536. this->theVector.begin(),
  537. this->theVector.begin()));
  538. }
  539. // Comparison tests.
  540. TYPED_TEST(CompactVectorTest, ComparisonTest) {
  541. SCOPED_TRACE("ComparisonTest");
  542. this->makeSequence(this->theVector, 1, 3);
  543. this->makeSequence(this->otherVector, 1, 3);
  544. EXPECT_TRUE(this->theVector == this->otherVector);
  545. EXPECT_FALSE(this->theVector != this->otherVector);
  546. this->otherVector.clear();
  547. this->makeSequence(this->otherVector, 2, 4);
  548. EXPECT_FALSE(this->theVector == this->otherVector);
  549. EXPECT_TRUE(this->theVector != this->otherVector);
  550. }
  551. // Constant vector tests.
  552. TYPED_TEST(CompactVectorTest, ConstVectorTest) {
  553. const TypeParam constVector;
  554. EXPECT_EQ(0u, constVector.size());
  555. EXPECT_TRUE(constVector.empty());
  556. EXPECT_TRUE(constVector.begin() == constVector.end());
  557. }
  558. // Direct array access.
  559. TYPED_TEST(CompactVectorTest, DirectVectorTest) {
  560. EXPECT_EQ(0u, this->theVector.size());
  561. this->theVector.reserve(4);
  562. EXPECT_LE(4u, this->theVector.capacity());
  563. EXPECT_EQ(0, Constructable::getNumConstructorCalls());
  564. this->theVector.push_back(1);
  565. this->theVector.push_back(2);
  566. this->theVector.push_back(3);
  567. this->theVector.push_back(4);
  568. EXPECT_EQ(4u, this->theVector.size());
  569. EXPECT_EQ(8, Constructable::getNumConstructorCalls());
  570. EXPECT_EQ(1, this->theVector[0].getValue());
  571. EXPECT_EQ(2, this->theVector[1].getValue());
  572. EXPECT_EQ(3, this->theVector[2].getValue());
  573. EXPECT_EQ(4, this->theVector[3].getValue());
  574. }
  575. TYPED_TEST(CompactVectorTest, IteratorTest) {
  576. std::list<int> L;
  577. this->theVector.insert(this->theVector.end(), L.begin(), L.end());
  578. }
  579. template <typename InvalidType> class DualCompactVectorsTest;
  580. template <typename VectorT1, typename VectorT2>
  581. class DualCompactVectorsTest<std::pair<VectorT1, VectorT2>> : public CompactVectorTestBase {
  582. protected:
  583. VectorT1 theVector;
  584. VectorT2 otherVector;
  585. template <typename T, size_t N>
  586. static size_t NumBuiltinElts(const TCompactVector<T, N>&) { return N; }
  587. };
  588. using DualCompactVectorTestTypes = ::testing::Types<
  589. // Small mode -> Small mode.
  590. std::pair<TCompactVector<Constructable, 4>, TCompactVector<Constructable, 4>>,
  591. // Small mode -> Big mode.
  592. std::pair<TCompactVector<Constructable, 4>, TCompactVector<Constructable, 2>>,
  593. // Big mode -> Small mode.
  594. std::pair<TCompactVector<Constructable, 2>, TCompactVector<Constructable, 4>>,
  595. // Big mode -> Big mode.
  596. std::pair<TCompactVector<Constructable, 2>, TCompactVector<Constructable, 2>>
  597. >;
  598. TYPED_TEST_SUITE(DualCompactVectorsTest, DualCompactVectorTestTypes);
  599. TYPED_TEST(DualCompactVectorsTest, MoveAssignment) {
  600. SCOPED_TRACE("MoveAssignTest-DualVectorTypes");
  601. // Set up our vector with four elements.
  602. for (unsigned I = 0; I < 4; ++I)
  603. this->otherVector.push_back(Constructable(I));
  604. const Constructable *OrigDataPtr = this->otherVector.data();
  605. // Move-assign from the other vector.
  606. this->theVector =
  607. std::move(this->otherVector);
  608. // Make sure we have the right result.
  609. this->assertValuesInOrder(this->theVector, 4u, 0, 1, 2, 3);
  610. // Make sure the # of constructor/destructor calls line up. There
  611. // are two live objects after clearing the other vector.
  612. this->otherVector.clear();
  613. EXPECT_EQ(Constructable::getNumConstructorCalls()-4,
  614. Constructable::getNumDestructorCalls());
  615. // If the source vector (otherVector) was in small-mode, assert that we just
  616. // moved the data pointer over.
  617. EXPECT_TRUE(this->NumBuiltinElts(this->otherVector) == 4 ||
  618. this->theVector.data() == OrigDataPtr);
  619. // There shouldn't be any live objects any more.
  620. this->theVector.clear();
  621. EXPECT_EQ(Constructable::getNumConstructorCalls(),
  622. Constructable::getNumDestructorCalls());
  623. // We shouldn't have copied anything in this whole process.
  624. EXPECT_EQ(Constructable::getNumCopyConstructorCalls(), 0);
  625. }
  626. struct notassignable {
  627. int &x;
  628. notassignable(int &x) : x(x) {}
  629. };
  630. TEST(CompactVectorCustomTest, NoAssignTest) {
  631. int x = 0;
  632. TCompactVector<notassignable, 2> vec;
  633. vec.push_back(notassignable(x));
  634. x = 42;
  635. EXPECT_EQ(42, vec.back().x);
  636. }
  637. struct MovedFrom {
  638. bool hasValue;
  639. MovedFrom() : hasValue(true) {
  640. }
  641. MovedFrom(MovedFrom&& m) : hasValue(m.hasValue) {
  642. m.hasValue = false;
  643. }
  644. MovedFrom &operator=(MovedFrom&& m) {
  645. hasValue = m.hasValue;
  646. m.hasValue = false;
  647. return *this;
  648. }
  649. };
  650. TEST(CompactVectorTest, MidInsert) {
  651. TCompactVector<MovedFrom, 3> v;
  652. v.push_back(MovedFrom());
  653. v.insert(v.begin(), MovedFrom());
  654. for (MovedFrom &m : v)
  655. EXPECT_TRUE(m.hasValue);
  656. }
  657. enum EmplaceableArgState {
  658. EAS_Defaulted,
  659. EAS_Arg,
  660. EAS_LValue,
  661. EAS_RValue,
  662. EAS_Failure
  663. };
  664. template <int I> struct EmplaceableArg {
  665. EmplaceableArgState State;
  666. EmplaceableArg() : State(EAS_Defaulted) {}
  667. EmplaceableArg(EmplaceableArg &&X)
  668. : State(X.State == EAS_Arg ? EAS_RValue : EAS_Failure) {}
  669. EmplaceableArg(EmplaceableArg &X)
  670. : State(X.State == EAS_Arg ? EAS_LValue : EAS_Failure) {}
  671. explicit EmplaceableArg(bool) : State(EAS_Arg) {}
  672. private:
  673. EmplaceableArg &operator=(EmplaceableArg &&) = delete;
  674. EmplaceableArg &operator=(const EmplaceableArg &) = delete;
  675. };
  676. enum EmplaceableState { ES_Emplaced, ES_Moved };
  677. struct Emplaceable {
  678. EmplaceableArg<0> A0;
  679. EmplaceableArg<1> A1;
  680. EmplaceableArg<2> A2;
  681. EmplaceableArg<3> A3;
  682. EmplaceableState State;
  683. Emplaceable() : State(ES_Emplaced) {}
  684. template <class A0Ty>
  685. explicit Emplaceable(A0Ty &&A0)
  686. : A0(std::forward<A0Ty>(A0)), State(ES_Emplaced) {}
  687. template <class A0Ty, class A1Ty>
  688. Emplaceable(A0Ty &&A0, A1Ty &&A1)
  689. : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)),
  690. State(ES_Emplaced) {}
  691. template <class A0Ty, class A1Ty, class A2Ty>
  692. Emplaceable(A0Ty &&A0, A1Ty &&A1, A2Ty &&A2)
  693. : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)),
  694. A2(std::forward<A2Ty>(A2)), State(ES_Emplaced) {}
  695. template <class A0Ty, class A1Ty, class A2Ty, class A3Ty>
  696. Emplaceable(A0Ty &&A0, A1Ty &&A1, A2Ty &&A2, A3Ty &&A3)
  697. : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)),
  698. A2(std::forward<A2Ty>(A2)), A3(std::forward<A3Ty>(A3)),
  699. State(ES_Emplaced) {}
  700. Emplaceable(Emplaceable &&) : State(ES_Moved) {}
  701. Emplaceable &operator=(Emplaceable &&) {
  702. State = ES_Moved;
  703. return *this;
  704. }
  705. private:
  706. Emplaceable(const Emplaceable &) = delete;
  707. Emplaceable &operator=(const Emplaceable &) = delete;
  708. };
  709. TEST(CompactVectorTest, EmplaceBack) {
  710. EmplaceableArg<0> A0(true);
  711. EmplaceableArg<1> A1(true);
  712. EmplaceableArg<2> A2(true);
  713. EmplaceableArg<3> A3(true);
  714. {
  715. TCompactVector<Emplaceable, 3> V;
  716. V.emplace_back();
  717. EXPECT_TRUE(V.size() == 1);
  718. EXPECT_TRUE(V.back().State == ES_Emplaced);
  719. EXPECT_TRUE(V.back().A0.State == EAS_Defaulted);
  720. EXPECT_TRUE(V.back().A1.State == EAS_Defaulted);
  721. EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
  722. EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
  723. }
  724. {
  725. TCompactVector<Emplaceable, 3> V;
  726. V.emplace_back(std::move(A0));
  727. EXPECT_TRUE(V.size() == 1);
  728. EXPECT_TRUE(V.back().State == ES_Emplaced);
  729. EXPECT_TRUE(V.back().A0.State == EAS_RValue);
  730. EXPECT_TRUE(V.back().A1.State == EAS_Defaulted);
  731. EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
  732. EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
  733. }
  734. {
  735. TCompactVector<Emplaceable, 3> V;
  736. V.emplace_back(A0);
  737. EXPECT_TRUE(V.size() == 1);
  738. EXPECT_TRUE(V.back().State == ES_Emplaced);
  739. EXPECT_TRUE(V.back().A0.State == EAS_LValue);
  740. EXPECT_TRUE(V.back().A1.State == EAS_Defaulted);
  741. EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
  742. EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
  743. }
  744. {
  745. TCompactVector<Emplaceable, 3> V;
  746. V.emplace_back(A0, A1);
  747. EXPECT_TRUE(V.size() == 1);
  748. EXPECT_TRUE(V.back().State == ES_Emplaced);
  749. EXPECT_TRUE(V.back().A0.State == EAS_LValue);
  750. EXPECT_TRUE(V.back().A1.State == EAS_LValue);
  751. EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
  752. EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
  753. }
  754. {
  755. TCompactVector<Emplaceable, 3> V;
  756. V.emplace_back(std::move(A0), std::move(A1));
  757. EXPECT_TRUE(V.size() == 1);
  758. EXPECT_TRUE(V.back().State == ES_Emplaced);
  759. EXPECT_TRUE(V.back().A0.State == EAS_RValue);
  760. EXPECT_TRUE(V.back().A1.State == EAS_RValue);
  761. EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
  762. EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
  763. }
  764. {
  765. TCompactVector<Emplaceable, 3> V;
  766. V.emplace_back(std::move(A0), A1, std::move(A2), A3);
  767. EXPECT_TRUE(V.size() == 1);
  768. EXPECT_TRUE(V.back().State == ES_Emplaced);
  769. EXPECT_TRUE(V.back().A0.State == EAS_RValue);
  770. EXPECT_TRUE(V.back().A1.State == EAS_LValue);
  771. EXPECT_TRUE(V.back().A2.State == EAS_RValue);
  772. EXPECT_TRUE(V.back().A3.State == EAS_LValue);
  773. }
  774. {
  775. TCompactVector<int, 1> V;
  776. V.emplace_back();
  777. V.emplace_back(42);
  778. EXPECT_EQ(2U, V.size());
  779. EXPECT_EQ(0, V[0]);
  780. EXPECT_EQ(42, V[1]);
  781. }
  782. }
  783. TEST(CompactVectorTest, Emplace) {
  784. EmplaceableArg<0> A0(true);
  785. EmplaceableArg<1> A1(true);
  786. EmplaceableArg<2> A2(true);
  787. EmplaceableArg<3> A3(true);
  788. {
  789. TCompactVector<Emplaceable, 3> V;
  790. V.emplace(V.end());
  791. EXPECT_TRUE(V.size() == 1);
  792. EXPECT_TRUE(V.back().State == ES_Emplaced);
  793. EXPECT_TRUE(V.back().A0.State == EAS_Defaulted);
  794. EXPECT_TRUE(V.back().A1.State == EAS_Defaulted);
  795. EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
  796. EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
  797. }
  798. {
  799. TCompactVector<Emplaceable, 3> V;
  800. V.emplace(V.end(), std::move(A0));
  801. EXPECT_TRUE(V.size() == 1);
  802. EXPECT_TRUE(V.back().State == ES_Emplaced);
  803. EXPECT_TRUE(V.back().A0.State == EAS_RValue);
  804. EXPECT_TRUE(V.back().A1.State == EAS_Defaulted);
  805. EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
  806. EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
  807. }
  808. {
  809. TCompactVector<Emplaceable, 3> V;
  810. V.emplace(V.end(), A0);
  811. EXPECT_TRUE(V.size() == 1);
  812. EXPECT_TRUE(V.back().State == ES_Emplaced);
  813. EXPECT_TRUE(V.back().A0.State == EAS_LValue);
  814. EXPECT_TRUE(V.back().A1.State == EAS_Defaulted);
  815. EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
  816. EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
  817. }
  818. {
  819. TCompactVector<Emplaceable, 3> V;
  820. V.emplace(V.end(), A0, A1);
  821. EXPECT_TRUE(V.size() == 1);
  822. EXPECT_TRUE(V.back().State == ES_Emplaced);
  823. EXPECT_TRUE(V.back().A0.State == EAS_LValue);
  824. EXPECT_TRUE(V.back().A1.State == EAS_LValue);
  825. EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
  826. EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
  827. }
  828. {
  829. TCompactVector<Emplaceable, 3> V;
  830. V.emplace(V.end(), std::move(A0), std::move(A1));
  831. EXPECT_TRUE(V.size() == 1);
  832. EXPECT_TRUE(V.back().State == ES_Emplaced);
  833. EXPECT_TRUE(V.back().A0.State == EAS_RValue);
  834. EXPECT_TRUE(V.back().A1.State == EAS_RValue);
  835. EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
  836. EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
  837. }
  838. {
  839. TCompactVector<Emplaceable, 3> V;
  840. V.emplace(V.end(), std::move(A0), A1, std::move(A2), A3);
  841. EXPECT_TRUE(V.size() == 1);
  842. EXPECT_TRUE(V.back().State == ES_Emplaced);
  843. EXPECT_TRUE(V.back().A0.State == EAS_RValue);
  844. EXPECT_TRUE(V.back().A1.State == EAS_LValue);
  845. EXPECT_TRUE(V.back().A2.State == EAS_RValue);
  846. EXPECT_TRUE(V.back().A3.State == EAS_LValue);
  847. }
  848. {
  849. TCompactVector<int, 1> V;
  850. V.emplace_back(42);
  851. V.emplace(V.begin(), 0);
  852. EXPECT_EQ(2U, V.size());
  853. EXPECT_EQ(0, V[0]);
  854. EXPECT_EQ(42, V[1]);
  855. }
  856. }
  857. template <class T, size_t N>
  858. class TStubArray
  859. {
  860. public:
  861. TStubArray(const TCompactVector<T, N>& vector)
  862. : Vector_(vector)
  863. { }
  864. bool equals(std::initializer_list<T> list)
  865. {
  866. return std::equal(Vector_.begin(), Vector_.end(), list.begin());
  867. }
  868. TCompactVector<T, N> Vector_;
  869. };
  870. template <typename T, size_t N>
  871. TStubArray<T, N> makeArrayRef(const TCompactVector<T, N>& vector)
  872. {
  873. return TStubArray<T, N>(vector);
  874. }
  875. TEST(CompactVectorTest, InitializerList) {
  876. TCompactVector<int, 2> V1 = {};
  877. EXPECT_TRUE(V1.empty());
  878. V1 = {0, 0};
  879. EXPECT_TRUE(makeArrayRef(V1).equals({0, 0}));
  880. V1 = {-1, -1};
  881. EXPECT_TRUE(makeArrayRef(V1).equals({-1, -1}));
  882. TCompactVector<int, 2> V2 = {1, 2, 3, 4};
  883. EXPECT_TRUE(makeArrayRef(V2).equals({1, 2, 3, 4}));
  884. V2.assign({4});
  885. EXPECT_TRUE(makeArrayRef(V2).equals({4}));
  886. V2.insert(V2.end(), {3, 2});
  887. EXPECT_TRUE(makeArrayRef(V2).equals({4, 3, 2}));
  888. V2.insert(V2.begin() + 1, 5);
  889. EXPECT_TRUE(makeArrayRef(V2).equals({4, 5, 3, 2}));
  890. }
  891. TEST(CompactVectorTest, AssignToShorter) {
  892. TCompactVector<TString, 4> lhs;
  893. TCompactVector<TString, 4> rhs;
  894. rhs.emplace_back("foo");
  895. lhs = rhs;
  896. EXPECT_EQ(1U, lhs.size());
  897. EXPECT_EQ("foo", lhs[0]);
  898. }
  899. TEST(CompactVectorTest, AssignToLonger) {
  900. TCompactVector<TString, 4> lhs;
  901. lhs.emplace_back("bar");
  902. lhs.emplace_back("baz");
  903. TCompactVector<TString, 4> rhs;
  904. rhs.emplace_back("foo");
  905. lhs = rhs;
  906. EXPECT_EQ(1U, lhs.size());
  907. EXPECT_EQ("foo", lhs[0]);
  908. }
  909. TEST(CompactVectorTest, ZeroPaddingOnHeapMeta) {
  910. TCompactVector<uint8_t, 6> vector;
  911. std::vector<uint8_t> expected;
  912. for (int i = 0; i < 10; ++i) {
  913. vector.push_back(i);
  914. expected.push_back(i);
  915. ASSERT_THAT(vector, ::testing::ElementsAreArray(expected));
  916. }
  917. }
  918. ////////////////////////////////////////////////////////////////////////////////
  919. } // namespace
  920. } // namespace NYT