Previously, it was possible for the number of stored columns per table to grow unbounded. While this likely isn't a problem in practice in most cases, one can imagine cases where people temporarily have thousands of attributes when are then never used again. We shouldn't have to store any data for these columns forever. This patch adds some simple garbage collection mechanism that keeps the number of stored unavailable columns per spreadsheet table below a certain threshold (50 currently). Least recently used columns are removed first. Pull Request: https://projects.blender.org/blender/blender/pulls/139469
128 lines
3.6 KiB
C++
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::stable_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
|