alsk/src/alsk/skeleton/utility.h

248 lines
7.9 KiB
C++

#ifndef ALSK_ALSK_SKELETON_UTILITY_H
#define ALSK_ALSK_SKELETON_UTILITY_H
#include <tmp/algorithm.h>
#include <tmp/tree.h>
#include "link/link.h"
#include "struct/struct.h"
#include "muscle/muscle.h"
#include "traits.h"
namespace alsk {
namespace impl {
/**
* Build inner skeletons
*/
template<typename, typename, typename, typename, typename> struct BuildSkeletonParts;
template<
template<typename...> class Skel, typename... Ss,
typename R, typename... Params, typename... Ls,
typename PParams, typename RParams, typename XParams
>
struct BuildSkeletonParts<alsk::S<Skel, Ss...>, alsk::L<Skel, R(Params...), Ls...>, PParams, RParams, XParams> {
using Placeholders = arg::Placeholders<PParams, RParams, XParams>;
using prms = tmp::Pack<RealType<Params, Placeholders>...>;
using rets = typename LinksToReturnTypes<Ls...>::type;
using xprm = tmp::Pack<>;
using type = alsk::Fun<
Skel<
R(RealType<Params, Placeholders>...),
typename BuildSkeletonParts<Ss, Ls, prms, rets, xprm>::type...
>,
RealType<R, arg::Placeholders<tmp::Pack<>, rets, xprm>>(Params...)
>;
};
template<typename S, typename L, typename, typename, typename>
struct BuildSkeletonParts {
using type = alsk::Fun<S, L>;
};
/**
* Build outer skeleton
*/
template<typename, typename> struct BuildSkeleton;
template<template<typename...> class Skel, typename... Ss, typename R, typename... Params, typename... Ls>
struct BuildSkeleton<alsk::S<Skel, Ss...>, alsk::L<Skel, R(Params...), Ls...>> {
using rets = typename LinksToReturnTypes<Ls...>::type;
using xprm = tmp::Pack<>;
using type = Skel<
R(Params...),
typename BuildSkeletonParts<Ss, Ls, tmp::Pack<Params...>, rets, xprm>::type...
>;
};
}
/**
* Build a skeleton from its structure and its links
*/
template<typename S, typename L>
using BuildSkeletonT = typename impl::BuildSkeleton<S, L>::type;
template<template<typename...> class S, template<typename...> class L>
struct BuildSkeleton {
template<typename, typename> struct Type;
template<typename... SParams, typename... LParams>
struct Type<tmp::Pack<SParams...>, tmp::Pack<LParams...>> {
using type = BuildSkeletonT<S<SParams...>, L<LParams...>>;
};
template<typename SParams, typename LParams>
using type = typename Type<SParams, LParams>::type;
template<typename SParams, typename LParams>
using skeleton = typename Type<SParams, LParams>::type;
};
// is it possible?
// template<template<typename...> class S, template<typename...> class L>
// template<typename SParams, typename LParams>
// using type = typename BuildSkeleton<S, L>::type<SParams, LParams>;
template<template<typename...> class Skeleton, typename S, typename L = S>
struct Branch {
template<typename... Ts>
using skeleton = Skeleton<Ts...>;
using signature = S;
using links = L;
};
template<typename T, typename L>
struct Leaf {
using type = T;
using links = L;
};
/**
* TreeFromSkeleton
*/
template<typename, typename=void> struct TreeFromSkeletonImpl;
template<template<typename...> class Skeleton, typename S, typename... Ps>
struct TreeFromSkeletonImpl<Skeleton<S, Ps...>, std::enable_if_t<isSkeleton<Skeleton<S, Ps...>>>> {
using type = tmp::Tree<Branch<Skeleton, S, S>, typename TreeFromSkeletonImpl<Ps>::type...>;
};
template<template<typename...> class Skeleton, typename S, typename... Ps, typename L>
struct TreeFromSkeletonImpl<Fun<Skeleton<S, Ps...>, L>, std::enable_if_t<isSkeleton<Skeleton<S, Ps...>>>> {
using type = tmp::Tree<Branch<Skeleton, S, L>, typename TreeFromSkeletonImpl<Ps>::type...>;
};
template<typename T, typename L>
struct TreeFromSkeletonImpl<Fun<T, L>, std::enable_if_t<not isSkeleton<T>>> {
using type = tmp::Tree<Leaf<T, L>>;
};
template<typename T>
using TreeFromSkeleton = typename TreeFromSkeletonImpl<T>::type;
/**
* SkeletonFromTree
*/
template<typename> struct SkeletonFromTreeImpl;
template<template<typename...> class Skeleton, typename S, typename L, typename... Cs>
struct SkeletonFromTreeImpl<tmp::Tree<Branch<Skeleton, S, L>, Cs...>> {
using type = Skeleton<S, typename SkeletonFromTreeImpl<Cs>::fun...>;
using fun = Fun<type, L>;
};
template<typename T, typename L, typename... Cs>
struct SkeletonFromTreeImpl<tmp::Tree<Leaf<T, L>, Cs...>> {
using type = T;
using fun = Fun<type, L>;
};
template<typename T>
using SkeletonFromTree = typename SkeletonFromTreeImpl<T>::type;
/**
*
*/
template<typename> struct GetTemplate;
template<template<typename...> class TT, typename... Ps>
struct GetTemplate<TT<Ps...>> {
template<typename... As>
using tmpl = TT<As...>;
};
template<template<typename...> class Skel, typename... Skargs>
struct SkeletonTraversal<Skel<Skargs...>, std::enable_if_t<isSkeleton<Skel<Skargs...>>>> {
template<typename Skeleton, typename F, typename T>
static decltype(auto) execute(std::size_t parDepth, Skeleton&& skeleton, F&& function, T&& init) {
using Traits = SkeletonTraits<Skel>;
return Traits::traverse(parDepth, std::forward<Skeleton>(skeleton), std::forward<F>(function), std::forward<T>(init));
}
template<typename Skeleton, typename F, typename T>
static decltype(auto) execute(Skeleton&& skeleton, F&& function, T&& init) {
using Traits = SkeletonTraits<Skel>;
return Traits::traverse(0, std::forward<Skeleton>(skeleton), std::forward<F>(function), std::forward<T>(init));
}
};
template<typename S>
struct SkeletonTraversal<S, std::enable_if_t<not isSkeleton<S>>> {
template<typename Skeleton, typename F, typename T>
static T execute(std::size_t, Skeleton&&, F&&, T&& init) { return init; }
template<typename Skeleton, typename F, typename T>
static T execute(Skeleton&&, F&&, T&& init) { return init; }
};
}
namespace alsk {
/*
template<typename S>
struct SkeletonParallelHeightImpl {
template<typename> struct CheckParallelityImpl;
template<template<typename...> class Skel, typename Sign, typename Link>
struct CheckParallelityImpl<Branch<Skel, Sign, Link>> {
using type = std::integral_constant<bool, not SkeletonTraits<Skel>::serial>;
};
template<typename T, typename Link>
struct CheckParallelityImpl<Leaf<T, Link>> {
using type = std::integral_constant<bool, false>;
};
template<typename P>
using CheckParallelity = typename CheckParallelityImpl<P>::type;
template<typename P>
using CheckParallelityEach = tmp::Transform<P, CheckParallelity>;
template<typename LHS, typename RHS>
using Sum = std::integral_constant<decltype(LHS::value), LHS::value + RHS::value>;
template<typename P>
using SumEach = tmp::Accumulate<P, Sum, std::integral_constant<tmp::Depth, 0>>;
template<typename LHS, typename RHS>
using Max = std::integral_constant<decltype(LHS::value), (LHS::value>RHS::value)? LHS::value:RHS::value>;
using tree = TreeFromSkeleton<S>;
using rtlpaths = tmp::TreeAllRTLPaths<tree>;
using parallel = tmp::Transform<rtlpaths, CheckParallelityEach>;
using parallelc = tmp::Transform<parallel, SumEach>;
using result = tmp::Accumulate<parallelc, Max, std::integral_constant<tmp::Depth, 0>>;
static constexpr tmp::Depth value = result::value;
};
/*/
template<typename S>
struct SkeletonParallelHeightImpl {
template<typename, typename...> struct CalcHeightImpl;
template<template<typename...> class Skel, typename Sign, typename Link, typename... Ts>
struct CalcHeightImpl<Branch<Skel, Sign, Link>, Ts...> {
static constexpr tmp::Depth par = SkeletonTraits<Skel>::serial? 0:1;
using type = std::integral_constant<tmp::Depth, par + tmp::detail::Max<Ts::type::value...>>;
};
template<typename T, typename Link, typename... Ts>
struct CalcHeightImpl<Leaf<T, Link>, Ts...> {
using type = std::integral_constant<tmp::Depth, 0>;
};
template<typename P, typename... Ts>
using CalcHeight = typename CalcHeightImpl<P, Ts...>::type;
using CalcHeightDefault = std::integral_constant<tmp::Depth, 0>;
using tree = TreeFromSkeleton<S>;
static constexpr tmp::Depth value = tmp::TreeAccumulate<tree, CalcHeight, CalcHeightDefault>::value;
};
//*/
template<typename S>
constexpr tmp::Depth skeletonParallelHeight = SkeletonParallelHeightImpl<S>::value;
}
#endif