mirror of
https://github.com/wichtounet/thor-os.git
synced 2025-09-13 14:36:37 -04:00
Completely review std::tuple
This commit is contained in:
parent
ebb6653828
commit
235dde40ee
71
tstl/include/integer_sequence.hpp
Normal file
71
tstl/include/integer_sequence.hpp
Normal 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
30
tstl/include/nth_type.hpp
Normal 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
|
@ -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>
|
template <size_t I, typename T>
|
||||||
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>
|
|
||||||
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 <typename U>
|
||||||
|
tuple_value(U&& value) : value(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){
|
||||||
|
this->value = std::forward<U>(value);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
T& get() noexcept {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
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<int I, typename H, typename... T>
|
template <size_t I, typename... T>
|
||||||
inline const H& get_helper(const tuple_impl<I, H, T...>& t) {
|
nth_type_t<I, T...>& get(tuple<T...>& v) noexcept {
|
||||||
return tuple_impl<I, H, T...>::head(t);
|
return static_cast<tuple_value<I, nth_type_t<I, T...>>&>(v.base).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int I, typename... E>
|
template <size_t I, typename... T>
|
||||||
inline typename tuple_element<I, tuple<E...> >::type& get(tuple<E...>& t){
|
nth_type_t<I, T...>&& get(tuple<T...>&& v) noexcept {
|
||||||
return get_helper<I>(t);
|
return static_cast<nth_type_t<I, T...>&&>(static_cast<tuple_value<I, nth_type_t<I, T...>>&&>(v.base).get());
|
||||||
}
|
|
||||||
|
|
||||||
template<int I, typename... E>
|
|
||||||
inline const typename tuple_element<I, tuple<E...> >::type get(const tuple<E...>& t){
|
|
||||||
return get_helper<I>(t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user