/* * 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 #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; namespace aux { template struct remove_reference_wrapper: type_is { /* DUMMY BODY */ }; template struct remove_reference_wrapper>: type_is { /* DUMMY BODY */ }; template using remove_reference_wrapper_t = typename remove_reference_wrapper::type; template using transform_tuple_types_t = remove_reference_wrapper_t>; } 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 // TODO: dafuq is ctypes? constexpr tuple tuple_cat(Tuples&&... tpls); /** * 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{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 */ } constexpr explicit tuple_impl(const Ts&... ts) : tuple_element_wrapper(ts)... { /* 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); } namespace aux { template struct tuple_ops { template static void assign(T&& lhs, U&& rhs) { get(forward(lhs)) = get(forward(rhs)); tuple_ops::assign(forward(lhs), forward(rhs)); } template static void swap(T& lhs, U& rhs) { std::swap(get(lhs), get(rhs)); tuple_ops::swap(lhs, rhs); } // TODO: for rel ops we will need this to be ascending, not descending template static bool eq(const T& lhs, const T& rhs) { return (get(lhs) == get(rhs)) && tuple_ops::eq(lhs, rhs); } }; template<> struct tuple_ops<0> { template static void assign(T&& lhs, U&& rhs) { get<0>(forward(lhs)) = get<0>(forward(rhs)); } template static void swap(T& lhs, U& rhs) { std::swap(get<0>(lhs), get<0>(rhs)); } }; } /** * 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) : base_t(ts...) { /* DUMMY BODY */ } template constexpr explicit tuple(Us&&... us) : base_t(forward(us)...) { /* DUMMY BODY */ } tuple(const tuple&) = default; tuple(tuple&&) = default; /* template */ /* constexpr tuple(const tuple& tpl) */ /* : base_t(tpl) */ //{ /* DUMMY BODY */ } /* template */ /* constexpr tuple(tuple& tpl) */ /* : base_t(forward>(tpl)...) */ //{ /* DUMMY BODY */ } 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::assign(*this, other); return *this; } tuple& operator=(tuple&& other) noexcept(aux::tuple_noexcept_assignment::value) { aux::tuple_ops::assign(*this, forward(other)); return *this; } template tuple& operator=(const tuple& other) { aux::tuple_ops::assign(*this, other); return *this; } template tuple& operator=(tuple&& other) { aux::tuple_ops::assign(*this, forward(other)...); return *this; } template> tuple& operator=(const pair& p) { get<0>(*this) = p.first; get<1>(*this) = p.second; } template> tuple& operator=(pair&& p) { get<0>(*this) = forward(p.first); get<1>(*this) = forward(p.second); } /** * 20.4.2.3, tuple swap: */ void swap(tuple& other) noexcept(aux::tuple_noexcept_swap::value) { aux::tuple_ops::swap(*this, other); } }; /** * 20.4.2.7, relational operators: */ template constexpr bool operator==(const tuple& lhs, const tuple rhs); template constexpr bool operator<(const tuple& lhs, const tuple rhs); template constexpr bool operator!=(const tuple& lhs, const tuple rhs); template constexpr bool operator>(const tuple& lhs, const tuple rhs); template constexpr bool operator<=(const tuple& lhs, const tuple rhs); template constexpr bool operator>=(const tuple& lhs, const tuple rhs); /** * 20.4.2.8, allocator-related traits: */ template struct uses_allocator; 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