Files
test2/source/blender/makesdna/DNA_array_utils.hh
Bastien Montagne dd168a35c5 Refactor: Replace MEM_cnew with a type-aware template version of MEM_callocN.
The general idea is to keep the 'old', C-style MEM_callocN signature, and slowly
replace most of its usages with the new, C++-style type-safer template version.

* `MEM_cnew<T>` allocation version is renamed to `MEM_callocN<T>`.
* `MEM_cnew_array<T>` allocation version is renamed to `MEM_calloc_arrayN<T>`.
* `MEM_cnew<T>` duplicate version is renamed to `MEM_dupallocN<T>`.

Similar templates type-safe version of `MEM_mallocN` will be added soon
as well.

Following discussions in !134452.

NOTE: For now static type checking in `MEM_callocN` and related are slightly
different for Windows MSVC. This compiler seems to consider structs using the
`DNA_DEFINE_CXX_METHODS` macro as non-trivial (likely because their default
copy constructors are deleted). So using checks on trivially
constructible/destructible instead on this compiler/system.

Pull Request: https://projects.blender.org/blender/blender/pulls/134771
2025-03-05 16:35:09 +01:00

105 lines
2.8 KiB
C++

/* 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"
#include "BLI_utildefines.h"
namespace blender::dna::array {
/**
* Removes an element from the array and shifts the elements after it towards the front.
*/
template<typename T>
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<T>);
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_calloc_arrayN<T>(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<typename T>
inline void clear(T **items, int *items_num, int *active_index, void (*destruct_item)(T *))
{
static_assert(std::is_trivial_v<T>);
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<typename T>
inline void move_index(T *items, const int items_num, const int from_index, const int to_index)
{
static_assert(std::is_trivial_v<T>);
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