unstable_remove_if.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. // Range v3 library
  2. //
  3. // Copyright Andrey Diduh 2019
  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 <vector>
  12. #include <cstdlib>
  13. #include <ctime>
  14. #include <random>
  15. #include <range/v3/action/unstable_remove_if.hpp>
  16. #include <range/v3/action/remove_if.hpp>
  17. #include <range/v3/action/sort.hpp>
  18. #include "../array.hpp"
  19. #include "../simple_test.hpp"
  20. #include "../test_utils.hpp"
  21. void logic_test()
  22. {
  23. using namespace ranges;
  24. const auto make_vector = []() -> std::vector<int> {
  25. return {1,2,3,4,5};
  26. };
  27. // empty
  28. {
  29. std::vector<int> vec;
  30. vec |= actions::unstable_remove_if([](int) { return true; });
  31. CHECK(vec.empty());
  32. }
  33. // all stay
  34. {
  35. std::vector<int> vec = make_vector();
  36. vec |= actions::unstable_remove_if([](int) { return false; });
  37. check_equal(vec, {1,2,3,4,5});
  38. }
  39. // all remove
  40. {
  41. std::vector<int> vec = make_vector();
  42. vec |= actions::unstable_remove_if([](int) { return true; });
  43. CHECK(vec.empty());
  44. }
  45. // remove one in the middle
  46. {
  47. std::vector<int> vec = make_vector();
  48. vec |= actions::unstable_remove_if([](int i) { return i == 2; });
  49. check_equal(vec, {1,5,3,4});
  50. }
  51. // remove first
  52. {
  53. std::vector<int> vec = make_vector();
  54. vec |= actions::unstable_remove_if([](int i) { return i == 1; });
  55. check_equal(vec, {5,2,3,4});
  56. }
  57. // remove last
  58. {
  59. std::vector<int> vec = make_vector();
  60. vec |= actions::unstable_remove_if([](int i) { return i == 5; });
  61. check_equal(vec, {1,2,3,4});
  62. }
  63. // remove group in the middle
  64. {
  65. std::vector<int> vec = make_vector();
  66. vec |= actions::unstable_remove_if([](int i) { return i == 2 || i == 3 || i == 4; });
  67. check_equal(vec, {1,5});
  68. }
  69. // remove group in the begin
  70. {
  71. std::vector<int> vec = make_vector();
  72. vec |= actions::unstable_remove_if([](int i) { return i == 1 || i == 2 || i == 3; });
  73. check_equal(vec, {5,4});
  74. }
  75. // remove group in the end
  76. {
  77. std::vector<int> vec = make_vector();
  78. vec |= actions::unstable_remove_if([](int i) { return i == 3 || i == 4 || i == 5; });
  79. check_equal(vec, {1,2});
  80. }
  81. // remains one in the middle
  82. {
  83. std::vector<int> vec = make_vector();
  84. vec |= actions::unstable_remove_if([](int i) { return i != 3; });
  85. check_equal(vec, {3});
  86. }
  87. // remains group in the middle
  88. {
  89. std::vector<int> vec = make_vector();
  90. vec |= actions::unstable_remove_if([](int i) { return (i != 3) && (i != 4); });
  91. check_equal(vec, {4,3});
  92. }
  93. }
  94. void num_pred_calls_test()
  95. {
  96. // std::ranges::remove_if requires:
  97. // "Exactly N applications of the corresponding predicate and any projection, where N = (last - first)"
  98. // https://en.cppreference.com/w/cpp/algorithm/ranges/remove
  99. // so expect the same of unstable_remove_if
  100. using namespace ranges;
  101. int pred_invocation_counter = 0;
  102. auto is_zero_count_invocations = [&pred_invocation_counter](int i) {
  103. ++pred_invocation_counter;
  104. return i == 0;
  105. };
  106. {
  107. std::vector<int> vec{0};
  108. pred_invocation_counter = 0;
  109. vec |= actions::unstable_remove_if(is_zero_count_invocations);
  110. check_equal(pred_invocation_counter, 1);
  111. }
  112. {
  113. std::vector<int> vec{1,1,1};
  114. pred_invocation_counter = 0;
  115. vec |= actions::unstable_remove_if(is_zero_count_invocations);
  116. check_equal(pred_invocation_counter, 3);
  117. }
  118. {
  119. std::vector<int> vec{1,0};
  120. pred_invocation_counter = 0;
  121. vec |= actions::unstable_remove_if(is_zero_count_invocations);
  122. check_equal(pred_invocation_counter, 2);
  123. }
  124. {
  125. std::vector<int> vec{1,2,0};
  126. pred_invocation_counter = 0;
  127. vec |= actions::unstable_remove_if(is_zero_count_invocations);
  128. check_equal(pred_invocation_counter, 3);
  129. }
  130. {
  131. std::vector<int> vec{0,0,0,0};
  132. pred_invocation_counter = 0;
  133. vec |= actions::unstable_remove_if(is_zero_count_invocations);
  134. check_equal(pred_invocation_counter, 4);
  135. }
  136. {
  137. std::vector<int> vec{1,2,3,0,0,0,0,4,5};
  138. pred_invocation_counter = 0;
  139. vec |= actions::unstable_remove_if(is_zero_count_invocations);
  140. check_equal(pred_invocation_counter, 9);
  141. }
  142. }
  143. class fuzzy_test_fn
  144. {
  145. int size;
  146. #if defined(__GLIBCXX__) && defined(RANGES_WORKAROUND_VALGRIND_RDRAND)
  147. std::random_device rd{"/dev/urandom"};
  148. #else
  149. std::random_device rd;
  150. #endif
  151. std::mt19937 eng{rd()};
  152. std::uniform_int_distribution<int> distr;
  153. public:
  154. explicit fuzzy_test_fn(int sz)
  155. : size(sz)
  156. , distr{0, sz}
  157. {}
  158. void operator()()
  159. {
  160. struct Int
  161. {
  162. int value;
  163. explicit Int(int v)
  164. : value(v)
  165. {}
  166. Int(Int const &) = default;
  167. Int(Int&& other) noexcept
  168. : value(0)
  169. {
  170. *this = std::move(other);
  171. }
  172. Int &operator=(Int const &) = default;
  173. Int &operator=(Int&& other) noexcept
  174. {
  175. const int sentinel = -1;
  176. CHECK(other.value != sentinel);
  177. value = other.value;
  178. other.value = sentinel;
  179. return *this;
  180. }
  181. RANGES_DIAGNOSTIC_PUSH
  182. RANGES_DIAGNOSTIC_IGNORE_UNNEEDED_MEMBER
  183. bool operator==(Int const &other) const
  184. {
  185. return value == other.value;
  186. }
  187. bool operator!=(Int const &other) const
  188. {
  189. return value != other.value;
  190. }
  191. bool operator<(Int const &other) const
  192. {
  193. return value < other.value;
  194. }
  195. bool operator>(Int const &other) const
  196. {
  197. return value > other.value;
  198. }
  199. bool operator<=(Int const &other) const
  200. {
  201. return value <= other.value;
  202. }
  203. bool operator>=(Int const &other) const
  204. {
  205. return value >= other.value;
  206. }
  207. RANGES_DIAGNOSTIC_POP
  208. };
  209. using namespace ranges;
  210. std::vector<Int> ordered_list;
  211. std::vector<Int> unordered_list;
  212. // fill
  213. for(int i=0; i < size; ++i)
  214. {
  215. ordered_list.emplace_back(i);
  216. unordered_list.emplace_back(i);
  217. }
  218. // erase
  219. const int erase_count = distr(eng);
  220. for(int i=0; i < erase_count; ++i)
  221. {
  222. const int value = distr(eng);
  223. const auto pred = [value](Int j) { return j.value == value; };
  224. unordered_list |= actions::unstable_remove_if(pred);
  225. ordered_list |= actions::remove_if(pred);
  226. }
  227. // compare
  228. unordered_list |= actions::sort;
  229. CHECK(ordered_list == unordered_list);
  230. }
  231. };
  232. int main()
  233. {
  234. logic_test();
  235. num_pred_calls_test();
  236. {
  237. const int size = 100;
  238. const int repeats = 1000;
  239. fuzzy_test_fn fuzzy_test(size);
  240. for(int i=0; i < repeats; ++i)
  241. fuzzy_test();
  242. }
  243. return ::test_result();
  244. }