mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 07:53:26 +00:00
Core: Add Node::iterate_children
as a fast way to iterate a node's children, without needing allocations or get_child
.
Adds `Iterable` class to templates.
This commit is contained in:
parent
6f2ab528ca
commit
175c38d0dc
4 changed files with 101 additions and 13 deletions
46
core/templates/iterable.h
Normal file
46
core/templates/iterable.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/**************************************************************************/
|
||||
/* iterable.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
template <typename I>
|
||||
class Iterable {
|
||||
I _begin;
|
||||
I _end;
|
||||
|
||||
public:
|
||||
I begin() { return _begin; }
|
||||
I end() { return _end; }
|
||||
|
||||
Iterable(I &&begin, I &&end) :
|
||||
_begin(std::move(begin)), _end(std::move(end)) {}
|
||||
Iterable(const I &begin, const I &end) :
|
||||
_begin(begin), _end(end) {}
|
||||
};
|
|
@ -1781,6 +1781,26 @@ void Node::_update_children_cache_impl() const {
|
|||
data.children_cache_dirty = false;
|
||||
}
|
||||
|
||||
template <bool p_include_internal>
|
||||
Iterable<Node::ChildrenIterator> Node::iterate_children() const {
|
||||
// The thread guard is omitted for performance reasons.
|
||||
// ERR_THREAD_GUARD_V(Iterable<ChildrenIterator>(nullptr, nullptr));
|
||||
|
||||
_update_children_cache();
|
||||
const uint32_t size = data.children_cache.size();
|
||||
// Might be null, but then size and internal counts are also 0.
|
||||
Node **ptr = data.children_cache.ptr();
|
||||
|
||||
if constexpr (p_include_internal) {
|
||||
return Iterable(ChildrenIterator(ptr), ChildrenIterator(ptr + size));
|
||||
} else {
|
||||
return Iterable(ChildrenIterator(ptr + data.internal_children_front_count_cache), ChildrenIterator(ptr + size - data.internal_children_back_count_cache));
|
||||
}
|
||||
}
|
||||
|
||||
template Iterable<Node::ChildrenIterator> Node::iterate_children<true>() const;
|
||||
template Iterable<Node::ChildrenIterator> Node::iterate_children<false>() const;
|
||||
|
||||
int Node::get_child_count(bool p_include_internal) const {
|
||||
ERR_THREAD_GUARD_V(0);
|
||||
if (p_include_internal) {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/string/node_path.h"
|
||||
#include "core/templates/iterable.h"
|
||||
#include "core/variant/typed_array.h"
|
||||
#include "scene/main/scene_tree.h"
|
||||
#include "scene/scene_string_names.h"
|
||||
|
@ -47,8 +48,6 @@ SAFE_NUMERIC_TYPE_PUN_GUARANTEES(uint32_t)
|
|||
class Node : public Object {
|
||||
GDCLASS(Node, Object);
|
||||
|
||||
friend class SceneTreeFTI;
|
||||
|
||||
protected:
|
||||
// During group processing, these are thread-safe.
|
||||
// Outside group processing, these avoid the cost of sync by working as plain primitive types.
|
||||
|
@ -132,6 +131,29 @@ public:
|
|||
|
||||
void _update_process(bool p_enable, bool p_for_children);
|
||||
|
||||
struct ChildrenIterator {
|
||||
_FORCE_INLINE_ Node *&operator*() const { return *_ptr; }
|
||||
_FORCE_INLINE_ Node **operator->() const { return _ptr; }
|
||||
_FORCE_INLINE_ ChildrenIterator &operator++() {
|
||||
_ptr++;
|
||||
return *this;
|
||||
}
|
||||
_FORCE_INLINE_ ChildrenIterator &operator--() {
|
||||
_ptr--;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const ChildrenIterator &b) const { return _ptr == b._ptr; }
|
||||
_FORCE_INLINE_ bool operator!=(const ChildrenIterator &b) const { return _ptr != b._ptr; }
|
||||
|
||||
ChildrenIterator(Node **p_ptr) { _ptr = p_ptr; }
|
||||
ChildrenIterator() {}
|
||||
ChildrenIterator(const ChildrenIterator &p_it) { _ptr = p_it._ptr; }
|
||||
|
||||
private:
|
||||
Node **_ptr = nullptr;
|
||||
};
|
||||
|
||||
private:
|
||||
struct GroupData {
|
||||
bool persistent = false;
|
||||
|
@ -484,6 +506,13 @@ public:
|
|||
void add_sibling(Node *p_sibling, bool p_force_readable_name = false);
|
||||
void remove_child(Node *p_child);
|
||||
|
||||
/// Optimal way to iterate the children of this node.
|
||||
/// The caller is responsible to ensure:
|
||||
/// - The thread has the rights to access the node (is_accessible_from_caller_thread() == true).
|
||||
/// - No children are inserted, removed, or have their index changed during iteration.
|
||||
template <bool p_include_internal = true>
|
||||
Iterable<ChildrenIterator> iterate_children() const;
|
||||
|
||||
int get_child_count(bool p_include_internal = true) const;
|
||||
Node *get_child(int p_index, bool p_include_internal = true) const;
|
||||
TypedArray<Node> get_children(bool p_include_internal = true) const;
|
||||
|
|
|
@ -465,19 +465,12 @@ void SceneTreeFTI::_update_dirty_nodes(Node *p_node, uint32_t p_current_half_fra
|
|||
return;
|
||||
}
|
||||
|
||||
// Temporary direct access to children cache for speed.
|
||||
// Maybe replaced later by a more generic fast access method
|
||||
// for children.
|
||||
p_node->_update_children_cache();
|
||||
Span<Node *> children = p_node->data.children_cache.span();
|
||||
uint32_t num_children = children.size();
|
||||
|
||||
// Not a Node3D.
|
||||
// Could be e.g. a viewport or something
|
||||
// so we should still recurse to children.
|
||||
if (!s) {
|
||||
for (uint32_t n = 0; n < num_children; n++) {
|
||||
_update_dirty_nodes(children.ptr()[n], p_current_half_frame, p_interpolation_fraction, p_active, nullptr, p_depth + 1);
|
||||
for (Node *node : p_node->iterate_children()) {
|
||||
_update_dirty_nodes(node, p_current_half_frame, p_interpolation_fraction, p_active, nullptr, p_depth + 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -592,8 +585,8 @@ void SceneTreeFTI::_update_dirty_nodes(Node *p_node, uint32_t p_current_half_fra
|
|||
s->_clear_dirty_bits(Node3D::DIRTY_GLOBAL_INTERPOLATED_TRANSFORM);
|
||||
|
||||
// Recurse to children.
|
||||
for (uint32_t n = 0; n < num_children; n++) {
|
||||
_update_dirty_nodes(children.ptr()[n], p_current_half_frame, p_interpolation_fraction, p_active, s->data.fti_global_xform_interp_set ? &s->data.global_transform_interpolated : &s->data.global_transform, p_depth + 1);
|
||||
for (Node *node : p_node->iterate_children()) {
|
||||
_update_dirty_nodes(node, p_current_half_frame, p_interpolation_fraction, p_active, s->data.fti_global_xform_interp_set ? &s->data.global_transform_interpolated : &s->data.global_transform, p_depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue