[Bf-blender-cvs] [c08924b] master: Rework library_query foreach looper - add optional recursivity.

Bastien Montagne noreply at git.blender.org
Thu Mar 24 16:10:50 CET 2016


Commit: c08924bf94f2dffaae7b3ef2fad3c49cb8043c89
Author: Bastien Montagne
Date:   Thu Mar 24 12:28:41 2016 +0100
Branches: master
https://developer.blender.org/rBc08924bf94f2dffaae7b3ef2fad3c49cb8043c89

Rework library_query foreach looper - add optional recursivity.

This commit:
* Fixes bad handling of 'stop iteration' (by adding a status flag, so that we can actually
  stop in helper functions too, and jumping to a finalize label instead of raw return, to
  allow propper clean up).
* Adds optional recursion into 'ID tree' - callback can also decide to exclude current id_pp
  from recursion. Note that this implies 'readonly', modifying IDs while recursing is not
  something we want to support!
* Changes callback signature/expected behavior: return behavior is now handled through flags,
  and 'parent' ID of id_pp is also passed (since it may not always be root id anymore).

Reviewers: sergey, campbellbarton

Differential Revision: https://developer.blender.org/D1869

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

M	source/blender/blenkernel/BKE_library_query.h
M	source/blender/blenkernel/intern/library.c
M	source/blender/blenkernel/intern/library_query.c
M	source/blender/editors/object/object_relations.c
M	source/blender/python/intern/bpy_rna_id_collection.c
M	source/blender/windowmanager/intern/wm_operators.c

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

diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index f07644d..86628ea 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -50,15 +50,23 @@ enum {
 	IDWALK_USER_ONE = (1 << 9),
 };
 
-/* Call a callback for each ID link which the given ID uses.
+enum {
+	IDWALK_RET_NOP            = 0,
+	IDWALK_RET_STOP_ITER      = 1 << 0,  /* Completly top iteration. */
+	IDWALK_RET_STOP_RECURSION = 1 << 1,  /* Stop recursion, that is, do not loop over ID used by current one. */
+};
+
+/**
+ * Call a callback for each ID link which the given ID uses.
  *
- * Return 'false' if you want to stop iteration.
+ * \return a set of flags to controll further iteration (0 to keep going).
  */
-typedef bool (*LibraryIDLinkCallback) (void *user_data, struct ID **id_pointer, int cd_flag);
+typedef int (*LibraryIDLinkCallback) (void *user_data, struct ID *id_self, struct ID **id_pointer, int cd_flag);
 
 /* Flags for the foreach function itself. */
 enum {
 	IDWALK_READONLY = (1 << 0),
+	IDWALK_RECURSE  = (1 << 1),  /* Also implies IDWALK_READONLY. */
 };
 
 /* Loop over all of the ID's this datablock links to. */
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 72801d6..895d215 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -1086,7 +1086,7 @@ void *BKE_libblock_copy(ID *id)
 	return BKE_libblock_copy_ex(G.main, id);
 }
 
-static bool id_relink_looper(void *UNUSED(user_data), ID **id_pointer, const int cd_flag)
+static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag)
 {
 	ID *id = *id_pointer;
 	if (id) {
@@ -1100,7 +1100,7 @@ static bool id_relink_looper(void *UNUSED(user_data), ID **id_pointer, const int
 			BKE_libblock_relink(id);
 		}
 	}
-	return true;
+	return IDWALK_RET_NOP;
 }
 
 void BKE_libblock_relink(ID *id)
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index f5e17c0..73b1294 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -61,6 +61,8 @@
 #include "DNA_world_types.h"
 
 #include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist_stack.h"
 
 #include "BKE_animsys.h"
 #include "BKE_constraint.h"
@@ -74,52 +76,80 @@
 #include "BKE_sequencer.h"
 #include "BKE_tracking.h"
 
-#define FOREACH_CALLBACK_INVOKE_ID_PP(self_id, id_pp, flag, callback, user_data, cb_flag) \
-	{ \
-		ID *old_id = *id_pp; \
-		bool keep_working = callback(user_data, id_pp, cb_flag); \
-		if (flag & IDWALK_READONLY) { \
-			BLI_assert(*id_pp == old_id); \
-			(void)old_id; /* quiet warning */ \
+
+#define FOREACH_FINALIZE _finalize
+#define FOREACH_FINALIZE_VOID FOREACH_FINALIZE: (void)0
+
+#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, cb_flag) \
+	if (!((_data)->status & IDWALK_STOP)) { \
+		const int _flag = (_data)->flag; \
+		ID *old_id = *(id_pp); \
+		const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, cb_flag); \
+		if (_flag & IDWALK_READONLY) { \
+			BLI_assert(*(id_pp) == old_id); \
 		} \
-		if (keep_working == false) { \
-			/* REAL DANGER! Beware of this return! */ \
-			/* TODO(sergey): Make it less creepy without too much duplicated code.. */ \
-			return; \
+		if (_flag & IDWALK_RECURSE) { \
+			if (!BLI_gset_haskey((_data)->ids_handled, old_id)) { \
+				BLI_gset_add((_data)->ids_handled, old_id); \
+				if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { \
+					BLI_LINKSTACK_PUSH((_data)->ids_todo, old_id); \
+				} \
+			} \
 		} \
+		if (callback_return & IDWALK_RET_STOP_ITER) { \
+			(_data)->status |= IDWALK_STOP; \
+			goto FOREACH_FINALIZE; \
+		} \
+	} \
+	else { \
+		goto FOREACH_FINALIZE; \
 	} ((void)0)
 
-#define FOREACH_CALLBACK_INVOKE_ID(self_id, id, flag, callback, user_data, cb_flag) \
+#define FOREACH_CALLBACK_INVOKE_ID(_data, id, cb_flag) \
 	{ \
 		CHECK_TYPE_ANY(id, ID *, void *); \
-		FOREACH_CALLBACK_INVOKE_ID_PP(self_id, (ID **)&(id), flag, callback, user_data, cb_flag); \
+		FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id), cb_flag); \
 	} ((void)0)
 
-#define FOREACH_CALLBACK_INVOKE(self_id, id_super, flag, callback, user_data, cb_flag) \
+#define FOREACH_CALLBACK_INVOKE(_data, id_super, cb_flag) \
 	{ \
 		CHECK_TYPE(&((id_super)->id), ID *); \
-		FOREACH_CALLBACK_INVOKE_ID_PP(self_id, (ID **)&id_super, flag, callback, user_data, cb_flag); \
+		FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id_super), cb_flag); \
 	} ((void)0)
 
+/* status */
+enum {
+	IDWALK_STOP     = 1 << 0,
+};
+
 typedef struct LibraryForeachIDData {
 	ID *self_id;
 	int flag;
 	LibraryIDLinkCallback callback;
 	void *user_data;
+	int status;
+
+	/* To handle recursion. */
+	GSet *ids_handled;  /* All IDs that are either already done, or still in ids_todo stack. */
+	BLI_LINKSTACK_DECLARE(ids_todo, ID *);
 } LibraryForeachIDData;
 
 static void library_foreach_rigidbodyworldSceneLooper(
         struct RigidBodyWorld *UNUSED(rbw), ID **id_pointer, void *user_data, int cd_flag)
 {
 	LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
-	FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag);
+	FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+	FOREACH_FINALIZE_VOID;
 }
 
 static void library_foreach_modifiersForeachIDLink(
         void *user_data, Object *UNUSED(object), ID **id_pointer, int cd_flag)
 {
 	LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
-	FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag);
+	FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+	FOREACH_FINALIZE_VOID;
 }
 
 static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID **id_pointer,
@@ -127,35 +157,45 @@ static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID
 {
 	LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
 	const int cd_flag = is_reference ? IDWALK_USER : IDWALK_NOP;
-	FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag);
+	FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+	FOREACH_FINALIZE_VOID;
 }
 
 static void library_foreach_particlesystemsObjectLooper(
         ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cd_flag)
 {
 	LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
-	FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag);
+	FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+	FOREACH_FINALIZE_VOID;
 }
 
 static void library_foreach_sensorsObjectLooper(
         bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cd_flag)
 {
 	LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
-	FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag);
+	FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+	FOREACH_FINALIZE_VOID;
 }
 
 static void library_foreach_controllersObjectLooper(
         bController *UNUSED(controller), ID **id_pointer, void *user_data, int cd_flag)
 {
 	LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
-	FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag);
+	FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+	FOREACH_FINALIZE_VOID;
 }
 
 static void library_foreach_actuatorsObjectLooper(
         bActuator *UNUSED(actuator), ID **id_pointer, void *user_data, int cd_flag)
 {
 	LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
-	FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag);
+	FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+	FOREACH_FINALIZE_VOID;
 }
 
 static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt)
@@ -170,17 +210,21 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *
 			/* only used targets */
 			DRIVER_TARGETS_USED_LOOPER(dvar)
 			{
-				FOREACH_CALLBACK_INVOKE_ID(data->self_id, dtar->id, data->flag, data->callback, data->user_data, IDWALK_NOP);
+				FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_NOP);
 			}
 			DRIVER_TARGETS_LOOPER_END
 		}
 	}
+
+	FOREACH_FINALIZE_VOID;
 }
 
 static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
 {
-	FOREACH_CALLBACK_INVOKE(data->self_id, mtex->object, data->flag, data->callback, data->user_data, IDWALK_NOP);
-	FOREACH_CALLBACK_INVOKE(data->self_id, mtex->tex, data->flag, data->callback, data->user_data, IDWALK_USER);
+	FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_NOP);
+	FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_USER);
+
+	FOREACH_FINALIZE_VOID;
 }
 
 
@@ -191,460 +235,478 @@ static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
  */
 void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
 {
-	AnimData *adt;
 	LibraryForeachIDData data;
 	int i;
 
-	data.self_id = id;
+	if (flag & IDWALK_RECURSE) {
+		/* For now, recusion implies read-only. */
+		flag |= IDWALK_READONLY;
+
+		data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+		BLI_LINKSTACK_INIT(data.ids_todo);
+	}
+	else {
+		data.ids_handled = NULL;
+	}
 	data.flag = flag;
 	data.callback = callback;
 	data.user_data = user_data;
 
-	adt = BKE_animdata_from_id(id);
-	if (adt) {
-		library_foreach_animationData(&data, adt);
-	}
-
 #define CALLBACK_INVOKE_ID(check_id, cb_flag) \
-	FOREACH_CALLBACK_INVOKE_ID(id, check_id, flag, callback, user_data, cb_flag)
+	FOREACH_CALLBACK_INVOKE_ID(&data, check_id, cb_flag)
 
 #define CALLBACK_INVOKE(check_id_super, cb_flag) \
-	FOREACH_CALLBACK_INVOKE(id, check_id_super, flag, callback, user_data, cb_flag)
-
-	switch (GS(id->name)) {
-		case ID_SCE:
-		{
-			Scene *scene = (Scene *) id;
-			ToolSettings *toolset

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list