/* mbed Microcontroller Library * Copyright (c) 2019 ARM Limited * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* class tuple implementation based on Sashsa Goldstein's series * "Implementing std::tuple from The Ground Up". * * http://blogs.microsoft.co.il/sasha/2015/01/12/implementing-tuple-part-1/ * * tuple_cat based on Peter Dimov's article "Simple C++11 metaprogramming", * which in turn is based on work by Eric Niebler and Stephan T. Lavavej. * * https://www.boost.org/doc/libs/develop/libs/mp11/doc/html/simple_cxx11_metaprogramming.html * * As ARM C 5 can't do constexpr std::move or std::forward, there's no way * tuple can be constexpr either, so this is a C++11 implementation, not C++14. * * Allocators are not supported. */ #ifndef __tuple #define __tuple #include #include namespace std { template struct tuple; template struct tuple_element; // ARM C 5 (incorrectly? doesn't allow duplicate using - utility has already done this (for pair) //template //using tuple_element_t = typename tuple_element::type; template struct tuple_element> : tuple_element> { }; template struct tuple_element<0, tuple> : type_identity { }; template struct tuple_element : type_identity>> { }; template struct tuple_element : type_identity>> { }; template struct tuple_element : type_identity>> { }; template tuple_element_t> &get(tuple &t) noexcept; template tuple_element_t> &&get(tuple &&t) noexcept; template const tuple_element_t> &get(const tuple &t) noexcept; template const tuple_element_t> &&get(const tuple &&t) noexcept; namespace impl { /* Tuple element container - tuple has these as multiple base classes */ template struct tuple_elem { constexpr tuple_elem() : value() { } // tuple default constructor value-initializes elements explicit tuple_elem(const T &val) : value(val) { } template ::value>> explicit tuple_elem(U&& val) : value(std::forward(val)) { } /* Copy and move constructors and assignments implicitly defined (only way to get default move in ARMC5) */ tuple_elem &operator=(const T &val) { value = val; return *this; } template ::value>> tuple_elem &operator=(U&& val) { value = std::forward(val); return *this; } void swap(T &other) { using namespace std; std::swap(value, other); } T value; }; template class tuple_base; /* C++17 form - conditional explicit idiom from N4387 */ template struct tuple_base, Types...> : tuple_elem... { private: template struct we_are_convertible_from : conjunction...> { }; template struct we_are_constructible_from : conjunction...> { }; void ignore(int...) { } public: /* Default constructor, 0 args */ constexpr tuple_base() : tuple_elem()... { } /* Direct constructor, 1+ args */ template = 1 && conjunction...>::value, bool> = false> explicit tuple_base(const Types &...args) : tuple_elem(args)... { } /* Converting constructor, 1+ args */ template = 1 && conjunction...>::value, bool> = true> explicit tuple_base(UTypes &&...args) : tuple_elem(std::forward(args))... { } /* Converting copy constructor */ template , is_constructible..., disjunction, conjunction &...>>, negation &>...>>, negation...>> > > >::value, bool> = true> explicit tuple_base(const tuple &other) : tuple_elem(get(other))... { } /* Converting move constructor */ template , is_constructible..., disjunction, conjunction...>>, negation>...>>, negation...>> > > >::value, bool> = true> explicit tuple_base(tuple &&other) : tuple_elem(std::forward(get(other)))... { } /* Converting pair copy constructor */ template , we_are_constructible_from >::value, bool> = true> explicit tuple_base(const pair &pair) : tuple_base(pair.first, pair.second) { } /* Converting pair move constructor */ template , we_are_constructible_from >::value, bool> = true> explicit tuple_base(pair &&pair) : tuple_elem<0, tuple_element_t<0, tuple>>(std::forward(pair.first)), tuple_elem<1, tuple_element_t<1, tuple>>(std::forward(pair.second)) { } /* Copy and move constructors and assignments implicitly defined (only way to get default move in ARMC5) */ template int do_copy1(const U &other) { impl::tuple_elem &e = *this; e = other; return 0; } template int do_move1(U &&other) { impl::tuple_elem &e = *this; e = std::move(other); return 0; } template tuple_base &operator=(const tuple &other) { ignore(do_copy1(get(other))...); return *this; } template void do_move(tuple &&other) { impl::tuple_elem>> &e = *this; e = std::forward>>(get(other)); do_move(std::forward>(other)); } template tuple_base &operator=(tuple &&other) { ignore(do_move1(std::forward(get(other)))...); return *this; } template tuple_base &operator=(const pair &pair) { do_copy1<0, tuple_element_t<0, tuple>>(pair.first); do_copy1<1, tuple_element_t<1, tuple>>(pair.second); return *this; } template tuple_base &operator=(pair &&pair) { do_move1<0, tuple_element_t<0, tuple>>(std::forward(pair.first)); do_move1<1, tuple_element_t<1, tuple>>(std::forward(pair.second)); return *this; } template int do_swap1(Tn &other) { impl::tuple_elem &e = *this; using std::swap; swap(e.value, other); return 0; } void swap(tuple &other) { ignore(do_swap1(get(other))...); } }; } template struct tuple : impl::tuple_base, Types...> { private: using base_type = impl::tuple_base, Types...>; // Need this deferred so not evaluated in conjunction // when size < 2 template struct is_pair_assignable : conjunction &, U1>, is_assignable &, U2>> { }; template struct we_are_convertible_from : conjunction...> { }; template struct we_are_constructible_from : conjunction...> { }; public: /* This would be simpler if ARM C 5 supported inheriting constructors, * but as it doesn't, we need to repeat stuff here and in tuple_base. */ /* C++17 form - conditional explicit idiom from N4387 */ /* Default constructor, 0 args */ template ...>::value, bool> = false> constexpr tuple() : base_type() { } /* Direct constructor, 1+ args */ template = 1 && conjunction...>::value && we_are_convertible_from::value, bool> = false> tuple(const Types &...args) : base_type(args...) { } template = 1 && conjunction...>::value && !we_are_convertible_from::value, bool> = true> explicit tuple(const Types &...args) : base_type(args...) { } /* Converting constructor, 1+ args */ template = 1 && conjunction...>::value && conjunction...>::value/*we_are_convertible_from::value*/, bool> = false> tuple(UTypes &&...args) : base_type(std::forward(args)...) { } template = 1 && conjunction...>::value && !conjunction...>::value/*we_are_convertible_from::value*/, bool> = true> explicit tuple(UTypes &&...args) : base_type(std::forward(args)...) { } /* Converting copy constructor */ template , is_constructible..., disjunction, conjunction &...>>, negation &>...>>, negation...>> > >, conjunction...> >::value, bool> = false> tuple(const tuple &other) : base_type(other) { } template , is_constructible..., disjunction, conjunction &...>>, negation &>...>>, negation...>> > >, negation...>> >::value, bool> = true> explicit tuple(const tuple &other) : base_type(other) { } /* Converting move constructor */ template , is_constructible..., disjunction, conjunction...>>, negation>...>>, negation...>> > >, conjunction...> >::value, bool> = false> tuple(tuple &&other) : base_type(std::forward>(other)) { } template , is_constructible..., disjunction, conjunction...>>, negation>...>>, negation...>> > >, negation...>> >::value, bool> = true> explicit tuple(tuple &&other) : base_type(std::forward>(other)) { } /* Converting pair copy constructor */ template , we_are_constructible_from, we_are_convertible_from >::value, bool> = false> tuple(const pair &p) : base_type(p) { } template , we_are_constructible_from, negation> >::value, bool> = true> explicit tuple(const pair &p) : base_type(p) { } /* Converting pair move constructor */ template , we_are_constructible_from, we_are_convertible_from >::value, bool> = false> tuple(pair &&p) : base_type(std::forward>(p)) { } template , we_are_constructible_from, negation> >::value, bool> = true> explicit tuple(pair &&p) : base_type(std::forward>(p)) { } /* Copy and move constructors and assignments implicitly defined (only way to get default move in ARMC5) */ template , conjunction...>>::value, int> = 0> tuple &operator=(const tuple &other) { *static_cast(this) = other; return *this; } template , conjunction...>>::value, int> = 0> tuple &operator=(tuple &&other) { *static_cast(this) = std::move(other); return *this; } template , is_pair_assignable>::value, int> = 0> tuple &operator=(const pair &pair) { *static_cast(this) = pair; return *this; } template , is_pair_assignable>::value, int> = 0> tuple &operator=(pair &&pair) { *static_cast(this) = std::move(pair); return *this; } }; namespace impl { template struct type_count : integral_constant { }; template struct type_count : integral_constant::value + type_count::value> { }; template struct type_find : integral_constant { }; template struct type_find : conditional_t::value, integral_constant, type_find> { }; } template struct tuple_size; template struct tuple_size> : integral_constant { }; template struct tuple_size : integral_constant::value> { }; template struct tuple_size : integral_constant::value> { }; template struct tuple_size : integral_constant::value> { }; template tuple_element_t> &get(tuple &t) noexcept { impl::tuple_elem>> &e = t; return e.value; } template tuple_element_t> &&get(tuple &&t) noexcept { impl::tuple_elem>> &&e = std::move(t); return std::forward>>(e.value); } template const tuple_element_t> &get(const tuple &t) noexcept { const impl::tuple_elem>> &e = t; return e.value; } template const tuple_element_t> &&get(const tuple &&t) noexcept { const impl::tuple_elem>> &&e = std::move(t); return std::forward>>(e.value); } template T &get(tuple &t) noexcept { static_assert(impl::type_count::value == 1, "not exactly 1 matching type in tuple"); return get::value>(t); } namespace impl{ template struct unwrap_ref_wrapper : type_identity { }; template struct unwrap_ref_wrapper> : type_identity { }; template struct tuple_decay : unwrap_ref_wrapper> { }; template using tuple_decay_t = typename tuple_decay::type; } template tuple...> make_tuple(Types&&... args) { return tuple...>(std::forward(args)...); } template tuple forward_as_tuple(Types&&... args) noexcept { return tuple(std::forward(args)...); } namespace impl { struct ignore { template constexpr const ignore &operator=(const T &) const { return *this; } }; } const impl::ignore ignore; template tuple tie(Types &... args) noexcept { return tuple(args...); } namespace impl { template struct tuple_cmp { static bool equal(const T &t, const U &u) { return get(t) == get(u) ? tuple_cmp::equal(t, u) : false; } static bool less(const T &t, const U &u) { return get(t) < get(u) ? true : get(u) < get(t) ? false : tuple_cmp::less(t, u); } }; template struct tuple_cmp { static bool equal(const T &t, const U &u) { return true; } static bool less(const T &t, const U &u) { return false; } }; } template bool operator==(const tuple &t, const tuple &u) { static_assert(sizeof...(TTypes) == sizeof...(UTypes), "tuple size mismatch"); return impl::tuple_cmp<0, sizeof...(TTypes), tuple, tuple>::equal(t, u); } template bool operator<(const tuple &t, const tuple &u) { static_assert(sizeof...(TTypes) == sizeof...(UTypes), "tuple size mismatch"); return impl::tuple_cmp<0, sizeof...(TTypes), tuple, tuple>::less(t, u); } template bool operator!=(const tuple &t, const tuple &u) { return !(t == u); } template bool operator>(const tuple &t, const tuple &u) { return u < t; } template bool operator<=(const tuple &t, const tuple &u) { return !(u < t); } template bool operator>=(const tuple &t, const tuple &u) { return !(t < u); } template void swap(tuple &x, tuple &y) { x.swap(y); } // Start deep meta-programming for tuple_cat namespace impl { // List of types Ts... template struct mp_list { }; // Given A<...>, B, produce B<...> template class B> struct _mp_rename; template