Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

370 linhas
15KB

  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2014-present
  5. //
  6. // Use, modification and distribution is subject to the
  7. // Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // Project home: https://github.com/ericniebler/range-v3
  12. //
  13. //===-------------------------- algorithm ---------------------------------===//
  14. //
  15. // The LLVM Compiler Infrastructure
  16. //
  17. // This file is dual licensed under the MIT and the University of Illinois Open
  18. // Source Licenses. See LICENSE.TXT for details.
  19. //
  20. //===----------------------------------------------------------------------===//
  21. #ifndef RANGES_V3_ALGORITHM_PERMUTATION_HPP
  22. #define RANGES_V3_ALGORITHM_PERMUTATION_HPP
  23. #include <meta/meta.hpp>
  24. #include <range/v3/range_fwd.hpp>
  25. #include <range/v3/algorithm/reverse.hpp>
  26. #include <range/v3/functional/comparisons.hpp>
  27. #include <range/v3/functional/identity.hpp>
  28. #include <range/v3/functional/invoke.hpp>
  29. #include <range/v3/iterator/concepts.hpp>
  30. #include <range/v3/iterator/operations.hpp>
  31. #include <range/v3/iterator/traits.hpp>
  32. #include <range/v3/range/access.hpp>
  33. #include <range/v3/range/concepts.hpp>
  34. #include <range/v3/range/traits.hpp>
  35. #include <range/v3/utility/static_const.hpp>
  36. #include <range/v3/utility/swap.hpp>
  37. namespace ranges
  38. {
  39. /// \addtogroup group-algorithms
  40. /// @{
  41. /// \cond
  42. namespace detail
  43. {
  44. template<typename I1, typename S1, typename I2, typename S2, typename C,
  45. typename P1, typename P2>
  46. bool is_permutation_impl(I1 begin1, S1 end1, I2 begin2, S2 end2, C pred, P1 proj1,
  47. P2 proj2)
  48. {
  49. // shorten sequences as much as possible by lopping off any equal parts
  50. for(; begin1 != end1 && begin2 != end2; ++begin1, ++begin2)
  51. if(!invoke(pred, invoke(proj1, *begin1), invoke(proj2, *begin2)))
  52. goto not_done;
  53. return begin1 == end1 && begin2 == end2;
  54. not_done:
  55. // begin1 != end1 && begin2 != end2 && *begin1 != *begin2
  56. auto l1 = distance(begin1, end1);
  57. auto l2 = distance(begin2, end2);
  58. if(l1 != l2)
  59. return false;
  60. // For each element in [f1, l1) see if there are the same number of
  61. // equal elements in [f2, l2)
  62. for(I1 i = begin1; i != end1; ++i)
  63. {
  64. // Have we already counted the number of *i in [f1, l1)?
  65. for(I1 j = begin1; j != i; ++j)
  66. if(invoke(pred, invoke(proj1, *j), invoke(proj1, *i)))
  67. goto next_iter;
  68. {
  69. // Count number of *i in [f2, l2)
  70. iter_difference_t<I2> c2 = 0;
  71. for(I2 j = begin2; j != end2; ++j)
  72. if(invoke(pred, invoke(proj1, *i), invoke(proj2, *j)))
  73. ++c2;
  74. if(c2 == 0)
  75. return false;
  76. // Count number of *i in [i, l1) (we can start with 1)
  77. iter_difference_t<I1> c1 = 1;
  78. for(I1 j = next(i); j != end1; ++j)
  79. if(invoke(pred, invoke(proj1, *i), invoke(proj1, *j)))
  80. ++c1;
  81. if(c1 != c2)
  82. return false;
  83. }
  84. next_iter:;
  85. }
  86. return true;
  87. }
  88. } // namespace detail
  89. /// \endcond
  90. RANGES_BEGIN_NIEBLOID(is_permutation)
  91. /// \brief function template \c is_permutation
  92. template<typename I1,
  93. typename S1,
  94. typename I2,
  95. typename C = equal_to,
  96. typename P1 = identity,
  97. typename P2 = identity>
  98. RANGES_DEPRECATED(
  99. "Use the variant of ranges::is_permutation that takes an upper bound "
  100. "for both sequences")
  101. auto RANGES_FUN_NIEBLOID(is_permutation)(I1 begin1,
  102. S1 end1,
  103. I2 begin2,
  104. C pred = C{},
  105. P1 proj1 = P1{},
  106. P2 proj2 = P2{}) //
  107. ->CPP_ret(bool)( //
  108. requires forward_iterator<I1> && sentinel_for<S1, I1> &&
  109. forward_iterator<I2> && indirectly_comparable<I1, I2, C, P1, P2>)
  110. {
  111. // shorten sequences as much as possible by lopping off any equal parts
  112. for(; begin1 != end1; ++begin1, ++begin2)
  113. if(!invoke(pred, invoke(proj1, *begin1), invoke(proj2, *begin2)))
  114. goto not_done;
  115. return true;
  116. not_done:
  117. // begin1 != end1 && *begin1 != *begin2
  118. auto l1 = distance(begin1, end1);
  119. if(l1 == 1)
  120. return false;
  121. I2 end2 = next(begin2, l1);
  122. // For each element in [f1, l1) see if there are the same number of
  123. // equal elements in [f2, l2)
  124. for(I1 i = begin1; i != end1; ++i)
  125. {
  126. // Have we already counted the number of *i in [f1, l1)?
  127. for(I1 j = begin1; j != i; ++j)
  128. if(invoke(pred, invoke(proj1, *j), invoke(proj1, *i)))
  129. goto next_iter;
  130. {
  131. // Count number of *i in [f2, l2)
  132. iter_difference_t<I2> c2 = 0;
  133. for(I2 j = begin2; j != end2; ++j)
  134. if(invoke(pred, invoke(proj1, *i), invoke(proj2, *j)))
  135. ++c2;
  136. if(c2 == 0)
  137. return false;
  138. // Count number of *i in [i, l1) (we can start with 1)
  139. iter_difference_t<I1> c1 = 1;
  140. for(I1 j = next(i); j != end1; ++j)
  141. if(invoke(pred, invoke(proj1, *i), invoke(proj1, *j)))
  142. ++c1;
  143. if(c1 != c2)
  144. return false;
  145. }
  146. next_iter:;
  147. }
  148. return true;
  149. }
  150. /// \overload
  151. template<typename I1,
  152. typename S1,
  153. typename I2,
  154. typename S2,
  155. typename C = equal_to,
  156. typename P1 = identity,
  157. typename P2 = identity>
  158. auto RANGES_FUN_NIEBLOID(is_permutation)(I1 begin1,
  159. S1 end1,
  160. I2 begin2,
  161. S2 end2,
  162. C pred = C{},
  163. P1 proj1 = P1{},
  164. P2 proj2 = P2{}) //
  165. ->CPP_ret(bool)( //
  166. requires forward_iterator<I1> && sentinel_for<S1, I1> &&
  167. forward_iterator<I2> && sentinel_for<S2, I2> &&
  168. indirectly_comparable<I1, I2, C, P1, P2>)
  169. {
  170. if(RANGES_CONSTEXPR_IF(sized_sentinel_for<S1, I1> &&
  171. sized_sentinel_for<S2, I2>))
  172. {
  173. RANGES_DIAGNOSTIC_PUSH
  174. RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
  175. return distance(begin1, end1) == distance(begin2, end2) &&
  176. (*this)(std::move(begin1),
  177. std::move(end1),
  178. std::move(begin2),
  179. std::move(pred),
  180. std::move(proj1),
  181. std::move(proj2));
  182. RANGES_DIAGNOSTIC_POP
  183. }
  184. return detail::is_permutation_impl(std::move(begin1),
  185. std::move(end1),
  186. std::move(begin2),
  187. std::move(end2),
  188. std::move(pred),
  189. std::move(proj1),
  190. std::move(proj2));
  191. }
  192. /// \overload
  193. template<typename Rng1,
  194. typename I2Ref,
  195. typename C = equal_to,
  196. typename P1 = identity,
  197. typename P2 = identity>
  198. RANGES_DEPRECATED(
  199. "Use the variant of ranges::is_permutation that takes an upper bound "
  200. "for both sequences")
  201. auto RANGES_FUN_NIEBLOID(is_permutation)(Rng1 && rng1,
  202. I2Ref && begin2,
  203. C pred = C{},
  204. P1 proj1 = P1{},
  205. P2 proj2 = P2{}) //
  206. ->CPP_ret(bool)( //
  207. requires forward_range<Rng1> && forward_iterator<uncvref_t<I2Ref>> &&
  208. indirectly_comparable<iterator_t<Rng1>, uncvref_t<I2Ref>, C, P1, P2>)
  209. {
  210. RANGES_DIAGNOSTIC_PUSH
  211. RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
  212. return (*this)(begin(rng1),
  213. end(rng1),
  214. (I2Ref &&) begin2,
  215. std::move(pred),
  216. std::move(proj1),
  217. std::move(proj2));
  218. RANGES_DIAGNOSTIC_POP
  219. }
  220. /// \overload
  221. template<typename Rng1,
  222. typename Rng2,
  223. typename C = equal_to,
  224. typename P1 = identity,
  225. typename P2 = identity>
  226. auto RANGES_FUN_NIEBLOID(is_permutation)(
  227. Rng1 && rng1, Rng2 && rng2, C pred = C{}, P1 proj1 = P1{}, P2 proj2 = P2{}) //
  228. ->CPP_ret(bool)( //
  229. requires forward_range<Rng1> && forward_range<Rng2> &&
  230. indirectly_comparable<iterator_t<Rng1>, iterator_t<Rng2>, C, P1, P2>)
  231. {
  232. if(RANGES_CONSTEXPR_IF(sized_range<Rng1> && sized_range<Rng2>))
  233. {
  234. RANGES_DIAGNOSTIC_PUSH
  235. RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
  236. return distance(rng1) == distance(rng2) && (*this)(begin(rng1),
  237. end(rng1),
  238. begin(rng2),
  239. std::move(pred),
  240. std::move(proj1),
  241. std::move(proj2));
  242. RANGES_DIAGNOSTIC_POP
  243. }
  244. return detail::is_permutation_impl(begin(rng1),
  245. end(rng1),
  246. begin(rng2),
  247. end(rng2),
  248. std::move(pred),
  249. std::move(proj1),
  250. std::move(proj2));
  251. }
  252. RANGES_END_NIEBLOID(is_permutation)
  253. RANGES_BEGIN_NIEBLOID(next_permutation)
  254. /// \brief function template \c next_permutation
  255. template<typename I, typename S, typename C = less, typename P = identity>
  256. auto RANGES_FUN_NIEBLOID(next_permutation)(
  257. I first, S end_, C pred = C{}, P proj = P{}) //
  258. ->CPP_ret(bool)( //
  259. requires bidirectional_iterator<I> && sentinel_for<S, I> &&
  260. sortable<I, C, P>)
  261. {
  262. if(first == end_)
  263. return false;
  264. I last = ranges::next(first, end_), i = last;
  265. if(first == --i)
  266. return false;
  267. while(true)
  268. {
  269. I ip1 = i;
  270. if(invoke(pred, invoke(proj, *--i), invoke(proj, *ip1)))
  271. {
  272. I j = last;
  273. while(!invoke(pred, invoke(proj, *i), invoke(proj, *--j)))
  274. ;
  275. ranges::iter_swap(i, j);
  276. ranges::reverse(ip1, last);
  277. return true;
  278. }
  279. if(i == first)
  280. {
  281. ranges::reverse(first, last);
  282. return false;
  283. }
  284. }
  285. }
  286. /// \overload
  287. template<typename Rng, typename C = less, typename P = identity>
  288. auto RANGES_FUN_NIEBLOID(next_permutation)(
  289. Rng && rng, C pred = C{}, P proj = P{}) //
  290. ->CPP_ret(bool)( //
  291. requires bidirectional_range<Rng> && sortable<iterator_t<Rng>, C, P>)
  292. {
  293. return (*this)(begin(rng), end(rng), std::move(pred), std::move(proj));
  294. }
  295. RANGES_END_NIEBLOID(next_permutation)
  296. RANGES_BEGIN_NIEBLOID(prev_permutation)
  297. /// \brief function template \c prev_permutation
  298. template<typename I, typename S, typename C = less, typename P = identity>
  299. auto RANGES_FUN_NIEBLOID(prev_permutation)(
  300. I first, S end_, C pred = C{}, P proj = P{}) //
  301. ->CPP_ret(bool)( //
  302. requires bidirectional_iterator<I> && sentinel_for<S, I> &&
  303. sortable<I, C, P>)
  304. {
  305. if(first == end_)
  306. return false;
  307. I last = ranges::next(first, end_), i = last;
  308. if(first == --i)
  309. return false;
  310. while(true)
  311. {
  312. I ip1 = i;
  313. if(invoke(pred, invoke(proj, *ip1), invoke(proj, *--i)))
  314. {
  315. I j = last;
  316. while(!invoke(pred, invoke(proj, *--j), invoke(proj, *i)))
  317. ;
  318. ranges::iter_swap(i, j);
  319. ranges::reverse(ip1, last);
  320. return true;
  321. }
  322. if(i == first)
  323. {
  324. ranges::reverse(first, last);
  325. return false;
  326. }
  327. }
  328. }
  329. /// \overload
  330. template<typename Rng, typename C = less, typename P = identity>
  331. auto RANGES_FUN_NIEBLOID(prev_permutation)(
  332. Rng && rng, C pred = C{}, P proj = P{}) //
  333. ->CPP_ret(bool)( //
  334. requires bidirectional_range<Rng> && sortable<iterator_t<Rng>, C, P>)
  335. {
  336. return (*this)(begin(rng), end(rng), std::move(pred), std::move(proj));
  337. }
  338. RANGES_END_NIEBLOID(prev_permutation)
  339. namespace cpp20
  340. {
  341. using ranges::is_permutation;
  342. using ranges::next_permutation;
  343. using ranges::prev_permutation;
  344. } // namespace cpp20
  345. /// @}
  346. } // namespace ranges
  347. #endif // include guard