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
