#ifndef __GBLIBCPP_TUPLE__ #define __GBLIBCPP_TUPLE__ #include #include #include #include namespace std { template struct tuple_element; template using tuple_element_t = typename tuple_element::type; template struct tuple_size; template inline constexpr std::size_t tuple_size_v = tuple_size::value; 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 {}; template constexpr auto get(std::tuple& tpl) noexcept -> tuple_element_t>& { return tpl.template _getl(); } template constexpr auto get(std::tuple&& tpl) noexcept -> tuple_element_t>&& { return tpl.template _getr(); } template constexpr auto get(const std::tuple& tpl) noexcept -> tuple_element_t> const& { return tpl.template _getl(); } template constexpr auto get(const std::tuple&& tpl) noexcept -> tuple_element_t> const&& { return tpl.template _getr(); } namespace __helpers { 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::move(val); else return std::move(next.template _getr()); } template constexpr const auto&& _getr(void) const { if constexpr (I == J) return std::move(val); else return std::move(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) { return val; } template constexpr Type const& _getl(void) const { return val; } template constexpr Type&& _getr(void) { return std::move(val); } template constexpr Type const&& _getr(void) const { return std::move(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; }; } // 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: constexpr tuple() : base() {} constexpr tuple(const Types&... args) : base(args...) {} template = 1 && !(sizeof...(Types) == 1 && (... && std::is_same_v)) , bool> = true> constexpr tuple(UTypes&&... args) : base(std::forward(args)...) {} template constexpr tuple(const tuple& other) : base(other) {} template constexpr tuple(tuple&& other) : base(std::move(other)) {} // TODO: std::pair constructors 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; } 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 > struct __to_tuple_type { using type = T; }; template struct __to_tuple_type<_T, std::reference_wrapper> { using type = std::add_lvalue_reference_t; }; template constexpr T make_from_tuple_impl(Tuple&& tpl, std::index_sequence) { return T { std::get(std::forward(tpl))... }; } 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::type...> { return std::tuple::type...> { 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 T make_from_tuple(Tuple&& tpl) { return __helpers::make_from_tuple_impl( std::forward(tpl), std::make_index_sequence< std::tuple_size_v>> {} ); } 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