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

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to