diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2019-03-18 13:32:06 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2019-03-18 13:36:50 +0300 |
commit | d0e28721b04a0235d4f6bfbe42f43672ff923444 (patch) | |
tree | af52e9e2f14a7e29eb40731b88584d00e309f821 /source | |
parent | 66932a2c814037f897af56693efb68b6993406fb (diff) |
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).
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_main.h | 28 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/blendfile.c | 15 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/library_query.c | 9 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna_id_collection.c | 87 |
4 files changed, 72 insertions, 67 deletions
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index 03f9f9a21ea..6b9c35d90d3 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -152,31 +152,29 @@ 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--) { \ - FOREACH_MAIN_LISTBASE_ID_BEGIN(_lbarray[_i], _id) + _lb = _lbarray[_i]; -#define FOREACH_MAIN_ID_END \ - FOREACH_MAIN_LISTBASE_ID_END; \ +#define 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) \ +/* 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 *_lbarray[MAX_LIBARRAY]; \ - int i = set_listbasepointers(_bmain, _lbarray); \ - while (i-- && !_do_break) { \ - FOREACH_MAIN_LISTBASE_ID_BEGIN(_lbarray[i], _id) \ + ListBase *_lb; \ + FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb) { \ + FOREACH_MAIN_LISTBASE_ID_BEGIN(_lbarray[_i], _id) -#define FOREACH_MAIN_ID_BREAKABLE_END FOREACH_MAIN_ID_END +#define FOREACH_MAIN_ID_END \ + FOREACH_MAIN_LISTBASE_ID_END; \ + } FOREACH_MAIN_LISTBASE_END; \ + } ((void)0) struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct ImBuf *img); diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 455f73c65c0..cd17911d65d 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -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 */ diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index 72e9d747206..9861b232dd9 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -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; } } diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c index 31b135fe933..7a5849f818d 100644 --- a/source/blender/python/intern/bpy_rna_id_collection.c +++ b/source/blender/python/intern/bpy_rna_id_collection.c @@ -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. */ + FOREACH_MAIN_LISTBASE_ID_BEGIN(lb, id) + { + /* 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; + } } - } - /* 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); - } + /* 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)) - { - 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 (!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; - } + 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); + 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 (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; |