From c7e674d40fd1e35046a6dc1689825a8f27b3a9c8 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 22 Jan 2024 21:07:28 +0100 Subject: [PATCH] Cleanup: extract low level dna array utilities to separate file This simplifies reusing those functions outside of the context of node sockets. Pull Request: https://projects.blender.org/blender/blender/pulls/117418 --- source/blender/makesdna/DNA_array_utils.hh | 103 ++++++++++++++++++ .../blender/makesrna/intern/rna_nodetree.cc | 7 +- source/blender/nodes/NOD_socket_items.hh | 90 +-------------- 3 files changed, 108 insertions(+), 92 deletions(-) create mode 100644 source/blender/makesdna/DNA_array_utils.hh diff --git a/source/blender/makesdna/DNA_array_utils.hh b/source/blender/makesdna/DNA_array_utils.hh new file mode 100644 index 00000000000..eb89b021aa6 --- /dev/null +++ b/source/blender/makesdna/DNA_array_utils.hh @@ -0,0 +1,103 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup DNA + * + * Contains functions that help dealing with arrays that are stored in DNA. Due to the constraints + * of DNA, all structs are trivial from the language's point of view (`std::is_trivial_v`). + * However, semantically, these types may have non-trivial copy-constructors and destructors. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_index_range.hh" + +namespace blender::dna::array { + +/** + * Removes an element from the array and shifts the elements after it towards the front. + */ +template +inline void remove_index( + T **items, int *items_num, int *active_index, const int index, void (*destruct_item)(T *)) +{ + static_assert(std::is_trivial_v); + BLI_assert(index >= 0); + BLI_assert(index < *items_num); + + const int old_items_num = *items_num; + const int new_items_num = old_items_num - 1; + + T *old_items = *items; + T *new_items = MEM_cnew_array(new_items_num, __func__); + + std::copy_n(old_items, index, new_items); + std::copy_n(old_items + index + 1, old_items_num - index - 1, new_items + index); + + destruct_item(&old_items[index]); + MEM_freeN(old_items); + + *items = new_items; + *items_num = new_items_num; + + if (active_index) { + const int old_active_index = active_index ? *active_index : 0; + const int new_active_index = std::max( + 0, old_active_index == new_items_num ? new_items_num - 1 : old_active_index); + *active_index = new_active_index; + } +} + +/** + * Removes all elements from an array and frees it. + */ +template +inline void clear(T **items, int *items_num, int *active_index, void (*destruct_item)(T *)) +{ + static_assert(std::is_trivial_v); + for (const int i : IndexRange(*items_num)) { + destruct_item(&(*items)[i]); + } + MEM_SAFE_FREE(*items); + *items_num = 0; + if (active_index) { + *active_index = 0; + } +} + +/** + * Moves one element from one index to another, moving other elements if necessary. + */ +template +inline void move_index(T *items, const int items_num, const int from_index, const int to_index) +{ + static_assert(std::is_trivial_v); + BLI_assert(from_index >= 0); + BLI_assert(from_index < items_num); + BLI_assert(to_index >= 0); + BLI_assert(to_index < items_num); + UNUSED_VARS_NDEBUG(items_num); + + if (from_index == to_index) { + return; + } + + if (from_index < to_index) { + const T tmp = items[from_index]; + for (int i = from_index; i < to_index; i++) { + items[i] = items[i + 1]; + } + items[to_index] = tmp; + } + else if (from_index > to_index) { + const T tmp = items[from_index]; + for (int i = from_index; i > to_index; i--) { + items[i] = items[i - 1]; + } + items[to_index] = tmp; + } +} + +} // namespace blender::dna::array diff --git a/source/blender/makesrna/intern/rna_nodetree.cc b/source/blender/makesrna/intern/rna_nodetree.cc index 4036f3f3589..6279d6f9235 100644 --- a/source/blender/makesrna/intern/rna_nodetree.cc +++ b/source/blender/makesrna/intern/rna_nodetree.cc @@ -3324,7 +3324,7 @@ static void rna_Node_ItemArray_remove(ID *id, return; } const int remove_index = item_to_remove - *ref.items; - blender::nodes::socket_items::remove_item( + blender::dna::array::remove_index( ref.items, ref.items_num, ref.active_index, remove_index, Accessor::destruct_item); bNodeTree *ntree = reinterpret_cast(id); @@ -3336,8 +3336,7 @@ static void rna_Node_ItemArray_remove(ID *id, template static void rna_Node_ItemArray_clear(ID *id, bNode *node, Main *bmain) { blender::nodes::socket_items::SocketItemsRef ref = Accessor::get_items_from_node(*node); - blender::nodes::socket_items::clear_items( - ref.items, ref.items_num, ref.active_index, Accessor::destruct_item); + blender::dna::array::clear(ref.items, ref.items_num, ref.active_index, Accessor::destruct_item); bNodeTree *ntree = reinterpret_cast(id); BKE_ntree_update_tag_node_property(ntree, node); @@ -3354,7 +3353,7 @@ static void rna_Node_ItemArray_move( if (from_index < 0 || to_index < 0 || from_index >= items_num || to_index >= items_num) { return; } - blender::nodes::socket_items::move_item(*ref.items, items_num, from_index, to_index); + blender::dna::array::move_index(*ref.items, items_num, from_index, to_index); bNodeTree *ntree = reinterpret_cast(id); BKE_ntree_update_tag_node_property(ntree, node); diff --git a/source/blender/nodes/NOD_socket_items.hh b/source/blender/nodes/NOD_socket_items.hh index 3462d08e195..5119d5203ae 100644 --- a/source/blender/nodes/NOD_socket_items.hh +++ b/source/blender/nodes/NOD_socket_items.hh @@ -23,6 +23,8 @@ #include "BKE_node.h" #include "BKE_node_runtime.hh" +#include "DNA_array_utils.hh" + #include "NOD_socket.hh" namespace blender::nodes::socket_items { @@ -53,94 +55,6 @@ inline bNode *find_node_by_item(bNodeTree &ntree, const typename Accessor::ItemT return nullptr; } -/** - * Low level utility to remove an item from the array and to shift the elements after it. - */ -template -inline void remove_item(T **items, - int *items_num, - int *active_index, - const int remove_index, - void (*destruct_item)(T *)) -{ - static_assert(std::is_trivial_v); - BLI_assert(remove_index >= 0); - BLI_assert(remove_index < *items_num); - - const int old_items_num = *items_num; - const int new_items_num = old_items_num - 1; - - T *old_items = *items; - T *new_items = MEM_cnew_array(new_items_num, __func__); - - std::copy_n(old_items, remove_index, new_items); - std::copy_n( - old_items + remove_index + 1, old_items_num - remove_index - 1, new_items + remove_index); - - destruct_item(&old_items[remove_index]); - MEM_SAFE_FREE(old_items); - - *items = new_items; - *items_num = new_items_num; - - if (active_index) { - const int old_active_index = active_index ? *active_index : 0; - const int new_active_index = std::max( - 0, old_active_index == new_items_num ? new_items_num - 1 : old_active_index); - *active_index = new_active_index; - } -} - -/** - * Low level utility to remove all elements from an items array. - */ -template -inline void clear_items(T **items, int *items_num, int *active_index, void (*destruct_item)(T *)) -{ - static_assert(std::is_trivial_v); - for (const int i : blender::IndexRange(*items_num)) { - destruct_item(&(*items)[i]); - } - MEM_SAFE_FREE(*items); - *items_num = 0; - if (active_index) { - *active_index = 0; - } -} - -/** - * Low level utility to move one item from one index to another. - */ -template -inline void move_item(T *items, const int items_num, const int from_index, const int to_index) -{ - static_assert(std::is_trivial_v); - BLI_assert(from_index >= 0); - BLI_assert(from_index < items_num); - BLI_assert(to_index >= 0); - BLI_assert(to_index < items_num); - UNUSED_VARS_NDEBUG(items_num); - - if (from_index == to_index) { - return; - } - - if (from_index < to_index) { - const T tmp = items[from_index]; - for (int i = from_index; i < to_index; i++) { - items[i] = items[i + 1]; - } - items[to_index] = tmp; - } - else if (from_index > to_index) { - const T tmp = items[from_index]; - for (int i = from_index; i > to_index; i--) { - items[i] = items[i - 1]; - } - items[to_index] = tmp; - } -} - /** * Destruct all the items and the free the array itself. */