sort.hpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*!
  2. @file
  3. Defines `boost::hana::sort`.
  4. Copyright Louis Dionne 2013-2022
  5. Distributed under the Boost Software License, Version 1.0.
  6. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  7. */
  8. #ifndef BOOST_HANA_SORT_HPP
  9. #define BOOST_HANA_SORT_HPP
  10. #include <boost/hana/fwd/sort.hpp>
  11. #include <boost/hana/at.hpp>
  12. #include <boost/hana/concept/sequence.hpp>
  13. #include <boost/hana/config.hpp>
  14. #include <boost/hana/core/dispatch.hpp>
  15. #include <boost/hana/core/make.hpp>
  16. #include <boost/hana/detail/nested_by.hpp> // required by fwd decl
  17. #include <boost/hana/length.hpp>
  18. #include <boost/hana/less.hpp>
  19. #include <utility> // std::declval, std::index_sequence
  20. namespace boost { namespace hana {
  21. //! @cond
  22. template <typename Xs, typename Predicate>
  23. constexpr auto sort_t::operator()(Xs&& xs, Predicate&& pred) const {
  24. using S = typename hana::tag_of<Xs>::type;
  25. using Sort = BOOST_HANA_DISPATCH_IF(sort_impl<S>,
  26. hana::Sequence<S>::value
  27. );
  28. #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
  29. static_assert(hana::Sequence<S>::value,
  30. "hana::sort(xs, predicate) requires 'xs' to be a Sequence");
  31. #endif
  32. return Sort::apply(static_cast<Xs&&>(xs),
  33. static_cast<Predicate&&>(pred));
  34. }
  35. template <typename Xs>
  36. constexpr auto sort_t::operator()(Xs&& xs) const {
  37. using S = typename hana::tag_of<Xs>::type;
  38. using Sort = BOOST_HANA_DISPATCH_IF(sort_impl<S>,
  39. hana::Sequence<S>::value
  40. );
  41. #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
  42. static_assert(hana::Sequence<S>::value,
  43. "hana::sort(xs) requires 'xs' to be a Sequence");
  44. #endif
  45. return Sort::apply(static_cast<Xs&&>(xs));
  46. }
  47. //! @endcond
  48. namespace detail {
  49. template <typename Xs, typename Pred>
  50. struct sort_predicate {
  51. template <std::size_t I, std::size_t J>
  52. using apply = decltype(std::declval<Pred>()(
  53. hana::at_c<I>(std::declval<Xs>()),
  54. hana::at_c<J>(std::declval<Xs>())
  55. ));
  56. };
  57. template <typename Left, typename Right>
  58. struct concat;
  59. template <std::size_t ...l, std::size_t ...r>
  60. struct concat<std::index_sequence<l...>, std::index_sequence<r...>> {
  61. using type = std::index_sequence<l..., r...>;
  62. };
  63. template <typename Pred, bool PickRight, typename Left, typename Right>
  64. struct merge;
  65. template <
  66. typename Pred,
  67. std::size_t l0,
  68. std::size_t l1,
  69. std::size_t ...l,
  70. std::size_t r0,
  71. std::size_t ...r>
  72. struct merge<
  73. Pred,
  74. false,
  75. std::index_sequence<l0, l1, l...>,
  76. std::index_sequence<r0, r...>
  77. > {
  78. using type = typename concat<
  79. std::index_sequence<l0>,
  80. typename merge<
  81. Pred,
  82. (bool)Pred::template apply<r0, l1>::value,
  83. std::index_sequence<l1, l...>,
  84. std::index_sequence<r0, r...>
  85. >::type
  86. >::type;
  87. };
  88. template <
  89. typename Pred,
  90. std::size_t l0,
  91. std::size_t r0,
  92. std::size_t ...r>
  93. struct merge<
  94. Pred,
  95. false,
  96. std::index_sequence<l0>,
  97. std::index_sequence<r0, r...>
  98. > {
  99. using type = std::index_sequence<l0, r0, r...>;
  100. };
  101. template <
  102. typename Pred,
  103. std::size_t l0,
  104. std::size_t ...l,
  105. std::size_t r0,
  106. std::size_t r1,
  107. std::size_t ...r>
  108. struct merge<
  109. Pred,
  110. true,
  111. std::index_sequence<l0, l...>,
  112. std::index_sequence<r0, r1, r...>
  113. > {
  114. using type = typename concat<
  115. std::index_sequence<r0>,
  116. typename merge<
  117. Pred,
  118. (bool)Pred::template apply<r1, l0>::value,
  119. std::index_sequence<l0, l...>,
  120. std::index_sequence<r1, r...>
  121. >::type
  122. >::type;
  123. };
  124. template <
  125. typename Pred,
  126. std::size_t l0,
  127. std::size_t ...l,
  128. std::size_t r0>
  129. struct merge<
  130. Pred,
  131. true,
  132. std::index_sequence<l0, l...>,
  133. std::index_sequence<r0>
  134. > {
  135. using type = std::index_sequence<r0, l0, l...>;
  136. };
  137. template <typename Pred, typename Left, typename Right>
  138. struct merge_helper;
  139. template <
  140. typename Pred,
  141. std::size_t l0,
  142. std::size_t ...l,
  143. std::size_t r0,
  144. std::size_t ...r>
  145. struct merge_helper<
  146. Pred,
  147. std::index_sequence<l0, l...>,
  148. std::index_sequence<r0, r...>
  149. > {
  150. using type = typename merge<
  151. Pred,
  152. (bool)Pred::template apply<r0, l0>::value,
  153. std::index_sequence<l0, l...>,
  154. std::index_sequence<r0, r...>
  155. >::type;
  156. };
  157. // split templated structure, Nr represents the number of elements
  158. // from Right to move to Left
  159. // There are two specializations:
  160. // The first handles the generic case (Nr > 0)
  161. // The second handles the stop condition (Nr == 0)
  162. // These two specializations are not strictly ordered as
  163. // the first cannot match Nr==0 && empty Right
  164. // the second cannot match Nr!=0
  165. // std::enable_if<Nr!=0> is therefore required to make sure these two
  166. // specializations will never both be candidates during an overload
  167. // resolution (otherwise ambiguity occurs for Nr==0 and non-empty Right)
  168. template <std::size_t Nr, typename Left, typename Right, typename=void>
  169. struct split;
  170. template <
  171. std::size_t Nr,
  172. std::size_t ...l,
  173. std::size_t ...r,
  174. std::size_t r0>
  175. struct split<
  176. Nr,
  177. std::index_sequence<l...>,
  178. std::index_sequence<r0, r...>,
  179. typename std::enable_if<Nr!=0>::type
  180. > {
  181. using sp = split<
  182. Nr-1,
  183. std::index_sequence<l..., r0>,
  184. std::index_sequence<r...>
  185. >;
  186. using left = typename sp::left;
  187. using right = typename sp::right;
  188. };
  189. template <std::size_t ...l, std::size_t ...r>
  190. struct split<0, std::index_sequence<l...>, std::index_sequence<r...>> {
  191. using left = std::index_sequence<l...>;
  192. using right = std::index_sequence<r...>;
  193. };
  194. template <typename Pred, typename Sequence>
  195. struct merge_sort_impl;
  196. template <typename Pred, std::size_t ...seq>
  197. struct merge_sort_impl<Pred, std::index_sequence<seq...>> {
  198. using sequence = std::index_sequence<seq...>;
  199. using sp = split<
  200. sequence::size() / 2,
  201. std::index_sequence<>,
  202. sequence
  203. >;
  204. using type = typename merge_helper<
  205. Pred,
  206. typename merge_sort_impl<Pred, typename sp::left>::type,
  207. typename merge_sort_impl<Pred, typename sp::right>::type
  208. >::type;
  209. };
  210. template <typename Pred, std::size_t x>
  211. struct merge_sort_impl<Pred, std::index_sequence<x>> {
  212. using type = std::index_sequence<x>;
  213. };
  214. template <typename Pred>
  215. struct merge_sort_impl<Pred, std::index_sequence<>> {
  216. using type = std::index_sequence<>;
  217. };
  218. } // end namespace detail
  219. template <typename S, bool condition>
  220. struct sort_impl<S, when<condition>> : default_ {
  221. template <typename Xs, std::size_t ...i>
  222. static constexpr auto apply_impl(Xs&& xs, std::index_sequence<i...>) {
  223. return hana::make<S>(hana::at_c<i>(static_cast<Xs&&>(xs))...);
  224. }
  225. template <typename Xs, typename Pred>
  226. static constexpr auto apply(Xs&& xs, Pred const&) {
  227. constexpr std::size_t Len = decltype(hana::length(xs))::value;
  228. using Indices = typename detail::merge_sort_impl<
  229. detail::sort_predicate<Xs&&, Pred>,
  230. std::make_index_sequence<Len>
  231. >::type;
  232. return apply_impl(static_cast<Xs&&>(xs), Indices{});
  233. }
  234. template <typename Xs>
  235. static constexpr auto apply(Xs&& xs)
  236. { return sort_impl::apply(static_cast<Xs&&>(xs), hana::less); }
  237. };
  238. }} // end namespace boost::hana
  239. #endif // !BOOST_HANA_SORT_HPP