Cleanup: Main `foreach ID` code: Remove `MAX_LIBARRAY` and improve comments.

The `MAX_LIBARRAY` define was an annoying doublon to the `INDEX_ID_MAX` enum value
now defined in `DNA_ID.h`, and it is no more useful.

And comments were somewhat outdated. Also added an explanation about
chosen order for the `INDEX_ID_<IDTYPE>` order.
This commit is contained in:
Bastien Montagne 2021-03-04 18:39:07 +01:00
parent f951aa063f
commit 63b7ff9f4e
19 changed files with 92 additions and 61 deletions

View File

@ -223,7 +223,7 @@ struct GSet *BKE_main_gset_create(struct Main *bmain, struct GSet *gset);
#define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb) \
{ \
ListBase *_lbarray[MAX_LIBARRAY]; \
ListBase *_lbarray[INDEX_ID_MAX]; \
int _i = set_listbasepointers((_bmain), _lbarray); \
while (_i--) { \
(_lb) = _lbarray[_i];
@ -234,9 +234,13 @@ struct GSet *BKE_main_gset_create(struct Main *bmain, struct GSet *gset);
((void)0)
/**
* DO NOT use break statement with that macro,
* use #FOREACH_MAIN_LISTBASE and #FOREACH_MAIN_LISTBASE_ID instead
* if you need that kind of control flow. */
* Top level `foreach`-like macro allowing to loop over all IDs in a given #Main data-base.
*
* NOTE: Order tries to go from 'user IDs' to 'used IDs' (e.g. collections will be processed
* before objects, which will be processed before obdata types, etc.).
*
* WARNING: DO NOT use break statement with that macro, use #FOREACH_MAIN_LISTBASE and
* #FOREACH_MAIN_LISTBASE_ID instead if you need that kind of control flow. */
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id) \
{ \
ListBase *_lb; \
@ -259,8 +263,8 @@ const char *BKE_main_blendfile_path_from_global(void);
struct ListBase *which_libbase(struct Main *bmain, short type);
#define MAX_LIBARRAY 41
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
//#define INDEX_ID_MAX 41
int set_listbasepointers(struct Main *main, struct ListBase *lb[]);
#define MAIN_VERSION_ATLEAST(main, ver, subver) \
((main)->versionfile > (ver) || \

View File

@ -865,7 +865,7 @@ bool BKE_blendfile_write_partial(Main *bmain_src,
ReportList *reports)
{
Main *bmain_dst = MEM_callocN(sizeof(Main), "copybuffer");
ListBase *lbarray_dst[MAX_LIBARRAY], *lbarray_src[MAX_LIBARRAY];
ListBase *lbarray_dst[INDEX_ID_MAX], *lbarray_src[INDEX_ID_MAX];
int a, retval;
void *path_list_backup = NULL;

View File

@ -783,7 +783,7 @@ void BKE_bpath_traverse_main(Main *bmain,
const int flag,
void *bpath_user_data)
{
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
int a = set_listbasepointers(bmain, lbarray);
while (a--) {
BKE_bpath_traverse_id_list(bmain, lbarray[a], visit_cb, flag, bpath_user_data);

View File

@ -63,7 +63,7 @@ bool BKE_idtype_cache_key_cmp(const void *key_a_v, const void *key_b_v)
(key_a->offset_in_ID != key_b->offset_in_ID) || (key_a->cache_v != key_b->cache_v);
}
static IDTypeInfo *id_types[MAX_LIBARRAY] = {NULL};
static IDTypeInfo *id_types[INDEX_ID_MAX] = {NULL};
static void id_type_init(void)
{

View File

@ -916,7 +916,7 @@ void BKE_main_id_tag_idcode(struct Main *mainvar,
*/
void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value)
{
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
int a;
a = set_listbasepointers(mainvar, lbarray);
@ -949,7 +949,7 @@ void BKE_main_id_flag_listbase(ListBase *lb, const int flag, const bool value)
*/
void BKE_main_id_flag_all(Main *bmain, const int flag, const bool value)
{
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
int a;
a = set_listbasepointers(bmain, lbarray);
while (a--) {
@ -1870,7 +1870,7 @@ void BKE_library_make_local(Main *bmain,
const bool untagged_only,
const bool set_fake)
{
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
LinkNode *todo_ids = NULL;
LinkNode *copied_ids = NULL;

View File

@ -240,7 +240,7 @@ void BKE_id_free_us(Main *bmain, void *idv) /* test users */
static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
{
const int tag = LIB_TAG_DOIT;
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
Link dummy_link = {0};
int base_count, i;

View File

@ -440,7 +440,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
typedef struct IDUsersIter {
ID *id;
ListBase *lb_array[MAX_LIBARRAY];
ListBase *lb_array[INDEX_ID_MAX];
int lb_idx;
ID *curr_id;
@ -514,7 +514,7 @@ int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
{
IDUsersIter iter;
ListBase *lb_array[MAX_LIBARRAY];
ListBase *lb_array[INDEX_ID_MAX];
ID *id = idv;
int i = set_listbasepointers(bmain, lb_array);
bool is_defined = false;
@ -567,7 +567,7 @@ bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked)
{
IDUsersIter iter;
ListBase *lb_array[MAX_LIBARRAY];
ListBase *lb_array[INDEX_ID_MAX];
ID *id = idv;
int i = set_listbasepointers(bmain, lb_array);
bool is_defined = false;
@ -805,7 +805,7 @@ void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
*/
void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
{
ListBase *lb_array[MAX_LIBARRAY];
ListBase *lb_array[INDEX_ID_MAX];
bool do_loop = true;
while (do_loop) {

View File

@ -53,7 +53,7 @@ Main *BKE_main_new(void)
void BKE_main_free(Main *mainvar)
{
/* also call when reading a file, erase all, etc */
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
int a;
/* Since we are removing whole main, no need to bother 'properly'
@ -532,18 +532,17 @@ ListBase *which_libbase(Main *bmain, short type)
}
/**
* puts into array *lb pointers to all the #ListBase structs in main,
* and returns the number of them as the function result. This is useful for
* generic traversal of all the blocks in a Main (by traversing all the
* lists in turn), without worrying about block types.
* Put the pointers to all the #ListBase structs in given `bmain` into the `*lb[INDEX_ID_MAX]`
* array, and return the number of those for convinience.
*
* \note #MAX_LIBARRAY define should match this code */
int set_listbasepointers(Main *bmain, ListBase **lb)
* This is useful for generic traversal of all the blocks in a #Main (by traversing all the lists
* in turn), without worrying about block types.
*
* \note The order of each ID type #ListBase in the array is determined by the `INDEX_ID_<IDTYPE>`
* enum definitions in `DNA_ID.h`. See also the #FOREACH_MAIN_ID_BEGIN macro in `BKE_main.h`
*/
int set_listbasepointers(Main *bmain, ListBase *lb[INDEX_ID_MAX])
{
/* BACKWARDS! also watch order of free-ing! (mesh<->mat), first items freed last.
* This is important because freeing data decreases user-counts of other data-blocks,
* if this data is its self freed it can crash. */
/* Libraries may be accessed from pretty much any other ID. */
lb[INDEX_ID_LI] = &(bmain->libraries);
@ -606,5 +605,5 @@ int set_listbasepointers(Main *bmain, ListBase **lb)
lb[INDEX_ID_NULL] = NULL;
return (MAX_LIBARRAY - 1);
return (INDEX_ID_MAX - 1);
}

View File

@ -66,7 +66,7 @@ struct IDNameLib_TypeMap {
* Opaque structure, external API users only see this.
*/
struct IDNameLib_Map {
struct IDNameLib_TypeMap type_maps[MAX_LIBARRAY];
struct IDNameLib_TypeMap type_maps[INDEX_ID_MAX];
struct GHash *uuid_map;
struct Main *bmain;
struct GSet *valid_id_pointers;
@ -77,7 +77,7 @@ static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id
short id_type)
{
if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) {
for (int i = 0; i < MAX_LIBARRAY; i++) {
for (int i = 0; i < INDEX_ID_MAX; i++) {
if (id_map->type_maps[i].id_type == id_type) {
return &id_map->type_maps[i];
}
@ -108,13 +108,13 @@ struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain,
id_map->idmap_types = idmap_types;
int index = 0;
while (index < MAX_LIBARRAY) {
while (index < INDEX_ID_MAX) {
struct IDNameLib_TypeMap *type_map = &id_map->type_maps[index];
type_map->map = NULL;
type_map->id_type = BKE_idtype_idcode_iter_step(&index);
BLI_assert(type_map->id_type != 0);
}
BLI_assert(index == MAX_LIBARRAY);
BLI_assert(index == INDEX_ID_MAX);
if (idmap_types & MAIN_IDMAP_TYPE_UUID) {
ID *id;
@ -231,7 +231,7 @@ void BKE_main_idmap_destroy(struct IDNameLib_Map *id_map)
{
if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) {
struct IDNameLib_TypeMap *type_map = id_map->type_maps;
for (int i = 0; i < MAX_LIBARRAY; i++, type_map++) {
for (int i = 0; i < INDEX_ID_MAX; i++, type_map++) {
if (type_map->map) {
BLI_ghash_free(type_map->map, NULL, NULL);
type_map->map = NULL;

View File

@ -60,7 +60,7 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
blo_split_main(&mainlist, bmain);
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
int i = set_listbasepointers(bmain, lbarray);
while (i--) {
for (ID *id = lbarray[i]->first; id != NULL; id = id->next) {

View File

@ -449,7 +449,7 @@ static void oldnewmap_free(OldNewMap *onm)
static void add_main_to_main(Main *mainvar, Main *from)
{
ListBase *lbarray[MAX_LIBARRAY], *fromarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX], *fromarray[INDEX_ID_MAX];
int a;
set_listbasepointers(mainvar, lbarray);
@ -517,7 +517,7 @@ void blo_split_main(ListBase *mainlist, Main *main)
lib_main_array[i] = libmain;
}
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
i = set_listbasepointers(main, lbarray);
while (i--) {
ID *id = lbarray[i]->first;
@ -1965,7 +1965,7 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
/* undo file support: add all library pointers in lookup */
void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
{
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
LISTBASE_FOREACH (Main *, ptr, old_mainlist) {
int i = set_listbasepointers(ptr, lbarray);
@ -4543,7 +4543,7 @@ void BLO_main_expander(BLOExpandDoitCallback expand_doit_func)
*/
void BLO_expand_main(void *fdhandle, Main *mainvar)
{
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
FileData *fd = fdhandle;
ID *id;
int a;
@ -4713,7 +4713,7 @@ static void add_loose_object_data_to_scene(Main *mainvar,
}
/* Loop over all ID types, instancing object-data for ID types that have support for it. */
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
int i = set_listbasepointers(mainvar, lbarray);
while (i--) {
const short idcode = BKE_idtype_idcode_from_index(i);
@ -4979,7 +4979,7 @@ static bool library_link_idcode_needs_tag_check(const short idcode, const int fl
*/
static void library_link_clear_tag(Main *mainvar, const int flag)
{
for (int i = 0; i < MAX_LIBARRAY; i++) {
for (int i = 0; i < INDEX_ID_MAX; i++) {
const short idcode = BKE_idtype_idcode_from_index(i);
BLI_assert(idcode != -1);
if (library_link_idcode_needs_tag_check(idcode, flag)) {
@ -5068,8 +5068,8 @@ static void split_main_newid(Main *mainptr, Main *main_newid)
BLI_strncpy(main_newid->name, mainptr->name, sizeof(main_newid->name));
main_newid->curlib = mainptr->curlib;
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray_newid[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
ListBase *lbarray_newid[INDEX_ID_MAX];
int i = set_listbasepointers(mainptr, lbarray);
set_listbasepointers(main_newid, lbarray_newid);
while (i--) {
@ -5227,7 +5227,7 @@ void *BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname)
static int has_linked_ids_to_read(Main *mainvar)
{
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
int a = set_listbasepointers(mainvar, lbarray);
while (a--) {
@ -5295,7 +5295,7 @@ static void read_library_linked_ids(FileData *basefd,
{
GHash *loaded_ids = BLI_ghash_str_new(__func__);
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
int a = set_listbasepointers(mainvar, lbarray);
while (a--) {
@ -5344,7 +5344,7 @@ static void read_library_clear_weak_links(FileData *basefd, ListBase *mainlist,
{
/* Any remaining weak links at this point have been lost, silently drop
* those by setting them to NULL pointers. */
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
int a = set_listbasepointers(mainvar, lbarray);
while (a--) {

View File

@ -1141,7 +1141,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 276, 5)) {
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
int a;
/* Important to clear all non-persistent flags from older versions here,

View File

@ -768,7 +768,7 @@ static void write_userdef(BlendWriter *writer, const UserDef *userdef)
/* Keep it last of write_foodata functions. */
static void write_libraries(WriteData *wd, Main *main)
{
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
ID *id;
int a, tot;
bool found_one;
@ -954,7 +954,7 @@ static bool write_file_handle(Main *mainvar,
* if needed, without duplicating whole code. */
Main *bmain = mainvar;
do {
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
int a = set_listbasepointers(bmain, lbarray);
while (a--) {
ID *id = lbarray[a]->first;

View File

@ -33,9 +33,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_ID.h" /* for ID_Type */
#include "BKE_main.h" /* for MAX_LIBARRAY */
#include "DNA_ID.h" /* for ID_Type and INDEX_ID_MAX */
#include "BLI_threads.h" /* for SpinLock */
@ -111,10 +109,10 @@ struct Depsgraph {
bool need_update;
/* Indicates which ID types were updated. */
char id_type_updated[MAX_LIBARRAY];
char id_type_updated[INDEX_ID_MAX];
/* Indicates type of IDs present in the depsgraph. */
char id_type_exist[MAX_LIBARRAY];
char id_type_exist[INDEX_ID_MAX];
/* Quick-Access Temp Data ............. */

View File

@ -111,7 +111,7 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar,
{
const short filter_id_type = id_filter_get();
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
int tot;
if (filter_id_type) {
lbarray[0] = which_libbase(&mainvar, space_outliner_.filter_id_type);

View File

@ -42,7 +42,7 @@ TreeDisplayIDOrphans::TreeDisplayIDOrphans(SpaceOutliner &space_outliner)
ListBase TreeDisplayIDOrphans::buildTree(const TreeSourceData &source_data)
{
ListBase tree = {nullptr};
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
short filter_id_type = (space_outliner_.filter & SO_FILTER_ID_TYPE) ?
space_outliner_.filter_id_type :
0;

View File

@ -722,8 +722,36 @@ typedef enum IDRecalcFlag {
FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF | FILTER_ID_WS | \
FILTER_ID_LP | FILTER_ID_HA | FILTER_ID_PT | FILTER_ID_VO | FILTER_ID_SIM)
/* IMPORTANT: this enum matches the order currently use in set_listbasepointers,
* keep them in sync! */
/**
* This enum defines the index assigned to each type of IDs in the array returned by
* #set_listbasepointers, and by extension, controls the default order in which each ID type is
* processed during standard 'foreach' looping over all IDs of a #Main data-base.
*
* About Order:
* ------------
*
* This is (losely) defined with a relationship order in mind, from lowest level (ID types using,
* referencing almost no other ID types) to highest level (ID types potentially using many other ID
* types).
*
* So e.g. it ensures that this dependency chain is respected:
* #Material <- #Mesh <- #Object <- #Collection <- #Scene
*
* Default order of processing of IDs in 'foreach' macros (#FOREACH_MAIN_ID_BEGIN and the like),
* built on top of #set_listbasepointers, is actually reversed compared to the order defined here,
* since processing usually needs to happen on users before it happens on used IDs (when freeing
* e.g.).
*
* DO NOT rely on this order as being full-proofed dependency order, there are many cases were it
* can be violated (most obvious cases being custom properties and drivers, which can reference any
* other ID types).
*
* However, this order can be considered as an optimization heuristic, especially when processing
* relationships in a non-recursive pattern: in typical cases, a vast majority of those
* relationships can be processed fine in the first pass, and only few additional passes are
* required to address all remaining relationship cases.
* See e.g. how #BKE_library_unused_linked_data_set_tag is doing this.
*/
enum {
INDEX_ID_LI = 0,
INDEX_ID_IP,
@ -763,6 +791,8 @@ enum {
INDEX_ID_SCE,
INDEX_ID_WS,
INDEX_ID_WM,
/* TODO: This should probably be tweaked, #Mask and #Simulation are rather low-level types that
* should most likely be defined //before// #Object and geometry type indices? */
INDEX_ID_MSK,
INDEX_ID_SIM,
INDEX_ID_NULL,

View File

@ -217,7 +217,7 @@ static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *k
ret->flag = ((is_link ? FILE_LINK : 0) | (is_rel ? FILE_RELPATH : 0) |
(use_assets_only ? FILE_ASSETS_ONLY : 0));
ret->dict = _PyDict_NewPresized(MAX_LIBARRAY);
ret->dict = _PyDict_NewPresized(INDEX_ID_MAX);
return (PyObject *)ret;
}
@ -248,7 +248,7 @@ static PyObject *bpy_lib_enter(BPy_Library *self)
{
PyObject *ret;
BPy_Library *self_from;
PyObject *from_dict = _PyDict_NewPresized(MAX_LIBARRAY);
PyObject *from_dict = _PyDict_NewPresized(INDEX_ID_MAX);
ReportList reports;
BKE_reports_init(&reports, RPT_STORE);

View File

@ -804,7 +804,7 @@ static void lib_relocate_do(Main *bmain,
ReportList *reports,
const bool do_reload)
{
ListBase *lbarray[MAX_LIBARRAY];
ListBase *lbarray[INDEX_ID_MAX];
int lba_idx;
LinkNode *itemlink;