Completely review std::tuple

This commit is contained in:
Baptiste Wicht 2016-09-03 20:06:35 +02:00
parent ebb6653828
commit 235dde40ee
3 changed files with 303 additions and 84 deletions

View File

@ -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<types.hpp>
#include<enable_if.hpp>
namespace std {
template<typename T, T... Values>
struct integer_sequence {
static constexpr size_t size() noexcept {
return sizeof...(Values);
}
};
template <size_t... Values>
using index_sequence = integer_sequence<size_t, Values...>;
template <typename, size_t, bool>
struct sequence_concat_impl;
template <typename T, T... I, size_t N>
struct sequence_concat_impl<integer_sequence<T, I...>, N, false> {
using type = integer_sequence<T, I..., (N + I)...>;
};
template <typename T, T... I, size_t N>
struct sequence_concat_impl<integer_sequence<T, I...>, N, true> {
using type = integer_sequence<T, I..., (N + I)..., 2 * N>;
};
// The 0 and 1 cannot be deduced directly, must use SFINAE
// Base type for generating a sequence
template <typename T, T N, typename Enable = void>
struct make_integer_sequence_impl;
// The general case construct a list by concatenating
template <typename T, T N, typename Enable>
struct make_integer_sequence_impl {
using type = typename sequence_concat_impl<typename make_integer_sequence_impl<T, N / 2>::type, N / 2, N % 2 == 1>::type;
};
// Specialization for empty sequence
template <typename T, T N>
struct make_integer_sequence_impl<T, N, std::enable_if_t<(N == 0)>> {
using type = integer_sequence<T>;
};
// Specialization for sequence of length one
template <typename T, T N>
struct make_integer_sequence_impl<T, N, std::enable_if_t<(N == 1)>> {
using type = integer_sequence<T, 0>;
};
template <typename T, T N>
using make_integer_sequence = typename make_integer_sequence_impl<T, N>::type;
template <size_t N>
using make_index_sequence = make_integer_sequence<size_t, N>;
} //end of namespace std
#endif

30
tstl/include/nth_type.hpp Normal file
View File

@ -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<types.hpp>
namespace std {
template<size_t I, size_t S, typename Head, typename... Tail>
struct nth_type_impl {
using type = typename nth_type_impl<I+1, S, Tail...>::type;
};
template<size_t I, typename Head, typename... Tail>
struct nth_type_impl<I, I, Head, Tail...> {
using type = Head;
};
template<size_t I, typename... Tail>
using nth_type_t = typename nth_type_impl<0, I, Tail...>::type;
} //end of namespace std
#endif

View File

@ -9,105 +9,223 @@
#define TUPLE_H #define TUPLE_H
#include<types.hpp> #include<types.hpp>
#include<enable_if.hpp>
#include<utility.hpp> // std::forward / std::move
#include<integer_sequence.hpp>
#include<nth_type.hpp>
namespace std { namespace std {
/* template <typename... T>
Base class used to store the head of the tuple impl. If struct tuple;
the head type is an empty type, use EBO to optimize size
*/
template<size_t I, typename H, bool Empty>
struct head_base;
template<size_t I, typename H>
struct head_base<I, H, true> : 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<size_t I, typename H>
struct head_base<I, H, false> {
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<size_t I, typename... E>
struct tuple_impl;
template<size_t I>
struct tuple_impl<I> {};
template<size_t I, typename H, typename... E>
struct tuple_impl<I, H, E...> : public tuple_impl<I + 1, E...>, private head_base<I, H, __is_empty(H)> {
typedef tuple_impl<I + 1, E...> parent_t;
typedef head_base<I, H, __is_empty(H)> 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<typename... E>
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 <size_t I, typename T> template <size_t I, typename T>
struct tuple_element; struct tuple_element;
template<size_t I, typename H, typename... T> template <size_t I, typename... T>
struct tuple_element<I, tuple<H, T...>> : tuple_element<I - 1, tuple<T...>> { }; struct tuple_element<I, tuple<T...>> {
using type = nth_type_t<I, T...>;
template<typename H, typename... T>
struct tuple_element<0, tuple<H, T...>> {
typedef H type;
}; };
template<int I, typename H, typename... T> template <size_t I, typename... T>
inline H& get_helper(tuple_impl<I, H, T...>& t){ using tuple_element_t = typename tuple_element<I, T...>::type;
return tuple_impl<I, H, T...>::head(t);
template <size_t I, typename... T>
const tuple_element_t<I, T...>& get(const tuple<T...>& v) noexcept;
template <size_t I, typename... T>
tuple_element_t<I, T...>& get(tuple<T...>& v) noexcept ;
template <size_t I, typename... T>
tuple_element_t<I, T...>&& get(tuple<T...>&& v) noexcept ;
template<size_t I, typename T, typename Enable = void>
struct tuple_value {
T value;
constexpr tuple_value(){}
tuple_value(const T& value) : value(value) {
//Nothing else to init
} }
template<int I, typename H, typename... T> template <typename U>
inline const H& get_helper(const tuple_impl<I, H, T...>& t) { tuple_value(U&& value) : value(std::forward<U>(value)) {
return tuple_impl<I, H, T...>::head(t); //Nothing else to init
} }
template<int I, typename... E> tuple_value( const tuple_value& ) = default;
inline typename tuple_element<I, tuple<E...> >::type& get(tuple<E...>& t){ tuple_value( tuple_value&& ) = default;
return get_helper<I>(t);
template <typename U>
tuple_value& operator=(U&& value){
this->value = std::forward<U>(value);
return *this;
} }
template<int I, typename... E> T& get() noexcept {
inline const typename tuple_element<I, tuple<E...> >::type get(const tuple<E...>& t){ return value;
return get_helper<I>(t); }
const T& get() const noexcept {
return value;
}
};
template<size_t I, typename T>
struct tuple_value<I, T, std::enable_if_t<__is_empty(T)>> : private T {
constexpr tuple_value(){}
tuple_value(const T& value) : T(value) {
//Nothing else to init
}
template <typename U>
tuple_value(U&& value) : T(std::forward<U>(value)) {
//Nothing else to init
}
tuple_value( const tuple_value& ) = default;
tuple_value( tuple_value&& ) = default;
template <typename U>
tuple_value& operator=(U&& value){
static_cast<T&>(*this) = std::forward<U>(value);
return *this;
}
T& get() noexcept {
return static_cast<T&>(*this);
}
const T& get() const noexcept {
return static_cast<const T&>(*this);
}
};
using swallow = bool[];
template <typename, typename...>
struct tuple_base;
template <size_t... I, typename... T>
struct tuple_base<std::index_sequence<I...>, T...> : tuple_value<I, T>... {
constexpr tuple_base() = default;
template<typename... U, typename = std::enable_if_t<(sizeof...(U) == sizeof...(T))>>
constexpr explicit tuple_base(U&&... values) : tuple_value<I, T>(std::forward<U>(values))... {
//Nothing else to init
}
template <typename... U>
constexpr explicit tuple_base(const tuple<U...>& values) : tuple_value<I, T>(get<I>(values))... {
//Nothing else to init
}
template <typename... U>
constexpr explicit tuple_base(tuple<U...>&& values) : tuple_value<I, T>(std::forward<U>(get<I>(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<I, T>::operator=(static_cast<tuple_value<I, T>&>(v).get()), true)...};
return *this;
}
tuple_base& operator=(tuple_base&& v) {
(void)swallow{(tuple_value<I, T>::operator=(std::forward<T>(static_cast<tuple_value<I, T>&>(v).get())), true)...};
return *this;
}
template <typename... U>
tuple_base& operator=(const tuple<U...>& v) {
(void)swallow{(tuple_value<I, T>::operator=(get<I>(v)), true)...};
return *this;
}
template <typename... U>
tuple_base& operator=(tuple<U...>&& v) {
(void)swallow{(tuple_value<I, T>::operator=(get<I>(std::move(v))), true)...};
return *this;
}
};
template <typename... T>
struct tuple {
using base_t = tuple_base<std::make_index_sequence<sizeof...(T)>, T...>;
base_t base;
constexpr tuple() : base(){
//Nothing else to init
}
constexpr tuple(const T&... values) : base(values...) {
//Nothing else to init
}
template<typename... U, typename = std::enable_if_t<(sizeof...(U) == sizeof...(T))>>
constexpr tuple(U&&... values) : base(std::forward<U>(values)...) {
//Nothing else to init
}
tuple( const tuple& ) = default;
tuple( tuple&& ) = default;
template<typename... U>
constexpr tuple(const tuple<U...>& v) : base(v) {
//Nothing else to init
}
template<typename... U>
constexpr tuple(tuple<U...>&& v) : base(std::move(v)) {
//Nothing else to init
}
template<typename TT>
tuple& operator=(TT&& value){
base = std::forward<TT>(value);
return *this;
}
};
template <typename T>
struct tuple_size;
template <typename... T>
struct tuple_size<tuple<T...>> {
static constexpr const size_t value = sizeof...(T);
};
template <size_t I, typename... T>
const nth_type_t<I, T...>& get(const tuple<T...>& v) noexcept {
return static_cast<const tuple_value<I, nth_type_t<I, T...>>&>(v.base).get();
}
template <size_t I, typename... T>
nth_type_t<I, T...>& get(tuple<T...>& v) noexcept {
return static_cast<tuple_value<I, nth_type_t<I, T...>>&>(v.base).get();
}
template <size_t I, typename... T>
nth_type_t<I, T...>&& get(tuple<T...>&& v) noexcept {
return static_cast<nth_type_t<I, T...>&&>(static_cast<tuple_value<I, nth_type_t<I, T...>>&&>(v.base).get());
} }
template<typename... E> template<typename... E>
inline tuple<E...> make_tuple(E... args){ inline tuple<E...> make_tuple(E&&... args){
return tuple<E...>(args...); return tuple<E...>(std::forward<E>(args)...);
}
template< class... Types >
constexpr tuple<Types&...> tie( Types&... args ){
return tuple<Types&...>(args...);
} }
} //end of namespace std } //end of namespace std