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.
This commit is contained in:
parent
1e55b58e4f
commit
18dc611b40
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue