Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

239 строки
8.0 KiB

  1. #pragma once
  2. #include <cpputils/mp/core.h>
  3. #include <cpputils/mp/misc/make.h>
  4. #include <cpputils/mp/misc/tag_of.h>
  5. #include <cpputils/mp/intern/ebo.h>
  6. #include <cpputils/mp/intern/operators_orderable.h>
  7. #include <cpputils/mp/intern/operators_comparable.h>
  8. #include <cpputils/mp/operations/first.h>
  9. #include <cpputils/mp/operations/second.h>
  10. #include <cpputils/mp/operations/compare/less.h>
  11. #include <cpputils/mp/operations/compare/less_equal.h>
  12. #include <cpputils/mp/operations/compare/equal.h>
  13. #include <cpputils/mp/operations/logical/or.h>
  14. #include <cpputils/mp/operations/logical/and.h>
  15. #include <cpputils/mp/operations/logical/not.h>
  16. namespace utl {
  17. namespace mp {
  18. struct tag_pair { };
  19. constexpr auto make_pair = make<tag_pair>;
  20. namespace __impl
  21. {
  22. template<int>
  23. struct pair_index;
  24. }
  25. template<typename First, typename Second>
  26. struct pair :
  27. private intern::ebo<__impl::pair_index<0>, First>,
  28. private intern::ebo<__impl::pair_index<1>, Second>
  29. {
  30. using tag = tag_pair;
  31. using this_type = pair<First, Second>;
  32. // default constructor
  33. template<typename... dummy, typename = enable_if_c<
  34. is_constructible<First, dummy...>::value &&
  35. is_constructible<Second, dummy...>::value>>
  36. constexpr pair()
  37. : intern::ebo<__impl::pair_index<0>, First>()
  38. , intern::ebo<__impl::pair_index<1>, Second>()
  39. { }
  40. // variadic constructors
  41. template<typename... dummy, typename = enable_if_c<
  42. is_constructible<First, const First&, dummy...>::value &&
  43. is_constructible<Second, const Second&, dummy...>::value>>
  44. constexpr pair(First f, Second s)
  45. : intern::ebo<__impl::pair_index<0>, First>(f)
  46. , intern::ebo<__impl::pair_index<1>, Second>(s)
  47. { }
  48. template<typename F, typename S, typename = enable_if_c<
  49. is_convertible<F&&, First>::value &&
  50. is_convertible<S&&, Second>::value>>
  51. constexpr pair(F&& f, S&& s)
  52. : intern::ebo<__impl::pair_index<0>, First>(std::forward<F>(f))
  53. , intern::ebo<__impl::pair_index<1>, Second>(std::forward<S>(s))
  54. { }
  55. // copy and move constructor
  56. template<typename F, typename S, typename = enable_if_c<
  57. is_constructible<First, const F&>::value &&
  58. is_constructible<Second, const S&>::value &&
  59. is_convertible<const F&, First>::value &&
  60. is_convertible<const S&, Second>::value>>
  61. constexpr pair(const pair<F, S>& other)
  62. : intern::ebo<__impl::pair_index<0>, First>(mp::first(other))
  63. , intern::ebo<__impl::pair_index<1>, Second>(mp::second(other))
  64. { }
  65. template<typename F, typename S, typename = enable_if_c<
  66. is_constructible<First, const F&>::value &&
  67. is_constructible<Second, const S&>::value &&
  68. is_convertible<const F&, First>::value &&
  69. is_convertible<const S&, Second>::value>>
  70. constexpr pair(pair<F, S>&& other)
  71. : intern::ebo<__impl::pair_index<0>, First>(mp::first(std::forward<pair<F, S>>(other)))
  72. , intern::ebo<__impl::pair_index<1>, Second>(mp::second(std::forward<pair<F, S>>(other)))
  73. { }
  74. // copy and move assignment
  75. template <typename F, typename S, typename = enable_if_c<
  76. is_assignable<First&, const F&>::value &&
  77. is_assignable<Second&, const S&>::value>>
  78. constexpr pair& operator=(const pair<F, S>& other) {
  79. mp::first(*this) = mp::first(other);
  80. mp::second(*this) = mp::second(other);
  81. return *this;
  82. }
  83. template <typename F, typename S, typename = enable_if_c<
  84. is_assignable<First&, const F &>::value &&
  85. is_assignable<Second&, const S &>::value>>
  86. constexpr pair& operator=(pair<F, S>&& other) {
  87. mp::first(*this) = mp::first(std::move<pair<F, S>>(other));
  88. mp::second(*this) = mp::second(std::move<pair<F, S>>(other));
  89. return *this;
  90. }
  91. constexpr auto first() const
  92. { return mp::first(*this); }
  93. constexpr auto second() const
  94. { return mp::second(*this); }
  95. // Prevent the compiler from defining the default copy and move
  96. // constructors, which interfere with the SFINAE above.
  97. ~pair() = default;
  98. friend struct __impl::first_impl<tag_pair>;
  99. friend struct __impl::second_impl<tag_pair>;
  100. };
  101. namespace intern {
  102. template<>
  103. struct operators_comparable<tag_pair>
  104. { static constexpr bool value = true; };
  105. template<>
  106. struct operators_orderable<tag_pair>
  107. { static constexpr bool value = true; };
  108. }
  109. namespace __impl
  110. {
  111. /* tag_of */
  112. template<typename First, typename Second>
  113. struct tag_of_impl<pair<First, Second>>
  114. { using type = tag_pair; };
  115. /* make */
  116. template<>
  117. struct make_impl<tag_pair>
  118. {
  119. template<typename F, typename S>
  120. static constexpr pair<decay_type<F>, decay_type<S>> apply(F&& f, S&& s)
  121. { return { static_cast<F&&>(f), static_cast<S&&>(s) }; }
  122. };
  123. /* first */
  124. template<>
  125. struct first_impl<tag_pair>
  126. {
  127. using type = int;
  128. template<typename First, typename Second>
  129. static constexpr auto apply(pair<First, Second>& p)
  130. {
  131. return intern::ebo_get<pair_index<0>>(
  132. static_cast<intern::ebo<pair_index<0>, First>&>(p)
  133. );
  134. }
  135. template<typename First, typename Second>
  136. static constexpr auto apply(pair<First, Second>&& p)
  137. {
  138. return intern::ebo_get<pair_index<0>>(
  139. static_cast<intern::ebo<pair_index<0>, First>&&>(p)
  140. );
  141. }
  142. template<typename First, typename Second>
  143. static constexpr auto apply(const pair<First, Second>& p)
  144. {
  145. return intern::ebo_get<pair_index<0>>(
  146. static_cast<const intern::ebo<pair_index<0>, First>&>(p)
  147. );
  148. }
  149. };
  150. /* second */
  151. template<>
  152. struct second_impl<tag_pair>
  153. {
  154. template<typename First, typename Second>
  155. static constexpr auto apply(pair<First, Second>& p)
  156. {
  157. return intern::ebo_get<pair_index<1>>(
  158. static_cast<intern::ebo<pair_index<1>, Second>&>(p)
  159. );
  160. }
  161. template<typename First, typename Second>
  162. static constexpr auto apply(pair<First, Second>&& p)
  163. {
  164. return intern::ebo_get<pair_index<1>>(
  165. static_cast<intern::ebo<pair_index<1>, Second>&&>(p)
  166. );
  167. }
  168. template<typename First, typename Second>
  169. static constexpr auto apply(const pair<First, Second>& p)
  170. {
  171. return intern::ebo_get<pair_index<1>>(
  172. static_cast<const intern::ebo<pair_index<1>, Second>&>(p)
  173. );
  174. }
  175. };
  176. /* equal */
  177. template<>
  178. struct equal_impl<tag_pair, tag_pair>
  179. {
  180. template<typename L, typename R>
  181. static constexpr auto apply(const L& l, const R& r)
  182. {
  183. return and_(
  184. equal(first(l), first(r)),
  185. equal(second(l), second(r)));
  186. }
  187. };
  188. /* less */
  189. template<>
  190. struct less_impl<tag_pair, tag_pair>
  191. {
  192. template<typename L, typename R>
  193. static constexpr auto apply(const L& l, const R& r)
  194. {
  195. return or_(
  196. less(first(l), first(r)),
  197. and_(
  198. less_equal(first (l), first (r)),
  199. less (second(l), second(r))
  200. )
  201. );
  202. }
  203. };
  204. }
  205. }
  206. }