transform.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // Range v3 library
  2. //
  3. // Copyright Eric Niebler 2014-present
  4. //
  5. // Use, modification and distribution is subject to the
  6. // Boost Software License, Version 1.0. (See accompanying
  7. // file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. // Project home: https://github.com/ericniebler/range-v3
  11. #include <string>
  12. #include <vector>
  13. #include <iterator>
  14. #include <functional>
  15. #include <range/v3/core.hpp>
  16. #include <range/v3/algorithm/move.hpp>
  17. #include <range/v3/functional/overload.hpp>
  18. #include <range/v3/iterator/insert_iterators.hpp>
  19. #include <range/v3/utility/copy.hpp>
  20. #include <range/v3/view/transform.hpp>
  21. #include <range/v3/view/counted.hpp>
  22. #include <range/v3/view/reverse.hpp>
  23. #include <range/v3/view/span.hpp>
  24. #include <range/v3/view/zip.hpp>
  25. #include "../simple_test.hpp"
  26. #include "../test_utils.hpp"
  27. struct is_odd
  28. {
  29. bool operator()(int i) const
  30. {
  31. return (i % 2) == 1;
  32. }
  33. };
  34. // https://github.com/ericniebler/range-v3/issues/996
  35. void bug_996()
  36. {
  37. std::vector<int> buff(12, -1);
  38. ::ranges::span<int> sp(buff.data(), 12);
  39. auto x = ::ranges::views::transform(sp, [](int a) { return a > 3 ? a : 42; });
  40. auto y = ::ranges::views::transform(x, sp, [](int a, int b) { return a + b; });
  41. auto rng = ::ranges::views::transform(y, [](int a) { return a + 1; });
  42. (void)rng;
  43. }
  44. int main()
  45. {
  46. using namespace ranges;
  47. int rgi[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  48. std::pair<int, int> rgp[] = {{1,1}, {2,2}, {3,3}, {4,4}, {5,5}, {6,6}, {7,7}, {8,8}, {9,9}, {10,10}};
  49. {
  50. auto rng = rgi | views::transform(is_odd());
  51. has_type<int &>(*begin(rgi));
  52. has_type<bool>(*begin(rng));
  53. CPP_assert(view_<decltype(rng)>);
  54. CPP_assert(sized_range<decltype(rng)>);
  55. CPP_assert(random_access_range<decltype(rng)>);
  56. ::check_equal(rng, {true, false, true, false, true, false, true, false, true, false});
  57. }
  58. {
  59. auto rng2 = rgp | views::transform(&std::pair<int,int>::first);
  60. has_type<int &>(*begin(rng2));
  61. CPP_assert(same_as<range_value_t<decltype(rng2)>, int>);
  62. CPP_assert(same_as<decltype(iter_move(begin(rng2))), int &&>);
  63. CPP_assert(view_<decltype(rng2)>);
  64. CPP_assert(common_range<decltype(rng2)>);
  65. CPP_assert(sized_range<decltype(rng2)>);
  66. CPP_assert(random_access_range<decltype(rng2)>);
  67. ::check_equal(rng2, {1,2,3,4,5,6,7,8,9,10});
  68. ::check_equal(rng2 | views::reverse, {10,9,8,7,6,5,4,3,2,1});
  69. CHECK(&*begin(rng2) == &rgp[0].first);
  70. CHECK(rng2.size() == 10u);
  71. }
  72. {
  73. auto rng3 = views::counted(rgp, 10) | views::transform(&std::pair<int,int>::first);
  74. has_type<int &>(*begin(rng3));
  75. CPP_assert(view_<decltype(rng3)>);
  76. CPP_assert(common_range<decltype(rng3)>);
  77. CPP_assert(sized_range<decltype(rng3)>);
  78. CPP_assert(random_access_range<decltype(rng3)>);
  79. ::check_equal(rng3, {1,2,3,4,5,6,7,8,9,10});
  80. CHECK(&*begin(rng3) == &rgp[0].first);
  81. CHECK(rng3.size() == 10u);
  82. }
  83. {
  84. auto rng4 = views::counted(ForwardIterator<std::pair<int, int>*>{rgp}, 10)
  85. | views::transform(&std::pair<int,int>::first);
  86. has_type<int &>(*begin(rng4));
  87. CPP_assert(view_<decltype(rng4)>);
  88. CPP_assert(!common_range<decltype(rng4)>);
  89. CPP_assert(sized_range<decltype(rng4)>);
  90. CPP_assert(forward_range<decltype(rng4)>);
  91. CPP_assert(!bidirectional_range<decltype(rng4)>);
  92. ::check_equal(rng4, {1,2,3,4,5,6,7,8,9,10});
  93. CHECK(&*begin(rng4) == &rgp[0].first);
  94. CHECK(rng4.size() == 10u);
  95. counted_iterator<ForwardIterator<std::pair<int, int>*>> i = begin(rng4).base();
  96. (void)i;
  97. }
  98. // Test transform with a mutable lambda
  99. {
  100. int cnt = 100;
  101. auto mutable_rng = views::transform(rgi, [cnt](int) mutable { return cnt++;});
  102. ::check_equal(mutable_rng, {100,101,102,103,104,105,106,107,108,109});
  103. CHECK(cnt == 100);
  104. CPP_assert(view_<decltype(mutable_rng)>);
  105. CPP_assert(!view_<decltype(mutable_rng) const>);
  106. }
  107. // Test iter_transform by transforming a zip view to select one element.
  108. {
  109. auto v0 = to<std::vector<MoveOnlyString>>({"a","b","c"});
  110. auto v1 = to<std::vector<MoveOnlyString>>({"x","y","z"});
  111. auto rng1 = views::zip(v0, v1);
  112. CPP_assert(random_access_range<decltype(rng1)>);
  113. std::vector<MoveOnlyString> res;
  114. using R1 = decltype(rng1);
  115. using I1 = iterator_t<R1>;
  116. // Needlessly verbose -- a simple transform would do the same, but this
  117. // is an interesting test.
  118. auto proj = overload(
  119. [](I1 i1) -> MoveOnlyString& {return (*i1).first;},
  120. [](copy_tag, I1) -> MoveOnlyString {return {};},
  121. [](move_tag, I1 i1) -> MoveOnlyString&& {return std::move((*i1).first);}
  122. );
  123. auto rng2 = rng1 | views::iter_transform(proj);
  124. move(rng2, ranges::back_inserter(res));
  125. ::check_equal(res, {"a","b","c"});
  126. ::check_equal(v0, {"","",""});
  127. ::check_equal(v1, {"x","y","z"});
  128. using R2 = decltype(rng2);
  129. CPP_assert(same_as<range_value_t<R2>, MoveOnlyString>);
  130. CPP_assert(same_as<range_reference_t<R2>, MoveOnlyString &>);
  131. CPP_assert(same_as<range_rvalue_reference_t<R2>, MoveOnlyString &&>);
  132. }
  133. // two range transform
  134. {
  135. auto v0 = to<std::vector<std::string>>({"a","b","c"});
  136. auto v1 = to<std::vector<std::string>>({"x","y","z"});
  137. auto rng = views::transform(v0, v1, [](std::string& s0, std::string& s1){return std::tie(s0, s1);});
  138. using R = decltype(rng);
  139. CPP_assert(same_as<range_value_t<R>, std::tuple<std::string&, std::string&>>);
  140. CPP_assert(same_as<range_reference_t<R>, std::tuple<std::string&, std::string&>>);
  141. CPP_assert(same_as<range_rvalue_reference_t<R>, std::tuple<std::string&, std::string&>>);
  142. using T = std::tuple<std::string, std::string>;
  143. ::check_equal(rng, {T{"a","x"}, T{"b","y"}, T{"c","z"}});
  144. }
  145. // two range indirect transform
  146. {
  147. auto v0 = to<std::vector<std::string>>({"a","b","c"});
  148. auto v1 = to<std::vector<std::string>>({"x","y","z"});
  149. using I = std::vector<std::string>::iterator;
  150. auto fun = overload(
  151. [](I i, I j) { return std::tie(*i, *j); },
  152. [](copy_tag, I, I) { return std::tuple<std::string, std::string>{}; },
  153. [](move_tag, I i, I j) { return common_tuple<std::string&&, std::string&&>{
  154. std::move(*i), std::move(*j)}; } );
  155. auto rng = views::iter_transform(v0, v1, fun);
  156. using R = decltype(rng);
  157. CPP_assert(same_as<range_value_t<R>, std::tuple<std::string, std::string>>);
  158. CPP_assert(same_as<range_reference_t<R>, std::tuple<std::string&, std::string&>>);
  159. CPP_assert(same_as<range_rvalue_reference_t<R>, common_tuple<std::string&&, std::string&&>>);
  160. using T = std::tuple<std::string, std::string>;
  161. ::check_equal(rng, {T{"a","x"}, T{"b","y"}, T{"c","z"}});
  162. }
  163. {
  164. auto rng = debug_input_view<int const>{rgi} | views::transform(is_odd{});
  165. ::check_equal(rng, {true, false, true, false, true, false, true, false, true, false});
  166. }
  167. {
  168. auto v0 = to<std::vector<std::string>>({"a","b","c"});
  169. auto v1 = to<std::vector<std::string>>({"x","y","z"});
  170. auto r0 = debug_input_view<std::string>{v0.data(), distance(v0)};
  171. auto r1 = debug_input_view<std::string>{v1.data(), distance(v1)};
  172. auto rng = views::transform(std::move(r0), std::move(r1),
  173. [](std::string &s0, std::string &s1){ return std::tie(s0, s1); });
  174. using R = decltype(rng);
  175. CPP_assert(same_as<range_value_t<R>, std::tuple<std::string &, std::string &>>);
  176. CPP_assert(same_as<range_reference_t<R>, std::tuple<std::string &, std::string &>>);
  177. CPP_assert(same_as<range_rvalue_reference_t<R>, std::tuple<std::string &, std::string &>>);
  178. using T = std::tuple<std::string, std::string>;
  179. ::check_equal(rng, {T{"a","x"}, T{"b","y"}, T{"c","z"}});
  180. }
  181. {
  182. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  183. #if defined(__clang__) && __clang_major__ < 6
  184. // Workaround https://bugs.llvm.org/show_bug.cgi?id=33314
  185. RANGES_DIAGNOSTIC_PUSH
  186. RANGES_DIAGNOSTIC_IGNORE_UNDEFINED_FUNC_TEMPLATE
  187. #endif
  188. std::vector<int> vi = {1, 2, 3};
  189. ranges::transform_view times_ten{vi, [](int i) { return i * 10; }};
  190. ::check_equal(times_ten, {10, 20, 30});
  191. #if defined(__clang__) && __clang_major__ < 6
  192. RANGES_DIAGNOSTIC_POP
  193. #endif // clang bug workaround
  194. #endif // use deduction guides
  195. }
  196. return test_result();
  197. }