[Bf-blender-cvs] [d0e28721b04] master: Cleanup: Main id looping: add FOREACH_MAIN_LISTBASE macro.

Bastien Montagne noreply at git.blender.org
Mon Mar 18 11:36:58 CET 2019


Commit: d0e28721b04a0235d4f6bfbe42f43672ff923444
Author: Bastien Montagne
Date:   Mon Mar 18 11:32:06 2019 +0100
Branches: master
https://developer.blender.org/rBd0e28721b04a0235d4f6bfbe42f43672ff923444

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).

===================================================================

M	source/blender/blenkernel/BKE_main.h
M	source/blender/blenkernel/intern/blendfile.c
M	source/blender/blenkernel/intern/library_query.c
M	source/blender/python/intern/bpy_rna_id_collection.c

===================================================================

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;



More information about the Bf-blender-cvs mailing list