Cleanup: Main id looping: add FOREACH_MAIN_LISTBASE macro.
We don't want to use flow control like `break` statement into the basic `FOREACH_MAIN_ID` macro, as this is a nested loop. When refined behavior is needed (like breaking whole iteration, or just skipping to next ID type), FOREACH_MAIN_LISTBASE and FOREACH_MAIN_LISTBASE_ID macros should be used instead. Based on D4382 by @campbellbarton (Other potential solution, using flow control macros: D4384).
This commit is contained in:
@@ -152,32 +152,30 @@ struct GSet *BKE_main_gset_create(struct Main *bmain, struct GSet *gset);
|
||||
} \
|
||||
} ((void)0)
|
||||
|
||||
|
||||
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id) \
|
||||
#define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb) \
|
||||
{ \
|
||||
ListBase *_lbarray[MAX_LIBARRAY]; \
|
||||
int _i = set_listbasepointers(_bmain, _lbarray); \
|
||||
while (_i--) { \
|
||||
_lb = _lbarray[_i];
|
||||
|
||||
#define FOREACH_MAIN_LISTBASE_END \
|
||||
} \
|
||||
} ((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. */
|
||||
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id) \
|
||||
{ \
|
||||
ListBase *_lb; \
|
||||
FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb) { \
|
||||
FOREACH_MAIN_LISTBASE_ID_BEGIN(_lbarray[_i], _id)
|
||||
|
||||
#define FOREACH_MAIN_ID_END \
|
||||
FOREACH_MAIN_LISTBASE_ID_END; \
|
||||
} \
|
||||
} FOREACH_MAIN_LISTBASE_END; \
|
||||
} ((void)0)
|
||||
|
||||
/** \param _do_break A boolean, to allow breaking iteration (only used to break by type,
|
||||
* you must also use an explicit `break;` operation if you want to
|
||||
* immediately break from inner by-ID loop).
|
||||
*/
|
||||
#define FOREACH_MAIN_ID_BREAKABLE_BEGIN(_bmain, _id, _do_break) \
|
||||
{ \
|
||||
ListBase *_lbarray[MAX_LIBARRAY]; \
|
||||
int i = set_listbasepointers(_bmain, _lbarray); \
|
||||
while (i-- && !_do_break) { \
|
||||
FOREACH_MAIN_LISTBASE_ID_BEGIN(_lbarray[i], _id) \
|
||||
|
||||
#define FOREACH_MAIN_ID_BREAKABLE_END FOREACH_MAIN_ID_END
|
||||
|
||||
|
||||
struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct ImBuf *img);
|
||||
struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data);
|
||||
|
||||
@@ -460,16 +460,21 @@ bool BKE_blendfile_read_from_memfile(
|
||||
void BKE_blendfile_read_make_empty(bContext *C)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
ListBase *lb;
|
||||
ID *id;
|
||||
|
||||
FOREACH_MAIN_ID_BEGIN(bmain, id)
|
||||
FOREACH_MAIN_LISTBASE_BEGIN(bmain, lb)
|
||||
{
|
||||
if (ELEM(GS(id->name), ID_SCE, ID_SCR, ID_WM, ID_WS)) {
|
||||
break; /* Only breaks iter on that ID type, and continues with IDs of next type. */
|
||||
FOREACH_MAIN_LISTBASE_ID_BEGIN(lb, id)
|
||||
{
|
||||
if (ELEM(GS(id->name), ID_SCE, ID_SCR, ID_WM, ID_WS)) {
|
||||
break;
|
||||
}
|
||||
BKE_id_delete(bmain, id);
|
||||
}
|
||||
BKE_id_delete(bmain, id);
|
||||
FOREACH_MAIN_LISTBASE_ID_END;
|
||||
}
|
||||
FOREACH_MAIN_ID_END;
|
||||
FOREACH_MAIN_LISTBASE_END;
|
||||
}
|
||||
|
||||
/* only read the userdef from a .blend */
|
||||
|
||||
@@ -1384,19 +1384,16 @@ void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
|
||||
}
|
||||
|
||||
for (bool do_loop = true; do_loop; ) {
|
||||
bool do_break = false;
|
||||
do_loop = false;
|
||||
FOREACH_MAIN_ID_BREAKABLE_BEGIN(bmain, id, do_break)
|
||||
FOREACH_MAIN_ID_BEGIN(bmain, id)
|
||||
{
|
||||
/* We only want to check that ID if it is currently known as used... */
|
||||
if ((id->tag & LIB_TAG_DOIT) == 0) {
|
||||
BKE_library_foreach_ID_link(
|
||||
bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY);
|
||||
}
|
||||
/* Else it is an unused ID (so far), no need to check it further. */
|
||||
do_break = true;
|
||||
break;
|
||||
}
|
||||
FOREACH_MAIN_ID_BREAKABLE_END;
|
||||
FOREACH_MAIN_ID_END;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -159,6 +159,7 @@ static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject *
|
||||
#else
|
||||
Main *bmain = G_MAIN; /* XXX Ugly, but should work! */
|
||||
#endif
|
||||
ListBase *lb;
|
||||
ID *id;
|
||||
|
||||
PyObject *subset = NULL;
|
||||
@@ -223,57 +224,61 @@ static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject *
|
||||
|
||||
data_cb.types_bitmap = key_types_bitmap;
|
||||
|
||||
FOREACH_MAIN_ID_BEGIN(bmain, id)
|
||||
FOREACH_MAIN_LISTBASE_BEGIN(bmain, lb)
|
||||
{
|
||||
/* We cannot skip here in case we have some filter on key types... */
|
||||
if (key_types_bitmap == NULL && val_types_bitmap != NULL) {
|
||||
if (!id_check_type(id, val_types_bitmap)) {
|
||||
break; /* Break iter on that type of IDs, continues with next ID type. */
|
||||
}
|
||||
}
|
||||
|
||||
/* One-time init, ID is just used as placeholder here, we abuse this in iterator callback
|
||||
* to avoid having to rebuild a complete bpyrna object each time for the key searching
|
||||
* (where only ID pointer value is used). */
|
||||
if (data_cb.py_id_key_lookup_only == NULL) {
|
||||
data_cb.py_id_key_lookup_only = pyrna_id_CreatePyObject(id);
|
||||
}
|
||||
|
||||
if (!data_cb.is_subset &&
|
||||
/* We do not want to pre-add keys of flitered out types. */
|
||||
(key_types_bitmap == NULL || id_check_type(id, key_types_bitmap)) &&
|
||||
/* We do not want to pre-add keys when we have filter on value types, but not on key types. */
|
||||
(val_types_bitmap == NULL || key_types_bitmap != NULL))
|
||||
FOREACH_MAIN_LISTBASE_ID_BEGIN(lb, id)
|
||||
{
|
||||
PyObject *key = data_cb.py_id_key_lookup_only;
|
||||
PyObject *set;
|
||||
/* We cannot skip here in case we have some filter on key types... */
|
||||
if (key_types_bitmap == NULL && val_types_bitmap != NULL) {
|
||||
if (!id_check_type(id, val_types_bitmap)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RNA_id_pointer_create(id, &((BPy_StructRNA *)key)->ptr);
|
||||
/* One-time init, ID is just used as placeholder here, we abuse this in iterator callback
|
||||
* to avoid having to rebuild a complete bpyrna object each time for the key searching
|
||||
* (where only ID pointer value is used). */
|
||||
if (data_cb.py_id_key_lookup_only == NULL) {
|
||||
data_cb.py_id_key_lookup_only = pyrna_id_CreatePyObject(id);
|
||||
}
|
||||
|
||||
/* We have to insert the key now, otherwise ID unused would be missing from final dict... */
|
||||
if ((set = PyDict_GetItem(data_cb.user_map, key)) == NULL) {
|
||||
/* Cannot use our placeholder key here! */
|
||||
key = pyrna_id_CreatePyObject(id);
|
||||
set = PySet_New(NULL);
|
||||
PyDict_SetItem(data_cb.user_map, key, set);
|
||||
Py_DECREF(set);
|
||||
Py_DECREF(key);
|
||||
if (!data_cb.is_subset &&
|
||||
/* We do not want to pre-add keys of flitered out types. */
|
||||
(key_types_bitmap == NULL || id_check_type(id, key_types_bitmap)) &&
|
||||
/* We do not want to pre-add keys when we have filter on value types, but not on key types. */
|
||||
(val_types_bitmap == NULL || key_types_bitmap != NULL))
|
||||
{
|
||||
PyObject *key = data_cb.py_id_key_lookup_only;
|
||||
PyObject *set;
|
||||
|
||||
RNA_id_pointer_create(id, &((BPy_StructRNA *)key)->ptr);
|
||||
|
||||
/* We have to insert the key now, otherwise ID unused would be missing from final dict... */
|
||||
if ((set = PyDict_GetItem(data_cb.user_map, key)) == NULL) {
|
||||
/* Cannot use our placeholder key here! */
|
||||
key = pyrna_id_CreatePyObject(id);
|
||||
set = PySet_New(NULL);
|
||||
PyDict_SetItem(data_cb.user_map, key, set);
|
||||
Py_DECREF(set);
|
||||
Py_DECREF(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (val_types_bitmap != NULL && !id_check_type(id, val_types_bitmap)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
data_cb.id_curr = id;
|
||||
BKE_library_foreach_ID_link(NULL, id, foreach_libblock_id_user_map_callback, &data_cb, IDWALK_CB_NOP);
|
||||
|
||||
if (data_cb.py_id_curr) {
|
||||
Py_DECREF(data_cb.py_id_curr);
|
||||
data_cb.py_id_curr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (val_types_bitmap != NULL && !id_check_type(id, val_types_bitmap)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
data_cb.id_curr = id;
|
||||
BKE_library_foreach_ID_link(NULL, id, foreach_libblock_id_user_map_callback, &data_cb, IDWALK_CB_NOP);
|
||||
|
||||
if (data_cb.py_id_curr) {
|
||||
Py_DECREF(data_cb.py_id_curr);
|
||||
data_cb.py_id_curr = NULL;
|
||||
}
|
||||
FOREACH_MAIN_LISTBASE_ID_END;
|
||||
}
|
||||
FOREACH_MAIN_ID_END;
|
||||
FOREACH_MAIN_LISTBASE_ID_END;
|
||||
|
||||
ret = data_cb.user_map;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user