@wimalopaan max66 ' ? , . , . :
. ( ),
using Tree = std::tuple<
IndexNode<4>{1, 2, 3, 7},
A,
B,
IndexNode<2>{4, 5},
C,
IndexNode<1>{6},
D,
E
>;
, :
Node(
A{},
B{},
Node(
C{},
Node(
D{}
)
),
E{}
);
IndexNode " , Node, ". max66 cntT. rank :
template<class> struct Type {};
template<class Terminal>
size_t rank_of(Type<Terminal>) {
return 1;
}
template<class... Children>
size_t rank_of(Type<Node<Children...>>) {
return (
1 +
... + rank_of(Type<Children>{})
);
}
Node . ( ) ParentInds.
#include "indexer.hpp"
#include "merge.hpp"
#include "types.hpp"
#include "vals.hpp"
template<class Terminal, class ParentInds=Vals<>>
auto indices_of(
Type<Terminal>,// break depth recursion for terminal node
ParentInds = ParentInds{}
) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
return Types<ParentInds>{};
}
template<class... Children, class ParentInds=Vals<>>
auto indices_of(
Type<Node<Children...>>,// continue recursion for non-terminal node
ParentInds parent_inds = ParentInds{}
) {
return indexer<Children...>([&] (auto... child_inds) {
return merge(
Types<ParentInds>{},
indices_of(
Type<Children>{},
parent_inds.append(child_inds)
)...
);
});
}
GCC 7.2:
auto indices_of(Type<Terminal>, ParentInds) [with Terminal = E; ParentInds = Vals<3>]
auto indices_of(Type<Terminal>, ParentInds) [with Terminal = D; ParentInds = Vals<2, 1, 0>]
auto indices_of(Type<Terminal>, ParentInds) [with Terminal = C; ParentInds = Vals<2, 0>]
auto indices_of(Type<Terminal>, ParentInds) [with Terminal = B; ParentInds = Vals<1>]
auto indices_of(Type<Terminal>, ParentInds) [with Terminal = A; ParentInds = Vals<0>]
, indices_of, :
template<class T>
constexpr auto transform(const T& t) {
static_assert(
std::is_same<
T,
Node<A, B, Node<C, Node<D> >, E>
>{}
);
auto inds = indices_of(Type<T>{});
static_assert(
std::is_same<
decltype(inds),
Types<
Vals<>,
Vals<0>,
Vals<1>,
Vals<2>,
Vals<2, 0>,
Vals<2, 1>,
Vals<2, 1, 0>,
Vals<3>
>
>{}
);
return indexer(inds.size, [&] (auto... is) {
return std::make_tuple(
transform_at(
inds.construct_type_at(is),
t,
is.next()
)...
);
});
}
(, ) (-):
#include <algorithm>
#include <iostream>
#include <tuple>
#include <numeric>
template<size_t i>
struct Val : std::integral_constant<size_t, i> {
template<size_t dist=1>
constexpr auto next(Val<dist> = {}) {
return Val<i+dist>{};
}
};
template<size_t... is>
struct Vals {
template<size_t i>
constexpr auto append(Val<i>) {
return Vals<is..., i>{};
}
};
template<size_t i0, size_t... is>
constexpr auto front(Vals<i0, is...>) { return Val<i0>{}; }
template<size_t i0, size_t... is>
constexpr auto pop_front(Vals<i0, is...>) { return Vals<is...>{}; }
template<class> struct Type {};
template<class... Ts>
struct Types {
static constexpr auto size = Val<sizeof...(Ts)>{};
template<std::size_t i, class... Args>
constexpr auto construct_type_at(Val<i>, Args&&... args) {
using Ret = std::tuple_element_t<i, std::tuple<Ts...>>;
return Ret(std::forward<Args>(args)...);
}
};
template<std::size_t... is, class F>
constexpr decltype(auto) indexer_impl(std::index_sequence<is...>, F f) {
return f(Val<is>{}...);
}
template<class... Ts, class F>
constexpr decltype(auto) indexer(F f) {
return indexer_impl(std::index_sequence_for<Ts...>{}, f);
}
template<size_t N, class F>
constexpr decltype(auto) indexer(std::integral_constant<size_t, N>, F f) {
return indexer_impl(std::make_index_sequence<N>{}, f);
}
template<class... Ts>
auto merge(Types<Ts...> done) {
return done;
}
template<class... Ts, class... Us, class... Vs>
auto merge(Types<Ts...>, Types<Us...>, Vs...) {
return merge(Types<Ts..., Us...>{}, Vs{}...);
}
struct TerminalNode { const char* msg{""}; };
std::ostream& operator<<(std::ostream& os, const TerminalNode& tn) {
return os << tn.msg << std::endl;
}
struct A : TerminalNode {};
struct B : TerminalNode {};
struct C : TerminalNode {};
struct D : TerminalNode {};
struct E : TerminalNode {};
template<typename... T>
struct Node {
constexpr Node(const T&... n) : mChildren{n...} {}
std::tuple<T...> mChildren;
};
template<size_t N>
struct IndexNode {
std::array<size_t, N> mChildren;
constexpr IndexNode(std::array<size_t, N> arr) : mChildren(arr) {}
friend std::ostream& operator<<(std::ostream& os, const IndexNode& self) {
for(auto r : self.mChildren) os << r << ", ";
return os << "\n";
}
};
template<class Terminal>
size_t rank_of(
Type<Terminal>
) {
return 1;
}
template<class... Children>
size_t rank_of(
Type<Node<Children...>>
) {
return (
1 +
... + rank_of(Type<Children>{})
);
}
template<class Terminal, class ParentInds=Vals<>>
auto indices_of(
Type<Terminal>,
ParentInds = ParentInds{}
) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
return Types<ParentInds>{};
}
template<class... Children, class ParentInds=Vals<>>
auto indices_of(
Type<Node<Children...>>,
ParentInds parent_inds = ParentInds{}
) {
return indexer<Children...>([&] (auto... child_inds) {
return merge(
Types<ParentInds>{},
indices_of(
Type<Children>{},
parent_inds.append(child_inds)
)...
);
});
}
template<class It, class T>
constexpr It exclusive_scan(It first, It last, It out, T init) {
for(auto it=first; it!=last; ++it) {
auto in = *it;
*out++ = init;
init += in;
}
return out;
}
template<size_t... child_inds, class Terminal, class Offset>
constexpr decltype(auto) transform_at(
Vals<child_inds...> inds,
const Terminal& terminal,
Offset
) {
static_assert(0 == sizeof...(child_inds));
return terminal;
}
template<size_t... child_inds, class... Children, class Offset>
constexpr decltype(auto) transform_at(
Vals<child_inds...> inds,
const Node<Children...>& node,
Offset offset = Offset{}
) {
if constexpr(0 == sizeof...(child_inds)) {
auto ranks = std::array{rank_of(Type<Children>{})...};
exclusive_scan(std::begin(ranks), std::end(ranks), std::begin(ranks), 0);
auto add_offset = [] (size_t& i) { i += Offset{}; };
std::for_each(std::begin(ranks), std::end(ranks), add_offset);
return IndexNode{ranks};
}
else {
return transform_at(
pop_front(inds),
std::get<front(inds)>(node.mChildren),
offset
);
}
}
template<class T>
constexpr auto transform(const T& t) {
auto inds = indices_of(Type<T>{});
return indexer(inds.size, [&] (auto... is) {
return std::make_tuple(
transform_at(
inds.construct_type_at(is),
t,
is.next()
)...
);
});
}
int main() {
auto tree = []() {
auto t = Node(
A{"FROM A"},
B{"FROM B"},
Node(
C{"FROM C"},
Node(
D{"FROM D"}
)
),
E{"FROM E"}
);
return transform(t);
}();
using Tree = decltype(tree);
indexer(std::tuple_size<Tree>{}, [&] (auto... is) {
(std::cout << ... << std::get<is>(tree));
});
return 0;
}