IteratorTest.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. /*
  2. * Copyright 2017-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <algorithm>
  17. #include <cassert>
  18. #include <cstddef>
  19. #include <deque>
  20. #include <functional>
  21. #include <map>
  22. #include <set>
  23. #include <tuple>
  24. #include <type_traits>
  25. #include <utility>
  26. #include <vector>
  27. #include <folly/container/Iterator.h>
  28. #include <folly/portability/GTest.h>
  29. namespace {
  30. /**
  31. * Container type used for unit tests.
  32. */
  33. template <typename T>
  34. using Container = std::deque<T>;
  35. // Constructor and assignment operator call counters for struct Object.
  36. std::size_t gDefaultCtrCnt;
  37. std::size_t gCopyCtrCnt;
  38. std::size_t gMoveCtrCnt;
  39. std::size_t gExplicitCtrCnt;
  40. std::size_t gMultiargCtrCnt;
  41. std::size_t gCopyOpCnt;
  42. std::size_t gMoveOpCnt;
  43. std::size_t gConvertOpCnt;
  44. /**
  45. * Class that increases various counters to keep track of how objects have
  46. * been constructed or assigned to, to verify iterator behavior.
  47. */
  48. struct Object {
  49. Object() {
  50. ++gDefaultCtrCnt;
  51. }
  52. Object(const Object&) {
  53. ++gCopyCtrCnt;
  54. }
  55. Object(Object&&) noexcept {
  56. ++gMoveCtrCnt;
  57. }
  58. explicit Object(int) {
  59. ++gExplicitCtrCnt;
  60. }
  61. explicit Object(int, int) {
  62. ++gMultiargCtrCnt;
  63. }
  64. Object& operator=(const Object&) {
  65. ++gCopyOpCnt;
  66. return *this;
  67. }
  68. Object& operator=(Object&&) noexcept {
  69. ++gMoveOpCnt;
  70. return *this;
  71. }
  72. Object& operator=(int) noexcept {
  73. ++gConvertOpCnt;
  74. return *this;
  75. }
  76. };
  77. /**
  78. * Reset all call counters to 0.
  79. */
  80. void init_counters() {
  81. gDefaultCtrCnt = gCopyCtrCnt = gMoveCtrCnt = gExplicitCtrCnt =
  82. gMultiargCtrCnt = gCopyOpCnt = gMoveOpCnt = gConvertOpCnt = 0;
  83. }
  84. /**
  85. * Test for iterator copy and move.
  86. */
  87. template <typename Iterator>
  88. void copy_and_move_test(Container<int>& q, Iterator it) {
  89. assert(q.empty());
  90. const auto it2(it); // copy construct
  91. it = it2; // copy assign from const
  92. it = it; // self assign
  93. auto it3(std::move(it)); // move construct
  94. it = std::move(it3); // move assign
  95. // Make sure iterator still works.
  96. it = 4711; // emplace
  97. EXPECT_EQ(q, Container<int>{4711});
  98. }
  99. /**
  100. * Test for emplacement with perfect forwarding.
  101. */
  102. template <typename Iterator>
  103. void emplace_test(Container<Object>& q, Iterator it) {
  104. using folly::make_emplace_args;
  105. assert(q.empty());
  106. init_counters();
  107. it = Object{}; // default construct + move construct
  108. Object obj; // default construct
  109. it = obj; // copy construct
  110. it = std::move(obj); // move construct
  111. const Object obj2; // default construct
  112. it = obj2; // copy construct from const
  113. it = std::move(obj2); // copy construct (const defeats move)
  114. it = 0; // explicit construct
  115. it = make_emplace_args(0, 0); // explicit multiarg construct
  116. it = std::make_pair(0, 0); // implicit multiarg construct
  117. it = std::make_tuple(0, 0); // implicit multiarg construct
  118. auto args = make_emplace_args(Object{}); // default construct + move construct
  119. it = args; // copy construct
  120. it = const_cast<const decltype(args)&>(args); // copy construct from const
  121. it = std::move(args); // move construct
  122. auto args2 = std::make_tuple(Object{}); // default construct + move construct
  123. it = args2; // (implicit multiarg) copy construct
  124. it = std::move(args2); // (implicit multiarg) move construct
  125. auto args3 = std::make_pair(0, 0);
  126. it = args3; // implicit multiarg construct
  127. it = std::move(args3); // implicit multiarg construct
  128. ASSERT_EQ(q.size(), 16);
  129. EXPECT_EQ(gDefaultCtrCnt, 5);
  130. EXPECT_EQ(gCopyCtrCnt, 6);
  131. EXPECT_EQ(gMoveCtrCnt, 6);
  132. EXPECT_EQ(gExplicitCtrCnt, 1);
  133. EXPECT_EQ(gMultiargCtrCnt, 5);
  134. EXPECT_EQ(gCopyOpCnt, 0);
  135. EXPECT_EQ(gMoveOpCnt, 0);
  136. EXPECT_EQ(gConvertOpCnt, 0);
  137. }
  138. } // namespace
  139. using namespace folly;
  140. /**
  141. * Basic tests for folly::emplace_iterator.
  142. */
  143. TEST(EmplaceIterator, EmplacerTest) {
  144. {
  145. Container<int> q;
  146. copy_and_move_test(q, emplacer(q, q.begin()));
  147. }
  148. {
  149. Container<Object> q;
  150. emplace_test(q, emplacer(q, q.begin()));
  151. }
  152. {
  153. Container<int> q;
  154. auto it = emplacer(q, q.begin());
  155. it = 0;
  156. it = 1;
  157. it = 2;
  158. it = emplacer(q, q.begin());
  159. it = 3;
  160. it = 4;
  161. EXPECT_EQ(q, Container<int>({3, 4, 0, 1, 2}));
  162. }
  163. }
  164. /**
  165. * Basic tests for folly::front_emplace_iterator.
  166. */
  167. TEST(EmplaceIterator, FrontEmplacerTest) {
  168. {
  169. Container<int> q;
  170. copy_and_move_test(q, front_emplacer(q));
  171. }
  172. {
  173. Container<Object> q;
  174. emplace_test(q, front_emplacer(q));
  175. }
  176. {
  177. Container<int> q;
  178. auto it = front_emplacer(q);
  179. it = 0;
  180. it = 1;
  181. it = 2;
  182. it = front_emplacer(q);
  183. it = 3;
  184. it = 4;
  185. EXPECT_EQ(q, Container<int>({4, 3, 2, 1, 0}));
  186. }
  187. }
  188. /**
  189. * Basic tests for folly::back_emplace_iterator.
  190. */
  191. TEST(EmplaceIterator, BackEmplacerTest) {
  192. {
  193. Container<int> q;
  194. copy_and_move_test(q, back_emplacer(q));
  195. }
  196. {
  197. Container<Object> q;
  198. emplace_test(q, back_emplacer(q));
  199. }
  200. {
  201. Container<int> q;
  202. auto it = back_emplacer(q);
  203. it = 0;
  204. it = 1;
  205. it = 2;
  206. it = back_emplacer(q);
  207. it = 3;
  208. it = 4;
  209. EXPECT_EQ(q, Container<int>({0, 1, 2, 3, 4}));
  210. }
  211. }
  212. /**
  213. * Basic tests for folly::hint_emplace_iterator.
  214. */
  215. TEST(EmplaceIterator, HintEmplacerTest) {
  216. {
  217. init_counters();
  218. std::map<int, Object> m;
  219. auto it = hint_emplacer(m, m.end());
  220. it = make_emplace_args(
  221. std::piecewise_construct,
  222. std::forward_as_tuple(0),
  223. std::forward_as_tuple(0));
  224. it = make_emplace_args(
  225. std::piecewise_construct,
  226. std::forward_as_tuple(1),
  227. std::forward_as_tuple(0, 0));
  228. it = make_emplace_args(
  229. std::piecewise_construct,
  230. std::forward_as_tuple(2),
  231. std::forward_as_tuple(Object{}));
  232. ASSERT_EQ(m.size(), 3);
  233. EXPECT_EQ(gDefaultCtrCnt, 1);
  234. EXPECT_EQ(gCopyCtrCnt, 0);
  235. EXPECT_EQ(gMoveCtrCnt, 1);
  236. EXPECT_EQ(gExplicitCtrCnt, 1);
  237. EXPECT_EQ(gMultiargCtrCnt, 1);
  238. EXPECT_EQ(gCopyOpCnt, 0);
  239. EXPECT_EQ(gMoveOpCnt, 0);
  240. EXPECT_EQ(gConvertOpCnt, 0);
  241. }
  242. {
  243. struct O {
  244. explicit O(int i_) : i(i_) {}
  245. bool operator<(const O& other) const {
  246. return i < other.i;
  247. }
  248. bool operator==(const O& other) const {
  249. return i == other.i;
  250. }
  251. int i;
  252. };
  253. std::vector<int> v1 = {0, 1, 2, 3, 4};
  254. std::vector<int> v2 = {0, 2, 4};
  255. std::set<O> diff;
  256. std::set_difference(
  257. v1.begin(),
  258. v1.end(),
  259. v2.begin(),
  260. v2.end(),
  261. hint_emplacer(diff, diff.end()));
  262. ASSERT_EQ(diff, std::set<O>({O(1), O(3)}));
  263. }
  264. }
  265. /**
  266. * Test std::copy() with explicit conversion. This would not compile with a
  267. * std::back_insert_iterator, because the constructor of Object that takes a
  268. * single int is explicit.
  269. */
  270. TEST(EmplaceIterator, Copy) {
  271. init_counters();
  272. Container<int> in({0, 1, 2});
  273. Container<Object> out;
  274. std::copy(in.begin(), in.end(), back_emplacer(out));
  275. EXPECT_EQ(3, out.size());
  276. EXPECT_EQ(gDefaultCtrCnt, 0);
  277. EXPECT_EQ(gCopyCtrCnt, 0);
  278. EXPECT_EQ(gMoveCtrCnt, 0);
  279. EXPECT_EQ(gExplicitCtrCnt, 3);
  280. EXPECT_EQ(gMultiargCtrCnt, 0);
  281. EXPECT_EQ(gCopyOpCnt, 0);
  282. EXPECT_EQ(gMoveOpCnt, 0);
  283. EXPECT_EQ(gConvertOpCnt, 0);
  284. }
  285. /**
  286. * Test std::transform() with multi-argument constructors. This would require
  287. * a temporary Object with std::back_insert_iterator.
  288. */
  289. TEST(EmplaceIterator, Transform) {
  290. init_counters();
  291. Container<int> in({0, 1, 2});
  292. Container<Object> out;
  293. std::transform(in.begin(), in.end(), back_emplacer(out), [](int i) {
  294. return make_emplace_args(i, i);
  295. });
  296. EXPECT_EQ(3, out.size());
  297. EXPECT_EQ(gDefaultCtrCnt, 0);
  298. EXPECT_EQ(gCopyCtrCnt, 0);
  299. EXPECT_EQ(gMoveCtrCnt, 0);
  300. EXPECT_EQ(gExplicitCtrCnt, 0);
  301. EXPECT_EQ(gMultiargCtrCnt, 3);
  302. EXPECT_EQ(gCopyOpCnt, 0);
  303. EXPECT_EQ(gMoveOpCnt, 0);
  304. EXPECT_EQ(gConvertOpCnt, 0);
  305. }
  306. /**
  307. * Test multi-argument store and forward.
  308. */
  309. TEST(EmplaceIterator, EmplaceArgs) {
  310. Object o1;
  311. const Object o2;
  312. Object& o3 = o1;
  313. const Object& o4 = o3;
  314. Object o5;
  315. {
  316. // Test copy construction.
  317. auto args = make_emplace_args(0, o1, o2, o3, o4, Object{}, std::cref(o2));
  318. init_counters();
  319. auto args2 = args;
  320. EXPECT_EQ(gDefaultCtrCnt, 0);
  321. EXPECT_EQ(gCopyCtrCnt, 5);
  322. EXPECT_EQ(gMoveCtrCnt, 0);
  323. EXPECT_EQ(gExplicitCtrCnt, 0);
  324. EXPECT_EQ(gMultiargCtrCnt, 0);
  325. EXPECT_EQ(gCopyOpCnt, 0);
  326. EXPECT_EQ(gMoveOpCnt, 0);
  327. EXPECT_EQ(gConvertOpCnt, 0);
  328. // Test copy assignment.
  329. init_counters();
  330. args = args2;
  331. EXPECT_EQ(gDefaultCtrCnt, 0);
  332. EXPECT_EQ(gCopyCtrCnt, 0);
  333. EXPECT_EQ(gMoveCtrCnt, 0);
  334. EXPECT_EQ(gExplicitCtrCnt, 0);
  335. EXPECT_EQ(gMultiargCtrCnt, 0);
  336. EXPECT_EQ(gCopyOpCnt, 5);
  337. EXPECT_EQ(gMoveOpCnt, 0);
  338. EXPECT_EQ(gConvertOpCnt, 0);
  339. }
  340. {
  341. // Test RVO.
  342. init_counters();
  343. auto args = make_emplace_args(
  344. 0, o1, o2, o3, o4, Object{}, std::cref(o2), rref(std::move(o5)));
  345. EXPECT_EQ(gDefaultCtrCnt, 1);
  346. EXPECT_EQ(gCopyCtrCnt, 4);
  347. EXPECT_EQ(gMoveCtrCnt, 1);
  348. EXPECT_EQ(gExplicitCtrCnt, 0);
  349. EXPECT_EQ(gMultiargCtrCnt, 0);
  350. EXPECT_EQ(gCopyOpCnt, 0);
  351. EXPECT_EQ(gMoveOpCnt, 0);
  352. EXPECT_EQ(gConvertOpCnt, 0);
  353. // Test move construction.
  354. init_counters();
  355. auto args2 = std::move(args);
  356. EXPECT_EQ(gDefaultCtrCnt, 0);
  357. EXPECT_EQ(gCopyCtrCnt, 0);
  358. EXPECT_EQ(gMoveCtrCnt, 5);
  359. EXPECT_EQ(gExplicitCtrCnt, 0);
  360. EXPECT_EQ(gMultiargCtrCnt, 0);
  361. EXPECT_EQ(gCopyOpCnt, 0);
  362. EXPECT_EQ(gMoveOpCnt, 0);
  363. EXPECT_EQ(gConvertOpCnt, 0);
  364. // Test move assignment.
  365. init_counters();
  366. args = std::move(args2);
  367. EXPECT_EQ(gDefaultCtrCnt, 0);
  368. EXPECT_EQ(gCopyCtrCnt, 0);
  369. EXPECT_EQ(gMoveCtrCnt, 0);
  370. EXPECT_EQ(gExplicitCtrCnt, 0);
  371. EXPECT_EQ(gMultiargCtrCnt, 0);
  372. EXPECT_EQ(gCopyOpCnt, 0);
  373. EXPECT_EQ(gMoveOpCnt, 5);
  374. EXPECT_EQ(gConvertOpCnt, 0);
  375. // Make sure arguments are stored correctly. lvalues by reference, rvalues
  376. // by (moved) copy. Rvalues cannot be stored by reference because they may
  377. // refer to an expired temporary by the time they are accessed.
  378. static_assert(
  379. std::is_same<
  380. int,
  381. std::tuple_element_t<0, decltype(args)::storage_type>>::value,
  382. "");
  383. static_assert(
  384. std::is_same<
  385. Object,
  386. std::tuple_element_t<1, decltype(args)::storage_type>>::value,
  387. "");
  388. static_assert(
  389. std::is_same<
  390. Object,
  391. std::tuple_element_t<2, decltype(args)::storage_type>>::value,
  392. "");
  393. static_assert(
  394. std::is_same<
  395. Object,
  396. std::tuple_element_t<3, decltype(args)::storage_type>>::value,
  397. "");
  398. static_assert(
  399. std::is_same<
  400. Object,
  401. std::tuple_element_t<4, decltype(args)::storage_type>>::value,
  402. "");
  403. static_assert(
  404. std::is_same<
  405. Object,
  406. std::tuple_element_t<5, decltype(args)::storage_type>>::value,
  407. "");
  408. static_assert(
  409. std::is_same<
  410. std::reference_wrapper<const Object>,
  411. std::tuple_element_t<6, decltype(args)::storage_type>>::value,
  412. "");
  413. static_assert(
  414. std::is_same<
  415. rvalue_reference_wrapper<Object>,
  416. std::tuple_element_t<7, decltype(args)::storage_type>>::value,
  417. "");
  418. // Check whether args.get() restores the original argument type for
  419. // rvalue references to emplace_args.
  420. static_assert(
  421. std::is_same<int&&, decltype(get_emplace_arg<0>(std::move(args)))>::
  422. value,
  423. "");
  424. static_assert(
  425. std::is_same<Object&, decltype(get_emplace_arg<1>(std::move(args)))>::
  426. value,
  427. "");
  428. static_assert(
  429. std::is_same<
  430. const Object&,
  431. decltype(get_emplace_arg<2>(std::move(args)))>::value,
  432. "");
  433. static_assert(
  434. std::is_same<Object&, decltype(get_emplace_arg<3>(std::move(args)))>::
  435. value,
  436. "");
  437. static_assert(
  438. std::is_same<
  439. const Object&,
  440. decltype(get_emplace_arg<4>(std::move(args)))>::value,
  441. "");
  442. static_assert(
  443. std::is_same<Object&&, decltype(get_emplace_arg<5>(std::move(args)))>::
  444. value,
  445. "");
  446. static_assert(
  447. std::is_same<
  448. const Object&,
  449. decltype(get_emplace_arg<6>(std::move(args)))>::value,
  450. "");
  451. static_assert(
  452. std::is_same<Object&&, decltype(get_emplace_arg<7>(std::move(args)))>::
  453. value,
  454. "");
  455. // lvalue references to emplace_args should behave mostly like std::tuples.
  456. // Note that get_emplace_arg<7>(args) does not compile, because
  457. // folly::rvalue_reference_wrappers can only be unwrapped through an rvalue
  458. // reference.
  459. static_assert(
  460. std::is_same<int&, decltype(get_emplace_arg<0>(args))>::value, "");
  461. static_assert(
  462. std::is_same<Object&, decltype(get_emplace_arg<1>(args))>::value, "");
  463. static_assert(
  464. std::is_same<Object&, decltype(get_emplace_arg<2>(args))>::value, "");
  465. static_assert(
  466. std::is_same<Object&, decltype(get_emplace_arg<3>(args))>::value, "");
  467. static_assert(
  468. std::is_same<Object&, decltype(get_emplace_arg<4>(args))>::value, "");
  469. static_assert(
  470. std::is_same<Object&, decltype(get_emplace_arg<5>(args))>::value, "");
  471. static_assert(
  472. std::is_same<const Object&, decltype(get_emplace_arg<6>(args))>::value,
  473. "");
  474. }
  475. }
  476. /**
  477. * Test implicit unpacking.
  478. */
  479. TEST(EmplaceIterator, ImplicitUnpack) {
  480. static std::size_t multiCtrCnt;
  481. static std::size_t pairCtrCnt;
  482. static std::size_t tupleCtrCnt;
  483. struct Object2 {
  484. Object2(int, int) {
  485. ++multiCtrCnt;
  486. }
  487. explicit Object2(const std::pair<int, int>&) {
  488. ++pairCtrCnt;
  489. }
  490. explicit Object2(const std::tuple<int, int>&) {
  491. ++tupleCtrCnt;
  492. }
  493. };
  494. auto test = [](auto&& it, bool expectUnpack) {
  495. multiCtrCnt = pairCtrCnt = tupleCtrCnt = 0;
  496. it = std::make_pair(0, 0);
  497. it = std::make_tuple(0, 0);
  498. if (expectUnpack) {
  499. EXPECT_EQ(multiCtrCnt, 2);
  500. EXPECT_EQ(pairCtrCnt, 0);
  501. EXPECT_EQ(tupleCtrCnt, 0);
  502. } else {
  503. EXPECT_EQ(multiCtrCnt, 0);
  504. EXPECT_EQ(pairCtrCnt, 1);
  505. EXPECT_EQ(tupleCtrCnt, 1);
  506. }
  507. };
  508. Container<Object2> q;
  509. test(emplacer(q, q.begin()), true);
  510. test(emplacer<false>(q, q.begin()), false);
  511. test(front_emplacer(q), true);
  512. test(front_emplacer<false>(q), false);
  513. test(back_emplacer(q), true);
  514. test(back_emplacer<false>(q), false);
  515. }