compressed_pair.hpp 7.7 KB

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