36template <
typename HTag>
77 std::optional<Position> position = std::nullopt)
82 auto it = _children.find(parent);
83 if (
it == _children.end()) {
84 position = position.value_or(
Position{});
86 std::tie(
it, std::ignore) = _children.emplace(
93 position =
children.back().position.after();
103 _reg.emplace_or_replace<
PC>(
child, parent, *position);
108 auto src = std::ranges::lower_bound(
113 auto dst = std::ranges::lower_bound(
116 src->position = *position;
137 it = _children.find(parent);
141 auto dst_pos = std::ranges::lower_bound(
191 if (
not pc)
return std::nullopt;
192 if (
pc->position == position)
return std::nullopt;
195 auto it = _children.find(
pc->parent);
199 auto old_loc = std::ranges::lower_bound(
203 auto new_loc = std::ranges::lower_bound(
217 pc->position = position;
233 if (
child == before)
return std::nullopt;
236 if (
not pc)
return std::nullopt;
238 auto it = _children.find(
pc->parent);
242 auto child_pos = std::ranges::lower_bound(
301 auto*
pc = _reg.try_get<
PC>(node);
302 return pc ?
pc->parent : entt::null;
307 auto*
pc = _reg.try_get<
PC>(node);
308 if (
pc)
return pc->position;
314 auto*
pc = _reg.try_get<
PC>(node);
325 auto it = _children.find(parent);
326 if (
it == _children.end())
return 0;
332 auto it = _children.find(parent);
333 if (
it == _children.end())
return std::nullopt;
335 if (
children.empty())
return std::nullopt;
355 auto it = _children.find(parent);
356 if (
it == _children.end())
co_return;
358 if (
order == SiblingOrder::Forward) {
359 for (
const auto&
c :
ch) {
363 for (
const auto&
c : std::ranges::reverse_view(
ch)) {
380 entt::entity
cur = node;
381 while (
cur != entt::null) {
382 auto*
pc = _reg.try_get<
PC>(
cur);
383 if (
not pc)
co_return;
416 return entttree::walk::dfs(
431 auto*
pc = _reg.try_get<
PC>(node);
432 while (
pc and pc->parent != entt::null) {
433 p.push_back(
pc->parent);
434 pc = _reg.try_get<
PC>(
pc->parent);
436 std::reverse(
p.begin(),
p.end());
448 entt::entity
node_b)
const
453 entt::entity
common = entt::null;
454 for (
size_t i = 0;
i <
n; ++
i) {
468 while (
pc and pc->parent != entt::null) {
470 pc = _reg.try_get<
PC>(
pc->parent);
478 entt::registry& _reg;
486 void _remove_from_child_list(
491 auto it = _children.find(parent);
492 if (
it == _children.end())
return;
494 auto loc = std::ranges::lower_bound(
497 [](
const ChildEntry& a,
const ChildEntry& b) {
return a < b; }
499 if (loc != ch.end()) ch.erase(loc);
500 if (ch.empty()) _children.erase(it);
504 bool _dedupe_position(
507 typename ChildList::iterator next)
509 bool at_start = next == v.begin();
510 bool at_end = next == v.end();
511 auto prev = not at_start ? std::prev(next) : next;
512 bool duped = not at_start
and p == prev->position;
513 duped |= not at_end
and p == next->position;
514 if (duped) [[unlikely]] {
515 if (not (at_start or at_end)) {
516 p = prev->position.between(next->position);
517 }
else if (not at_start) {
518 p = prev->position.after();
520 p = next->position.before();
DfsOrder
Controls the visit order for depth-first traversal.
SiblingOrder
Controls the iteration order of siblings within a parent.
ECS components and node types used by the hierarchy, transform, and bounds systems.
std::vector< ChildEntry > ChildList
Sorted list of children for a single parent.
Internal representation of a child in the sorted children cache.
Position position
Sibling ordering key.
entt::entity eid
Child entity.
A system for maintaining parent-child relationships on entities.
entt::entity parent_of(entt::entity node) const
Returns the parent of node, or entt::null if the node is a root or not in the hierarchy.
std::optional< Position > last_child_position(entt::entity parent) const
Returns the position of the last child, or std::nullopt if there are no children.
Generator< NodeEntry > traverse_dfs(entt::entity root, SiblingOrder sibling_order=SiblingOrder::Forward, DfsOrder recursion_order=DfsOrder::ShallowFirst) const
Convenience: flatten a depth-first traversal into a generator.
std::optional< PC > get_connection(entt::entity node) const
Returns the full ParentConnection for node, or std::nullopt if not in the hierarchy.
Generator< NodeEntry > ancestors(entt::entity node) const
Returns a generator which yields the ancestors of a given node.
bool is_ancestor_of(entt::entity ancestor, entt::entity descendant) const
Returns true if ancestor is a strict ancestor of descendant.
auto traverse(entt::entity root, SiblingOrder order) const
Returns a Traversal of the hierarchy rooted at root.
std::optional< Position > order_child_before(entt::entity child, entt::entity before)
Move a child to the position before a sibling.
entt::sigh< void(entt::entity, PC)> on_added
Emitted after a child is added to the hierarchy. Args: (child, new_connection).
Generator< NodeEntry > children(entt::entity parent, SiblingOrder order) const
Visit each child of a given node.
entt::sigh< void(entt::entity, PC)> on_removed
Emitted after a child is removed from the hierarchy. Args: (child, old_connection).
Position set_parent(entt::entity child, entt::entity parent, std::optional< Position > position=std::nullopt)
Set the parent of a child entity.
size_t child_count(entt::entity parent) const
Returns the number of children of a given node.
TreePath path(entt::entity node) const
Returns the path from the root to the given node.
entt::sigh< void(entt::entity, PC, PC)> on_changed
Emitted after a child's parent or position changes. Args: (child, old_connection, new_connection).
std::optional< Position > set_child_position(entt::entity child, Position position)
Change the position of a child among its siblings.
entt::entity deepest_common_ancestor(entt::entity node_a, entt::entity node_b) const
Returns the deepest common ancestor of two nodes.
size_t size() const
The number of non-root nodes in the hierarchy (i.e. entities with a parent).
std::optional< Position > position_of(entt::entity node) const
Returns the sibling position of node, or std::nullopt if not in the hierarchy.
std::optional< PC > unparent(entt::entity child)
Remove a child from its parent.
A node handle yielded by hierarchy traversals and queries.
entt::entity node_id
The entity this entry represents.
A fractional index with strong ordering, used for sibling positioning.
A path from a root entity down to a descendant.
Lazy, composable graph traversal framework built on C++20 generators.
and
Transform a traversal inductively, threading parent context through successors.
auto make_traversal(std::optional< Node > &&root, Successors &&successors)
Construct a Traversal from an optional root and a successor function.