#ifndef __GBLIBCPP_TUPLE__ #define __GBLIBCPP_TUPLE__ #include #include #include #include #include #include namespace std { template struct tuple_element { using type = std::add_const_t>; }; template struct tuple_element { using type = std::add_volatile_t>; }; template struct tuple_element { using type = std::add_cv_t>; }; namespace __helpers { template struct __const_tuple_size {}; template struct __const_tuple_size::value)>> : std::integral_constant::value> {}; } // namespace __helpers template struct tuple_size : __helpers::__const_tuple_size {}; template class tuple; template struct tuple_element> : tuple_element> {}; template struct tuple_element<0, std::tuple> { using type = Type; }; template struct tuple_size> : std::integral_constant {}; namespace __helpers { template class tuple_impl; template <> class tuple_impl<0> { template friend class tuple_impl; template friend constexpr auto std::get(std::tuple& tpl) noexcept -> tuple_element_t>&; template friend constexpr auto std::get(std::tuple&& tpl) noexcept -> tuple_element_t>&&; template friend constexpr auto std::get(const std::tuple& tpl) noexcept -> tuple_element_t> const&; template friend constexpr auto std::get(const std::tuple&& tpl) noexcept -> tuple_element_t> const&&; template constexpr void _getl(void) const = delete; template constexpr void _getr(void) const = delete; public: constexpr tuple_impl() noexcept = default; constexpr tuple_impl(const tuple_impl& arg) noexcept = default; constexpr tuple_impl(tuple_impl&& arg) noexcept = default; template constexpr tuple_impl(const std::tuple& other) = delete; template constexpr tuple_impl(std::tuple&& other) = delete; constexpr tuple_impl& operator=(const tuple_impl& other) noexcept = default; constexpr tuple_impl& operator=(tuple_impl&& other) noexcept = default; }; template class tuple_impl { template friend class tuple_impl; template friend constexpr auto std::get(std::tuple& tpl) noexcept -> tuple_element_t>&; template friend constexpr auto std::get(std::tuple&& tpl) noexcept -> tuple_element_t>&&; template friend constexpr auto std::get(const std::tuple& tpl) noexcept -> tuple_element_t> const&; template friend constexpr auto std::get(const std::tuple&& tpl) noexcept -> tuple_element_t> const&&; Type val; tuple_impl next; template constexpr auto& _getl(void) { if constexpr (I == J) return val; else return next.template _getl(); } template constexpr const auto& _getl(void) const { if constexpr (I == J) return val; else return next.template _getl(); } template constexpr auto&& _getr(void) { if constexpr (I == J) return std::forward(val); else return std::forward< decltype(next.template _getr())>( next.template _getr()); } template constexpr const auto&& _getr(void) const { if constexpr (I == J) return std::forward(val); else return std::forward< decltype(next.template _getr())>( next.template _getr()); } public: constexpr tuple_impl() : val(), next() {} constexpr tuple_impl(const tuple_impl& arg) = default; constexpr tuple_impl(tuple_impl&& arg) = default; constexpr tuple_impl(const Type& val, const Types&... vals) : val(val), next(vals...) {} template constexpr tuple_impl(UType&& val, UTypes&&... vals) : val(std::forward(val)), next(std::forward(vals)...) {} template constexpr tuple_impl(const std::tuple& other) : val(std::get(other)), next(other) {} template constexpr tuple_impl(std::tuple&& other) : val(std::get(other)), next(std::move(other)) {} constexpr tuple_impl& operator=(const tuple_impl& other) = default; constexpr tuple_impl& operator=(tuple_impl&& other) = default; }; template class tuple_impl { template friend class tuple_impl; template friend constexpr auto std::get(std::tuple& tpl) noexcept -> tuple_element_t>&; template friend constexpr auto std::get(std::tuple&& tpl) noexcept -> tuple_element_t>&&; template friend constexpr auto std::get(const std::tuple& tpl) noexcept -> tuple_element_t> const&; template friend constexpr auto std::get(const std::tuple&& tpl) noexcept -> tuple_element_t> const&&; Type val; template constexpr Type& _getl(void) { static_assert(J == I); return val; } template constexpr Type const& _getl(void) const { static_assert(J == I); return val; } template constexpr Type&& _getr(void) { static_assert(J == I); return std::forward(val); } template constexpr Type const&& _getr(void) const { static_assert(J == I); return std::forward(val); } public: constexpr tuple_impl() : val() {} constexpr tuple_impl(const tuple_impl& arg) = default; constexpr tuple_impl(tuple_impl&& arg) = default; constexpr tuple_impl(const Type& val) : val(val) {} template constexpr tuple_impl(UType&& val) : val(std::forward(val)) {} template constexpr tuple_impl(const std::tuple& other) : val(std::get(other)) {} template constexpr tuple_impl(std::tuple&& other) : val(std::get(other)) {} constexpr tuple_impl& operator=(const tuple_impl& other) = default; constexpr tuple_impl& operator=(tuple_impl&& other) = default; }; template struct tuple_constraints { static constexpr std::size_t Tsize = sizeof...(Types); template static constexpr auto idx_seq(std::index_sequence seq) { return seq; } template struct tuple_copy_move_constructible_impl; template struct tuple_copy_move_constructible_impl, UTypes...> : std::bool_constant< Tsize == sizeof...(UTypes) && (... && std::is_constructible_v(std::declval()))>) && ((Tsize != 1) || (!(... && std::is_convertible_v) && !(... && std::is_constructible_v) && !(... && std::is_same_v))) > {}; template struct tuple_copy_move_constructible : tuple_copy_move_constructible_impl< UTuple, decltype(idx_seq(std::index_sequence_for{})), UTypes...> {}; template > struct tuple_pair_constructible; template struct tuple_pair_constructible> : std::bool_constant(std::declval()))>) > {}; template struct tuple_pair_copy_assignable : std::bool_constant< sizeof...(Types) == 2 && (... && std::is_assignable_v) > {}; template struct tuple_pair_move_assignable : std::bool_constant< sizeof...(Types) == 2 && (... && std::is_assignable_v) > {}; }; } // namespace __helpers template class tuple : public __helpers::tuple_impl<0, Types...> { private: using base = __helpers::tuple_impl<0, Types...>; template constexpr void __copy_assignment( const tuple& other, std::index_sequence) { ((std::get(*this) = std::get(other)), ...); } template constexpr void __move_assignment( tuple&& other, std::index_sequence) { ((std::get(*this) = std::forward(std::get(other))), ...); } public: template ) && __helpers::template_true_type<_>::value , bool> = true> constexpr tuple() : base() {} template = 1 && (... && std::is_copy_constructible_v) && __helpers::template_true_type<_>::value , bool> = true> constexpr tuple(const Types&... args) : base(args...) {} template = 1 && (... && std::is_constructible_v) && !(sizeof...(Types) == 1 && (... && std::is_same_v>)) , bool> = true> constexpr tuple(UTypes&&... args) : base(std::forward(args)...) {} template ::template tuple_copy_move_constructible&, UTypes...>::value , bool> = true> constexpr tuple(const tuple& other) : base(other) {} template ::template tuple_copy_move_constructible&&, UTypes...>::value , bool> = true> constexpr tuple(tuple&& other) : base(std::move(other)) {} template ::template tuple_pair_constructible&>::value , bool> = true> constexpr tuple(const std::pair& p) : base(std::get<0>(p), std::get<1>(p)) {} template ::template tuple_pair_constructible&&>::value , bool> = true> constexpr tuple(std::pair&& p) : base(std::get<0>(std::move(p)), std::get<1>(std::move(p))) {} constexpr tuple(const tuple&) = default; constexpr tuple(tuple&&) = default; constexpr tuple& operator=(const tuple& other) = default; constexpr tuple& operator=(tuple&& other) = default; template ) , bool> = true> constexpr tuple& operator=(const tuple& other) { __copy_assignment(other, index_sequence_for {}); return *this; } template ) , bool> = true> constexpr tuple& operator=(tuple&& other) { __move_assignment(std::move(other), index_sequence_for {}); return *this; } template ::template tuple_pair_copy_assignable::value , bool> = true> constexpr tuple& operator=(const std::pair& p) { std::get<0>(*this) = p.first; std::get<1>(*this) = p.second; return *this; } template ::template tuple_pair_move_assignable::value , bool> = true> constexpr tuple& operator=(std::pair&& p) { std::get<0>(*this) = std::forward(p.first); std::get<1>(*this) = std::forward(p.second); return *this; } constexpr void swap(tuple& other) { std::swap(*this, other); } }; template tuple(Types...) -> tuple; namespace __helpers { struct ignore_t { template constexpr void operator=(T&&) const noexcept {} }; template constexpr auto apply_impl(Func&& func, Tuple&& tpl, std::index_sequence) { return std::invoke( std::forward(func), std::get(std::forward(tpl))...); } } // namespace __helpers inline constexpr __helpers::ignore_t ignore; template constexpr void swap(std::tuple& lhs, std::tuple& rhs) noexcept(noexcept(lhs.swap(rhs))) { lhs.swap(rhs); } template constexpr auto make_tuple(Types&&... args) -> std::tuple<__helpers::to_tuple_type_t...> { return std::tuple<__helpers::to_tuple_type_t...> { std::forward(args)... }; } template constexpr std::tuple tie(Types&... args) noexcept { return { args... }; } template constexpr std::tuple forward_as_tuple(Types&&... args) noexcept { return { std::forward(args)... }; } template constexpr decltype(auto) apply(Func&& func, Tuple&& tpl) { return __helpers::apply_impl( std::forward(func), std::forward(tpl), std::make_index_sequence< std::tuple_size_v>> {} ); } } // namespace std #endif