HelenOS sources
This source file includes following definitions.
- make_tuple
- forward_as_tuple
- tie
- get
- get
- get
- get
- get
- get
- swap
- swap
- swap
#ifndef LIBCPP_BITS_TUPLE
#define LIBCPP_BITS_TUPLE
#include <__bits/aux.hpp>
#include <__bits/tuple/tuple_cat.hpp>
#include <__bits/tuple/tuple_ops.hpp>
#include <__bits/type_transformation.hpp>
#include <functional>
#include <type_traits>
#include <utility>
namespace std
{
template<class... Ts>
class tuple;
namespace aux
{
struct ignore_t
{
template<class T>
const ignore_t& operator=(const T&) const
{
return *this;
}
};
}
inline constexpr aux::ignore_t ignore;
template<class... Ts>
constexpr auto make_tuple(Ts&&... ts)
{
return tuple<aux::transform_tuple_types_t<Ts>...>(forward<Ts>(ts)...);
}
template<class... Ts>
constexpr tuple<Ts&&...> forward_as_tuple(Ts&&... ts) noexcept
{
return tuple<Ts&&...>(forward<Ts>(ts)...);
}
template<class... Ts>
constexpr tuple<Ts&...> tie(Ts&... ts) noexcept
{
return tuple<Ts&...>(ts...);
}
template<class... Tuples>
constexpr aux::tuple_cat_type_t<Tuples...> tuple_cat(Tuples&&... tpls)
{
return aux::tuple_cat(
forward<Tuples>(tpls)...,
make_index_sequence<sizeof...(Tuples)>{},
aux::generate_indices_t<Tuples...>{}
);
}
template<class T>
class tuple_size;
template<class T>
class tuple_size<const T>
: public integral_constant<size_t, tuple_size<T>::value>
{ };
template<class T>
class tuple_size<volatile T>
: public integral_constant<size_t, tuple_size<T>::value>
{ };
template<class T>
class tuple_size<const volatile T>
: public integral_constant<size_t, tuple_size<T>::value>
{ };
template<class... Ts>
class tuple_size<tuple<Ts...>>
: public integral_constant<size_t, sizeof...(Ts)>
{ };
template<class T>
inline constexpr size_t tuple_size_v = tuple_size<T>::value;
template<size_t I, class T>
class tuple_element;
template<size_t I, class T>
class tuple_element<I, const T>
{
using type = add_const_t<typename tuple_element<I, T>::type>;
};
template<size_t I, class T>
class tuple_element<I, volatile T>
{
using type = add_volatile_t<typename tuple_element<I, T>::type>;
};
template<size_t I, class T>
class tuple_element<I, const volatile T>
{
using type = add_cv_t<typename tuple_element<I, T>::type>;
};
namespace aux
{
template<size_t I, class T, class... Ts>
struct type_at: type_at<I - 1, Ts...>
{ };
template<class T, class... Ts>
struct type_at<0, T, Ts...>
{
using type = T;
};
template<size_t I, class... Ts>
using type_at_t = typename type_at<I, Ts...>::type;
}
template<size_t I, class... Ts>
class tuple_element<I, tuple<Ts...>>
{
public:
using type = aux::type_at_t<I, Ts...>;
};
template<size_t I, class T>
using tuple_element_t = typename tuple_element<I, T>::type;
namespace aux
{
template<size_t I, class T>
struct tuple_element_wrapper
{
constexpr tuple_element_wrapper() = default;
constexpr explicit tuple_element_wrapper(T&& val)
: value{forward<T>(val)}
{ }
template<
class U,
class = enable_if_t<
is_convertible_v<U, T> && !is_same_v<U, T>,
void
>
>
constexpr explicit tuple_element_wrapper(U&& val)
: value(forward<U>(val))
{ }
T value;
};
template<class, class...>
class tuple_impl;
template<size_t... Is, class... Ts>
class tuple_impl<index_sequence<Is...>, Ts...>: public tuple_element_wrapper<Is, Ts>...
{
public:
constexpr tuple_impl()
: tuple_element_wrapper<Is, Ts>{}...
{ }
template<class... Us>
constexpr explicit tuple_impl(Us&&... us)
: tuple_element_wrapper<Is, Ts>(forward<Us>(us))...
{ }
template<class... Us>
constexpr tuple_impl(const tuple<Us...>& tpl)
: tuple_impl{tpl, make_index_sequence<sizeof...(Us)>{}}
{ }
template<class... Us>
constexpr tuple_impl(tuple<Us...>&& tpl)
: tuple_impl{move<tuple<Us...>>(tpl), make_index_sequence<sizeof...(Us)>{}}
{ }
template<class... Us, size_t... Iss>
constexpr tuple_impl(const tuple<Us...>& tpl, index_sequence<Iss...>)
: tuple_impl{get<Iss>(tpl)...}
{ }
template<class... Us, size_t... Iss>
constexpr tuple_impl(tuple<Us...>&& tpl, index_sequence<Iss...>)
: tuple_impl{get<Iss>(move(tpl))...}
{ }
};
template<class T, class... Ts>
struct tuple_noexcept_swap
{
static constexpr bool value = noexcept(std::swap(declval<T&>(), declval<T&>()))
&& tuple_noexcept_swap<Ts...>::value;
};
template<class T>
struct tuple_noexcept_swap<T>
{
static constexpr bool value = noexcept(std::swap(declval<T&>(), declval<T&>()));
};
template<class T, class... Ts>
struct tuple_noexcept_assignment
{
static constexpr bool value = is_nothrow_move_assignable<T>::value
&& tuple_noexcept_assignment<Ts...>::value;
};
template<class T>
struct tuple_noexcept_assignment<T>
{
static constexpr bool value = is_nothrow_move_assignable<T>::value;
};
}
template<size_t I, class... Ts>
constexpr tuple_element_t<I, tuple<Ts...>>& get(tuple<Ts...>& tpl) noexcept
{
aux::tuple_element_wrapper<I, tuple_element_t<I, tuple<Ts...>>>& wrapper = tpl;
return wrapper.value;
}
template<size_t I, class... Ts>
constexpr tuple_element_t<I, tuple<Ts...>>&& get(tuple<Ts...>&& tpl) noexcept
{
return forward<typename tuple_element<I, tuple<Ts...>>::type&&>(get<I>(tpl));
}
template<size_t I, class... Ts>
constexpr const tuple_element_t<I, tuple<Ts...>>& get(const tuple<Ts...>& tpl) noexcept
{
const aux::tuple_element_wrapper<I, tuple_element_t<I, tuple<Ts...>>>& wrapper = tpl;
return wrapper.value;
}
namespace aux
{
template<size_t I, class U, class T, class... Ts>
struct index_of_type: index_of_type<I + 1, U, Ts...>
{ };
template<size_t I, class T, class... Ts>
struct index_of_type<I, T, T, Ts...>: std::integral_constant<std::size_t, I>
{ };
}
template<class T, class... Ts>
constexpr T& get(tuple<Ts...>& tpl) noexcept
{
return get<aux::index_of_type<0, T, Ts...>::value>(tpl);
}
template<class T, class... Ts>
constexpr T&& get(tuple<Ts...>&& tpl) noexcept
{
return get<aux::index_of_type<0, T, Ts...>::value>(forward<tuple<Ts...>>(tpl));
}
template<class T, class... Ts>
constexpr const T& get(const tuple<Ts...>& tpl) noexcept
{
return get<aux::index_of_type<0, T, Ts...>::value>(tpl);
}
template<class... Ts>
class tuple: public aux::tuple_impl<make_index_sequence<sizeof...(Ts)>, Ts...>
{
using base_t = aux::tuple_impl<make_index_sequence<sizeof...(Ts)>, Ts...>;
public:
constexpr tuple()
: base_t{}
{ }
constexpr explicit tuple(
const Ts&... ts, enable_if_t<sizeof...(Ts) != 0>* = nullptr)
: base_t(ts...)
{ }
template<class... Us>
constexpr explicit tuple(Us&&... us, enable_if_t<sizeof...(Us) == sizeof...(Ts)>* = nullptr)
: base_t(forward<Us>(us)...)
{ }
tuple(const tuple&) = default;
tuple(tuple&&) = default;
template<class... Us>
constexpr tuple(const tuple<Us...>& tpl, enable_if_t<sizeof...(Us) == sizeof...(Ts)>* = nullptr)
: base_t(tpl)
{ }
template<class... Us>
constexpr tuple(tuple<Us...>&& tpl, enable_if_t<sizeof...(Us) == sizeof...(Ts)>* = nullptr)
: base_t(move(tpl))
{ }
template<class U1, class U2>
constexpr tuple(const pair<U1, U2>& p)
: base_t{}
{
get<0>(*this) = p.first;
get<1>(*this) = p.second;
}
template<class U1, class U2>
constexpr tuple(pair<U1, U2>&& p)
: base_t{}
{
get<0>(*this) = forward<U1>(p.first);
get<1>(*this) = forward<U2>(p.second);
}
tuple& operator=(const tuple& other)
{
aux::tuple_ops<0, sizeof...(Ts) - 1>::assign_copy(*this, other);
return *this;
}
tuple& operator=(tuple&& other) noexcept(aux::tuple_noexcept_assignment<Ts...>::value)
{
aux::tuple_ops<0, sizeof...(Ts) - 1>::assign_move(*this, move(other));
return *this;
}
template<class... Us>
tuple& operator=(const tuple<Us...>& other)
{
aux::tuple_ops<0, sizeof...(Ts) - 1>::assign_copy(*this, other);
return *this;
}
template<class... Us>
tuple& operator=(tuple<Us...>&& other)
{
aux::tuple_ops<0, sizeof...(Ts) - 1>::assign_move(*this, move(other));
return *this;
}
template<class U1, class U2>
tuple& operator=(const pair<U1, U2>& p)
{
get<0>(*this) = p.first;
get<1>(*this) = p.second;
return *this;
}
template<class U1, class U2>
tuple& operator=(pair<U1, U2>&& p)
{
get<0>(*this) = forward<U1>(p.first);
get<1>(*this) = forward<U2>(p.second);
return *this;
}
void swap(tuple& other) noexcept(aux::tuple_noexcept_swap<Ts...>::value)
{
aux::tuple_ops<0, sizeof...(Ts) - 1>::swap(*this, other);
}
};
template<>
class tuple<>
{
tuple() = default;
void swap(tuple&) noexcept
{ }
};
template<class... Ts, class... Us>
constexpr bool operator==(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
{
if constexpr (sizeof...(Ts) == 0)
return true;
else
return aux::tuple_ops<0, sizeof...(Ts) - 1>::eq(lhs, rhs);
}
template<class... Ts, class... Us>
constexpr bool operator<(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
{
if constexpr (sizeof...(Ts) == 0)
return false;
else
return aux::tuple_ops<0, sizeof...(Ts) - 1>::lt(lhs, rhs);
}
template<class... Ts, class... Us>
constexpr bool operator!=(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
{
return !(lhs == rhs);
}
template<class... Ts, class... Us>
constexpr bool operator>(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
{
return rhs < lhs;
}
template<class... Ts, class... Us>
constexpr bool operator<=(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
{
return !(rhs < lhs);
}
template<class... Ts, class... Us>
constexpr bool operator>=(const tuple<Ts...>& lhs, const tuple<Us...> rhs)
{
return !(lhs < rhs);
}
template<class... Ts, class Alloc>
struct uses_allocator<tuple<Ts...>, Alloc>: true_type
{ };
template<class... Ts>
void swap(tuple<Ts...>& lhs, tuple<Ts...>& rhs)
noexcept(noexcept(lhs.swap(rhs)))
{
lhs.swap(rhs);
}
}
#endif
HelenOS homepage, sources at GitHub