/* * Copyright (c) 2018 Jaroslav Jindrak * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef LIBCPP_TUPLE #define LIBCPP_TUPLE #include <__bits/aux.hpp> #include <__bits/tuple/tuple_cat.hpp> #include <__bits/tuple/tuple_ops.hpp> #include <__bits/type_transformation.hpp> #include #include #include namespace std { template class tuple; /** * 20.4.2.4, tuple creation functions: */ namespace aux { struct ignore_t { template const ignore_t& operator=(const T&) const { return *this; } }; } inline constexpr aux::ignore_t ignore; template // TODO: test the reference_wrapper version once we got reference_wrapper constexpr auto make_tuple(Ts&&... ts) { return tuple...>(forward(ts)...); } template constexpr tuple forward_as_tuple(Ts&&... ts) noexcept { return tuple(forward(ts)...); } template constexpr tuple tie(Ts&... ts) noexcept { return tuple(ts...); } template constexpr aux::tuple_cat_type_t tuple_cat(Tuples&&... tpls) { // TODO: currently does not work because of index mismatch return aux::tuple_cat( forward(tpls)..., make_index_sequence{}, aux::generate_indices_t{} ); } /** * 20.4.2.5, tuple helper classes: */ template class tuple_size; // undefined template class tuple_size : public integral_constant::value> { /* DUMMY BODY */ }; template class tuple_size : public integral_constant::value> { /* DUMMY BODY */ }; template class tuple_size : public integral_constant::value> { /* DUMMY BODY */ }; template class tuple_size> : public integral_constant { /* DUMMY BODY */ }; template inline constexpr size_t tuple_size_v = tuple_size::value; template class tuple_element; // undefined template class tuple_element { using type = add_const_t::type>; }; template class tuple_element { using type = add_volatile_t::type>; }; template class tuple_element { using type = add_cv_t::type>; }; namespace aux { template struct type_at: type_at { /* DUMMY BODY */ }; template struct type_at<0, T, Ts...> { using type = T; }; template using type_at_t = typename type_at::type; } template class tuple_element> { public: using type = aux::type_at_t; }; template using tuple_element_t = typename tuple_element::type; namespace aux { template struct tuple_element_wrapper { constexpr tuple_element_wrapper() = default; constexpr explicit tuple_element_wrapper(T&& val) : value{forward(val)} { /* DUMMY BODY */ } template< class U, class = enable_if_t< is_convertible_v && !is_same_v, void > > constexpr explicit tuple_element_wrapper(U&& val) : value(forward(val)) { /* DUMMY BODY */ } T value; }; template class tuple_impl; // undefined template class tuple_impl, Ts...>: public tuple_element_wrapper... { public: constexpr tuple_impl() : tuple_element_wrapper{}... { /* DUMMY BODY */ } template constexpr explicit tuple_impl(Us&&... us) : tuple_element_wrapper(forward(us))... { /* DUMMY BODY */ } template constexpr tuple_impl(const tuple& tpl) : tuple_impl{tpl, make_index_sequence{}} { /* DUMMY BODY */ } template constexpr tuple_impl(tuple&& tpl) : tuple_impl{move>(tpl), make_index_sequence{}} { /* DUMMY BODY */ } template constexpr tuple_impl(const tuple& tpl, index_sequence) : tuple_impl{get(tpl)...} { /* DUMMY BODY */ } template constexpr tuple_impl(tuple&& tpl, index_sequence) : tuple_impl{get(move(tpl))...} { /* DUMMY BODY */ } }; template struct tuple_noexcept_swap { static constexpr bool value = noexcept(std::swap(declval(), declval())) && tuple_noexcept_swap::value; }; template struct tuple_noexcept_swap { static constexpr bool value = noexcept(std::swap(declval(), declval())); }; template struct tuple_noexcept_assignment { static constexpr bool value = is_nothrow_move_assignable::value && tuple_noexcept_assignment::value; }; template struct tuple_noexcept_assignment { static constexpr bool value = is_nothrow_move_assignable::value; }; } /** * 20.4.2.6, element access: */ template constexpr tuple_element_t>& get(tuple& tpl) noexcept { aux::tuple_element_wrapper>>& wrapper = tpl; return wrapper.value; } template constexpr tuple_element_t>&& get(tuple&& tpl) noexcept { return forward>::type&&>(get(tpl)); } template constexpr const tuple_element_t>& get(const tuple& tpl) noexcept { const aux::tuple_element_wrapper>>& wrapper = tpl; return wrapper.value; } namespace aux { template struct index_of_type: index_of_type { /* DUMMY BODY */ }; template struct index_of_type: std::integral_constant { /* DUMMY BODY */ }; } template constexpr T& get(tuple& tpl) noexcept { return get::value>(tpl); } template constexpr T&& get(tuple&& tpl) noexcept { return get::value>(forward>(tpl)); } template constexpr const T& get(const tuple& tpl) noexcept { return get::value>(tpl); } /** * 20.4.2, class template tuple: */ template class tuple: public aux::tuple_impl, Ts...> { using base_t = aux::tuple_impl, Ts...>; public: /** * 20.4.2.1, tuple construction: */ constexpr tuple() : base_t{} { /* DUMMY BODY */ } constexpr explicit tuple( const Ts&... ts, enable_if_t* = nullptr) : base_t(ts...) { /* DUMMY BODY */ } template // TODO: is_convertible == true for all Us to all Ts constexpr explicit tuple(Us&&... us, enable_if_t* = nullptr) : base_t(forward(us)...) { /* DUMMY BODY */ } tuple(const tuple&) = default; tuple(tuple&&) = default; template constexpr tuple(const tuple& tpl, enable_if_t* = nullptr) : base_t(tpl) { /* DUMMY BODY */ } template constexpr tuple(tuple&& tpl, enable_if_t* = nullptr) : base_t(move(tpl)) { /* DUMMY BODY */ } // TODO: pair related construction and assignment needs convertibility, not size template constexpr tuple(const pair& p) : base_t{} { get<0>(*this) = p.first; get<1>(*this) = p.second; } template constexpr tuple(pair&& p) : base_t{} { get<0>(*this) = forward(p.first); get<1>(*this) = forward(p.second); } // TODO: allocator-extended constructors /** * 20.4.2.2, tuple assignment: */ tuple& operator=(const tuple& other) { aux::tuple_ops<0, sizeof...(Ts) - 1>::assign_copy(*this, other); return *this; } tuple& operator=(tuple&& other) noexcept(aux::tuple_noexcept_assignment::value) { aux::tuple_ops<0, sizeof...(Ts) - 1>::assign_move(*this, move(other)); return *this; } template tuple& operator=(const tuple& other) { aux::tuple_ops<0, sizeof...(Ts) - 1>::assign_copy(*this, other); return *this; } template tuple& operator=(tuple&& other) { aux::tuple_ops<0, sizeof...(Ts) - 1>::assign_move(*this, move(other)); return *this; } template tuple& operator=(const pair& p) { get<0>(*this) = p.first; get<1>(*this) = p.second; return *this; } template tuple& operator=(pair&& p) { get<0>(*this) = forward(p.first); get<1>(*this) = forward(p.second); return *this; } /** * 20.4.2.3, tuple swap: */ void swap(tuple& other) noexcept(aux::tuple_noexcept_swap::value) { aux::tuple_ops<0, sizeof...(Ts) - 1>::swap(*this, other); } }; /** * 20.4.2.7, relational operators: */ template constexpr bool operator==(const tuple& lhs, const tuple rhs) { if constexpr (sizeof...(Ts) == 0) return true; else return aux::tuple_ops<0, sizeof...(Ts) - 1>::eq(lhs, rhs); } template constexpr bool operator<(const tuple& lhs, const tuple rhs) { if constexpr (sizeof...(Ts) == 0) return false; else return aux::tuple_ops<0, sizeof...(Ts) - 1>::lt(lhs, rhs); } template constexpr bool operator!=(const tuple& lhs, const tuple rhs) { return !(lhs == rhs); } template constexpr bool operator>(const tuple& lhs, const tuple rhs) { return rhs < lhs; } template constexpr bool operator<=(const tuple& lhs, const tuple rhs) { return !(rhs < lhs); } template constexpr bool operator>=(const tuple& lhs, const tuple rhs) { return !(lhs < rhs); } /** * 20.4.2.8, allocator-related traits: */ template struct uses_allocator, Alloc>: true_type { /* DUMMY BODY */ }; /** * 20.4.2.9, specialized algorithms: */ template void swap(tuple& lhs, tuple& rhs) noexcept(noexcept(lhs.swap(rhs))) { lhs.swap(rhs); } } #endif