From 235dde40ee7e54cac63eea643fffee308b09595a Mon Sep 17 00:00:00 2001 From: Baptiste Wicht Date: Sat, 3 Sep 2016 20:06:35 +0200 Subject: [PATCH] Completely review std::tuple --- tstl/include/integer_sequence.hpp | 71 ++++++++ tstl/include/nth_type.hpp | 30 ++++ tstl/include/tuple.hpp | 286 +++++++++++++++++++++--------- 3 files changed, 303 insertions(+), 84 deletions(-) create mode 100644 tstl/include/integer_sequence.hpp create mode 100644 tstl/include/nth_type.hpp diff --git a/tstl/include/integer_sequence.hpp b/tstl/include/integer_sequence.hpp new file mode 100644 index 00000000..ddfd4b10 --- /dev/null +++ b/tstl/include/integer_sequence.hpp @@ -0,0 +1,71 @@ +//======================================================================= +// Copyright Baptiste Wicht 2013-2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= + +#ifndef TSTL_INTEGER_SEQUENCE_H +#define TSTL_INTEGER_SEQUENCE_H + +#include +#include + +namespace std { + +template +struct integer_sequence { + static constexpr size_t size() noexcept { + return sizeof...(Values); + } +}; + +template +using index_sequence = integer_sequence; + +template +struct sequence_concat_impl; + +template +struct sequence_concat_impl, N, false> { + using type = integer_sequence; +}; + +template +struct sequence_concat_impl, N, true> { + using type = integer_sequence; +}; + +// The 0 and 1 cannot be deduced directly, must use SFINAE + +// Base type for generating a sequence +template +struct make_integer_sequence_impl; + +// The general case construct a list by concatenating +template +struct make_integer_sequence_impl { + using type = typename sequence_concat_impl::type, N / 2, N % 2 == 1>::type; +}; + +// Specialization for empty sequence +template +struct make_integer_sequence_impl> { + using type = integer_sequence; +}; + +// Specialization for sequence of length one +template +struct make_integer_sequence_impl> { + using type = integer_sequence; +}; + +template +using make_integer_sequence = typename make_integer_sequence_impl::type; + +template +using make_index_sequence = make_integer_sequence; + +} //end of namespace std + +#endif diff --git a/tstl/include/nth_type.hpp b/tstl/include/nth_type.hpp new file mode 100644 index 00000000..b823e8dd --- /dev/null +++ b/tstl/include/nth_type.hpp @@ -0,0 +1,30 @@ +//======================================================================= +// Copyright Baptiste Wicht 2013-2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= + +#ifndef TSTL_NTH_TYPE_H +#define TSTL_NTH_TYPE_H + +#include + +namespace std { + +template +struct nth_type_impl { + using type = typename nth_type_impl::type; +}; + +template +struct nth_type_impl { + using type = Head; +}; + +template +using nth_type_t = typename nth_type_impl<0, I, Tail...>::type; + +} //end of namespace std + +#endif diff --git a/tstl/include/tuple.hpp b/tstl/include/tuple.hpp index 3b1492c7..32f76cb2 100644 --- a/tstl/include/tuple.hpp +++ b/tstl/include/tuple.hpp @@ -9,105 +9,223 @@ #define TUPLE_H #include +#include +#include // std::forward / std::move +#include +#include namespace std { -/* - Base class used to store the head of the tuple impl. If - the head type is an empty type, use EBO to optimize size -*/ +template +struct tuple; -template -struct head_base; - -template -struct head_base : H { - head_base() : H(){} - head_base(const H& h) : H(h){} - - static H& head(head_base& b){ return b; } - static const H& head(const head_base& b){ return b; } -}; - -template -struct head_base { - H head_impl; - - head_base() : head_impl(){} - head_base(const H& h) : head_impl(h){} - - static H& head(head_base& b){ return b.head_impl; } - static const H& head(const head_base& b){ return b.head_impl; } -}; - -/* Tuple implementation */ - -template -struct tuple_impl; - -template -struct tuple_impl {}; - -template -struct tuple_impl : public tuple_impl, private head_base { - typedef tuple_impl parent_t; - typedef head_base base_parent_t; - - tuple_impl() : parent_t(), base_parent_t() {} - - explicit tuple_impl(const H& head, const E&... elements): parent_t(elements...), base_parent_t(head) {} - - static H& head(tuple_impl& t){ return base_parent_t::head(t); } - static const H& head(const tuple_impl& t){ return base_parent_t::head(t); } -}; - -/* tuple class */ - -template -struct tuple : tuple_impl<0, E...> { - typedef tuple_impl<0, E...> parent_t; - - tuple() : parent_t(){} - - explicit tuple(const E&... elements): parent_t(elements...) {} -}; - -/* Helper to get the type of a tuple */ - -template +template struct tuple_element; -template -struct tuple_element> : tuple_element> { }; - -template -struct tuple_element<0, tuple> { - typedef H type; +template +struct tuple_element> { + using type = nth_type_t; }; -template -inline H& get_helper(tuple_impl& t){ - return tuple_impl::head(t); +template +using tuple_element_t = typename tuple_element::type; + +template +const tuple_element_t& get(const tuple& v) noexcept; + +template +tuple_element_t& get(tuple& v) noexcept ; + +template +tuple_element_t&& get(tuple&& v) noexcept ; + +template +struct tuple_value { + T value; + + constexpr tuple_value(){} + + tuple_value(const T& value) : value(value) { + //Nothing else to init + } + + template + tuple_value(U&& value) : value(std::forward(value)) { + //Nothing else to init + } + + tuple_value( const tuple_value& ) = default; + tuple_value( tuple_value&& ) = default; + + template + tuple_value& operator=(U&& value){ + this->value = std::forward(value); + + return *this; + } + + T& get() noexcept { + return value; + } + + const T& get() const noexcept { + return value; + } +}; + +template +struct tuple_value> : private T { + constexpr tuple_value(){} + + tuple_value(const T& value) : T(value) { + //Nothing else to init + } + + template + tuple_value(U&& value) : T(std::forward(value)) { + //Nothing else to init + } + + tuple_value( const tuple_value& ) = default; + tuple_value( tuple_value&& ) = default; + + template + tuple_value& operator=(U&& value){ + static_cast(*this) = std::forward(value); + + return *this; + } + + T& get() noexcept { + return static_cast(*this); + } + + const T& get() const noexcept { + return static_cast(*this); + } +}; + +using swallow = bool[]; + +template +struct tuple_base; + +template +struct tuple_base, T...> : tuple_value... { + constexpr tuple_base() = default; + + template> + constexpr explicit tuple_base(U&&... values) : tuple_value(std::forward(values))... { + //Nothing else to init + } + + template + constexpr explicit tuple_base(const tuple& values) : tuple_value(get(values))... { + //Nothing else to init + } + + template + constexpr explicit tuple_base(tuple&& values) : tuple_value(std::forward(get(values)))... { + //Nothing else to init + } + + tuple_base( const tuple_base& ) = default; + tuple_base( tuple_base&& ) = default; + + tuple_base& operator=(const tuple_base& v) { + (void)swallow{(tuple_value::operator=(static_cast&>(v).get()), true)...}; + return *this; + } + + tuple_base& operator=(tuple_base&& v) { + (void)swallow{(tuple_value::operator=(std::forward(static_cast&>(v).get())), true)...}; + return *this; + } + + template + tuple_base& operator=(const tuple& v) { + (void)swallow{(tuple_value::operator=(get(v)), true)...}; + return *this; + } + + template + tuple_base& operator=(tuple&& v) { + (void)swallow{(tuple_value::operator=(get(std::move(v))), true)...}; + return *this; + } +}; + +template +struct tuple { + using base_t = tuple_base, T...>; + + base_t base; + + constexpr tuple() : base(){ + //Nothing else to init + } + + constexpr tuple(const T&... values) : base(values...) { + //Nothing else to init + } + + template> + constexpr tuple(U&&... values) : base(std::forward(values)...) { + //Nothing else to init + } + + tuple( const tuple& ) = default; + tuple( tuple&& ) = default; + + template + constexpr tuple(const tuple& v) : base(v) { + //Nothing else to init + } + + template + constexpr tuple(tuple&& v) : base(std::move(v)) { + //Nothing else to init + } + + template + tuple& operator=(TT&& value){ + base = std::forward(value); + + return *this; + } +}; + +template +struct tuple_size; + +template +struct tuple_size> { + static constexpr const size_t value = sizeof...(T); +}; + +template +const nth_type_t& get(const tuple& v) noexcept { + return static_cast>&>(v.base).get(); } -template -inline const H& get_helper(const tuple_impl& t) { - return tuple_impl::head(t); +template +nth_type_t& get(tuple& v) noexcept { + return static_cast>&>(v.base).get(); } -template -inline typename tuple_element >::type& get(tuple& t){ - return get_helper(t); -} - -template -inline const typename tuple_element >::type get(const tuple& t){ - return get_helper(t); +template +nth_type_t&& get(tuple&& v) noexcept { + return static_cast&&>(static_cast>&&>(v.base).get()); } template -inline tuple make_tuple(E... args){ - return tuple(args...); +inline tuple make_tuple(E&&... args){ + return tuple(std::forward(args)...); +} + +template< class... Types > +constexpr tuple tie( Types&... args ){ + return tuple(args...); } } //end of namespace std