/// \file // Range v3 library // // Copyright Eric Niebler 2013-present // Copyright Casey Carter 2016 // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Project home: https://github.com/ericniebler/range-v3 // #ifndef RANGES_V3_UTILITY_COMPRESSED_PAIR_HPP #define RANGES_V3_UTILITY_COMPRESSED_PAIR_HPP #include <type_traits> #include <utility> #include <meta/meta.hpp> #include <concepts/concepts.hpp> #include <range/v3/range_fwd.hpp> #include <range/v3/utility/box.hpp> #include <range/v3/utility/static_const.hpp> namespace ranges { /// \cond namespace compressed_tuple_detail { // tagging individual elements with the complete type list disambiguates // base classes when composing compressed_tuples recursively. template<typename T, std::size_t I, typename... Ts> using storage = box<T, meta::list<meta::size_t<I>, Ts...>>; template<typename List, typename Indices> struct compressed_tuple_; template<typename... Ts, std::size_t... Is> struct RANGES_EMPTY_BASES compressed_tuple_<meta::list<Ts...>, meta::index_sequence<Is...>> : storage<Ts, Is, Ts...>... { static_assert(same_as<meta::index_sequence<Is...>, meta::make_index_sequence<sizeof...(Is)>>, "What madness is this?!?"); compressed_tuple_() = default; template<typename... Args, meta::if_<meta::and_c<META_IS_CONSTRUCTIBLE(Ts, Args)...>, int> = 0> constexpr compressed_tuple_(Args &&... args) noexcept( meta::strict_and<std::is_nothrow_constructible<storage<Ts, Is, Ts...>, Args>...>::value) : storage<Ts, Is, Ts...>{static_cast<Args &&>(args)}... {} template< typename... Us, meta::if_<meta::and_c<META_IS_CONSTRUCTIBLE(Us, Ts const &)...>, int> = 0> constexpr operator std::tuple<Us...>() const noexcept( meta::strict_and<std::is_nothrow_constructible<Us, Ts const &>...>::value) { return std::tuple<Us...>{get<Is>(*this)...}; } template<std::size_t I, typename T = meta::at_c<meta::list<Ts...>, I>> friend constexpr T & get(compressed_tuple_ & tuple) noexcept { return static_cast<storage<T, I, Ts...> &>(tuple).get(); } template<std::size_t I, typename T = meta::at_c<meta::list<Ts...>, I>> friend constexpr T const & get(compressed_tuple_ const & tuple) noexcept { return static_cast<storage<T, I, Ts...> const &>(tuple).get(); } template<std::size_t I, typename T = meta::at_c<meta::list<Ts...>, I>> friend constexpr T && get(compressed_tuple_ && tuple) noexcept { return static_cast<storage<T, I, Ts...> &&>(tuple).get(); } template<std::size_t I, typename T = meta::at_c<meta::list<Ts...>, I>> friend constexpr T const && get(compressed_tuple_ const && tuple) noexcept { return static_cast<storage<T, I, Ts...> const &&>(tuple).get(); } }; template<typename... Ts> using compressed_tuple RANGES_DEPRECATED( "ranges::compressed_tuple is deprecated.") = compressed_tuple_<meta::list<Ts...>, meta::make_index_sequence<sizeof...(Ts)>>; } // namespace compressed_tuple_detail /// \endcond using compressed_tuple_detail::compressed_tuple; struct make_compressed_tuple_fn { // clang-format off template<typename... Args> constexpr auto CPP_auto_fun(operator())(Args &&... args) (const) ( return compressed_tuple<bind_element_t<Args>...>{static_cast<Args &&>(args)...} ) // clang-format on }; /// \ingroup group-utility /// \sa `make_compressed_tuple_fn` RANGES_INLINE_VARIABLE(make_compressed_tuple_fn, make_compressed_tuple) template<typename First, typename Second> struct RANGES_EMPTY_BASES compressed_pair : box<First, meta::size_t<0>> , box<Second, meta::size_t<1>> { using first_type = First; using second_type = Second; compressed_pair() = default; CPP_template(typename U, typename V)( // requires constructible_from<First, U> && constructible_from<Second, V>) // constexpr compressed_pair(U && u, V && v) noexcept(noexcept(First((U &&) u)) && noexcept(Second((V &&) v))) : box<First, meta::size_t<0>>{(U &&) u} , box<Second, meta::size_t<1>>{(V &&) v} {} constexpr First & first() & { return this->box<First, meta::size_t<0>>::get(); } constexpr First const & first() const & { return this->box<First, meta::size_t<0>>::get(); } constexpr First && first() && { return static_cast<First &&>(this->box<First, meta::size_t<0>>::get()); } constexpr Second & second() & { return this->box<Second, meta::size_t<1>>::get(); } constexpr Second const & second() const & { return this->box<Second, meta::size_t<1>>::get(); } constexpr Second && second() && { return static_cast<Second &&>(this->box<Second, meta::size_t<1>>::get()); } CPP_template(typename F, typename S)( // requires convertible_to<First const &, F> && convertible_to<Second const &, S>) // constexpr operator std::pair<F, S>() const { return std::pair<F, S>{first(), second()}; } }; struct make_compressed_pair_fn { // clang-format off template<typename First, typename Second> constexpr auto CPP_auto_fun(operator())(First &&f, Second &&s) (const) ( return compressed_pair<bind_element_t<First>, bind_element_t<Second>>{ static_cast<First &&>(f), static_cast<Second &&>(s) } ) // clang-format on }; /// \ingroup group-utility /// \sa `make_compressed_pair_fn` RANGES_INLINE_VARIABLE(make_compressed_pair_fn, make_compressed_pair) } // namespace ranges RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS namespace std { template<typename... Ts, size_t... Is> struct tuple_size<::ranges::compressed_tuple_detail::compressed_tuple_< ::meta::list<Ts...>, ::meta::index_sequence<Is...>>> : integral_constant<size_t, sizeof...(Ts)> {}; template<size_t I, typename... Ts, size_t... Is> struct tuple_element<I, ::ranges::compressed_tuple_detail::compressed_tuple_< ::meta::list<Ts...>, ::meta::index_sequence<Is...>>> { using type = ::meta::at_c<::meta::list<Ts...>, I>; }; template<typename First, typename Second> struct tuple_size<::ranges::compressed_pair<First, Second>> : integral_constant<size_t, 2> {}; template<typename First, typename Second> struct tuple_element<0, ::ranges::compressed_pair<First, Second>> { using type = First; }; template<typename First, typename Second> struct tuple_element<1, ::ranges::compressed_pair<First, Second>> { using type = Second; }; } // namespace std RANGES_DIAGNOSTIC_POP #endif