Files
test2/source/blender/makesdna/DNA_array_utils.hh
Jacques Lucke 0b24f15939 Spreadsheet: persistent table layouts
The main goal of this patch is that the column widths and ordering is not reset
every time one switches between different contexts.

It does that by keeping track of multiple `SpreadsheetTable`. There is one for
each table that is viewed (so e.g. the point and edge domain of the same mesh
are two different tables). Each table has an identifier and an array of columns.

There is some garbage collection in place so that the number of stored tables
does not increase unbounded.

This also comes with an updated Python API:
```python
import bpy
spreadsheet = bpy.context.screen.areas[...].spaces.active
active_table = spreadsheet.tables.active
print(active_table.id.type)
print(active_table.id.attribute_domain)
print(active_table.columns[0].id.name)
```

In the future, we might add some smarter logic to keep tables with different
identifiers more in sync. We don't have a great heuristic for that yet.

Pull Request: https://projects.blender.org/blender/blender/pulls/139205
2025-05-23 06:07:04 +02:00

128 lines
3.6 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_function_ref.hh"
#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 for which the predicate is true. The remaining ones stay in the order they
* were in before.
*/
template<typename T>
inline void remove_if(T **items,
int *items_num,
FunctionRef<bool(const T &)> predicate,
void (*destruct_item)(T *))
{
static_assert(std::is_trivial_v<T>);
/* This sorts the items-to-remove to the back. */
const int remaining = std::partition(*items,
*items + *items_num,
[&](const T &value) { return !predicate(value); }) -
*items;
for (const int i : IndexRange::from_begin_end(remaining, *items_num)) {
destruct_item(&(*items)[i]);
}
*items_num = remaining;
}
/**
* 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