split.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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 <cctype>
  13. #include <sstream>
  14. #include <range/v3/core.hpp>
  15. #include <range/v3/view/counted.hpp>
  16. #include <range/v3/view/c_str.hpp>
  17. #include <range/v3/view/empty.hpp>
  18. #include <range/v3/view/remove_if.hpp>
  19. #include <range/v3/view/split.hpp>
  20. #include <range/v3/view/split_when.hpp>
  21. #include "../simple_test.hpp"
  22. #include "../test_utils.hpp"
  23. #include "../test_iterators.hpp"
  24. RANGES_DIAGNOSTIC_IGNORE_SIGN_CONVERSION
  25. #if defined(__clang__) && __clang_major__ < 6
  26. // Workaround https://bugs.llvm.org/show_bug.cgi?id=33314
  27. RANGES_DIAGNOSTIC_IGNORE_UNDEFINED_FUNC_TEMPLATE
  28. #endif
  29. namespace
  30. {
  31. struct starts_with_g
  32. {
  33. template<typename I, typename S>
  34. std::pair<bool, I> operator()(I b, S) const
  35. {
  36. return {*b == 'g', b};
  37. }
  38. };
  39. #ifdef RANGES_WORKAROUND_MSVC_790554
  40. template<std::size_t N>
  41. auto c_str(char const (&sz)[N])
  42. {
  43. return ranges::subrange<char const*>{&sz[0], &sz[N-1]};
  44. }
  45. #else // ^^^ workaround / no workaround vvv
  46. template<std::size_t N>
  47. ranges::subrange<char const*> c_str(char const (&sz)[N])
  48. {
  49. return {&sz[0], &sz[N-1]};
  50. }
  51. #endif // RANGES_WORKAROUND_MSVC_790554
  52. }
  53. void moar_tests()
  54. {
  55. using namespace ranges;
  56. std::string greeting = "now is the time";
  57. std::string pattern = " ";
  58. {
  59. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  60. split_view sv{greeting, pattern};
  61. #else
  62. split_view<views::all_t<std::string&>, views::all_t<std::string&>> sv{greeting, pattern};
  63. #endif
  64. auto i = sv.begin();
  65. check_equal(*i, {'n','o','w'});
  66. ++i;
  67. CHECK(i != sv.end());
  68. check_equal(*i, {'i','s'});
  69. ++i;
  70. CHECK(i != sv.end());
  71. check_equal(*i, {'t','h','e'});
  72. ++i;
  73. CHECK(i != sv.end());
  74. check_equal(*i, {'t','i','m','e'});
  75. ++i;
  76. CHECK(i == sv.end());
  77. using R = decltype(sv);
  78. CPP_assert(forward_range<R>);
  79. CPP_assert(forward_range<R const>);
  80. }
  81. {
  82. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  83. split_view sv{greeting, ' '};
  84. #else
  85. split_view<views::all_t<std::string&>, single_view<char>> sv{greeting, ' '};
  86. #endif
  87. auto i = sv.begin();
  88. CHECK(i != sv.end());
  89. check_equal(*i, {'n','o','w'});
  90. ++i;
  91. CHECK(i != sv.end());
  92. check_equal(*i, {'i','s'});
  93. ++i;
  94. CHECK(i != sv.end());
  95. check_equal(*i, {'t','h','e'});
  96. ++i;
  97. CHECK(i != sv.end());
  98. check_equal(*i, {'t','i','m','e'});
  99. ++i;
  100. CHECK(i == sv.end());
  101. using R = decltype(sv);
  102. CPP_assert(forward_range<R>);
  103. CPP_assert(forward_range<R const>);
  104. }
  105. {
  106. std::stringstream sin{greeting};
  107. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  108. auto rng = subrange{
  109. std::istreambuf_iterator<char>{sin},
  110. std::istreambuf_iterator<char>{}};
  111. #else
  112. auto rng = make_subrange(
  113. std::istreambuf_iterator<char>{sin},
  114. std::istreambuf_iterator<char>{});
  115. #endif
  116. auto sv = views::split(rng, ' ');
  117. auto i = sv.begin();
  118. CHECK(i != sv.end());
  119. check_equal(*i, {'n','o','w'});
  120. ++i;
  121. CHECK(i != sv.end());
  122. check_equal(*i, {'i','s'});
  123. ++i;
  124. CHECK(i != sv.end());
  125. check_equal(*i, {'t','h','e'});
  126. ++i;
  127. CHECK(i != sv.end());
  128. check_equal(*i, {'t','i','m','e'});
  129. ++i;
  130. CHECK(i == sv.end());
  131. using R = decltype(sv);
  132. CPP_assert(input_range<R>);
  133. CPP_assert(!forward_range<R>);
  134. CPP_assert(!input_range<R const>);
  135. }
  136. {
  137. std::string list{"eggs,milk,,butter"};
  138. auto sv = views::split(list, ',');
  139. auto i = sv.begin();
  140. CHECK(i != sv.end());
  141. check_equal(*i, {'e','g','g','s'});
  142. ++i;
  143. CHECK(i != sv.end());
  144. check_equal(*i, {'m','i','l','k'});
  145. ++i;
  146. CHECK(i != sv.end());
  147. check_equal(*i, views::empty<char>);
  148. ++i;
  149. CHECK(i != sv.end());
  150. check_equal(*i, {'b','u','t','t','e','r'});
  151. ++i;
  152. CHECK(i == sv.end());
  153. }
  154. {
  155. std::string list{"eggs,milk,,butter"};
  156. std::stringstream sin{list};
  157. auto rng = make_subrange(
  158. std::istreambuf_iterator<char>{sin},
  159. std::istreambuf_iterator<char>{});
  160. auto sv = rng | views::split(',');
  161. auto i = sv.begin();
  162. CHECK(i != sv.end());
  163. check_equal(*i, {'e','g','g','s'});
  164. ++i;
  165. CHECK(i != sv.end());
  166. check_equal(*i, {'m','i','l','k'});
  167. ++i;
  168. CHECK(i != sv.end());
  169. check_equal(*i, views::empty<char>);
  170. ++i;
  171. CHECK(i != sv.end());
  172. check_equal(*i, {'b','u','t','t','e','r'});
  173. ++i;
  174. CHECK(i == sv.end());
  175. }
  176. {
  177. std::string hello("hello");
  178. auto sv = views::split(hello, views::empty<char>);
  179. auto i = sv.begin();
  180. CHECK(i != sv.end());
  181. check_equal(*i, single_view<char>{'h'});
  182. ++i;
  183. CHECK(i != sv.end());
  184. check_equal(*i, single_view<char>{'e'});
  185. ++i;
  186. CHECK(i != sv.end());
  187. check_equal(*i, single_view<char>{'l'});
  188. ++i;
  189. CHECK(i != sv.end());
  190. check_equal(*i, single_view<char>{'l'});
  191. ++i;
  192. CHECK(i != sv.end());
  193. check_equal(*i, single_view<char>{'o'});
  194. ++i;
  195. CHECK(i == sv.end());
  196. }
  197. {
  198. std::string hello{"hello"};
  199. std::stringstream sin{hello};
  200. auto rng = make_subrange(
  201. std::istreambuf_iterator<char>{sin},
  202. std::istreambuf_iterator<char>{});
  203. auto sv = views::split(rng, views::empty<char>);
  204. auto i = sv.begin();
  205. CHECK(i != sv.end());
  206. check_equal(*i, single_view<char>{'h'});
  207. ++i;
  208. CHECK(i != sv.end());
  209. check_equal(*i, single_view<char>{'e'});
  210. ++i;
  211. CHECK(i != sv.end());
  212. check_equal(*i, single_view<char>{'l'});
  213. ++i;
  214. CHECK(i != sv.end());
  215. check_equal(*i, single_view<char>{'l'});
  216. ++i;
  217. CHECK(i != sv.end());
  218. check_equal(*i, single_view<char>{'o'});
  219. ++i;
  220. CHECK(i == sv.end());
  221. }
  222. {
  223. std::string hello{"hello"};
  224. auto sv = views::split(hello, views::empty<char>);
  225. auto i = sv.begin();
  226. CHECK(i != sv.end());
  227. ++i;
  228. CHECK(i != sv.end());
  229. ++i;
  230. CHECK(i != sv.end());
  231. check_equal(*i, single_view<char>{'l'});
  232. ++i;
  233. CHECK(i != sv.end());
  234. check_equal(*i, single_view<char>{'l'});
  235. ++i;
  236. CHECK(i != sv.end());
  237. ++i;
  238. CHECK(i == sv.end());
  239. }
  240. {
  241. std::string hello{"hello"};
  242. std::stringstream sin{hello};
  243. auto rng = make_subrange(
  244. std::istreambuf_iterator<char>{sin},
  245. std::istreambuf_iterator<char>{});
  246. auto sv = views::split(rng, views::empty<char>);
  247. auto i = sv.begin();
  248. CHECK(i != sv.end());
  249. ++i;
  250. CHECK(i != sv.end());
  251. ++i;
  252. CHECK(i != sv.end());
  253. check_equal(*i, single_view<char>{'l'});
  254. ++i;
  255. CHECK(i != sv.end());
  256. check_equal(*i, single_view<char>{'l'});
  257. ++i;
  258. CHECK(i != sv.end());
  259. ++i;
  260. CHECK(i == sv.end());
  261. }
  262. }
  263. int main()
  264. {
  265. using namespace ranges;
  266. {
  267. std::string str("Now is the time for all good men to come to the aid of their country.");
  268. auto rng = views::split(str, ' ');
  269. CHECK(distance(rng) == 16);
  270. if(distance(rng) == 16)
  271. {
  272. check_equal(*(next(begin(rng),0)), c_str("Now"));
  273. check_equal(*(next(begin(rng),1)), c_str("is"));
  274. check_equal(*(next(begin(rng),2)), c_str("the"));
  275. check_equal(*(next(begin(rng),3)), c_str("time"));
  276. check_equal(*(next(begin(rng),4)), c_str("for"));
  277. check_equal(*(next(begin(rng),5)), c_str("all"));
  278. check_equal(*(next(begin(rng),6)), c_str("good"));
  279. check_equal(*(next(begin(rng),7)), c_str("men"));
  280. check_equal(*(next(begin(rng),8)), c_str("to"));
  281. check_equal(*(next(begin(rng),9)), c_str("come"));
  282. check_equal(*(next(begin(rng),10)), c_str("to"));
  283. check_equal(*(next(begin(rng),11)), c_str("the"));
  284. check_equal(*(next(begin(rng),12)), c_str("aid"));
  285. check_equal(*(next(begin(rng),13)), c_str("of"));
  286. check_equal(*(next(begin(rng),14)), c_str("their"));
  287. check_equal(*(next(begin(rng),15)), c_str("country."));
  288. }
  289. }
  290. {
  291. std::string str("Now is the time for all good men to come to the aid of their country.");
  292. auto rng = views::split(str, c_str(" "));
  293. CHECK(distance(rng) == 16);
  294. if(distance(rng) == 16)
  295. {
  296. check_equal(*(next(begin(rng),0)), c_str("Now"));
  297. check_equal(*(next(begin(rng),1)), c_str("is"));
  298. check_equal(*(next(begin(rng),2)), c_str("the"));
  299. check_equal(*(next(begin(rng),3)), c_str("time"));
  300. check_equal(*(next(begin(rng),4)), c_str("for"));
  301. check_equal(*(next(begin(rng),5)), c_str("all"));
  302. check_equal(*(next(begin(rng),6)), c_str("good"));
  303. check_equal(*(next(begin(rng),7)), c_str("men"));
  304. check_equal(*(next(begin(rng),8)), c_str("to"));
  305. check_equal(*(next(begin(rng),9)), c_str("come"));
  306. check_equal(*(next(begin(rng),10)), c_str("to"));
  307. check_equal(*(next(begin(rng),11)), c_str("the"));
  308. check_equal(*(next(begin(rng),12)), c_str("aid"));
  309. check_equal(*(next(begin(rng),13)), c_str("of"));
  310. check_equal(*(next(begin(rng),14)), c_str("their"));
  311. check_equal(*(next(begin(rng),15)), c_str("country."));
  312. }
  313. }
  314. {
  315. std::string str("Now is the time for all ggood men to come to the aid of their country.");
  316. auto rng = views::split_when(str, starts_with_g{});
  317. CHECK(distance(rng) == 3);
  318. if(distance(rng) == 3)
  319. {
  320. check_equal(*begin(rng), c_str("Now is the time for all "));
  321. check_equal(*next(begin(rng)), c_str("g"));
  322. check_equal(*(next(begin(rng),2)), c_str("good men to come to the aid of their country."));
  323. }
  324. }
  325. {
  326. std::string str("Now is the time for all ggood men to come to the aid of their country.");
  327. ForwardIterator<std::string::iterator> i {str.begin()};
  328. auto rng = views::counted(i, str.size()) | views::split_when(starts_with_g{});
  329. CHECK(distance(rng) == 3);
  330. if(distance(rng) == 3)
  331. {
  332. check_equal(*begin(rng), c_str("Now is the time for all "));
  333. check_equal(*next(begin(rng)), c_str("g"));
  334. check_equal(*(next(begin(rng),2)), c_str("good men to come to the aid of their country."));
  335. }
  336. }
  337. {
  338. std::string str("meow");
  339. auto rng = views::split(str, views::empty<char>);
  340. CHECK(distance(rng) == 4);
  341. if(distance(rng) == 4)
  342. {
  343. check_equal(*(next(begin(rng),0)), c_str("m"));
  344. check_equal(*(next(begin(rng),1)), c_str("e"));
  345. check_equal(*(next(begin(rng),2)), c_str("o"));
  346. check_equal(*(next(begin(rng),3)), c_str("w"));
  347. }
  348. }
  349. {
  350. int a[] = {0, 2, 3, 1, 4, 5, 1, 6, 7};
  351. auto rng = a | views::remove_if([](int i) { return i % 2 == 0; });
  352. auto srng = views::split(rng, 1);
  353. CHECK(distance(srng) == 3);
  354. check_equal(*begin(srng), {3});
  355. check_equal(*next(begin(srng), 1), {5});
  356. check_equal(*next(begin(srng), 2), {7});
  357. }
  358. {
  359. std::string str("now is \t the\ttime");
  360. auto rng = views::split_when(str, (int(*)(int))&std::isspace);
  361. CHECK(distance(rng) == 4);
  362. if(distance(rng) == 4)
  363. {
  364. check_equal(*(next(begin(rng),0)), c_str("now"));
  365. check_equal(*(next(begin(rng),1)), c_str("is"));
  366. check_equal(*(next(begin(rng),2)), c_str("the"));
  367. check_equal(*(next(begin(rng),3)), c_str("time"));
  368. }
  369. }
  370. { // Regression test for https://stackoverflow.com/questions/49015671
  371. auto const str = "quick brown fox";
  372. auto rng = views::c_str(str) | views::split(' ');
  373. CPP_assert(forward_range<decltype(rng)>);
  374. }
  375. { // Regression test for #986
  376. std::string s;
  377. s | ranges::views::split_when([](char) { return true; });
  378. }
  379. moar_tests();
  380. { // Regression test for #1041
  381. auto is_escape = [](auto first, auto last) {
  382. return std::make_pair(next(first) != last, first);
  383. };
  384. auto escapes = views::split_when(views::c_str(R"(\t)"), is_escape);
  385. CPP_assert(forward_range<decltype(escapes)>);
  386. auto const first = begin(escapes);
  387. CHECK(first != end(escapes));
  388. CHECK(first != next(first));
  389. }
  390. return test_result();
  391. }