160 lines
4.0 KiB
C
160 lines
4.0 KiB
C
|
#ifndef TMP_TREE_H
|
||
|
#define TMP_TREE_H
|
||
|
|
||
|
#include "bind.h"
|
||
|
#include "pack.h"
|
||
|
#include "packalgo.h"
|
||
|
#include "utility.h"
|
||
|
|
||
|
namespace tmp {
|
||
|
|
||
|
/**
|
||
|
* Tree
|
||
|
*/
|
||
|
template<typename...> struct Tree;
|
||
|
|
||
|
template<typename N, typename... Cs>
|
||
|
struct Tree<N, Cs...> {
|
||
|
using node = N;
|
||
|
using children = Pack<Cs...>;
|
||
|
};
|
||
|
|
||
|
template<>
|
||
|
struct Tree<> {};
|
||
|
|
||
|
/**
|
||
|
* TreeNode
|
||
|
*
|
||
|
* for use in flat tree representations
|
||
|
*/
|
||
|
enum class TreeNodeType { Branch, Leaf };
|
||
|
template<Depth D, typename T, TreeNodeType N>
|
||
|
struct TreeNode {
|
||
|
static constexpr Depth depth = D;
|
||
|
using type = T;
|
||
|
static constexpr TreeNodeType nodeType = N;
|
||
|
};
|
||
|
|
||
|
template<typename T, TreeNodeType NT = TreeNodeType::Branch>
|
||
|
using TreeRoot = TreeNode<0, T, NT>;
|
||
|
|
||
|
template<Depth D, typename T>
|
||
|
using TreeBranch = TreeNode<D, T, TreeNodeType::Branch>;
|
||
|
|
||
|
template<Depth D, typename T>
|
||
|
using TreeLeaf = TreeNode<D, T, TreeNodeType::Leaf>;
|
||
|
|
||
|
/**
|
||
|
* TreeIsLeaf
|
||
|
*/
|
||
|
template<typename> struct TreeIsLeafImpl: std::true_type {};
|
||
|
template<typename... Ts>
|
||
|
struct TreeIsLeafImpl<Tree<Ts...>>: std::false_type {};
|
||
|
|
||
|
template<typename T>
|
||
|
constexpr bool TreeIsLeaf = TreeIsLeafImpl<T>::value;
|
||
|
|
||
|
/**
|
||
|
* PackFromTreeNLR
|
||
|
*
|
||
|
* creates a pack from a tree using NLR
|
||
|
* tree traversal algorithm
|
||
|
*/
|
||
|
template<typename, Depth=0> struct PackFromTreeNLRImpl;
|
||
|
|
||
|
template<typename N, typename... LRs, Depth D>
|
||
|
struct PackFromTreeNLRImpl<Tree<N, LRs...>, D> {
|
||
|
using type = PackPushFront<
|
||
|
PackCat<typename PackFromTreeNLRImpl<LRs, D+1>::type...>,
|
||
|
TreeBranch<D, N>
|
||
|
>;
|
||
|
};
|
||
|
|
||
|
template<typename N, Depth D>
|
||
|
struct PackFromTreeNLRImpl<Tree<N>, D> {
|
||
|
using type = Pack<TreeLeaf<D, N>>;
|
||
|
};
|
||
|
|
||
|
template<Depth D>
|
||
|
struct PackFromTreeNLRImpl<Tree<>, D> {
|
||
|
using type = Pack<>;
|
||
|
};
|
||
|
|
||
|
template<typename T, Depth D = 0>
|
||
|
using PackFromTreeNLR = typename PackFromTreeNLRImpl<T, D>::type;
|
||
|
|
||
|
/**
|
||
|
* TreeFromPackNLR
|
||
|
*
|
||
|
* creates a tree from a pack
|
||
|
* reverses PackFromTreeNLR
|
||
|
*/
|
||
|
namespace detail {
|
||
|
|
||
|
template<Depth D, typename T>
|
||
|
using PartialTree = Pack<std::integral_constant<decltype(D), D>, T>;
|
||
|
|
||
|
template<Depth LIM>
|
||
|
struct GreaterThan {
|
||
|
template<typename T, typename=void> struct CmpImpl;
|
||
|
template<Depth D, typename T>
|
||
|
struct CmpImpl<PartialTree<D, T>>: std::integral_constant<bool, (D > LIM)> {};
|
||
|
template<typename T>
|
||
|
struct CmpImpl<T>: std::true_type {};
|
||
|
|
||
|
template<typename T>
|
||
|
using Cmp = CmpImpl<T>;
|
||
|
};
|
||
|
|
||
|
}
|
||
|
|
||
|
/* property:
|
||
|
* one block either groups future blocks or
|
||
|
* has a bigger or equal depth than following
|
||
|
*
|
||
|
* property:
|
||
|
* the list of depths when building is always
|
||
|
* decreasing (quite easy to demonstrate)
|
||
|
*/
|
||
|
template<typename, typename=void> struct TreeFromPackNLRImpl;
|
||
|
|
||
|
template<Depth D, typename T, typename... Ns>
|
||
|
struct TreeFromPackNLRImpl<Pack<TreeBranch<D, T>, Ns...>, std::enable_if_t<D != 0>> {
|
||
|
using next = typename TreeFromPackNLRImpl<Pack<Ns...>>::subtree;
|
||
|
using cutd = Cut<next, detail::GreaterThan<D>::template Cmp>;
|
||
|
using children = Transform<PackGet<cutd, 0>, Bind2ndV<Size, PackGet, 1>::template F1>;
|
||
|
using siblings = PackGet<cutd, 1>;
|
||
|
using part = detail::PartialTree<D, Repack<Tree, PackPushFront<children, T>>>;
|
||
|
using subtree = PackPushFront<siblings, part>;
|
||
|
|
||
|
using type = Repack<Tree, subtree>;
|
||
|
};
|
||
|
|
||
|
template<typename T, TreeNodeType NT, typename... Ns>
|
||
|
struct TreeFromPackNLRImpl<Pack<TreeRoot<T, NT>, Ns...>> {
|
||
|
using next = typename TreeFromPackNLRImpl<Pack<Ns...>>::subtree;
|
||
|
using children = Transform<next, Bind2ndV<Size, PackGet, 1>::template F1>;
|
||
|
using subtree = PackPushFront<children, T>;
|
||
|
using type = Repack<Tree, subtree>;
|
||
|
};
|
||
|
|
||
|
template<Depth D, typename T, typename... Ns>
|
||
|
struct TreeFromPackNLRImpl<Pack<TreeLeaf<D, T>, Ns...>, std::enable_if_t<D != 0>> {
|
||
|
using part = detail::PartialTree<D, Tree<T>>;
|
||
|
using subtree = PackPushFront<typename TreeFromPackNLRImpl<Pack<Ns...>>::subtree, part>;
|
||
|
using type = Repack<Tree, subtree>;
|
||
|
};
|
||
|
|
||
|
template<>
|
||
|
struct TreeFromPackNLRImpl<Pack<>> {
|
||
|
using subtree = Pack<>;
|
||
|
using type = Repack<Tree, subtree>;
|
||
|
};
|
||
|
|
||
|
template<typename P>
|
||
|
using TreeFromPackNLR = typename TreeFromPackNLRImpl<P>::type;
|
||
|
|
||
|
}
|
||
|
|
||
|
#endif
|