/// \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 #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::value...>::value) requires default_constructible>) : common_tuple::forward_tuple_interface{} {} 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(typename... Us)( requires constructible_from, detail::rargs>) common_tuple(std::tuple & that) // noexcept( meta::and_c::value...>::value) // : common_tuple(that, meta::make_index_sequence{}) {} template(typename... Us)( requires constructible_from, detail::rargs>) common_tuple(std::tuple const & that) // noexcept(meta::and_c< std::is_nothrow_constructible::value...>::value) // : common_tuple(that, meta::make_index_sequence{}) {} template(typename... Us)( requires constructible_from, detail::args>) common_tuple(std::tuple && that) // noexcept( meta::and_c::value...>::value) // : common_tuple(std::move(that), meta::make_index_sequence{}) {} template(typename... Us)( requires constructible_from, detail::rargs>) common_tuple(common_tuple & that) // noexcept( meta::and_c::value...>::value) // : common_tuple(that, meta::make_index_sequence{}) {} template(typename... Us)( requires constructible_from, detail::rargs>) common_tuple(common_tuple const & that) // noexcept(meta::and_c< std::is_nothrow_constructible::value...>::value) // : common_tuple(that, meta::make_index_sequence{}) {} template(typename... Us)( requires constructible_from, detail::args>) common_tuple(common_tuple && that) // noexcept( meta::and_c::value...>::value) // : 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(typename... Us)( requires std::is_assignable &, detail::rargs>::value) // common_tuple & operator=(std::tuple & that) noexcept( meta::and_c::value...>::value) { (void)tuple_transform(base(), that, element_assign_{}); return *this; } template(typename... Us)( requires std::is_assignable &, detail::rargs>::value) // common_tuple & operator=(std::tuple const & that) noexcept( meta::and_c::value...>::value) { (void)tuple_transform(base(), that, element_assign_{}); return *this; } template(typename... Us)( requires std::is_assignable &, detail::args>::value) // common_tuple & operator=(std::tuple && that) noexcept( meta::and_c::value...>::value) { (void)tuple_transform(base(), std::move(that), element_assign_{}); return *this; } template(typename... Us)( requires std::is_assignable &, detail::rargs>::value) common_tuple const & operator=(std::tuple & that) const noexcept( meta::and_c::value...>::value) { (void)tuple_transform(base(), that, element_assign_{}); return *this; } template(typename... Us)( requires std::is_assignable &, detail::rargs>::value) common_tuple const & operator=(std::tuple const & that) const noexcept(meta::and_c< std::is_nothrow_assignable::value...>::value) { (void)tuple_transform(base(), that, element_assign_{}); return *this; } template(typename... Us)( requires std::is_assignable &, detail::args>::value) common_tuple const & operator=(std::tuple && that) const noexcept( meta::and_c::value...>::value) { (void)tuple_transform(base(), std::move(that), element_assign_{}); return *this; } // Conversion 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{}); } 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{}); } 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(typename... Ts, typename... Us)( \ requires and_v...>) \ bool operator OP(common_tuple const & a, common_tuple const & b) \ { \ return a.base() OP b.base(); \ } \ template(typename... Ts, typename... Us)( \ requires and_v...>) \ bool operator OP(std::tuple const & a, common_tuple const & b) \ { \ return a OP b.base(); \ } \ template(typename... Ts, typename... Us)( \ requires and_v...>) \ bool operator OP(common_tuple const & a, std::tuple const & b) \ { \ 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(typename F2, typename S2)( requires constructible_from AND constructible_from) common_pair(F2 && f2, S2 && s2) // noexcept(std::is_nothrow_constructible::value && std::is_nothrow_constructible::value) // : std::pair{static_cast(f2), static_cast(s2)} {} template(typename F2, typename S2)( requires constructible_from AND constructible_from) common_pair(std::pair & that) // noexcept(std::is_nothrow_constructible::value && std::is_nothrow_constructible::value) // : std::pair{that.first, that.second} {} template(typename F2, typename S2)( requires constructible_from AND constructible_from) common_pair(std::pair const & that) // noexcept(std::is_nothrow_constructible::value && std::is_nothrow_constructible::value) // : std::pair{that.first, that.second} {} template(typename F2, typename S2)( requires constructible_from AND constructible_from) common_pair(std::pair && that) // noexcept(std::is_nothrow_constructible::value && std::is_nothrow_constructible::value) // : std::pair{std::forward(that.first), std::forward(that.second)} {} // Conversion template(typename F2, typename S2)( requires constructible_from AND constructible_from) operator std::pair() & // noexcept(std::is_nothrow_constructible::value && std::is_nothrow_constructible::value) { return {this->first, this->second}; } template(typename F2, typename S2)( requires constructible_from AND constructible_from) operator std::pair() const & // noexcept(std::is_nothrow_constructible::value && std::is_nothrow_constructible::value) { return {this->first, this->second}; } template(typename F2, typename S2)( requires constructible_from AND 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(typename F2, typename S2)( requires assignable_from AND assignable_from) common_pair & operator=(std::pair & that) // noexcept(std::is_nothrow_assignable::value && std::is_nothrow_assignable::value) { this->first = that.first; this->second = that.second; return *this; } template(typename F2, typename S2)( requires assignable_from AND assignable_from) common_pair & operator=(std::pair const & that) // noexcept(std::is_nothrow_assignable::value && std::is_nothrow_assignable::value) { this->first = that.first; this->second = that.second; return *this; } template(typename F2, typename S2)( requires assignable_from AND assignable_from) common_pair & operator=(std::pair && that) // noexcept(std::is_nothrow_assignable::value && std::is_nothrow_assignable::value) { this->first = static_cast(that.first); this->second = static_cast(that.second); return *this; } template(typename F2, typename S2)( requires assignable_from AND assignable_from) common_pair const & operator=(std::pair & that) const // noexcept(std::is_nothrow_assignable::value && std::is_nothrow_assignable::value) { this->first = that.first; this->second = that.second; return *this; } template(typename F2, typename S2)( requires assignable_from AND assignable_from) common_pair const & operator=(std::pair const & that) const // noexcept(std::is_nothrow_assignable::value && std::is_nothrow_assignable::value) { this->first = that.first; this->second = that.second; return *this; } template(typename F2, typename S2)( requires assignable_from AND assignable_from) common_pair const & operator=(std::pair && that) const // noexcept(std::is_nothrow_assignable::value && std::is_nothrow_assignable::value) { this->first = static_cast(that.first); this->second = static_cast(that.second); return *this; } }; // Logical operators template(typename F1, typename S1, typename F2, typename S2)( requires equality_comparable_with AND equality_comparable_with) bool operator==(common_pair const & a, common_pair const & b) { return a.first == b.first && a.second == b.second; } template(typename F1, typename S1, typename F2, typename S2)( requires equality_comparable_with AND equality_comparable_with) bool operator==(common_pair const & a, std::pair const & b) { return a.first == b.first && a.second == b.second; } template(typename F1, typename S1, typename F2, typename S2)( requires equality_comparable_with AND equality_comparable_with) bool operator==(std::pair const & a, common_pair const & b) { return a.first == b.first && a.second == b.second; } template(typename F1, typename S1, typename F2, typename S2)( requires totally_ordered_with AND totally_ordered_with) bool operator<(common_pair const & a, common_pair const & b) { return a.first < b.first || (!(b.first < a.first) && a.second < b.second); } template(typename F1, typename S1, typename F2, typename S2)( requires totally_ordered_with AND totally_ordered_with) bool operator<(std::pair const & a, common_pair const & b) { return a.first < b.first || (!(b.first < a.first) && a.second < b.second); } template(typename F1, typename S1, typename F2, typename S2)( requires totally_ordered_with AND totally_ordered_with) bool operator<(common_pair const & a, std::pair const & b) { return a.first < b.first || (!(b.first < a.first) && a.second < b.second); } #define LOGICAL_OP(OP, CONCEPT, RET) \ template(typename F1, typename S1, typename F2, typename S2)( \ requires CONCEPT AND CONCEPT) \ bool operator OP(common_pair const & a, common_pair const & b) \ { \ return RET; \ } \ template(typename F1, typename S1, typename F2, typename S2)( \ requires CONCEPT AND CONCEPT) \ bool operator OP(std::pair const & a, common_pair const & b) \ { \ return RET; \ } \ template(typename F1, typename S1, typename F2, typename S2)( \ requires CONCEPT AND CONCEPT) \ bool operator OP(common_pair const & a, std::pair const & b) \ { \ 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 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 RANGES_BEGIN_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> {}; #if RANGES_CXX_VER > RANGES_CXX_STD_17 RANGES_BEGIN_NAMESPACE_VERSION template struct common_type; // common_type for pairs template struct common_type, ::ranges::common_pair> : ::ranges::detail::common_type_tuple_like< std::pair, ::ranges::common_pair, ::meta::quote<::ranges::common_pair>> {}; template struct common_type<::ranges::common_pair, std::pair> : ::ranges::detail::common_type_tuple_like< ::ranges::common_pair, std::pair, ::meta::quote<::ranges::common_pair>> {}; template struct common_type<::ranges::common_pair, ::ranges::common_pair> : ::ranges::detail::common_type_tuple_like<::ranges::common_pair, ::ranges::common_pair, ::meta::quote<::ranges::common_pair>> {}; // common_type for tuples template struct common_type<::ranges::common_tuple, std::tuple> : ::ranges::detail::common_type_tuple_like< ::ranges::common_tuple, std::tuple, ::meta::quote<::ranges::common_tuple>> {}; template struct common_type, ::ranges::common_tuple> : ::ranges::detail::common_type_tuple_like< std::tuple, ::ranges::common_tuple, ::meta::quote<::ranges::common_tuple>> {}; template struct common_type<::ranges::common_tuple, ::ranges::common_tuple> : ::ranges::detail::common_type_tuple_like<::ranges::common_tuple, ::ranges::common_tuple, ::meta::quote<::ranges::common_tuple>> {}; template class, template class> struct basic_common_reference; // common reference for pairs template class Qual1, template class Qual2> struct basic_common_reference<::ranges::common_pair, std::pair, Qual1, Qual2> : ::ranges::detail::common_ref_tuple_like< ::ranges::common_pair, Qual1>, std::pair, Qual2>, ::meta::quote<::ranges::common_pair>> {}; 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<::ranges::common_pair>> {}; template class Qual1, template class Qual2> struct basic_common_reference<::ranges::common_pair, ::ranges::common_pair, Qual1, Qual2> : ::ranges::detail::common_ref_tuple_like<::ranges::common_pair, Qual1>, ::ranges::common_pair, Qual2>, ::meta::quote<::ranges::common_pair>> {}; // common reference for tuples template class Qual1, template class Qual2> struct basic_common_reference<::ranges::common_tuple, std::tuple, Qual1, Qual2> : ::ranges::detail::common_ref_tuple_like< ::ranges::common_tuple...>, std::tuple...>, ::meta::quote<::ranges::common_tuple>> {}; 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<::ranges::common_tuple>> {}; template class Qual1, template class Qual2> struct basic_common_reference<::ranges::common_tuple, ::ranges::common_tuple, Qual1, Qual2> : ::ranges::detail::common_ref_tuple_like<::ranges::common_tuple...>, ::ranges::common_tuple...>, ::meta::quote<::ranges::common_tuple>> {}; RANGES_END_NAMESPACE_VERSION #endif // RANGES_CXX_VER > RANGES_CXX_STD_17 RANGES_END_NAMESPACE_STD RANGES_DIAGNOSTIC_POP #include #endif