43template <
typename Node_,
typename Successors_>
69 return std::move(*
this);
98template <
typename G,
typename T>
100 { g } -> std::convertible_to<bool>;
101 { *g } -> std::convertible_to<T>;
102 { ++g } -> std::convertible_to<G&>;
107template <
typename T,
typename Node>
109requires (TraversalValue<T> t, Node& n) {
110 { t.root.has_value() } -> std::convertible_to<bool>;
111 { *(t.root) } -> std::convertible_to<Node>;
119 typename TraversalNode<T>;
120 typename TraversalSuccessors<T>;
125template <
typename Successors,
typename Node>
129template <
typename Successors,
typename Node>
130using SuccessorOutput =
decltype(*std::declval<SuccessorGenerator<Successors,Node>&>());
133template <
typename Traversal>
140template <
typename Traversal>
160template <
typename Node,
typename Successors>
161requires requires (Successors
s, Node&
n) {
165 std::optional<Node>&& root,
166 Successors&& successors)
168 using S = std::remove_cvref_t<Successors>;
171 std::forward<Successors>(successors)
177template <
typename Node,
typename Successors>
178requires requires (Successors s, Node& n) {
179 { s(n) } -> GeneratorConcept<Node>;
182 const std::optional<Node>& root,
183 Successors&& successors)
185 using S = std::remove_cvref_t<Successors>;
188 std::forward<Successors>(successors)
194template <
typename Node,
typename Successors>
195requires requires (Successors s, std::remove_cvref_t<Node>& n) {
196 { s(n) } -> GeneratorConcept<std::remove_cvref_t<Node>>;
200 Successors&& successors)
202 using N = std::remove_cvref_t<Node>;
204 std::make_optional(N{std::forward<Node>(root)}),
205 std::forward<Successors>(successors)
232template <AnyTraversalConcept T,
typename Filter>
240 std::move(
base.root),
242 successors = std::move(
base.successors),
246 if (should_explore(node)) {
247 return MaybeGenerator<G>{ successors(node) };
265template <AnyTraversalConcept T,
typename Filter>
271 std::optional<Node> root;
274 root = std::move(*
base.root);
280 successors = std::move(
base.successors),
284 for (auto g = successors(node); g; ++g) {
287 if (should_admit(child)) {
288 co_yield std::move(child);
304template <AnyTraversalConcept T>
311 std::move(
base.root),
313 successors = std::move(
base.successors)
317 std::vector<Node> children;
318 for (auto g = successors(node); g; ++g) {
319 children.emplace_back(*g);
321 for (
auto it = children.rbegin();
it != children.rend(); ++
it) {
322 co_yield std::move(*
it);
339template <AnyTraversalConcept Traversal,
typename Transform>
342 using Node =
typename T::Node;
344 using Value = std::remove_cvref_t<std::invoke_result_t<Transform&, Node&>>;
346 T base = std::forward<Traversal>(
t);
355 successors = std::move(
base.successors),
360 for (auto g = successors(node); g; ++g) {
362 co_yield xform(child);
376template <
typename Node,
typename SuccessorGenerator>
379 SuccessorGenerator successors;
381 template <
typename N,
typename Successors>
382 DfsEntry(N&& n, Successors& next):
383 node(std::forward<N>(n)),
384 successors(next(node)) {}
388template <DfsOrder recursion_order,
typename Node,
typename Successors>
390 std::optional<Node> root,
391 Successors successors)
394 std::invoke_result_t<Successors&, Node&>
396 using StackEntry = DfsEntry<Node, SuccessorGenerator>;
398 if (not root)
co_return;
400 std::list<StackEntry> stack;
401 stack.emplace_back(std::move(*root), successors);
403 if constexpr (recursion_order == DfsOrder::ShallowFirst) {
404 co_yield stack.back().node;
407 while (not stack.empty()) {
408 StackEntry& entry = stack.back();
409 if (entry.successors) {
411 Node next_node = *entry.successors;
415 std::move(next_node),
418 if constexpr (recursion_order == DfsOrder::ShallowFirst) {
419 co_yield stack.back().node;
422 if constexpr (recursion_order == DfsOrder::DeepFirst) {
431template <
typename Node,
typename Successors>
433 std::optional<Node> root,
434 Successors successors)
436 if (not root)
co_return;
438 std::deque<Node> queue;
439 queue.emplace_back(std::move(*root));
441 while (not queue.empty()) {
442 Node node = std::move(queue.front());
445 for (
auto g = successors(node); g; ++g) {
448 queue.emplace_back(std::move(child));
451 co_yield std::move(node);
469 DfsOrder recursion_order = DfsOrder::ShallowFirst,
470 AnyTraversalConcept T
477 return detail::dfs<recursion_order, Node>(
478 std::move(
base.root),
479 std::move(
base.successors)
485template <AnyTraversalConcept T>
493 return dfs<DfsOrder::DeepFirst>(std::forward<T>(t));
502template <AnyTraversalConcept T>
508 return detail::bfs<Node>(
509 std::move(
base.root),
510 std::move(
base.successors)
541requires TraversalConcept<Trav, Node>
543 {
c(parent, std::move(
n)) } -> std::convertible_to<std::optional<Value>>;
545 and std::invocable<Get&, Value&>
546auto inductive_transform(Trav&& t, Compose&& make_successor, Get&& get_node) {
547 using Traversal = TraversalValue<Trav>;
549 Traversal base = std::forward<Trav>(t);
551 std::optional<Value> root_value;
553 std::optional<Value> no_parent = std::nullopt;
554 Node root_node = *base.root;
555 root_value = make_successor(no_parent, std::move(root_node));
559 std::move(root_value),
561 successors = std::move(base.successors),
562 get_node = std::forward<Get>(get_node),
563 make_successor = std::forward<Compose>(make_successor)
564 ] (Value& parent) mutable -> Generator<Value> {
565 auto&& parent_node = get_node(parent);
566 std::optional<Value> parent_value = parent;
567 for (auto g = successors(parent_node); g; ++g) {
569 std::optional<Value> value = make_successor(
573 if (value) co_yield std::move(*value);
Satisfied by any type that is a Traversal over its own Node type.
A type G that can be advanced, dereferenced, and tested for exhaustion.
Satisfied by types that have a root and a successors function yielding Node.
Common type aliases, enumerations, and utility functions used throughout entttree.
DfsOrder
Controls the visit order for depth-first traversal.
Coroutine-based generator and related wrapper types.
A system for maintaining parent-child relationships on entities.
A lazy description of a rooted graph traversal.
std::optional< Node > root
The starting point of the traversal, or empty to disable it.
Traversal & enable(bool enable) &
Conditionally disable the traversal.
Successors successors
A function returning a generator of the successors of a node.
Traversal && enable(bool enable) &&
Conditionally disable the traversal.
auto reverse_successors(T &&t)
Reverse the order of each node's successors.
auto bfs(T &&t)
Flatten a Traversal into a breadth-first Generator.
auto dfs(T &&t)
Flatten a Traversal into a depth-first Generator.
decltype(*std::declval< SuccessorGenerator< Successors, Node > & >()) SuccessorOutput
The value type yielded by a successor generator.
auto prune_if(T &&t, Filter should_explore)
Prevent certain nodes from generating successors.
std::remove_cvref_t< T > TraversalValue
Strip references/cv to get the bare Traversal type.
typename TraversalValue< T >::Node TraversalNode
Extract the Node type from a Traversal (after stripping cvref).
std::remove_cvref_t< SuccessorGenerator< TraversalSuccessors< Traversal >, TraversalNode< Traversal > > > TraversalGenerator
The concrete generator type produced by a traversal's successor function.
and
Transform a traversal inductively, threading parent context through successors.
typename TraversalValue< T >::Successors TraversalSuccessors
Extract the Successors callable type from a Traversal.
auto make_traversal(std::optional< Node > &&root, Successors &&successors)
Construct a Traversal from an optional root and a successor function.
std::invoke_result_t< Successors &, Node & > SuccessorGenerator
The generator type returned by a successor function.
auto map_nodes(Traversal &&t, Transform &&xform)
Transform the node type of a traversal.
auto exclude_if(T &&t, Filter should_admit)
Remove certain nodes from the graph entirely.