You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

227 lines
7.8KB

  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2013-present
  5. // Copyright Casey Carter 2016
  6. //
  7. // Use, modification and distribution is subject to the
  8. // Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. //
  12. // Project home: https://github.com/ericniebler/range-v3
  13. //
  14. #ifndef RANGES_V3_UTILITY_COMPRESSED_PAIR_HPP
  15. #define RANGES_V3_UTILITY_COMPRESSED_PAIR_HPP
  16. #include <type_traits>
  17. #include <utility>
  18. #include <meta/meta.hpp>
  19. #include <concepts/concepts.hpp>
  20. #include <range/v3/range_fwd.hpp>
  21. #include <range/v3/utility/box.hpp>
  22. #include <range/v3/utility/static_const.hpp>
  23. namespace ranges
  24. {
  25. /// \cond
  26. namespace compressed_tuple_detail
  27. {
  28. // tagging individual elements with the complete type list disambiguates
  29. // base classes when composing compressed_tuples recursively.
  30. template<typename T, std::size_t I, typename... Ts>
  31. using storage = box<T, meta::list<meta::size_t<I>, Ts...>>;
  32. template<typename List, typename Indices>
  33. struct compressed_tuple_;
  34. template<typename... Ts, std::size_t... Is>
  35. struct RANGES_EMPTY_BASES
  36. compressed_tuple_<meta::list<Ts...>, meta::index_sequence<Is...>>
  37. : storage<Ts, Is, Ts...>...
  38. {
  39. static_assert(same_as<meta::index_sequence<Is...>,
  40. meta::make_index_sequence<sizeof...(Is)>>,
  41. "What madness is this?!?");
  42. compressed_tuple_() = default;
  43. template<typename... Args,
  44. meta::if_<meta::and_c<META_IS_CONSTRUCTIBLE(Ts, Args)...>, int> = 0>
  45. constexpr compressed_tuple_(Args &&... args) noexcept(
  46. meta::strict_and<std::is_nothrow_constructible<storage<Ts, Is, Ts...>,
  47. Args>...>::value)
  48. : storage<Ts, Is, Ts...>{static_cast<Args &&>(args)}...
  49. {}
  50. template<
  51. typename... Us,
  52. meta::if_<meta::and_c<META_IS_CONSTRUCTIBLE(Us, Ts const &)...>, int> = 0>
  53. constexpr operator std::tuple<Us...>() const noexcept(
  54. meta::strict_and<std::is_nothrow_constructible<Us, Ts const &>...>::value)
  55. {
  56. return std::tuple<Us...>{get<Is>(*this)...};
  57. }
  58. template<std::size_t I, typename T = meta::at_c<meta::list<Ts...>, I>>
  59. friend constexpr T & get(compressed_tuple_ & tuple) noexcept
  60. {
  61. return static_cast<storage<T, I, Ts...> &>(tuple).get();
  62. }
  63. template<std::size_t I, typename T = meta::at_c<meta::list<Ts...>, I>>
  64. friend constexpr T const & get(compressed_tuple_ const & tuple) noexcept
  65. {
  66. return static_cast<storage<T, I, Ts...> const &>(tuple).get();
  67. }
  68. template<std::size_t I, typename T = meta::at_c<meta::list<Ts...>, I>>
  69. friend constexpr T && get(compressed_tuple_ && tuple) noexcept
  70. {
  71. return static_cast<storage<T, I, Ts...> &&>(tuple).get();
  72. }
  73. template<std::size_t I, typename T = meta::at_c<meta::list<Ts...>, I>>
  74. friend constexpr T const && get(compressed_tuple_ const && tuple) noexcept
  75. {
  76. return static_cast<storage<T, I, Ts...> const &&>(tuple).get();
  77. }
  78. };
  79. template<typename... Ts>
  80. using compressed_tuple RANGES_DEPRECATED(
  81. "ranges::compressed_tuple is deprecated.") =
  82. compressed_tuple_<meta::list<Ts...>,
  83. meta::make_index_sequence<sizeof...(Ts)>>;
  84. } // namespace compressed_tuple_detail
  85. /// \endcond
  86. using compressed_tuple_detail::compressed_tuple;
  87. struct make_compressed_tuple_fn
  88. {
  89. // clang-format off
  90. template<typename... Args>
  91. constexpr auto CPP_auto_fun(operator())(Args &&... args) (const)
  92. (
  93. return compressed_tuple<bind_element_t<Args>...>{static_cast<Args &&>(args)...}
  94. )
  95. // clang-format on
  96. };
  97. /// \ingroup group-utility
  98. /// \sa `make_compressed_tuple_fn`
  99. RANGES_INLINE_VARIABLE(make_compressed_tuple_fn, make_compressed_tuple)
  100. template<typename First, typename Second>
  101. struct RANGES_EMPTY_BASES compressed_pair
  102. : box<First, meta::size_t<0>>
  103. , box<Second, meta::size_t<1>>
  104. {
  105. using first_type = First;
  106. using second_type = Second;
  107. compressed_pair() = default;
  108. CPP_template(typename U, typename V)( //
  109. requires constructible_from<First, U> && constructible_from<Second, V>) //
  110. constexpr compressed_pair(U && u,
  111. V && v) noexcept(noexcept(First((U &&) u)) &&
  112. noexcept(Second((V &&) v)))
  113. : box<First, meta::size_t<0>>{(U &&) u}
  114. , box<Second, meta::size_t<1>>{(V &&) v}
  115. {}
  116. constexpr First & first() &
  117. {
  118. return this->box<First, meta::size_t<0>>::get();
  119. }
  120. constexpr First const & first() const &
  121. {
  122. return this->box<First, meta::size_t<0>>::get();
  123. }
  124. constexpr First && first() &&
  125. {
  126. return static_cast<First &&>(this->box<First, meta::size_t<0>>::get());
  127. }
  128. constexpr Second & second() &
  129. {
  130. return this->box<Second, meta::size_t<1>>::get();
  131. }
  132. constexpr Second const & second() const &
  133. {
  134. return this->box<Second, meta::size_t<1>>::get();
  135. }
  136. constexpr Second && second() &&
  137. {
  138. return static_cast<Second &&>(this->box<Second, meta::size_t<1>>::get());
  139. }
  140. CPP_template(typename F, typename S)( //
  141. requires convertible_to<First const &, F> &&
  142. convertible_to<Second const &, S>) //
  143. constexpr
  144. operator std::pair<F, S>() const
  145. {
  146. return std::pair<F, S>{first(), second()};
  147. }
  148. };
  149. struct make_compressed_pair_fn
  150. {
  151. // clang-format off
  152. template<typename First, typename Second>
  153. constexpr auto CPP_auto_fun(operator())(First &&f, Second &&s) (const)
  154. (
  155. return compressed_pair<bind_element_t<First>, bind_element_t<Second>>{
  156. static_cast<First &&>(f), static_cast<Second &&>(s)
  157. }
  158. )
  159. // clang-format on
  160. };
  161. /// \ingroup group-utility
  162. /// \sa `make_compressed_pair_fn`
  163. RANGES_INLINE_VARIABLE(make_compressed_pair_fn, make_compressed_pair)
  164. } // namespace ranges
  165. RANGES_DIAGNOSTIC_PUSH
  166. RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
  167. namespace std
  168. {
  169. template<typename... Ts, size_t... Is>
  170. struct tuple_size<::ranges::compressed_tuple_detail::compressed_tuple_<
  171. ::meta::list<Ts...>, ::meta::index_sequence<Is...>>>
  172. : integral_constant<size_t, sizeof...(Ts)>
  173. {};
  174. template<size_t I, typename... Ts, size_t... Is>
  175. struct tuple_element<I, ::ranges::compressed_tuple_detail::compressed_tuple_<
  176. ::meta::list<Ts...>, ::meta::index_sequence<Is...>>>
  177. {
  178. using type = ::meta::at_c<::meta::list<Ts...>, I>;
  179. };
  180. template<typename First, typename Second>
  181. struct tuple_size<::ranges::compressed_pair<First, Second>>
  182. : integral_constant<size_t, 2>
  183. {};
  184. template<typename First, typename Second>
  185. struct tuple_element<0, ::ranges::compressed_pair<First, Second>>
  186. {
  187. using type = First;
  188. };
  189. template<typename First, typename Second>
  190. struct tuple_element<1, ::ranges::compressed_pair<First, Second>>
  191. {
  192. using type = Second;
  193. };
  194. } // namespace std
  195. RANGES_DIAGNOSTIC_POP
  196. #endif