From 8bec7dce35890565db310cabbf7d95b5bd96776f Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 23 Dec 2024 15:01:07 +0100 Subject: [PATCH] Nodes: avoid O(n^2) when looking up interface input indices Previously, the code was O(n^2) because it iterated over all interface sockets, and for each it tried to find the corresponding index by iterating over all inputs again. Now, a `VectorSet` is used to make finding the index `O(1)`. The new utility function may also be useful elsewhere. Pull Request: https://projects.blender.org/blender/blender/pulls/132272 --- source/blender/blenkernel/BKE_node_runtime.hh | 24 ++++++++++++++++--- .../blenkernel/BKE_node_tree_interface.hh | 7 +++--- .../blenkernel/intern/node_tree_interface.cc | 6 ++--- source/blender/makesdna/DNA_node_types.h | 8 ++++++- source/blender/modifiers/intern/MOD_nodes.cc | 3 +-- 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh index 765c3a6bcce..a6c4542cc60 100644 --- a/source/blender/blenkernel/BKE_node_runtime.hh +++ b/source/blender/blenkernel/BKE_node_runtime.hh @@ -611,7 +611,7 @@ inline blender::Span bNodeTree::interface_inputs() inline blender::Span bNodeTree::interface_inputs() const { BLI_assert(this->tree_interface.items_cache_is_available()); - return this->tree_interface.runtime->inputs_; + return this->tree_interface.runtime->inputs_.as_span(); } inline blender::Span bNodeTree::interface_outputs() @@ -623,7 +623,7 @@ inline blender::Span bNodeTree::interface_outputs() inline blender::Span bNodeTree::interface_outputs() const { BLI_assert(this->tree_interface.items_cache_is_available()); - return this->tree_interface.runtime->outputs_; + return this->tree_interface.runtime->outputs_.as_span(); } inline blender::Span bNodeTree::interface_items() @@ -635,7 +635,25 @@ inline blender::Span bNodeTree::interface_items() inline blender::Span bNodeTree::interface_items() const { BLI_assert(this->tree_interface.items_cache_is_available()); - return this->tree_interface.runtime->items_; + return this->tree_interface.runtime->items_.as_span(); +} + +inline int bNodeTree::interface_input_index(const bNodeTreeInterfaceSocket &io_socket) const +{ + BLI_assert(this->tree_interface.items_cache_is_available()); + return this->tree_interface.runtime->inputs_.index_of_as(&io_socket); +} + +inline int bNodeTree::interface_output_index(const bNodeTreeInterfaceSocket &io_socket) const +{ + BLI_assert(this->tree_interface.items_cache_is_available()); + return this->tree_interface.runtime->outputs_.index_of_as(&io_socket); +} + +inline int bNodeTree::interface_item_index(const bNodeTreeInterfaceItem &io_item) const +{ + BLI_assert(this->tree_interface.items_cache_is_available()); + return this->tree_interface.runtime->items_.index_of_as(&io_item); } /** \} */ diff --git a/source/blender/blenkernel/BKE_node_tree_interface.hh b/source/blender/blenkernel/BKE_node_tree_interface.hh index bc2c006e7e6..67748d171b8 100644 --- a/source/blender/blenkernel/BKE_node_tree_interface.hh +++ b/source/blender/blenkernel/BKE_node_tree_interface.hh @@ -15,6 +15,7 @@ #include "BLI_cache_mutex.hh" #include "BLI_parameter_pack_utils.hh" #include "BLI_vector.hh" +#include "BLI_vector_set.hh" namespace blender::bke { @@ -39,10 +40,10 @@ class bNodeTreeInterfaceRuntime { CacheMutex items_cache_mutex_; /* Runtime topology cache for linear access to items. */ - Vector items_; + VectorSet items_; /* Socket-only lists for input/output access by index. */ - Vector inputs_; - Vector outputs_; + VectorSet inputs_; + VectorSet outputs_; }; namespace node_interface { diff --git a/source/blender/blenkernel/intern/node_tree_interface.cc b/source/blender/blenkernel/intern/node_tree_interface.cc index 2b43a3faebb..ef5d86fae8d 100644 --- a/source/blender/blenkernel/intern/node_tree_interface.cc +++ b/source/blender/blenkernel/intern/node_tree_interface.cc @@ -1423,13 +1423,13 @@ void bNodeTreeInterface::ensure_items_cache() const bNodeTreeInterface &mutable_self = const_cast(*this); mutable_self.foreach_item([&](bNodeTreeInterfaceItem &item) { - runtime.items_.append(&item); + runtime.items_.add_new(&item); if (bNodeTreeInterfaceSocket *socket = get_item_as(&item)) { if (socket->flag & NODE_INTERFACE_SOCKET_INPUT) { - runtime.inputs_.append(socket); + runtime.inputs_.add_new(socket); } if (socket->flag & NODE_INTERFACE_SOCKET_OUTPUT) { - runtime.outputs_.append(socket); + runtime.outputs_.add_new(socket); } } return true; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index b09f666690b..54ff3b371dc 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -16,9 +16,11 @@ /** Workaround to forward-declare C++ type in C header. */ #ifdef __cplusplus -# include # include +# include "BLI_vector.hh" +# include "BLI_vector_set.hh" + namespace blender { template class Span; template class MutableSpan; @@ -847,6 +849,10 @@ typedef struct bNodeTree { blender::Span interface_outputs() const; blender::Span interface_items(); blender::Span interface_items() const; + + int interface_input_index(const bNodeTreeInterfaceSocket &io_socket) const; + int interface_output_index(const bNodeTreeInterfaceSocket &io_socket) const; + int interface_item_index(const bNodeTreeInterfaceItem &io_item) const; #endif } bNodeTree; diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 8264be5f82a..12d838b6235 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -2154,8 +2154,7 @@ static void draw_property_for_socket(DrawGroupInputsContext &ctx, uiLayout *row = uiLayoutRow(layout, true); uiLayoutSetPropDecorate(row, true); - const int input_index = - const_cast(ctx.nmd.node_group)->interface_inputs().first_index(&socket); + const int input_index = ctx.nmd.node_group->interface_input_index(socket); /* Use #uiItemPointerR to draw pointer properties because #uiItemR would not have enough * information about what type of ID to select for editing the values. This is because