Last active
December 31, 2015 22:08
-
-
Save wx257osn2/8051171 to your computer and use it in GitHub Desktop.
O(log N) C++11 constexpr tuple
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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