diff --git a/platform/cxxsupport/TOOLCHAIN_ARMC5/tuple b/platform/cxxsupport/TOOLCHAIN_ARMC5/tuple new file mode 100644 index 00000000000..5d3bca572c2 --- /dev/null +++ b/platform/cxxsupport/TOOLCHAIN_ARMC5/tuple @@ -0,0 +1,734 @@ +/* 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