alsk/inc/tmp/tree.h

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