Skip to content

Instantly share code, notes, and snippets.

@wx257osn2
Last active December 31, 2015 22:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wx257osn2/8051171 to your computer and use it in GitHub Desktop.
Save wx257osn2/8051171 to your computer and use it in GitHub Desktop.
O(log N) C++11 constexpr tuple
#include<type_traits>
#include<array>
#include<utility>
#include<algorithm>
#ifdef VEILER_USE_TUPLE_STRICT_AND_POSITIVE_INSTANTIATION
#define VEILER_TUPLE_STRICT_CHECK(...) typename std::enable_if<(__VA_ARGS__)>::type* = nullptr
#define VEILER_TUPLE_POSITIVE_NOEXCEPT(...) noexcept(__VA_ARGS__)
#else
#define VEILER_TUPLE_STRICT_CHECK(...) void* = nullptr
#define VEILER_TUPLE_POSITIVE_NOEXCEPT(...)
#endif
namespace veiler{
namespace detail{
namespace tuple{
template<long long...>struct index_tuple;
template<typename,long long...>struct make_reverse_index_tuple_impl;
template<long long... Idxs, long long Idx, long long... Rmning>
struct make_reverse_index_tuple_impl<index_tuple<Idxs...>, Idx, Rmning...> :
make_reverse_index_tuple_impl<index_tuple<Idx, Idxs...>, Rmning...>{};
template<long long... Idxs>
struct make_reverse_index_tuple_impl<index_tuple<Idxs...>>{using type = index_tuple<Idxs...>;};
template<typename>struct make_reverse_index_tuple;
template<long long... Idxs>
struct make_reverse_index_tuple<index_tuple<Idxs...>> :
make_reverse_index_tuple_impl<index_tuple<>, Idxs...>{};
template<typename,long long>struct make_index_range_next;
template<long long... Idxs, long long N>
struct make_index_range_next<index_tuple<Idxs...>, N>{using type = index_tuple<Idxs..., (Idxs+N)...>;};
template<typename,long long,long long>struct make_index_range_next_;
template<long long... Idxs, long long N, long long T>
struct make_index_range_next_<index_tuple<Idxs...>, N, T>{using type = index_tuple<Idxs..., (Idxs+N)..., T>;};
template<long long,long long,long long,typename = void>struct make_index_range_impl;
template<long long B, long long S, long long N>
struct make_index_range_impl<B, S, N, typename std::enable_if<(N==0 || N==1)>::type>{
using type = typename std::conditional<!N, index_tuple<>, index_tuple<B>>::type;
};
template<long long B, long long S, long long N>
struct make_index_range_impl<B, S, N, typename std::enable_if<(N>1)>::type>{
using type = typename std::conditional<N % 2,
typename make_index_range_next_<
typename make_index_range_impl<B, S, N/2>::type,
B + N/2 * S,
B + (N-1) * S
>::type,
typename make_index_range_next<
typename make_index_range_impl<B, S, N/2>::type,
B + N/2 * S
>::type
>::type;
};
template<long long B, long long E, long long S = (B<E ? 1 : -1)>
struct make_index_range{using type = typename make_index_range_impl<B, S, (E - B + (S>0 ? S-1 : S+1)) / S>::type;};
template<typename... Types>
struct make_indexes : make_index_range<0, sizeof...(Types), 1>{};
template<long long... Idxs>
struct index_tuple{
static constexpr std::size_t size()noexcept{return sizeof...(Idxs);}
};
template<typename...>struct type_tuple;
template<typename T>
struct type_wrapper{using type = T;};
template<typename,typename>struct make_type_tuple_impl;
template<typename... Lefts, typename... Rights>
struct make_type_tuple_impl<type_tuple<Lefts...>, type_tuple<Rights...>>{
using type = type_tuple<Lefts..., Rights...>;
};
template<std::size_t N, typename T = void>
struct make_type_tuple :
make_type_tuple_impl<
typename make_type_tuple< N/2, T>::type,
typename make_type_tuple<N - N/2, T>::type
>{};
template<typename T>
struct make_type_tuple<1,T>{using type = type_tuple<T>;};
template<typename T>
struct make_type_tuple<0,T>{using type = type_tuple<>;};
template<typename>struct type_at_impl_impl;
template<typename... Types>
struct type_at_impl_impl<type_tuple<Types...>>{template<typename T>static T eval(Types*..., T*, ...);};
template<std::size_t N, typename... Types>
struct type_at_impl{
using type = decltype(type_at_impl_impl<typename make_type_tuple<N>::type>::eval(static_cast<Types*>(nullptr)...));
};
template<typename T, std::size_t N>class type_at{
template<template<typename...>class Type, class... Args>
static auto impl(type_wrapper<Type<Args...>>)->typename type_at_impl<N, type_wrapper<Args>...>::type;
public:
using type = typename decltype(impl(type_wrapper<T>{}))::type;
};
template<typename... Types>
struct type_tuple{
template<std::size_t N>
using at = typename type_at<type_tuple<Types...>, N>::type;
};
template<typename...>class value_btree;
template<typename T, typename Left, typename Right>
class value_btree<T, Left, Right>{
T t;
Left left;
Right right;
public:
static constexpr std::size_t size = 3;
constexpr value_btree(const T& _, const Left& l, const Right& r)
noexcept(std::is_nothrow_copy_constructible<T>::value &&
std::is_nothrow_copy_constructible<Left>::value &&
std::is_nothrow_copy_constructible<Right>::value) :
t(_), left(l), right(r){}
constexpr value_btree(T&& _, Left&& l, Right&& r)
noexcept(std::is_nothrow_move_constructible<T>::value &&
std::is_nothrow_move_constructible<Left>::value &&
std::is_nothrow_move_constructible<Right>::value) :
t(std::forward<T>(_)), left(std::forward<Left>(l)), right(std::forward<Right>(r)){}
template<std::size_t N, typename std::enable_if<N==0>::type* = nullptr>
static constexpr T& get(value_btree& btree)noexcept{return btree.t;}
template<std::size_t N, typename std::enable_if<N==1>::type* = nullptr>
static constexpr Left& get(value_btree& btree)noexcept{return btree.left;}
template<std::size_t N, typename std::enable_if<N==2>::type* = nullptr>
static constexpr Right& get(value_btree& btree)noexcept{return btree.right;}
template<std::size_t N, typename std::enable_if<N==0>::type* = nullptr>
static constexpr T&& get(value_btree&& btree)noexcept{return std::forward<T>(btree.t);}
template<std::size_t N, typename std::enable_if<N==1>::type* = nullptr>
static constexpr Left&& get(value_btree&& btree)noexcept{return std::forward<Left>(btree.left);}
template<std::size_t N, typename std::enable_if<N==2>::type* = nullptr>
static constexpr Right&& get(value_btree&& btree)noexcept{return std::forward<Right>(btree.right);}
template<std::size_t N, typename std::enable_if<N==0>::type* = nullptr>
static constexpr const T& get(const value_btree& btree)noexcept{return btree.t;}
template<std::size_t N, typename std::enable_if<N==1>::type* = nullptr>
static constexpr const Left& get(const value_btree& btree)noexcept{return btree.left;}
template<std::size_t N, typename std::enable_if<N==2>::type* = nullptr>
static constexpr const Right& get(const value_btree& btree)noexcept{return btree.right;}
void swap(value_btree& rhs)
noexcept(noexcept(std::swap(std::declval<T&>(), std::declval<T&>())) &&
noexcept(std::swap(std::declval<Left&>(), std::declval<Left&>())) &&
noexcept(std::swap(std::declval<Right&>(), std::declval<Right&>()))){
using std::swap;
swap(t, rhs.t);
swap(left, rhs.left);
swap(right, rhs.right);
}
constexpr bool and_()const noexcept{return t && left && right;}
constexpr bool or_()const noexcept{return t || left || right;}
template<typename F>
static constexpr auto btree_apply(value_btree&& btree, const F& f)
->decltype((f(std::forward<value_btree<T, Left, Right>>(btree)))){
return f(std::forward<value_btree<T, Left, Right>>(btree));
}
template<typename U, typename L, typename R>
friend constexpr bool operator==(const value_btree<T, Left, Right>& lhs, const value_btree<U, L, R>& rhs)
noexcept(noexcept(bool(lhs.t == rhs.t) && bool(lhs.left == rhs.left) && bool(lhs.right == rhs.right))){
return bool(lhs.t == rhs.t) && bool(lhs.left == rhs.left) && bool(lhs.right == rhs.right);
}
template<typename U, typename L, typename R>
friend constexpr bool operator!=(const value_btree<T, Left, Right>& lhs, const value_btree<U, L, R>& rhs)
noexcept(noexcept(!(lhs == rhs))){
return !(lhs == rhs);
}
template<typename U, typename L, typename R>
friend constexpr bool operator< (const value_btree<T, Left, Right>& lhs, const value_btree<U, L, R>& rhs)
noexcept(noexcept(bool(lhs.t < rhs.t) || (!bool(rhs.t < lhs.t) && (
bool(lhs.left < rhs.left) || (!bool(rhs.left < lhs.left) &&
bool(lhs.right < rhs.right)))))){
return bool(lhs.t < rhs.t) || (!bool(rhs.t < lhs.t) && (
bool(lhs.left < rhs.left) || (!bool(rhs.left < lhs.left)&&
bool(lhs.right < rhs.right))));
}
template<typename U, typename L, typename R>
friend constexpr bool operator> (const value_btree<T, Left, Right>& lhs, const value_btree<U, L, R>& rhs)
noexcept(noexcept(rhs < lhs)){
return rhs < lhs;
}
template<typename U, typename L, typename R>
friend constexpr bool operator<=(const value_btree<T, Left, Right>& lhs, const value_btree<U, L, R>& rhs)
noexcept(noexcept(!(rhs < lhs))){
return !(rhs < lhs);
}
template<typename U, typename L, typename R>
friend constexpr bool operator>=(const value_btree<T, Left, Right>& lhs, const value_btree<U, L, R>& rhs)
noexcept(noexcept(!(lhs < rhs))){
return !(lhs < rhs);
}
};
template<typename T, typename Left>
class value_btree<T, Left>{
T t;
Left left;
public:
static constexpr std::size_t size = 2;
constexpr value_btree(const T& _, const Left& l)
noexcept(std::is_nothrow_copy_constructible<T>::value &&
std::is_nothrow_copy_constructible<Left>::value) :
t(_), left(l){}
constexpr value_btree(T&& _, Left&& l)
noexcept(std::is_nothrow_move_constructible<T>::value &&
std::is_nothrow_move_constructible<Left>::value) :
t(std::forward<T>(_)), left(std::forward<Left>(l)){}
template<std::size_t N, typename std::enable_if<N==0>::type* = nullptr>
static constexpr T& get(value_btree& btree)noexcept{return btree.t;}
template<std::size_t N, typename std::enable_if<N==1>::type* = nullptr>
static constexpr Left& get(value_btree& btree)noexcept{return btree.left;}
template<std::size_t N, typename std::enable_if<N==0>::type* = nullptr>
static constexpr T&& get(value_btree&& btree)noexcept{return std::forward<T>(btree.t);}
template<std::size_t N, typename std::enable_if<N==1>::type* = nullptr>
static constexpr Left&& get(value_btree&& btree)noexcept{return std::forward<Left>(btree.left);}
template<std::size_t N, typename std::enable_if<N==0>::type* = nullptr>
static constexpr const T& get(const value_btree& btree)noexcept{return btree.t;}
template<std::size_t N, typename std::enable_if<N==1>::type* = nullptr>
static constexpr const Left& get(const value_btree& btree)noexcept{return btree.left;}
void swap(value_btree& rhs)
noexcept(noexcept(std::swap(std::declval<T&>(), std::declval<T&>())) &&
noexcept(std::swap(std::declval<Left&>(), std::declval<Left&>()))){
using std::swap;
swap(t, rhs.t);
swap(left, rhs.left);
}
constexpr bool and_()const noexcept{return t && left;}
constexpr bool or_()const noexcept{return t || left;}
template<typename F>
static constexpr auto btree_apply(value_btree&& btree, const F& f)
->decltype((f(std::forward<value_btree<T, Left>>(btree)))){
return f(std::forward<value_btree<T, Left>>(btree));
}
template<typename U, typename L>
friend constexpr bool operator==(const value_btree<T, Left>& lhs, const value_btree<U, L>& rhs)
noexcept(noexcept(bool(lhs.t == rhs.t) && bool(lhs.left == rhs.left))){
return bool(lhs.t == rhs.t) && bool(lhs.left == rhs.left);
}
template<typename U, typename L>
friend constexpr bool operator!=(const value_btree<T, Left>& lhs, const value_btree<U, L>& rhs)
noexcept(noexcept(!(lhs == rhs))){
return !(lhs == rhs);
}
template<typename U, typename L>
friend constexpr bool operator< (const value_btree<T, Left>& lhs, const value_btree<U, L>& rhs)
noexcept(noexcept(bool(lhs.t < rhs.t) || (!bool(rhs.t < lhs.t) &&
bool(lhs.left < rhs.left)))){
return bool(lhs.t < rhs.t) || (!bool(rhs.t < lhs.t) &&
bool(lhs.left < rhs.left));
}
template<typename U, typename L>
friend constexpr bool operator> (const value_btree<T, Left>& lhs, const value_btree<U, L>& rhs)
noexcept(noexcept(rhs < lhs)){
return rhs < lhs;
}
template<typename U, typename L>
friend constexpr bool operator<=(const value_btree<T, Left>& lhs, const value_btree<U, L>& rhs)
noexcept(noexcept(!(rhs < lhs))){
return !(rhs < lhs);
}
template<typename U, typename L>
friend constexpr bool operator>=(const value_btree<T, Left>& lhs, const value_btree<U, L>& rhs)
noexcept(noexcept(!(lhs < rhs))){
return !(lhs < rhs);
}
};
template<typename T>
class value_btree<T>{
T t;
public:
static constexpr std::size_t size = 1;
constexpr value_btree(const T& _)
noexcept(std::is_nothrow_copy_constructible<T>::value) :
t(_){}
constexpr value_btree(T&& _)
noexcept(std::is_nothrow_move_constructible<T>::value) :
t(std::forward<T>(_)){}
template<std::size_t N, typename std::enable_if<N==0>::type* = nullptr>
static constexpr T& get(value_btree& btree)noexcept{return btree.t;}
template<std::size_t N, typename std::enable_if<N==0>::type* = nullptr>
static constexpr T&& get(value_btree&& btree)noexcept{return std::forward<T>(btree.t);}
template<std::size_t N, typename std::enable_if<N==0>::type* = nullptr>
static constexpr const T& get(const value_btree& btree)noexcept{return btree.t;}
constexpr bool and_()const noexcept{return t;}
constexpr bool or_()const noexcept{return t;}
void swap(value_btree& rhs)
noexcept(noexcept(std::swap(std::declval<T&>(),std::declval<T&>()))){
using std::swap;
swap(t, rhs.t);
}
template<typename F>
static constexpr auto btree_apply(value_btree&& btree, const F& f)
->decltype((f(std::forward<value_btree<T>>(btree)))){
return f(std::forward<value_btree<T>>(btree));
}
template<typename U>
friend constexpr bool operator==(const value_btree<T>& lhs, const value_btree<U>& rhs)
noexcept(noexcept(bool(lhs.t == rhs.t))){
return bool(lhs.t == rhs.t);
}
template<typename U>
friend constexpr bool operator!=(const value_btree<T>& lhs, const value_btree<U>& rhs)
noexcept(noexcept(!(lhs == rhs))){
return !(lhs == rhs);
}
template<typename U>
friend constexpr bool operator< (const value_btree<T>& lhs, const value_btree<U>& rhs)
noexcept(noexcept(bool(lhs.t < rhs.t))){
return bool(lhs.t < rhs.t);
}
template<typename U>
friend constexpr bool operator> (const value_btree<T>& lhs, const value_btree<U>& rhs)
noexcept(noexcept(rhs < lhs)){
return rhs < lhs;
}
template<typename U>
friend constexpr bool operator<=(const value_btree<T>& lhs, const value_btree<U>& rhs)
noexcept(noexcept(!(rhs < lhs))){
return !(rhs < lhs);
}
template<typename U>
friend constexpr bool operator>=(const value_btree<T>& lhs, const value_btree<U>& rhs)
noexcept(noexcept(!(lhs < rhs))){
return !(lhs < rhs);
}
};
template<typename... LArgs, typename... RArgs, typename T, typename... Lefts, typename... Rights>
class value_btree<type_tuple<LArgs...>, type_tuple<RArgs...>, T, value_btree<Lefts...>, value_btree<Rights...>>{
T t;
value_btree<Lefts...> left;
value_btree<Rights...> right;
public:
static constexpr std::size_t size = 1 + value_btree<Lefts...>::size + value_btree<Rights...>::size;
constexpr value_btree(const T& _, const LArgs&... largs, const RArgs&... rargs)
noexcept(std::is_nothrow_copy_constructible<T>::value &&
std::is_nothrow_constructible<value_btree<Lefts...>, const LArgs&...>::value &&
std::is_nothrow_constructible<value_btree<Rights...>, const RArgs&...>::value) :
t(_), left(largs...), right(rargs...){}
constexpr value_btree(T&& _, LArgs&&... largs, RArgs&&... rargs)
noexcept(std::is_nothrow_move_constructible<T>::value &&
std::is_nothrow_constructible<value_btree<Lefts...>, LArgs&&...>::value &&
std::is_nothrow_constructible<value_btree<Rights...>, RArgs&&...>::value) :
t(std::forward<T>(_)), left(std::forward<LArgs>(largs)...), right(std::forward<RArgs>(rargs)...){}
template<std::size_t N, typename std::enable_if<N==0>::type* = nullptr>
static constexpr T& get(value_btree& btree)noexcept{return btree.t;}
template<std::size_t N, typename std::enable_if<N-1 < (size-1)/2>::type* = nullptr>
static constexpr auto get(value_btree& btree)noexcept
->decltype((value_btree<Lefts...>::template get<N-1>(btree.left))){
return value_btree<Lefts...>::template get<N-1>(btree.left);
}
template<std::size_t N, typename std::enable_if<(size-1)/2 <= N-1>::type* = nullptr>
static constexpr auto get(value_btree& btree)noexcept
->decltype((value_btree<Rights...>::template get<N-1 - (size-1)/2>(btree.right))){
return value_btree<Rights...>::template get<N-1 - (size-1)/2>(btree.right);
}
template<std::size_t N, typename std::enable_if<N==0>::type* = nullptr>
static constexpr T&& get(value_btree&& btree)noexcept{return std::forward<T>(btree.t);}
template<std::size_t N, typename std::enable_if<N-1 < (size-1)/2>::type* = nullptr>
static constexpr auto get(value_btree&& btree)noexcept
->decltype((value_btree<Lefts...>::template get<N-1>(std::forward<value_btree<Lefts...>>(btree.left)))){
return value_btree<Lefts...>::template get<N-1>(std::forward<value_btree<Lefts...>>(btree.left));
}
template<std::size_t N, typename std::enable_if<(size-1)/2 <= N-1>::type* = nullptr>
static constexpr auto get(value_btree&& btree)noexcept
->decltype((value_btree<Rights...>::template get<N-1 - (size-1)/2>(std::forward<value_btree<Rights...>>(btree.right)))){
return value_btree<Rights...>::template get<N-1 - (size-1)/2>(std::forward<value_btree<Rights...>>(btree.right));
}
template<std::size_t N, typename std::enable_if<N==0>::type* = nullptr>
static constexpr const T& get(const value_btree& btree)noexcept{return btree.t;}
template<std::size_t N, typename std::enable_if<N-1 < (size-1)/2>::type* = nullptr>
static constexpr auto get(const value_btree& btree)noexcept
->decltype((value_btree<Lefts...>::template get<N-1>(btree.left))){
return value_btree<Lefts...>::template get<N-1>(btree.left);
}
template<std::size_t N, typename std::enable_if<(size-1)/2 <= N-1>::type* = nullptr>
static constexpr auto get(const value_btree& btree)noexcept
->decltype((value_btree<Rights...>::template get<N-1 - (size-1)/2>(btree.right))){
return value_btree<Rights...>::template get<N-1 - (size-1)/2>(btree.right);
}
void swap(value_btree& rhs)
noexcept(noexcept(std::swap(std::declval<T&>(), std::declval<T&>())) &&
noexcept(std::declval<value_btree<Lefts...>&>() .swap(std::declval<value_btree<Lefts...>&>())) &&
noexcept(std::declval<value_btree<Rights...>&>().swap(std::declval<value_btree<Rights...>&>()))){
using std::swap;
swap(t, rhs.t);
left.swap(rhs.left);
right.swap(rhs.right);
}
constexpr bool and_()const noexcept{return t && left.and_() && right.and_();}
constexpr bool or_()const noexcept{return t || left. or_() || right. or_();}
template<typename F>
static constexpr auto btree_apply(value_btree&& btree, const F& f)
->decltype(f(value_btree<T,
decltype(value_btree<Lefts... >::btree_apply(std::forward<value_btree<Lefts... >>(btree.left), f)),
decltype(value_btree<Rights...>::btree_apply(std::forward<value_btree<Rights...>>(btree.right), f))>(
std::forward<T>(btree.t),
value_btree<Lefts... >::btree_apply(std::forward<value_btree<Lefts... >>(btree.left), f),
value_btree<Rights...>::btree_apply(std::forward<value_btree<Rights...>>(btree.right), f)))){
return f(value_btree<T,
decltype(value_btree<Lefts... >::btree_apply(std::forward<value_btree<Lefts... >>(btree.left), f)),
decltype(value_btree<Rights...>::btree_apply(std::forward<value_btree<Rights...>>(btree.right), f))>(
std::forward<T>(btree.t),
value_btree<Lefts... >::btree_apply(std::forward<value_btree<Lefts... >>(btree.left), f),
value_btree<Rights...>::btree_apply(std::forward<value_btree<Rights...>>(btree.right), f)));
}
template<typename... As, typename... Bs, typename U, typename... Ls, typename... Rs>
friend constexpr bool operator==(const value_btree<type_tuple<LArgs...>, type_tuple<RArgs...>, T, value_btree<Lefts...>, value_btree<Rights...>>& lhs,
const value_btree<type_tuple<As...>, type_tuple<Bs...>, U, value_btree<Ls...>, value_btree<Rs...>>& rhs)
noexcept(noexcept(bool(lhs.t == rhs.t) && lhs.left == rhs.left && lhs.right == rhs.right)){
return bool(lhs.t == rhs.t) && lhs.left == rhs.left && lhs.right == rhs.right;
}
template<typename... As, typename... Bs, typename U, typename... Ls, typename... Rs>
friend constexpr bool operator!=(const value_btree<type_tuple<LArgs...>, type_tuple<RArgs...>, T, value_btree<Lefts...>, value_btree<Rights...>>& lhs,
const value_btree<type_tuple<As...>, type_tuple<Bs...>, U, value_btree<Ls...>, value_btree<Rs...>>& rhs)
noexcept(noexcept(!(lhs == rhs))){
return !(lhs == rhs);
}
template<typename... As, typename... Bs, typename U, typename... Ls, typename... Rs>
friend constexpr bool operator< (const value_btree<type_tuple<LArgs...>, type_tuple<RArgs...>, T, value_btree<Lefts...>, value_btree<Rights...>>& lhs,
const value_btree<type_tuple<As...>, type_tuple<Bs...>, U, value_btree<Ls...>, value_btree<Rs...>>& rhs)
noexcept(noexcept(bool(lhs.t < rhs.t) || (!bool(rhs.t < lhs.t) && (
bool(lhs.left < rhs.left) || (!bool(rhs.left < lhs.left) &&
bool(lhs.right < rhs.right)))))){
return bool(lhs.t < rhs.t) || (!bool(rhs.t < lhs.t) && (
bool(lhs.left < rhs.left) || (!bool(rhs.left < lhs.left) &&
bool(lhs.right < rhs.right))));
}
template<typename... As, typename... Bs, typename U, typename... Ls, typename... Rs>
friend constexpr bool operator> (const value_btree<type_tuple<LArgs...>, type_tuple<RArgs...>, T, value_btree<Lefts...>, value_btree<Rights...>>& lhs,
const value_btree<type_tuple<As...>, type_tuple<Bs...>, U, value_btree<Ls...>, value_btree<Rs...>>& rhs)
noexcept(noexcept(rhs < lhs)){
return rhs < lhs;
}
template<typename... As, typename... Bs, typename U, typename... Ls, typename... Rs>
friend constexpr bool operator<=(const value_btree<type_tuple<LArgs...>, type_tuple<RArgs...>, T, value_btree<Lefts...>, value_btree<Rights...>>& lhs,
const value_btree<type_tuple<As...>, type_tuple<Bs...>, U, value_btree<Ls...>, value_btree<Rs...>>& rhs)
noexcept(noexcept(!(rhs < lhs))){
return !(rhs < lhs);
}
template<typename... As, typename... Bs, typename U, typename... Ls, typename... Rs>
friend constexpr bool operator>=(const value_btree<type_tuple<LArgs...>, type_tuple<RArgs...>, T, value_btree<Lefts...>, value_btree<Rights...>>& lhs,
const value_btree<type_tuple<As...>, type_tuple<Bs...>, U, value_btree<Ls...>, value_btree<Rs...>>& rhs)
noexcept(noexcept(!(lhs < rhs))){
return !(lhs < rhs);
}
};
template<>
class value_btree<>{
public:
static constexpr std::size_t size = 0;
constexpr value_btree() = default;
void swap(value_btree<>&)const noexcept{}
constexpr bool and_()const noexcept{return false;}
constexpr bool or_()const noexcept{return false;}
friend constexpr bool operator==(const value_btree<>&, const value_btree<>&)noexcept{return true;}
friend constexpr bool operator!=(const value_btree<>&, const value_btree<>&)noexcept{return false;}
friend constexpr bool operator< (const value_btree<>&, const value_btree<>&)noexcept{return false;}
friend constexpr bool operator> (const value_btree<>&, const value_btree<>&)noexcept{return false;}
friend constexpr bool operator<=(const value_btree<>&, const value_btree<>&)noexcept{return true;}
friend constexpr bool operator>=(const value_btree<>&, const value_btree<>&)noexcept{return true;}
};
template<std::size_t,typename>struct make_value_btree;
template<std::size_t N, typename T, typename... Args>
struct make_value_btree<N, type_tuple<T, Args...>>{
private:
using Left = make_value_btree< (N-1)/2, type_tuple<Args...>>;
using Right = make_value_btree<(N-1)-(N-1)/2, typename Left::remaining>;
template<typename U, typename... LArgs, typename... RArgs>
static auto impl(type_tuple<U>, type_tuple<LArgs...>, type_tuple<RArgs...>)->type_tuple<U, LArgs..., RArgs...>;
public:
using remaining = typename Right::remaining;
using args = decltype(impl(std::declval<type_tuple<T>>(), std::declval<typename Left::args>(), std::declval<typename Right::args>()));
using type = value_btree<typename Left::args, typename Right::args, T, typename Left::type, typename Right::type>;
};
template<typename T, typename U, typename V, typename... Args>
struct make_value_btree<3, type_tuple<T, U, V, Args...>>{
using args = type_tuple<T, U, V>;
using type = value_btree<T, U, V>;
using remaining = type_tuple<Args...>;
};
template<typename T, typename U, typename... Args>
struct make_value_btree<2, type_tuple<T, U, Args...>>{
using args = type_tuple<T, U>;
using type = value_btree<T, U>;
using remaining = type_tuple<Args...>;
};
template<typename T, typename... Args>
struct make_value_btree<1, type_tuple<T, Args...>>{
using args = type_tuple<T>;
using type = value_btree<T>;
using remaining = type_tuple<Args...>;
};
template<>
struct make_value_btree<0,type_tuple<>>{
using type = value_btree<>;
};
template<std::size_t N>
class cond_tuple{
using impl_type = typename make_value_btree<N, typename make_type_tuple<N, bool>::type>::type;
impl_type impl;
public:
template<typename... Args>
constexpr cond_tuple(Args... conds)
noexcept(std::is_nothrow_constructible<impl_type, decltype(static_cast<bool>(conds))...>::value) :
impl(std::forward<bool>(static_cast<bool>(conds))...){}
constexpr bool and_()const noexcept{return impl.and_();}
constexpr bool or_()const noexcept{return impl. or_();}
};
template<typename... Args>
constexpr cond_tuple<sizeof...(Args)> make_cond_tuple(Args&&... conds)
noexcept(std::is_nothrow_constructible<cond_tuple<sizeof...(Args)>, decltype(static_cast<bool>(std::forward<Args>(conds)))...>::value){
return cond_tuple<sizeof...(Args)>(std::forward<bool>(static_cast<bool>(std::forward<Args>(conds)))...);
}
template<typename... Types>class tuple{
using impl_type = typename make_value_btree<sizeof...(Types), type_tuple<Types...>>::type;
impl_type impl;
template<typename... UTypes, long long... Idxs>
constexpr tuple(const tuple<UTypes...>& u, index_tuple<Idxs...>)
VEILER_TUPLE_POSITIVE_NOEXCEPT(make_cond_tuple(std::is_nothrow_constructible<Types, const UTypes&>::value...).and_()) :
impl(tuple<UTypes...>::template get<Idxs>(u)...){}
template<typename... UTypes, long long... Idxs>
constexpr tuple(tuple<UTypes...>&& u, index_tuple<Idxs...>)
VEILER_TUPLE_POSITIVE_NOEXCEPT(make_cond_tuple(std::is_nothrow_constructible<Types, UTypes&&>::value...).and_()) :
impl(tuple<UTypes...>::template get<Idxs>(std::forward<tuple<UTypes...>>(u))...){}
template<typename... Args>
static void expand_variadic_templates(Args&&...){}
template<long long... Idxs>
tuple& move_assign(tuple&& src, index_tuple<Idxs...>)
VEILER_TUPLE_POSITIVE_NOEXCEPT(make_cond_tuple(std::is_nothrow_move_assignable<Types>::value...).and_()){
expand_variadic_templates((
get<Idxs>(*this) = get<Idxs>(std::forward<tuple>(src))
,0)...);
return *this;
}
public:
static constexpr std::size_t size = impl_type::size;
template<VEILER_TUPLE_STRICT_CHECK(make_cond_tuple(std::is_default_constructible<Types>::value...).and_())>
constexpr tuple()
VEILER_TUPLE_POSITIVE_NOEXCEPT(make_cond_tuple(std::is_nothrow_default_constructible<Types>::value...).and_()) :
impl{}{}
template<VEILER_TUPLE_STRICT_CHECK(make_cond_tuple(std::is_copy_constructible<Types>::value...).and_())>
explicit constexpr tuple(const Types&... args)
VEILER_TUPLE_POSITIVE_NOEXCEPT(make_cond_tuple(std::is_nothrow_copy_constructible<Types>::value...).and_()) :
impl(args...){}
template<typename... UTypes,
VEILER_TUPLE_STRICT_CHECK(sizeof...(Types) == sizeof...(UTypes) &&
make_cond_tuple(std::is_constructible<Types, UTypes&&>::value...).and_())>
explicit constexpr tuple(UTypes&&... args)
VEILER_TUPLE_POSITIVE_NOEXCEPT(make_cond_tuple(std::is_nothrow_constructible<Types, UTypes&&>::value...).and_()) :
impl(std::forward<UTypes>(args)...){}
tuple(const tuple& t) = default;
tuple(tuple&& t) = default;
template<typename... UTypes,
VEILER_TUPLE_STRICT_CHECK(sizeof...(Types) == sizeof...(UTypes) &&
make_cond_tuple(std::is_constructible<Types, const UTypes&>::value...).and_())>
constexpr tuple(const tuple<UTypes...>& u)
VEILER_TUPLE_POSITIVE_NOEXCEPT(make_cond_tuple(std::is_nothrow_constructible<Types, const UTypes&>::value...).and_()) :
tuple(u, typename make_indexes<UTypes...>::type{}){}
template<typename... UTypes,
VEILER_TUPLE_STRICT_CHECK(sizeof...(Types) == sizeof...(UTypes) && make_cond_tuple(std::is_constructible<Types, UTypes&&>::value...).and_())>
constexpr tuple(tuple<UTypes...>&& u)
VEILER_TUPLE_POSITIVE_NOEXCEPT(make_cond_tuple(std::is_constructible<Types, UTypes&&>::value...).and_()) :
tuple(std::forward<tuple<UTypes...>>(u), typename make_indexes<UTypes...>::type{}){}
template<typename U1, typename U2,
VEILER_TUPLE_STRICT_CHECK(sizeof...(Types) == 2 &&
std::is_constructible<typename type_tuple<Types...>::template at<0>, const U1&>::value &&
std::is_constructible<typename type_tuple<Types...>::template at<1>, const U2&>::value)>
constexpr tuple(const std::pair<U1, U2>& u)
noexcept(std::is_nothrow_constructible<typename type_tuple<Types...>::template at<0>, const U1&>::value &&
std::is_nothrow_constructible<typename type_tuple<Types...>::template at<1>, const U2&>::value) :
impl(u.first, u.second){}
template<typename U1, typename U2,
VEILER_TUPLE_STRICT_CHECK(sizeof...(Types) == 2 &&
std::is_constructible<typename type_tuple<Types...>::template at<0>, U1&&>::value &&
std::is_constructible<typename type_tuple<Types...>::template at<1>, U2&&>::value)>
constexpr tuple(std::pair<U1, U2>&& u)
noexcept(std::is_nothrow_constructible<typename type_tuple<Types...>::template at<0>, U1&&>::value &&
std::is_nothrow_constructible<typename type_tuple<Types...>::template at<1>, U2&&>::value) :
impl(std::forward<U1>(u.first), std::forward<U2>(u.second)){}
template<VEILER_TUPLE_STRICT_CHECK(make_cond_tuple(std::is_copy_assignable<Types>::value...).and_())>
tuple& operator=(const tuple& src)
VEILER_TUPLE_POSITIVE_NOEXCEPT(make_cond_tuple(std::is_nothrow_copy_assignable<Types>::value...).and_()){
this->impl = src.impl;
return *this;
}
template<VEILER_TUPLE_STRICT_CHECK(make_cond_tuple(std::is_move_assignable<Types>::value...).and_())>
tuple& operator=(tuple&& src)
VEILER_TUPLE_POSITIVE_NOEXCEPT(make_cond_tuple(std::is_nothrow_move_assignable<Types>::value...).and_()){
this->impl = std::forward<impl_type>(src.impl);
return *this;
}
template<typename... UTypes,
VEILER_TUPLE_STRICT_CHECK(sizeof...(Types) == sizeof...(UTypes) &&
make_cond_tuple(std::is_assignable<Types&, const UTypes&>::value...).and_())>
tuple& operator=(const tuple<UTypes...>& src)
VEILER_TUPLE_POSITIVE_NOEXCEPT(make_cond_tuple(std::is_nothrow_constructible<Types, const UTypes&>::value...).and_()){
this->impl = std::forward<impl_type>(tuple(src).impl);
return *this;
}
template<typename... UTypes,
VEILER_TUPLE_STRICT_CHECK(sizeof...(Types) == sizeof...(UTypes) &&
make_cond_tuple(std::is_assignable<Types&,UTypes&&>::value...).and_())>
tuple& operator=(tuple<UTypes...>&& src)
VEILER_TUPLE_POSITIVE_NOEXCEPT(make_cond_tuple(std::is_nothrow_constructible<Types, UTypes&&>::value...).and_()){
this->impl = std::forward<impl_type>(tuple(std::forward<tuple<UTypes...>>(src)).impl);
return *this;
}
template<typename U1, typename U2,
VEILER_TUPLE_STRICT_CHECK(sizeof...(Types) == 2 &&
std::is_assignable<typename type_tuple<Types...>::template at<0>&, const U1&>::value &&
std::is_assignable<typename type_tuple<Types...>::template at<1>&, const U2&>::value)>
tuple& operator=(const std::pair<U1,U2>& src)
VEILER_TUPLE_POSITIVE_NOEXCEPT(std::is_nothrow_assignable<typename type_tuple<Types...>::template at<0>&, const U1&>::value &&
std::is_nothrow_assignable<typename type_tuple<Types...>::template at<1>&, const U2&>::value){
get<0>(*this) = src.first;
get<1>(*this) = src.second;
return *this;
}
template<typename U1, typename U2,
VEILER_TUPLE_STRICT_CHECK(sizeof...(Types) == 2 &&
std::is_assignable<typename type_tuple<Types...>::template at<0>&, U1&&>::value &&
std::is_assignable<typename type_tuple<Types...>::template at<1>&, U2&&>::value)>
tuple& operator=(std::pair<U1,U2>&& src)
VEILER_TUPLE_POSITIVE_NOEXCEPT(std::is_nothrow_assignable<typename type_tuple<Types...>::template at<0>&, U1&&>::value &&
std::is_nothrow_assignable<typename type_tuple<Types...>::template at<1>&, U2&&>::value){
get<0>(*this) = std::forward<U1>(src.first);
get<1>(*this) = std::forward<U2>(src.second);
return *this;
}
template<std::size_t N>
using at = decltype(impl_type::template get<N>(std::declval<impl_type>()));
void swap(tuple& rhs)
noexcept(noexcept(std::declval<impl_type&>().swap(std::declval<impl_type&>()))){
return impl.swap(rhs.impl);
}
template<std::size_t N>
static constexpr auto get(tuple& tpl)noexcept
->decltype((impl_type::template get<N>(tpl.impl))){
return impl_type::template get<N>(tpl.impl);
}
template<std::size_t N>
static constexpr auto get(const tuple& tpl)noexcept
->decltype((impl_type::template get<N>(tpl.impl))){
return impl_type::template get<N>(tpl.impl);
}
template<std::size_t N>
static constexpr auto get(tuple&& tpl)noexcept
->decltype((impl_type::template get<N>(std::forward<impl_type>(tpl.impl)))){
return impl_type::template get<N>(std::forward<impl_type>(tpl.impl));
}
template<typename... Rights,
VEILER_TUPLE_STRICT_CHECK(sizeof...(Types) == sizeof...(Rights) &&
std::is_convertible<
decltype(std::declval<typename const tuple::impl_type&>() == std::declval<typename const tuple<Rights...>::impl_type&>()),
bool
>::value)>
friend constexpr bool operator==(const tuple& lhs, const tuple<Rights...>& rhs)
noexcept(noexcept(lhs.impl == rhs.impl)){
return lhs.impl == rhs.impl;
}
template<typename... Rights,
VEILER_TUPLE_STRICT_CHECK(sizeof...(Types) == sizeof...(Rights) &&
std::is_convertible<
decltype(std::declval<typename const tuple::impl_type&>() != std::declval<typename const tuple<Rights...>::impl_type&>()),
bool
>::value)>
friend constexpr bool operator!=(const tuple& lhs, const tuple<Rights...>& rhs)
noexcept(noexcept(lhs.impl != rhs.impl)){
return lhs.impl != rhs.impl;
}
template<typename... Rights,
VEILER_TUPLE_STRICT_CHECK(sizeof...(Types) == sizeof...(Rights) &&
std::is_convertible<
decltype(std::declval<typename const tuple::impl_type&>() < std::declval<typename const tuple<Rights...>::impl_type&>()),
bool
>::value)>
friend constexpr bool operator< (const tuple& lhs, const tuple<Rights...>& rhs)
noexcept(noexcept(lhs.impl < rhs.impl)){
return lhs.impl < rhs.impl;
}
template<typename... Rights,
VEILER_TUPLE_STRICT_CHECK(sizeof...(Types) == sizeof...(Rights) &&
std::is_convertible<
decltype(std::declval<typename const tuple::impl_type&>() > std::declval<typename const tuple<Rights...>::impl_type&>()),
bool
>::value)>
friend constexpr bool operator> (const tuple& lhs, const tuple<Rights...>& rhs)
noexcept(noexcept(lhs.impl > rhs.impl)){
return lhs.impl > rhs.impl;
}
template<typename... Rights,
VEILER_TUPLE_STRICT_CHECK(sizeof...(Types) == sizeof...(Rights) &&
std::is_convertible<
decltype(std::declval<typename const tuple::impl_type&>() <= std::declval<typename const tuple<Rights...>::impl_type&>()),
bool
>::value)>
friend constexpr bool operator<=(const tuple& lhs, const tuple<Rights...>& rhs)
noexcept(noexcept(lhs.impl <= rhs.impl)){
return lhs.impl <= rhs.impl;
}
template<typename... Rights,
VEILER_TUPLE_STRICT_CHECK(sizeof...(Types) == sizeof...(Rights) &&
std::is_convertible<
decltype(std::declval<typename const tuple::impl_type&>() >= std::declval<typename const tuple<Rights...>::impl_type&>()),
bool
>::value)>
friend constexpr bool operator>=(const tuple& lhs, const tuple<Rights...>& rhs)
noexcept(noexcept(lhs.impl >= rhs.impl)){
return lhs.impl >= rhs.impl;
}
};
template<>
class tuple<>{
using impl_type = typename make_value_btree<0, type_tuple<>>::type;
impl_type impl;
public:
constexpr tuple() = default;
constexpr tuple(const tuple&) = default;
constexpr tuple(tuple&&) = default;
void swap(tuple&)const noexcept{}
friend constexpr bool operator==(const tuple& lhs,const tuple&)noexcept{return lhs.impl == lhs.impl;}
friend constexpr bool operator!=(const tuple& lhs,const tuple&)noexcept{return lhs.impl != lhs.impl;}
friend constexpr bool operator< (const tuple& lhs,const tuple&)noexcept{return lhs.impl < lhs.impl;}
friend constexpr bool operator> (const tuple& lhs,const tuple&)noexcept{return lhs.impl > lhs.impl;}
friend constexpr bool operator<=(const tuple& lhs,const tuple&)noexcept{return lhs.impl <= lhs.impl;}
friend constexpr bool operator>=(const tuple& lhs,const tuple&)noexcept{return lhs.impl >= lhs.impl;}
};
template<std::size_t N, typename... Types>
constexpr auto get(tuple<Types...>& tpl)noexcept
->decltype((tuple<Types...>::template get<N>(tpl))){
return tuple<Types...>::template get<N>(tpl);
}
template<std::size_t N, typename... Types>
constexpr auto get(tuple<Types...>&& tpl)noexcept
->decltype((tuple<Types...>::template get<N>(std::forward<tuple<Types...>>(tpl)))){
return tuple<Types...>::template get<N>(std::forward<tuple<Types...>>(tpl));
}
template<std::size_t N, typename... Types>
constexpr auto get(const tuple<Types...>& tpl)noexcept
->decltype((tuple<Types...>::template get<N>(tpl))){
return tuple<Types...>::template get<N>(tpl);
}
template<typename... Types>
void swap(tuple<Types...>& lhs, tuple<Types...>& rhs)
noexcept(noexcept(lhs.swap(rhs))){
lhs.swap(rhs);
}
template<typename... Args>
constexpr tuple<Args&&...> forward_as_tuple(Args&&... args)noexcept{
return tuple<Args&&...>(std::forward<Args>(args)...);
}
template<typename U>struct unwrap_reference_wrapper{using type = U;};
template<typename X>struct unwrap_reference_wrapper<std::reference_wrapper<X>>{using type = X&;};
template<typename... Args>
constexpr auto make_tuple(Args&&... args)
VEILER_TUPLE_POSITIVE_NOEXCEPT(make_cond_tuple(std::is_nothrow_constructible<
typename unwrap_reference_wrapper<typename std::decay<Args>::type>::type,
Args&&
>::value...).and_())
->tuple<typename unwrap_reference_wrapper<typename std::decay<Args>::type>::type...>{
return tuple<typename unwrap_reference_wrapper<typename std::decay<Args>::type>::type...>(std::forward<Args>(args)...);
}
namespace{
struct _ignore_t{
constexpr _ignore_t(){}
template<typename T>
constexpr const _ignore_t& operator=(T&&)const noexcept{return *this;}
}constexpr ignore;
class _apply_impl_t{
template<typename F>class curried_apply{
F f;
template<typename... Args, long long... Indices>
constexpr auto impl(const tuple<Args...>& tup, index_tuple<Indices...>)const
->decltype(f(get<Indices>(tup)...)){
return f(get<Indices>(tup)...);
}
template<typename... Args, long long... Indices>
constexpr auto impl(tuple<Args...>&& tup, index_tuple<Indices...>)const
->decltype(std::forward<F>(f)(get<Indices>(std::forward<tuple<Args...>>(tup))...)){
return std::forward<F>(f)(get<Indices>(std::forward<tuple<Args...>>(tup))...);
}
public:
constexpr curried_apply(F&& f):f(std::forward<F>(f)){}
template<typename... Args>constexpr auto operator()(const tuple<Args...>& tup)const
->decltype(this->impl(tup,typename make_indexes<Args...>::type{})){
return this->impl(tup,typename make_indexes<Args...>::type{});
}
template<typename... Args>
constexpr auto operator()(tuple<Args...>&& tup)const
->decltype(this->impl(std::forward<tuple<Args...>>(tup),typename make_indexes<Args...>::type{})){
return this->impl(std::forward<tuple<Args...>>(tup),typename make_indexes<Args...>::type{});
}
template<typename... Args>
friend constexpr auto operator|(const curried_apply<F>& f,const tuple<Args...>& tup)
->decltype(f(tup)){
return f(tup);
}
template<typename... Args>
friend constexpr auto operator|(curried_apply<F>&& f,tuple<Args...>&& tup)
->decltype(std::forward<curried_apply<F>>(f)(std::forward<tuple<Args...>>(tup))){
return std::forward<curried_apply<F>>(f)(std::forward<tuple<Args...>>(tup));
}
};
public:
constexpr _apply_impl_t(){}
template<typename F,typename... Args>
constexpr auto operator()(F&& f,tuple<Args...>&& tup)const
->decltype(curried_apply<F>(std::forward<F>(f))(std::forward<tuple<Args...>>(tup))){
return curried_apply<F>(std::forward<F>(f))(std::forward<tuple<Args...>>(tup));
}
template<typename F>
friend constexpr curried_apply<F> operator|(F&& f,_apply_impl_t){
return curried_apply<F>(std::forward<F>(f));
}
}constexpr apply;
}
template<typename... Ts1, long long... Idxs1, typename... Ts2, long long... Idxs2, typename... Ts3, long long... Idxs3>
constexpr tuple<Ts1..., Ts2..., Ts3...> tuple_cat_impl_impl(tuple<Ts1...>&& t1, index_tuple<Idxs1...>,
tuple<Ts2...>&& t2, index_tuple<Idxs2...>,
tuple<Ts3...>&& t3, index_tuple<Idxs3...>){
return tuple<Ts1..., Ts2..., Ts3...>(get<Idxs1>(std::forward<tuple<Ts1...>>(t1))...,
get<Idxs2>(std::forward<tuple<Ts2...>>(t2))...,
get<Idxs3>(std::forward<tuple<Ts3...>>(t3))...);
}
namespace{
struct _tuple_cat_impl_t{
template<typename... Ts, typename... Lefts, typename... Rights>
constexpr auto operator()(value_btree<tuple<Ts...>, tuple<Lefts...>, tuple<Rights...>>&& btree)const
->decltype((tuple_cat_impl_impl(value_btree<tuple<Ts...>, tuple<Lefts...>, tuple<Rights...>>::template get<0>
(std::forward<value_btree<tuple<Ts...>, tuple<Lefts...>, tuple<Rights...>>>(btree)),
typename make_indexes<Ts...>::type{},
value_btree<tuple<Ts...>, tuple<Lefts...>, tuple<Rights...>>::template get<1>
(std::forward<value_btree<tuple<Ts...>, tuple<Lefts...>, tuple<Rights...>>>(btree)),
typename make_indexes<Lefts...>::type{},
value_btree<tuple<Ts...>, tuple<Lefts...>, tuple<Rights...>>::template get<2>
(std::forward<value_btree<tuple<Ts...>, tuple<Lefts...>, tuple<Rights...>>>(btree)),
typename make_indexes<Rights...>::type{}))){
return tuple_cat_impl_impl(value_btree<tuple<Ts...>, tuple<Lefts...>, tuple<Rights...>>::template get<0>
(std::forward<value_btree<tuple<Ts...>, tuple<Lefts...>, tuple<Rights...>>>(btree)),
typename make_indexes<Ts...>::type{},
value_btree<tuple<Ts...>, tuple<Lefts...>, tuple<Rights...>>::template get<1>
(std::forward<value_btree<tuple<Ts...>, tuple<Lefts...>, tuple<Rights...>>>(btree)),
typename make_indexes<Lefts...>::type{},
value_btree<tuple<Ts...>, tuple<Lefts...>, tuple<Rights...>>::template get<2>
(std::forward<value_btree<tuple<Ts...>, tuple<Lefts...>, tuple<Rights...>>>(btree)),
typename make_indexes<Rights...>::type{});
}
template<typename... Ts, typename... Lefts>
constexpr auto operator()(value_btree<tuple<Ts...>,tuple<Lefts...>>&& btree)const
->decltype((tuple_cat_impl_impl(value_btree<tuple<Ts...>, tuple<Lefts...>>::template get<0>
(std::forward<value_btree<tuple<Ts...>, tuple<Lefts...>>>(btree)),
typename make_indexes<Ts...>::type{},
value_btree<tuple<Ts...>, tuple<Lefts...>>::template get<1>
(std::forward<value_btree<tuple<Ts...>, tuple<Lefts...>>>(btree)),
typename make_indexes<Lefts...>::type{},
tuple<>{},
index_tuple<>{}))){
return tuple_cat_impl_impl(value_btree<tuple<Ts...>, tuple<Lefts...>>::template get<0>
(std::forward<value_btree<tuple<Ts...>, tuple<Lefts...>>>(btree)),
typename make_indexes<Ts...>::type{},
value_btree<tuple<Ts...>, tuple<Lefts...>>::template get<1>
(std::forward<value_btree<tuple<Ts...>, tuple<Lefts...>>>(btree)),
typename make_indexes<Lefts...>::type{},
tuple<>{},
index_tuple<>{});
}
template<typename... Ts>
constexpr tuple<Ts...>&& operator()(value_btree<tuple<Ts...>>&& btree)const noexcept{
return std::forward<tuple<Ts...>>(value_btree<tuple<Ts...>>::template get<0>(std::forward<value_btree<tuple<Ts...>>>(btree)));
}
constexpr tuple<> operator()(value_btree<>)const noexcept{return tuple<>{};}
template<typename Dummy1, typename Dummy2, typename... Ts, typename... Lefts, typename... Rights>
constexpr auto operator()(value_btree<Dummy1, Dummy2, tuple<Ts...>, value_btree<Lefts...>, value_btree<Rights...>>&& btree)const
->decltype((value_btree<Dummy1, Dummy2, tuple<Ts...>, value_btree<Lefts...>, value_btree<Rights...>>::btree_apply(
std::forward<value_btree<Dummy1, Dummy2, tuple<Ts...>, value_btree<Lefts...>, value_btree<Rights...>>>(btree),
*this))){
return value_btree<Dummy1, Dummy2, tuple<Ts...>, value_btree<Lefts...>, value_btree<Rights...>>::btree_apply(
std::forward<value_btree<Dummy1, Dummy2, tuple<Ts...>, value_btree<Lefts...>, value_btree<Rights...>>>(btree),
*this);
}
constexpr _tuple_cat_impl_t(){}
}constexpr tuple_cat_impl;
}
template<typename... Types>
constexpr tuple<Types...>&& convert_to_tuple(tuple<Types...>&& tpl)noexcept{return std::forward<tuple<Types...>>(tpl);}
template<typename U1, typename U2>
constexpr tuple<U1, U2> convert_to_tuple(std::pair<U1, U2>&& pair)
noexcept(std::is_nothrow_constructible<tuple<U1, U2>, std::pair<U1, U2>&&>::value){
return tuple<U1, U2>(std::forward<std::pair<U1, U2>>(pair));
}
template<typename T, std::size_t N, long long... Indices, typename... Types>
constexpr tuple<Types...> convert_array_to_tuple_impl(std::array<T, N>&& array, index_tuple<Indices...>, type_tuple<Types...>)
noexcept(std::is_nothrow_constructible<tuple<Types...>, Types&&...>::value){
return tuple<Types...>(std::forward<T>(array[Indices])...);
}
template<typename T, std::size_t N>
constexpr auto convert_to_tuple(std::array<T, N>&& array)
noexcept(noexcept(convert_array_to_tuple_impl(std::forward<std::array<T, N>>(array),
typename make_index_range<0, N, 1>::type{},
typename make_type_tuple<N, T>::type{})))
->decltype((convert_array_to_tuple_impl(std::forward<std::array<T, N>>(array),
typename make_index_range<0, N, 1>::type{},
typename make_type_tuple<N,T>::type{}))){
return convert_array_to_tuple_impl(std::forward<std::array<T, N>>(array),
typename make_index_range<0, N, 1>::type{},
typename make_type_tuple<N,T>::type{});
}
template<typename... Tuples>
constexpr auto tuple_cat_(Tuples&&... tpls)
->decltype((tuple_cat_impl(typename make_value_btree<sizeof...(Tuples), type_tuple<Tuples...>>::type(std::forward<Tuples>(tpls)...)))){
return tuple_cat_impl(typename make_value_btree<sizeof...(Tuples), type_tuple<Tuples...>>::type(std::forward<Tuples>(tpls)...));
}
template<typename... TupleLikes>
constexpr auto tuple_cat(TupleLikes&&... tpl_likes)
noexcept(noexcept(tuple_cat_(convert_to_tuple(std::forward<TupleLikes>(tpl_likes))...)))
->decltype((tuple_cat_(convert_to_tuple(std::forward<TupleLikes>(tpl_likes))...))){
return tuple_cat_(convert_to_tuple(std::forward<TupleLikes>(tpl_likes))...);
}
template<typename... Args>
constexpr tuple<Args&...> tie(Args&... args)noexcept{return tuple<Args&...>(args...);}
}
}
using detail::tuple::make_reverse_index_tuple;
using detail::tuple::make_index_range;
using detail::tuple::make_indexes;
using detail::tuple::index_tuple;
using detail::tuple::type_at;
using detail::tuple::type_tuple;
using detail::tuple::cond_tuple;
using detail::tuple::make_cond_tuple;
using detail::tuple::tuple;
using detail::tuple::swap;
using detail::tuple::forward_as_tuple;
using detail::tuple::make_tuple;
using detail::tuple::ignore;
using detail::tuple::apply;
using detail::tuple::tuple_cat;
using detail::tuple::tie;
using detail::tuple::get;
}
#include<iostream>
template<long long... Indices>
constexpr auto make_tuple_from_index_range(veiler::index_tuple<Indices...>)
->decltype(veiler::make_tuple(Indices...)){
return veiler::make_tuple(Indices...);
}
constexpr int test(int a,int b,int c,int d,int e){
return a+b+c+d+e;
}
int main(){
using namespace veiler;
{
static constexpr auto t = make_tuple(1,2,3,4,5);
static_assert(get<1>(t) == 2,"");
}
{
static constexpr auto t = make_tuple(1,2,3,4,5);
static_assert((test |apply| t) == 15,"");
}
{
static constexpr auto t = tuple_cat(make_tuple(1,2,3),make_tuple(4,5),make_tuple(6),make_tuple(),make_tuple(7,8,9,10));
static_assert(t == make_tuple(1,2,3,4,5,6,7,8,9,10),"");
}
{
//constexpr auto t = make_tuple_from_index_range(typename make_index_range<0,4096>::type{});
//static_assert(get<4095>(t) == 4095,"");
}
{
auto t = make_tuple(1,2,3,4,5);
t = make_tuple(2,3,4,5,6);
t = std::move(make_tuple(1,2,3,4,5));
t = make_tuple(1.0,2.0,3.,4,5);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment