functools_ut.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. #include <library/cpp/iterator/functools.h>
  2. #include <library/cpp/testing/gtest/gtest.h>
  3. #include <util/generic/vector.h>
  4. #include <util/generic/xrange.h>
  5. #include <util/generic/adaptor.h>
  6. #include <set>
  7. // default-win-x86_64-release compiler can't decompose tuple to structure binding (02.03.2019)
  8. #ifndef _WINDOWS
  9. # define FOR_DISPATCH_2(i, j, r) \
  10. for (auto [i, j] : r)
  11. # define FOR_DISPATCH_3(i, j, k, r) \
  12. for (auto [i, j, k] : r)
  13. #else
  14. # define FOR_DISPATCH_2(i, j, r) \
  15. for (auto __t_##i##_##j : r) \
  16. if (auto& i = std::get<0>(__t_##i##_##j); true) \
  17. if (auto& j = std::get<1>(__t_##i##_##j); true)
  18. # define FOR_DISPATCH_3(i, j, k, r) \
  19. for (auto __t_##i##_##j##_##k : r) \
  20. if (auto& i = std::get<0>(__t_##i##_##j##_##k); true) \
  21. if (auto& j = std::get<1>(__t_##i##_##j##_##k); true) \
  22. if (auto& k = std::get<2>(__t_##i##_##j##_##k); true)
  23. #endif
  24. using namespace NFuncTools;
  25. template <typename TContainer>
  26. auto ToVector(TContainer&& container) {
  27. return std::vector{container.begin(), container.end()};
  28. }
  29. template <typename TContainerObjOrRef>
  30. void TestViewCompileability(TContainerObjOrRef&& container) {
  31. using TContainer = std::decay_t<TContainerObjOrRef>;
  32. using TIterator = typename TContainer::iterator;
  33. static_assert(std::is_same_v<decltype(container.begin()), TIterator>);
  34. // iterator_traits must work!
  35. using difference_type = typename std::iterator_traits<TIterator>::difference_type;
  36. using value_type = typename std::iterator_traits<TIterator>::value_type;
  37. using reference = typename std::iterator_traits<TIterator>::reference;
  38. using pointer = typename std::iterator_traits<TIterator>::pointer;
  39. {
  40. // operator assignment
  41. auto it = container.begin();
  42. it = container.end();
  43. it = std::move(container.begin());
  44. // operator copying
  45. auto it2 = it;
  46. Y_UNUSED(it2);
  47. auto it3 = std::move(it);
  48. Y_UNUSED(it3);
  49. Y_UNUSED(*it3);
  50. EXPECT_TRUE(it3 == it3);
  51. EXPECT_FALSE(it3 != it3);
  52. // const TIterator
  53. const auto it4 = it3;
  54. Y_UNUSED(*it4);
  55. EXPECT_TRUE(it4 == it4);
  56. EXPECT_FALSE(it4 != it4);
  57. EXPECT_TRUE(it3 == it4);
  58. EXPECT_TRUE(it4 == it3);
  59. EXPECT_FALSE(it3 != it4);
  60. EXPECT_FALSE(it4 != it3);
  61. }
  62. auto it = container.begin();
  63. // sanity check for types
  64. using TConstReference = const std::remove_reference_t<reference>&;
  65. TConstReference ref = *it;
  66. Y_UNUSED(ref);
  67. (void) static_cast<value_type>(*it);
  68. (void) static_cast<difference_type>(1);
  69. if constexpr (std::is_reference_v<decltype(*it)>) {
  70. pointer ptr = &*it;
  71. Y_UNUSED(ptr);
  72. }
  73. // std compatibility
  74. ToVector(container);
  75. // const iterators
  76. [](const auto& cont) {
  77. auto constBeginIterator = cont.begin();
  78. auto constEndIterator = cont.end();
  79. static_assert(std::is_same_v<decltype(constBeginIterator), typename TContainer::const_iterator>);
  80. Y_UNUSED(constBeginIterator);
  81. Y_UNUSED(constEndIterator);
  82. }(container);
  83. }
  84. struct TTestSentinel {};
  85. struct TTestIterator {
  86. int operator*() const {
  87. return X;
  88. }
  89. void operator++() {
  90. ++X;
  91. }
  92. bool operator!=(const TTestSentinel&) const {
  93. return X < 3;
  94. }
  95. int X;
  96. };
  97. // container with minimal interface
  98. auto MakeMinimalisticContainer() {
  99. return MakeIteratorRange(TTestIterator{}, TTestSentinel{});
  100. }
  101. TEST(FuncTools, CompileRange) {
  102. TestViewCompileability(Range(19));
  103. TestViewCompileability(Range(10, 19));
  104. TestViewCompileability(Range(10, 19, 2));
  105. }
  106. TEST(FuncTools, Enumerate) {
  107. TVector<size_t> a = {1, 2, 4};
  108. TVector<size_t> b;
  109. TVector<size_t> c = {1};
  110. for (auto& v : {a, b, c}) {
  111. size_t j = 0;
  112. FOR_DISPATCH_2(i, x, Enumerate(v)) {
  113. EXPECT_EQ(v[i], x);
  114. EXPECT_EQ(i, j++);
  115. EXPECT_LT(i, v.size());
  116. }
  117. EXPECT_EQ(j, v.size());
  118. }
  119. // Test correctness of iterator traits.
  120. auto enumerated = Enumerate(a);
  121. static_assert(std::ranges::input_range<decltype(enumerated)>);
  122. static_assert(
  123. std::is_same_v<decltype(enumerated.begin())::pointer,
  124. std::iterator_traits<decltype(enumerated.begin())>::pointer>);
  125. // Post-increment test.
  126. auto it = enumerated.begin();
  127. EXPECT_EQ(*(it++), (std::tuple{0, 1}));
  128. EXPECT_EQ(*it, (std::tuple{1, 2}));
  129. TVector<size_t> d = {0, 0, 0};
  130. FOR_DISPATCH_2(i, x, Enumerate(d)) {
  131. x = i;
  132. }
  133. EXPECT_THAT(
  134. d,
  135. testing::ElementsAre(0u, 1u, 2u)
  136. );
  137. }
  138. TEST(FuncTools, EnumerateTemporary) {
  139. TVector<size_t> a = {1, 2, 4};
  140. TVector<size_t> b;
  141. TVector<size_t> c = {1};
  142. for (auto& v : {a, b, c}) {
  143. size_t j = 0;
  144. FOR_DISPATCH_2(i, x, Enumerate(TVector(v))) {
  145. EXPECT_EQ(v[i], x);
  146. EXPECT_EQ(i, j++);
  147. EXPECT_LT(i, v.size());
  148. }
  149. EXPECT_EQ(j, v.size());
  150. }
  151. FOR_DISPATCH_2(i, x, Enumerate(TVector<size_t>{1, 2, 3})) {
  152. EXPECT_EQ(i + 1, x);
  153. }
  154. }
  155. TEST(FuncTools, CompileEnumerate) {
  156. auto container = std::vector{1, 2, 3};
  157. TestViewCompileability(Enumerate(container));
  158. const auto constContainer = std::vector{1, 2, 3};
  159. TestViewCompileability(Enumerate(constContainer));
  160. const int arrayContainer[] = {1, 2, 3};
  161. TestViewCompileability(Enumerate(arrayContainer));
  162. std::vector<std::pair<int, int>> res;
  163. FOR_DISPATCH_2(i, x, Enumerate(MakeMinimalisticContainer())) {
  164. res.push_back({i, x});
  165. }
  166. EXPECT_EQ(res, (std::vector<std::pair<int, int>>{
  167. {0, 0}, {1, 1}, {2, 2},
  168. }));
  169. }
  170. TEST(FuncTools, Zip) {
  171. TVector<std::pair<TVector<size_t>, TVector<size_t>>> ts = {
  172. {{1, 2, 3}, {4, 5, 6}},
  173. {{1, 2, 3}, {4, 5, 6, 7}},
  174. {{1, 2, 3, 4}, {4, 5, 6}},
  175. {{1, 2, 3, 4}, {}},
  176. };
  177. FOR_DISPATCH_2(a, b, ts) {
  178. size_t k = 0;
  179. FOR_DISPATCH_2(i, j, Zip(a, b)) {
  180. EXPECT_EQ(++k, i);
  181. EXPECT_EQ(i + 3, j);
  182. }
  183. EXPECT_EQ(k, Min(a.size(), b.size()));
  184. }
  185. }
  186. TEST(FuncTools, ZipReference) {
  187. TVector a = {0, 1, 2};
  188. TVector b = {2, 1, 0, -1};
  189. FOR_DISPATCH_2(ai, bi, Zip(a, b)) {
  190. ai = bi;
  191. }
  192. EXPECT_THAT(
  193. a,
  194. testing::ElementsAre(2u, 1u, 0u)
  195. );
  196. }
  197. TEST(FuncTools, Zip3) {
  198. TVector<std::tuple<TVector<i32>, TVector<i32>, TVector<i32>>> ts = {
  199. {{1, 2, 3}, {4, 5, 6}, {11, 3}},
  200. {{1, 2, 3}, {4, 5, 6, 7}, {9, 0}},
  201. {{1, 2, 3, 4}, {9}, {4, 5, 6}},
  202. {{1, 2, 3, 4}, {1}, {}},
  203. {{}, {1}, {1, 2, 3, 4}},
  204. };
  205. FOR_DISPATCH_3(a, b, c, ts) {
  206. TVector<std::tuple<i32, i32, i32>> e;
  207. for (size_t j = 0; j < a.size() && j < b.size() && j < c.size(); ++j) {
  208. e.push_back({a[j], b[j], c[j]});
  209. }
  210. TVector<std::tuple<i32, i32, i32>> f;
  211. FOR_DISPATCH_3(ai, bi, ci, Zip(a, b, c)) {
  212. f.push_back({ai, bi, ci});
  213. }
  214. EXPECT_EQ(e, f);
  215. }
  216. }
  217. TEST(FuncTools, CompileZip) {
  218. auto container = std::vector{1, 2, 3};
  219. TestViewCompileability(Zip(container));
  220. TestViewCompileability(Zip(container, container, container));
  221. const auto constContainer = std::vector{1, 2, 3};
  222. TestViewCompileability(Zip(constContainer, constContainer));
  223. const int arrayContainer[] = {1, 2, 3};
  224. TestViewCompileability(Zip(arrayContainer, arrayContainer));
  225. std::vector<std::pair<int, int>> res;
  226. FOR_DISPATCH_2(a, b, Zip(MakeMinimalisticContainer(), container)) {
  227. res.push_back({a, b});
  228. }
  229. EXPECT_EQ(res, (std::vector<std::pair<int, int>>{
  230. {0, 1}, {1, 2}, {2, 3},
  231. }));
  232. }
  233. TEST(FuncTools, Filter) {
  234. TVector<TVector<i32>> ts = {
  235. {},
  236. {1},
  237. {2},
  238. {1, 2},
  239. {2, 1},
  240. {1, 2, 3, 4, 5, 6, 7},
  241. };
  242. auto pred = [](i32 x) -> bool { return x & 1; };
  243. for (auto& a : ts) {
  244. TVector<i32> b;
  245. for (i32 x : a) {
  246. if (pred(x)) {
  247. b.push_back(x);
  248. }
  249. }
  250. TVector<i32> c;
  251. for (i32 x : Filter(pred, a)) {
  252. c.push_back(x);
  253. }
  254. EXPECT_EQ(b, c);
  255. }
  256. }
  257. TEST(FuncTools, CompileFilter) {
  258. auto container = std::vector{1, 2, 3};
  259. auto isOdd = [](int x) { return bool(x & 1); };
  260. TestViewCompileability(Filter(isOdd, container));
  261. const int arrayContainer[] = {1, 2, 3};
  262. TestViewCompileability(Filter(isOdd, arrayContainer));
  263. }
  264. TEST(FuncTools, Map) {
  265. TVector<TVector<i32>> ts = {
  266. {},
  267. {1},
  268. {1, 2},
  269. {1, 2, 3, 4, 5, 6, 7},
  270. };
  271. auto f = [](i32 x) { return x * x; };
  272. for (auto& a : ts) {
  273. TVector<i32> b;
  274. for (i32 x : a) {
  275. b.push_back(f(x));
  276. }
  277. TVector<i32> c;
  278. for (i32 x : Map(f, a)) {
  279. c.push_back(x);
  280. }
  281. EXPECT_EQ(b, c);
  282. }
  283. TVector floats = {1.4, 4.1, 13.9};
  284. TVector ints = {1, 4, 13};
  285. TVector<float> roundedFloats = {1, 4, 13};
  286. TVector<int> res;
  287. TVector<float> resFloat;
  288. for (auto i : Map<int>(floats)) {
  289. res.push_back(i);
  290. }
  291. for (auto i : Map<float>(Map<int>(floats))) {
  292. resFloat.push_back(i);
  293. }
  294. EXPECT_EQ(ints, res);
  295. EXPECT_EQ(roundedFloats, resFloat);
  296. }
  297. TEST(FuncTools, CompileMap) {
  298. auto container = std::vector{1, 2, 3};
  299. auto sqr = [](int x) { return x * x; };
  300. TestViewCompileability(Map(sqr, container));
  301. const int arrayContainer[] = {1, 2, 3};
  302. TestViewCompileability(Map(sqr, arrayContainer));
  303. }
  304. TEST(FuncTools, MapRandomAccess) {
  305. auto sqr = [](int x) { return x * x; };
  306. {
  307. auto container = std::vector{1, 2, 3};
  308. auto mapped = Map(sqr, container);
  309. static_assert(
  310. std::is_same_v<decltype(mapped)::iterator::iterator_category, std::random_access_iterator_tag>
  311. );
  312. }
  313. {
  314. auto container = std::set<int>{1, 2, 3};
  315. auto mapped = Map(sqr, container);
  316. static_assert(
  317. std::is_same_v<decltype(mapped)::iterator::iterator_category, std::input_iterator_tag>
  318. );
  319. }
  320. }
  321. TEST(FuncTools, CartesianProduct) {
  322. TVector<std::pair<TVector<i32>, TVector<i32>>> ts = {
  323. {{1, 2, 3}, {4, 5, 6}},
  324. {{1, 2, 3}, {4, 5, 6, 7}},
  325. {{1, 2, 3, 4}, {4, 5, 6}},
  326. {{1, 2, 3, 4}, {}},
  327. {{}, {1, 2, 3, 4}},
  328. };
  329. for (auto [a, b] : ts) {
  330. TVector<std::pair<i32, i32>> c;
  331. for (auto ai : a) {
  332. for (auto bi : b) {
  333. c.push_back({ai, bi});
  334. }
  335. }
  336. TVector<std::pair<i32, i32>> d;
  337. FOR_DISPATCH_2(ai, bi, CartesianProduct(a, b)) {
  338. d.push_back({ai, bi});
  339. }
  340. EXPECT_EQ(c, d);
  341. }
  342. {
  343. TVector<TVector<int>> g = {{}, {}};
  344. TVector h = {10, 11, 12};
  345. FOR_DISPATCH_2(gi, i, CartesianProduct(g, h)) {
  346. gi.push_back(i);
  347. }
  348. EXPECT_EQ(g[0], h);
  349. EXPECT_EQ(g[1], h);
  350. }
  351. }
  352. TEST(FuncTools, CartesianProduct3) {
  353. TVector<std::tuple<TVector<i32>, TVector<i32>, TVector<i32>>> ts = {
  354. {{1, 2, 3}, {4, 5, 6}, {11, 3}},
  355. {{1, 2, 3}, {4, 5, 6, 7}, {9}},
  356. {{1, 2, 3, 4}, {9}, {4, 5, 6}},
  357. {{1, 2, 3, 4}, {1}, {}},
  358. {{}, {1}, {1, 2, 3, 4}},
  359. };
  360. FOR_DISPATCH_3(a, b, c, ts) {
  361. TVector<std::tuple<i32, i32, i32>> e;
  362. for (auto ai : a) {
  363. for (auto bi : b) {
  364. for (auto ci : c) {
  365. e.push_back({ai, bi, ci});
  366. }
  367. }
  368. }
  369. TVector<std::tuple<i32, i32, i32>> f;
  370. FOR_DISPATCH_3(ai, bi, ci, CartesianProduct(a, b, c)) {
  371. f.push_back({ai, bi, ci});
  372. }
  373. EXPECT_EQ(e, f);
  374. }
  375. }
  376. TEST(FuncTools, CompileCartesianProduct) {
  377. auto container = std::vector{1, 2, 3};
  378. TestViewCompileability(CartesianProduct(container, container));
  379. const auto constContainer = std::vector{1, 2, 3};
  380. TestViewCompileability(CartesianProduct(constContainer, constContainer));
  381. const int arrayContainer[] = {1, 2, 3};
  382. TestViewCompileability(CartesianProduct(arrayContainer, arrayContainer));
  383. std::vector<std::pair<int, int>> res;
  384. FOR_DISPATCH_2(a, b, CartesianProduct(MakeMinimalisticContainer(), MakeMinimalisticContainer())) {
  385. res.push_back({a, b});
  386. }
  387. EXPECT_EQ(res, (std::vector<std::pair<int, int>>{
  388. {0, 0}, {0, 1}, {0, 2},
  389. {1, 0}, {1, 1}, {1, 2},
  390. {2, 0}, {2, 1}, {2, 2},
  391. }));
  392. }
  393. TEST(FuncTools, Concatenate2) {
  394. TVector<std::pair<TVector<i32>, TVector<i32>>> ts = {
  395. {{1, 2, 3}, {4, 5, 6}},
  396. {{1, 2, 3}, {4, 5, 6, 7}},
  397. {{1, 2, 3, 4}, {4, 5, 6}},
  398. {{1, 2, 3, 4}, {}},
  399. {{}, {1, 2, 3, 4}},
  400. };
  401. for (auto [a, b] : ts) {
  402. TVector<i32> c;
  403. for (auto ai : a) {
  404. c.push_back(ai);
  405. }
  406. for (auto bi : b) {
  407. c.push_back(bi);
  408. }
  409. TVector<i32> d;
  410. for (auto x : Concatenate(a, b)) {
  411. d.push_back(x);
  412. }
  413. EXPECT_EQ(c, d);
  414. }
  415. {
  416. TVector<i32> a = {1, 2, 3, 4};
  417. TVector<i32> c;
  418. for (auto x : Concatenate(a, TVector<i32>{5, 6})) {
  419. c.push_back(x);
  420. }
  421. EXPECT_EQ(c, (TVector<i32>{1, 2, 3, 4, 5, 6}));
  422. }
  423. }
  424. TEST(FuncTools, CompileConcatenate) {
  425. auto container = std::vector{1, 2, 3};
  426. TestViewCompileability(Concatenate(container, container));
  427. const auto constContainer = std::vector{1, 2, 3};
  428. TestViewCompileability(Concatenate(constContainer, constContainer));
  429. const int arrayContainer[] = {1, 2, 3};
  430. TestViewCompileability(Concatenate(arrayContainer, arrayContainer));
  431. std::vector<int> res;
  432. for (auto a : Concatenate(MakeMinimalisticContainer(), MakeMinimalisticContainer())) {
  433. res.push_back(a);
  434. }
  435. EXPECT_EQ(res, (std::vector{0, 1, 2, 0, 1, 2}));
  436. }
  437. TEST(FuncTools, Combo) {
  438. FOR_DISPATCH_2(i, j, Enumerate(xrange(10u))) {
  439. EXPECT_EQ(i, j);
  440. }
  441. FOR_DISPATCH_2(i, jk, Enumerate(Enumerate(xrange(10u)))) {
  442. EXPECT_EQ(i, std::get<0>(jk));
  443. EXPECT_EQ(std::get<0>(jk), std::get<1>(jk));
  444. }
  445. TVector<size_t> a = {0, 1, 2};
  446. FOR_DISPATCH_2(i, j, Enumerate(Reversed(a))) {
  447. EXPECT_EQ(i, 2 - j);
  448. }
  449. FOR_DISPATCH_2(i, j, Enumerate(Map<float>(a))) {
  450. EXPECT_EQ(i, (size_t)j);
  451. }
  452. FOR_DISPATCH_2(i, j, Zip(a, Map<float>(a))) {
  453. EXPECT_EQ(i, (size_t)j);
  454. }
  455. auto mapper = [](auto&& x) {
  456. return std::get<0>(x) + std::get<1>(x);
  457. };
  458. FOR_DISPATCH_2(i, j, Zip(a, Map(mapper, Zip(a, a)))) {
  459. EXPECT_EQ(j, 2 * i);
  460. }
  461. }
  462. TEST(FuncTools, CopyIterator) {
  463. TVector a = {1, 2, 3, 4};
  464. TVector b = {4, 5, 6, 7};
  465. // calls f on 2nd, 3d and 4th positions (numeration from 1st)
  466. auto testIterator = [](auto it, auto f) {
  467. ++it;
  468. auto it2 = it;
  469. ++it2;
  470. ++it2;
  471. auto it3 = it;
  472. ++it3;
  473. f(*it, *it3, *it2);
  474. };
  475. {
  476. auto iterable = Enumerate(a);
  477. testIterator(std::begin(iterable),
  478. [](auto p2, auto p3, auto p4) {
  479. EXPECT_EQ(std::get<0>(p2), 1u);
  480. EXPECT_EQ(std::get<1>(p2), 2);
  481. EXPECT_EQ(std::get<0>(p3), 2u);
  482. EXPECT_EQ(std::get<1>(p3), 3);
  483. EXPECT_EQ(std::get<0>(p4), 3u);
  484. EXPECT_EQ(std::get<1>(p4), 4);
  485. });
  486. }
  487. {
  488. auto iterable = Map([](i32 x) { return x*x; }, a);
  489. testIterator(std::begin(iterable),
  490. [](auto p2, auto p3, auto p4) {
  491. EXPECT_EQ(p2, 4);
  492. EXPECT_EQ(p3, 9);
  493. EXPECT_EQ(p4, 16);
  494. });
  495. }
  496. {
  497. auto iterable = Zip(a, b);
  498. testIterator(std::begin(iterable),
  499. [](auto p2, auto p3, auto p4) {
  500. EXPECT_EQ(std::get<0>(p2), 2);
  501. EXPECT_EQ(std::get<1>(p2), 5);
  502. EXPECT_EQ(std::get<0>(p3), 3);
  503. EXPECT_EQ(std::get<1>(p3), 6);
  504. EXPECT_EQ(std::get<0>(p4), 4);
  505. EXPECT_EQ(std::get<1>(p4), 7);
  506. });
  507. }
  508. {
  509. auto c = {1, 2, 3, 4, 5, 6, 7, 8};
  510. auto iterable = Filter([](i32 x) { return !(x & 1); }, c);
  511. testIterator(std::begin(iterable),
  512. [](auto p2, auto p3, auto p4) {
  513. EXPECT_EQ(p2, 4);
  514. EXPECT_EQ(p3, 6);
  515. EXPECT_EQ(p4, 8);
  516. });
  517. }
  518. {
  519. auto iterable = CartesianProduct(TVector{0, 1}, TVector{2, 3});
  520. // (0, 2), (0, 3), (1, 2), (1, 3)
  521. testIterator(std::begin(iterable),
  522. [](auto p2, auto p3, auto p4) {
  523. EXPECT_EQ(std::get<0>(p2), 0);
  524. EXPECT_EQ(std::get<1>(p2), 3);
  525. EXPECT_EQ(std::get<0>(p3), 1);
  526. EXPECT_EQ(std::get<1>(p3), 2);
  527. EXPECT_EQ(std::get<0>(p4), 1);
  528. EXPECT_EQ(std::get<1>(p4), 3);
  529. });
  530. }
  531. }