/// \file // Range v3 library // // Copyright Eric Niebler 2013-present // // 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_COMMON_TUPLE_HPP #define RANGES_V3_UTILITY_COMMON_TUPLE_HPP #include #include #include #include #include #include #include #include #include namespace ranges { /// \cond namespace detail { template std::tuple to_std_tuple(Tup && tup, meta::index_sequence) { return std::tuple{adl_get(static_cast(tup))...}; } #ifdef RANGES_WORKAROUND_MSVC_786312 template struct args_; template inline constexpr bool argstructible = false; template inline constexpr bool argstructible, args_> = (META_IS_CONSTRUCTIBLE(Ts, Us) && ...); template inline constexpr bool argsignable = false; template inline constexpr bool argsignable, args_> = (std::is_assignable_v && ...); #endif // RANGES_WORKAROUND_MSVC_786312 template struct args_ { template args_(args_, meta::if_c< #ifdef RANGES_WORKAROUND_MSVC_786312 argstructible> #else // ^^^ workaround / no workaround vvv meta::and_c::value #endif // RANGES_WORKAROUND_MSVC_786312 > * = nullptr) {} template meta::if_c< #ifdef RANGES_WORKAROUND_MSVC_786312 argsignable>, #else // ^^^ workaround / no workaround vvv meta::and_c::value...>::value, #endif // RANGES_WORKAROUND_MSVC_786312 args_ &> operator=(args_) { return *this; } }; template using args = args_; template using rargs = args_; } // namespace detail /// \endcond template struct common_tuple : _tuple_wrapper_::forward_tuple_interface> { private: template common_tuple(That && that, meta::index_sequence) : common_tuple::forward_tuple_interface{ detail::adl_get(static_cast(that))...} {} struct element_assign_ { template int operator()(T & t, U && u) const { t = static_cast(u); return 0; } }; public: // Construction CPP_member CPP_ctor(common_tuple)()( // noexcept(meta::and_c< std::is_nothrow_default_constructible::value...>::value) // requires default_constructible>) : common_tuple::forward_tuple_interface{} {} CPP_template(typename... Us)( // requires constructible_from, detail::args>) // explicit common_tuple(Us &&... us) noexcept( meta::and_c::value...>::value) : common_tuple::forward_tuple_interface{static_cast(us)...} {} template CPP_ctor(common_tuple)(std::tuple & that)( // noexcept( meta::and_c::value...>::value) // requires constructible_from, detail::rargs>) : common_tuple(that, meta::make_index_sequence{}) {} template CPP_ctor(common_tuple)(std::tuple const & that)( // noexcept(meta::and_c< std::is_nothrow_constructible::value...>::value) // requires constructible_from, detail::rargs>) : common_tuple(that, meta::make_index_sequence{}) {} template CPP_ctor(common_tuple)(std::tuple && that)( // noexcept( meta::and_c::value...>::value) // requires constructible_from, detail::args>) : common_tuple(std::move(that), meta::make_index_sequence{}) {} template CPP_ctor(common_tuple)(common_tuple & that)( // noexcept( meta::and_c::value...>::value) // requires constructible_from, detail::rargs>) : common_tuple(that, meta::make_index_sequence{}) {} template CPP_ctor(common_tuple)(common_tuple const & that)( // noexcept(meta::and_c< std::is_nothrow_constructible::value...>::value) // requires constructible_from, detail::rargs>) : common_tuple(that, meta::make_index_sequence{}) {} template CPP_ctor(common_tuple)(common_tuple && that)( // noexcept( meta::and_c::value...>::value) // requires constructible_from, detail::args>) : common_tuple(std::move(that), meta::make_index_sequence{}) {} std::tuple & base() noexcept { return *this; } std::tuple const & base() const noexcept { return *this; } // Assignment template auto operator=(std::tuple & that) noexcept( meta::and_c::value...>::value) -> CPP_ret(common_tuple &)( // requires assignable_from &, detail::rargs>) { (void)tuple_transform(base(), that, element_assign_{}); return *this; } template auto operator=(std::tuple const & that) noexcept( meta::and_c::value...>::value) -> CPP_ret(common_tuple &)( // requires assignable_from &, detail::rargs>) { (void)tuple_transform(base(), that, element_assign_{}); return *this; } template auto operator=(std::tuple && that) noexcept( meta::and_c::value...>::value) -> CPP_ret(common_tuple &)( // requires assignable_from &, detail::args>) { (void)tuple_transform(base(), std::move(that), element_assign_{}); return *this; } template auto operator=(std::tuple & that) const noexcept( meta::and_c::value...>::value) -> CPP_ret(common_tuple const &)( // requires assignable_from &, detail::rargs>) { (void)tuple_transform(base(), that, element_assign_{}); return *this; } template auto operator=(std::tuple const & that) const noexcept(meta::and_c< std::is_nothrow_assignable::value...>::value) -> CPP_ret(common_tuple const &)( // requires assignable_from &, detail::rargs>) { (void)tuple_transform(base(), that, element_assign_{}); return *this; } template auto operator=(std::tuple && that) const noexcept( meta::and_c::value...>::value) -> CPP_ret(common_tuple const &)( // requires assignable_from &, detail::args>) { (void)tuple_transform(base(), std::move(that), element_assign_{}); return *this; } // Conversion CPP_template(typename... Us)( // requires constructible_from, detail::rargs>) // operator std::tuple() & noexcept( meta::and_c::value...>::value) { return detail::to_std_tuple( *this, meta::make_index_sequence{}); } CPP_template(typename... Us)( // requires constructible_from, detail::rargs>) // operator std::tuple() const & noexcept( meta::and_c::value...>::value) { return detail::to_std_tuple( *this, meta::make_index_sequence{}); } CPP_template(typename... Us)( // requires constructible_from, detail::args>) // operator std::tuple() && noexcept(meta::and_c::value...>::value) { return detail::to_std_tuple( std::move(*this), meta::make_index_sequence{}); } }; // Logical operators #define LOGICAL_OP(OP, CONCEPT) \ template \ auto operator OP(common_tuple const & a, common_tuple const & b) \ ->CPP_ret(bool)(requires and_v...>) \ { \ return a.base() OP b.base(); \ } \ template \ auto operator OP(std::tuple const & a, common_tuple const & b) \ ->CPP_ret(bool)(requires and_v...>) \ { \ return a OP b.base(); \ } \ template \ auto operator OP(common_tuple const & a, std::tuple const & b) \ ->CPP_ret(bool)(requires and_v...>) \ { \ return a.base() OP b; \ } \ /**/ LOGICAL_OP(==, equality_comparable_with) LOGICAL_OP(!=, equality_comparable_with) LOGICAL_OP(<, totally_ordered_with) LOGICAL_OP(<=, totally_ordered_with) LOGICAL_OP(>, totally_ordered_with) LOGICAL_OP(>=, totally_ordered_with) #undef LOGICAL_OP struct make_common_tuple_fn { template common_tuple...> operator()(Args &&... args) const noexcept( meta::and_c, unwrap_reference_t>::value...>::value) { return common_tuple...>{ unwrap_reference(static_cast(args))...}; } }; /// \ingroup group-utility /// \sa `make_common_tuple_fn` RANGES_INLINE_VARIABLE(make_common_tuple_fn, make_common_tuple) template struct common_pair : std::pair { private: std::pair const & base() const noexcept { return *this; } public: // Construction CPP_member CPP_ctor(common_pair)()( // noexcept(std::is_nothrow_default_constructible::value && std::is_nothrow_default_constructible::value) // requires default_constructible && default_constructible) : std::pair{} {} template CPP_ctor(common_pair)(F2 && f2, S2 && s2)( // noexcept(std::is_nothrow_constructible::value && std::is_nothrow_constructible::value) // requires constructible_from && constructible_from) : std::pair{static_cast(f2), static_cast(s2)} {} template CPP_ctor(common_pair)(std::pair & that)( // noexcept(std::is_nothrow_constructible::value && std::is_nothrow_constructible::value) // requires constructible_from && constructible_from) : std::pair{that.first, that.second} {} template CPP_ctor(common_pair)(std::pair const & that)( // noexcept(std::is_nothrow_constructible::value && std::is_nothrow_constructible::value) // requires constructible_from && constructible_from) : std::pair{that.first, that.second} {} template CPP_ctor(common_pair)(std::pair && that)( // noexcept(std::is_nothrow_constructible::value && std::is_nothrow_constructible::value) // requires constructible_from && constructible_from) : std::pair{std::forward(that.first), std::forward(that.second)} {} // Conversion CPP_template(typename F2, typename S2)( // requires constructible_from && constructible_from) // operator std::pair() & noexcept(std::is_nothrow_constructible::value && std::is_nothrow_constructible::value) { return {this->first, this->second}; } CPP_template(typename F2, typename S2)( // requires constructible_from && constructible_from) // operator std::pair() const & noexcept( std::is_nothrow_constructible::value && std::is_nothrow_constructible::value) { return {this->first, this->second}; } CPP_template(typename F2, typename S2)( // requires constructible_from && constructible_from) // operator std::pair() && noexcept(std::is_nothrow_constructible::value && std::is_nothrow_constructible::value) { return {std::forward(this->first), std::forward(this->second)}; } // Assignment template auto operator=(std::pair & that) noexcept( std::is_nothrow_assignable::value && std::is_nothrow_assignable::value) -> CPP_ret(common_pair &)( // requires assignable_from && assignable_from) { this->first = that.first; this->second = that.second; return *this; } template auto operator=(std::pair const & that) noexcept( std::is_nothrow_assignable::value && std::is_nothrow_assignable::value) -> CPP_ret(common_pair &)( // requires assignable_from && assignable_from) { this->first = that.first; this->second = that.second; return *this; } template auto operator=(std::pair && that) noexcept( std::is_nothrow_assignable::value && std::is_nothrow_assignable::value) -> CPP_ret(common_pair &)( // requires assignable_from && assignable_from) { this->first = static_cast(that.first); this->second = static_cast(that.second); return *this; } template auto operator=(std::pair & that) const noexcept(std::is_nothrow_assignable::value && std::is_nothrow_assignable::value) -> CPP_ret(common_pair const &)( // requires assignable_from && assignable_from) { this->first = that.first; this->second = that.second; return *this; } template auto operator=(std::pair const & that) const noexcept(std::is_nothrow_assignable::value && std::is_nothrow_assignable::value) -> CPP_ret(common_pair const &)( // requires assignable_from && assignable_from) { this->first = that.first; this->second = that.second; return *this; } template auto operator=(std::pair && that) const noexcept( std::is_nothrow_assignable::value && std::is_nothrow_assignable::value) -> CPP_ret(common_pair const &)( // requires assignable_from && assignable_from) { this->first = static_cast(that.first); this->second = static_cast(that.second); return *this; } }; // Logical operators template auto operator==(common_pair const & a, common_pair const & b) -> CPP_ret(bool)( // requires equality_comparable_with && equality_comparable_with) { return a.first == b.first && a.second == b.second; } template auto operator==(common_pair const & a, std::pair const & b) -> CPP_ret(bool)( // requires equality_comparable_with && equality_comparable_with) { return a.first == b.first && a.second == b.second; } template auto operator==(std::pair const & a, common_pair const & b) -> CPP_ret(bool)( // requires equality_comparable_with && equality_comparable_with) { return a.first == b.first && a.second == b.second; } template auto operator<(common_pair const & a, common_pair const & b) -> CPP_ret(bool)( // requires totally_ordered_with && totally_ordered_with) { return a.first < b.first || (!(b.first < a.first) && a.second < b.second); } template auto operator<(std::pair const & a, common_pair const & b) -> CPP_ret(bool)( // requires totally_ordered_with && totally_ordered_with) { return a.first < b.first || (!(b.first < a.first) && a.second < b.second); } template auto operator<(common_pair const & a, std::pair const & b) -> CPP_ret(bool)( // requires totally_ordered_with && totally_ordered_with) { return a.first < b.first || (!(b.first < a.first) && a.second < b.second); } #define LOGICAL_OP(OP, CONCEPT, RET) \ template \ auto operator OP(common_pair const & a, common_pair const & b) \ ->CPP_ret(bool)(requires CONCEPT && CONCEPT) \ { \ return RET; \ } \ template \ auto operator OP(std::pair const & a, common_pair const & b) \ ->CPP_ret(bool)(requires CONCEPT && CONCEPT) \ { \ return RET; \ } \ template \ auto operator OP(common_pair const & a, std::pair const & b) \ ->CPP_ret(bool)(requires CONCEPT && CONCEPT) \ { \ return RET; \ } \ /**/ LOGICAL_OP(!=, equality_comparable_with, !(a == b)) LOGICAL_OP(<=, totally_ordered_with, !(b < a)) LOGICAL_OP(>, totally_ordered_with, (b < a)) LOGICAL_OP(>=, totally_ordered_with, !(a < b)) #undef LOGICAL_OP struct make_common_pair_fn { template, typename S = bind_element_t> common_pair operator()(First && f, Second && s) const noexcept( std::is_nothrow_constructible>::value && std::is_nothrow_constructible>::value) { return {unwrap_reference(static_cast(f)), unwrap_reference(static_cast(s))}; } }; /// \ingroup group-utility /// \sa `make_common_pair_fn` RANGES_INLINE_VARIABLE(make_common_pair_fn, make_common_pair) /// \cond namespace detail { template struct common_type_tuple_like {}; template class T0, typename... Ts, template class T1, typename... Us, typename TupleLike> struct common_type_tuple_like, T1, TupleLike, meta::if_c> : meta::lazy::let< meta::lazy::invoke>...>> {}; template using make_common_pair = meta::if_, std::is_reference>, common_pair, std::pair>; template using make_common_tuple = meta::if_, meta::quote>, common_tuple, std::tuple>; template struct common_ref_tuple_like {}; template class T0, typename... Ts, template class T1, typename... Us, typename TupleLike> struct common_ref_tuple_like, T1, TupleLike, meta::if_c> : meta::lazy::let>...>> {}; } // namespace detail /// \endcond } // namespace ranges /// \cond namespace concepts { // common_type for pairs template struct common_type, ranges::common_pair> : ranges::detail::common_type_tuple_like< std::pair, ranges::common_pair, meta::quote> {}; template struct common_type, std::pair> : ranges::detail::common_type_tuple_like< ranges::common_pair, std::pair, meta::quote> {}; template struct common_type, ranges::common_pair> : ranges::detail::common_type_tuple_like, ranges::common_pair, meta::quote> {}; // common_type for tuples template struct common_type, std::tuple> : ranges::detail::common_type_tuple_like< ranges::common_tuple, std::tuple, meta::quote> {}; template struct common_type, ranges::common_tuple> : ranges::detail::common_type_tuple_like< std::tuple, ranges::common_tuple, meta::quote> {}; template struct common_type, ranges::common_tuple> : ranges::detail::common_type_tuple_like, ranges::common_tuple, meta::quote> {}; // common reference for pairs template class Qual1, template class Qual2> struct basic_common_reference, std::pair, Qual1, Qual2> : ranges::detail::common_ref_tuple_like< ranges::common_pair, Qual1>, std::pair, Qual2>, meta::quote> {}; template class Qual1, template class Qual2> struct basic_common_reference, ranges::common_pair, Qual1, Qual2> : ranges::detail::common_ref_tuple_like< std::pair, Qual1>, ranges::common_pair, Qual2>, meta::quote> {}; template class Qual1, template class Qual2> struct basic_common_reference, ranges::common_pair, Qual1, Qual2> : ranges::detail::common_ref_tuple_like, Qual1>, ranges::common_pair, Qual2>, meta::quote> {}; // common reference for tuples template class Qual1, template class Qual2> struct basic_common_reference, std::tuple, Qual1, Qual2> : ranges::detail::common_ref_tuple_like< ranges::common_tuple...>, std::tuple...>, meta::quote> {}; template class Qual1, template class Qual2> struct basic_common_reference, ranges::common_tuple, Qual1, Qual2> : ranges::detail::common_ref_tuple_like< std::tuple...>, ranges::common_tuple...>, meta::quote> {}; template class Qual1, template class Qual2> struct basic_common_reference, ranges::common_tuple, Qual1, Qual2> : ranges::detail::common_ref_tuple_like...>, ranges::common_tuple...>, meta::quote> {}; } // namespace concepts /// \endcond RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS namespace std { template struct tuple_size<::ranges::common_pair> : std::integral_constant {}; template struct tuple_element<0, ::ranges::common_pair> { using type = First; }; template struct tuple_element<1, ::ranges::common_pair> { using type = Second; }; template struct tuple_size<::ranges::common_tuple> : std::integral_constant {}; template struct tuple_element> : tuple_element> {}; } // namespace std RANGES_DIAGNOSTIC_POP #endif