diff options
author | Bastien Montagne <bastien@blender.org> | 2022-07-27 12:19:48 +0300 |
---|---|---|
committer | Bastien Montagne <bastien@blender.org> | 2022-07-27 12:22:48 +0300 |
commit | 18dc611b401690c477a97b7d74f4c666c9b41e42 (patch) | |
tree | fbbc625f5588f4b682c1eba1a9233b2f96494e55 /source/blender | |
parent | 1e55b58e4ff31b10cf9806ca41991346ab3d4513 (diff) |
ID namemap: Add check for consistency.
Add a util function to check that content of a given Main and the
namemaps in it are consistent.
Add some asserts calling this check after file read, and after some
override operations.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_main_namemap.h | 8 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/lib_override.cc | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/main_namemap.cc | 89 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_files.c | 3 |
4 files changed, 104 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_main_namemap.h b/source/blender/blenkernel/BKE_main_namemap.h index d201e45a2c9..c5fce803a03 100644 --- a/source/blender/blenkernel/BKE_main_namemap.h +++ b/source/blender/blenkernel/BKE_main_namemap.h @@ -46,6 +46,14 @@ bool BKE_main_namemap_get_name(struct Main *bmain, struct ID *id, char *name) AT void BKE_main_namemap_remove_name(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL(); +/** + * Check that all ID names in given `bmain` are unique (per ID type and library), and that existing + * name maps are consistent with existing relevant IDs. + * + * This is typically called within an assert, or in tests. + */ +bool BKE_main_namemap_validate(struct Main *bmain) ATTR_NONNULL(); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/intern/lib_override.cc b/source/blender/blenkernel/intern/lib_override.cc index 3130ecca77f..8ca42905042 100644 --- a/source/blender/blenkernel/intern/lib_override.cc +++ b/source/blender/blenkernel/intern/lib_override.cc @@ -2670,6 +2670,8 @@ void BKE_lib_override_library_main_resync(Main *bmain, library->filepath); } } + + BLI_assert(BKE_main_namemap_validate(bmain)); } void BKE_lib_override_library_delete(Main *bmain, ID *id_root) @@ -3746,6 +3748,8 @@ void BKE_lib_override_library_main_update(Main *bmain) } FOREACH_MAIN_ID_END; + BLI_assert(BKE_main_namemap_validate(bmain)); + G_MAIN = orig_gmain; } diff --git a/source/blender/blenkernel/intern/main_namemap.cc b/source/blender/blenkernel/intern/main_namemap.cc index 00115d2a0be..3a7b325b3d2 100644 --- a/source/blender/blenkernel/intern/main_namemap.cc +++ b/source/blender/blenkernel/intern/main_namemap.cc @@ -22,6 +22,10 @@ #include "MEM_guardedalloc.h" +#include "CLG_log.h" + +static CLG_LogRef LOG = {"bke.main_namemap"}; + //#define DEBUG_PRINT_MEMORY_USAGE using namespace blender; @@ -363,3 +367,88 @@ void BKE_main_namemap_remove_name(struct Main *bmain, struct ID *id, const char } val->mark_unused(number); } + +struct Uniqueness_Key { + char name[MAX_ID_NAME]; + Library *lib; + uint64_t hash() const + { + return BLI_ghashutil_combine_hash(BLI_ghashutil_strhash_n(name, MAX_ID_NAME), + BLI_ghashutil_ptrhash(lib)); + } + bool operator==(const Uniqueness_Key &o) const + { + return lib == o.lib && !BLI_ghashutil_strcmp(name, o.name); + } +}; + +bool BKE_main_namemap_validate(Main *bmain) +{ + Set<Uniqueness_Key> id_names_libs; + bool is_valid = true; + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { + Uniqueness_Key key; + BLI_strncpy(key.name, id_iter->name, MAX_ID_NAME); + key.lib = id_iter->lib; + if (!id_names_libs.add(key)) { + is_valid = false; + CLOG_ERROR(&LOG, + "ID name '%s' (from library '%s') is found more than once", + id_iter->name, + id_iter->lib != nullptr ? id_iter->lib->filepath : "<None>"); + } + + UniqueName_Map *name_map = get_namemap_for(bmain, id_iter, false); + if (name_map == nullptr) { + continue; + } + UniqueName_TypeMap *type_map = name_map->find_by_type(GS(id_iter->name)); + BLI_assert(type_map != nullptr); + + UniqueName_Key key_namemap; + /* Remove full name from the set. */ + BLI_strncpy(key_namemap.name, id_iter->name + 2, MAX_NAME); + if (!type_map->full_names.contains(key_namemap)) { + is_valid = false; + CLOG_ERROR(&LOG, + "ID name '%s' (from library '%s') exists in current Main, but is not listed in " + "the namemap", + id_iter->name, + id_iter->lib != nullptr ? id_iter->lib->filepath : "<None>"); + } + } + FOREACH_MAIN_ID_END; + + Library *lib = nullptr; + UniqueName_Map *name_map = bmain->name_map; + do { + if (name_map != nullptr) { + int i = 0; + for (short idcode = BKE_idtype_idcode_iter_step(&i); idcode != 0; + idcode = BKE_idtype_idcode_iter_step(&i)) { + UniqueName_TypeMap *type_map = name_map->find_by_type(idcode); + if (type_map != nullptr) { + for (const UniqueName_Key &id_name : type_map->full_names) { + Uniqueness_Key key; + *(reinterpret_cast<short *>(key.name)) = idcode; + BLI_strncpy(key.name + 2, id_name.name, MAX_NAME); + key.lib = lib; + if (!id_names_libs.contains(key)) { + is_valid = false; + CLOG_ERROR(&LOG, + "ID name '%s' (from library '%s') is listed in the namemap, but does not " + "exists in current Main", + key.name, + lib != nullptr ? lib->filepath : "<None>"); + } + } + } + } + } + lib = static_cast<Library *>((lib == nullptr) ? bmain->libraries.first : lib->id.next); + name_map = (lib != nullptr) ? lib->runtime.name_map : nullptr; + } while (lib != nullptr); + + return is_valid; +} diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index a4d5bed21da..45e8f8786df 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -71,6 +71,7 @@ #include "BKE_lib_override.h" #include "BKE_lib_remap.h" #include "BKE_main.h" +#include "BKE_main_namemap.h" #include "BKE_packedFile.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -1004,6 +1005,8 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) WM_cursor_wait(false); + BLI_assert(BKE_main_namemap_validate(CTX_data_main(C))); + return success; } |