stl-compat.cc 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // -*- mode: c++; coding: utf-8 -*-
  2. // ra-ra/test - Using STL algos & types together with ra::.
  3. // (c) Daniel Llorens - 2014
  4. // This library is free software; you can redistribute it and/or modify it under
  5. // the terms of the GNU Lesser General Public License as published by the Free
  6. // Software Foundation; either version 3 of the License, or (at your option) any
  7. // later version.
  8. #include <ranges>
  9. #include <iostream>
  10. #include <iterator>
  11. #include <span>
  12. #include <version>
  13. #include "ra/test.hh"
  14. using std::cout, std::endl, std::flush, ra::TestRecorder;
  15. int main()
  16. {
  17. TestRecorder tr;
  18. tr.section("random access iterators");
  19. {
  20. // TODO rank-0 begin()/end() in ra::Small
  21. // TODO others?
  22. }
  23. tr.section("copyable iterators, but not random access");
  24. {
  25. {
  26. ra::Big<int, 1> a = { 1, 2, 3 };
  27. ra::Big<int, 1> b = { 0, 0, 0 };
  28. std::transform(a.begin(), a.end(), b.begin(), [](int a) { return -a; });
  29. tr.test_eq(a, -b);
  30. }
  31. {
  32. ra::Big<int, 2> a({2, 3}, ra::_0 - 2*ra::_1);
  33. ra::Big<int, 2> b({2, 3}, 99);
  34. std::transform(a.begin(), a.end(), b.begin(), [](int a) { return -a; });
  35. tr.test_eq(a, -b);
  36. }
  37. {
  38. ra::Small<int, 2, 3> a(ra::_0 - 2*ra::_1);
  39. ra::Small<int, 2, 3> b(99);
  40. std::transform(a.begin(), a.end(), b.begin(), [](int a) { return -a; });
  41. tr.test_eq(a, -b);
  42. }
  43. }
  44. tr.section("raw pointers");
  45. {
  46. ra::Big<int, 1> a = {1, 2, 3};
  47. int b[] = { +1, -1, +1 };
  48. tr.test_eq(ra::Small<int, 3> {2, 1, 4}, a + ra::ptr(b));
  49. ra::ptr(b) = ra::Small<int, 3> {7, 4, 5};
  50. tr.test_eq(ra::Small<int, 3> {7, 4, 5}, ra::ptr(b));
  51. int cp[3] = {1, 2, 3};
  52. // ra::Big<int, 1> c({3}, &cp[0]); // forbidden, confusing for higher rank c (pointer matches as rank 1).
  53. ra::Big<int, 1> c({3}, ra::ptr(cp));
  54. tr.test_eq(ra::Small<int, 3> {1, 2, 3}, c);
  55. ra::Big<int, 1> d(3, ra::ptr(cp)); // alt shape
  56. tr.test_eq(ra::Small<int, 3> {1, 2, 3}, d);
  57. }
  58. tr.section("raw pointers");
  59. {
  60. ra::Big<int, 1> a = {1, 2, 3};
  61. ra::ptr(a.data()) = map([](auto const & a) { return -a; }, ra::iota(3, 1, 9));
  62. tr.test_eq(ra::start({-1, -10, -19}), a);
  63. }
  64. tr.section("ptr with other iterators");
  65. {
  66. std::vector a = {1, 2, 3};
  67. ra::Small<int, 3> b = ra::ptr(a.begin());
  68. tr.test_eq(ra::Small<int, 3> {1, 2, 3}, b);
  69. }
  70. tr.section("ptr with step");
  71. {
  72. std::vector a = {1, 2, 3, 4, 5, 6};
  73. tr.test_eq(std::vector {1, 3, 5}, ra::ptr(a.begin(), 3, 2));
  74. tr.test_eq(5, ra::ptr(a.begin(), 3, 2).at(std::array { 2 }));
  75. }
  76. tr.section("ptr with step");
  77. {
  78. char const * s = "hello";
  79. auto p = ra::ptr(s, std::integral_constant<int, 2> {});
  80. static_assert(2==ra::size(p)); // ok
  81. tr.test_eq(ra::start({'h', 'e'}), p);
  82. }
  83. tr.section("check that begin() and end() match for empty views");
  84. {
  85. ra::Big<int, 3> aa({0, 2, 3}, 0.);
  86. auto a = aa(ra::all, 1);
  87. tr.test(aa.empty());
  88. tr.test(a.begin()==a.end());
  89. }
  90. tr.section("foreign vectors from std::");
  91. {
  92. tr.info("adapted std::array has static size").test_eq(3, size_s(ra::start(std::array {1, 2, 0})));
  93. tr.info("adapted std::vector has dynamic size").test_eq(ra::ANY, ra::size_s<decltype(ra::start(std::vector {1, 2, 0}))>());
  94. }
  95. tr.section("std::string");
  96. {
  97. tr.info("std::string is is_foreign_vector unless registered as is_scalar")
  98. .test_eq(ra::is_scalar<std::string> ? 0 : 1, ra::rank_s<decltype(std::string("hello"))>());
  99. tr.info("explicit adaption to rank 1 is possible").test_eq(5, size(ra::ptr(std::string("hello"))));
  100. tr.info("note the difference with a char array").test_eq(6, ra::size("hello"));
  101. }
  102. tr.section("other std::ranges");
  103. {
  104. tr.test_eq(15, size(ra::start(std::ranges::iota_view(-5, 10))));
  105. tr.info("adapted std::ranges::iota_view has dynamic size")
  106. .test_eq(ra::ANY, size_s(ra::start(std::ranges::iota_view(-5, 10))));
  107. tr.test_eq(ra::iota(15, -5), std::ranges::iota_view(-5, 10));
  108. }
  109. tr.section("STL predicates");
  110. {
  111. ra::ViewBig<int, 2> a;
  112. tr.test(std::input_iterator<decltype(a.begin())>);
  113. // tr.test(std::weak_output_iterator<decltype(a.begin()), int>); // p2550 when ready c++
  114. tr.test(std::input_iterator<decltype(begin(a+1))>);
  115. tr.test(std::sentinel_for<decltype(end(a+1)), decltype(begin(a+1))>);
  116. ra::Big<int, 2> b;
  117. tr.test(std::random_access_iterator<decltype(ra::begin(b))>);
  118. ra::Small<int, 2, 3> c;
  119. tr.test(std::random_access_iterator<decltype(ra::begin(c))>);
  120. }
  121. tr.section("STLIterator works with arbitrary expr not just views");
  122. {
  123. ra::Big<int, 3> a({4, 2, 3}, ra::_0 - ra::_1 + ra::_2);
  124. ra::Big<int, 1> b(4*2*3, 0);
  125. std::ranges::copy(std::ranges::subrange(ra::STLIterator(a+1), std::default_sentinel), begin(b));
  126. tr.test_eq(ra::ravel_free(a) + 1, b);
  127. b = 0;
  128. // FIXME broken bc of hairy ADL issues (https://stackoverflow.com/a/33576098). Use ra::range instead.
  129. // static_assert(std::ranges::input_range<decltype(a+1)>);
  130. std::ranges::copy(range(a+1), begin(b));
  131. tr.test_eq(ra::ravel_free(a) + 1, b);
  132. }
  133. tr.section("STLIterator as output");
  134. {
  135. using complex = std::complex<double>;
  136. ra::Big<complex, 3> a({4, 2, 3}, ra::_0 - ra::_1 + ra::_2);
  137. ra::Big<double, 1> b(4*2*3, real_part(ra::ravel_free(a)));
  138. std::ranges::copy(std::ranges::subrange(b), ra::STLIterator(imag_part(a)));
  139. tr.test_eq((ra::_0 - ra::_1 + ra::_2)*1.*complex(1, 1), a);
  140. a = 0;
  141. std::ranges::copy(std::ranges::subrange(b), begin(imag_part(a)));
  142. tr.test_eq((ra::_0 - ra::_1 + ra::_2)*1.*complex(0, 1), a);
  143. a = 0;
  144. std::ranges::copy(range(b*1.) | std::views::transform([](auto x) { return -x; }), begin(a));
  145. tr.test_eq((ra::_0 - ra::_1 + ra::_2)*(-1.), a);
  146. }
  147. tr.section("ra::begin / ra::end use members if they exist");
  148. {
  149. ra::Big<char, 1> A = {'x', 'z', 'y'};
  150. std::sort(ra::begin(A), ra::end(A));
  151. tr.test_eq(ra::start({'x', 'y', 'z'}), A);
  152. }
  153. {
  154. ra::Big<char, 1> A = {'x', 'z', 'y'};
  155. std::ranges::sort(ra::range(A));
  156. tr.test_eq(ra::start({'x', 'y', 'z'}), A);
  157. }
  158. #if __cpp_lib_span >= 202002L
  159. tr.section("std::span");
  160. {
  161. std::vector a = {1, 2, 3, 4};
  162. auto b = std::span(a);
  163. tr.test_eq(1, ra::rank(b));
  164. tr.test_eq(ra::iota(4, 1), b);
  165. }
  166. #endif
  167. return tr.summary();
  168. }