Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/main_namemap.cc')
-rw-r--r--source/blender/blenkernel/intern/main_namemap.cc141
1 files changed, 138 insertions, 3 deletions
diff --git a/source/blender/blenkernel/intern/main_namemap.cc b/source/blender/blenkernel/intern/main_namemap.cc
index 00115d2a0be..5a8f90ea10a 100644
--- a/source/blender/blenkernel/intern/main_namemap.cc
+++ b/source/blender/blenkernel/intern/main_namemap.cc
@@ -5,6 +5,7 @@
*/
#include "BKE_idtype.h"
+#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_main_namemap.h"
@@ -22,6 +23,10 @@
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"bke.main_namemap"};
+
//#define DEBUG_PRINT_MEMORY_USAGE
using namespace blender;
@@ -57,7 +62,7 @@ static bool id_name_final_build(char *name, char *base_name, size_t base_name_le
/* Code above may have generated invalid utf-8 string, due to raw truncation.
* Ensure we get a valid one now. */
- base_name_len -= (size_t)BLI_str_utf8_invalid_strip(base_name, base_name_len);
+ base_name_len -= size_t(BLI_str_utf8_invalid_strip(base_name, base_name_len));
/* Also truncate orig name, and start the whole check again. */
name[base_name_len] = '\0';
@@ -92,7 +97,7 @@ struct UniqueName_Key {
* one larger.
*/
struct UniqueName_Value {
- static constexpr unsigned max_exact_tracking = 1024;
+ static constexpr uint max_exact_tracking = 1024;
BLI_BITMAP_DECLARE(mask, max_exact_tracking);
int max_value = 0;
@@ -223,7 +228,7 @@ static void main_namemap_populate(UniqueName_Map *name_map, struct Main *bmain,
/* Get the name map object used for the given Main/ID.
* Lazily creates and populates the contents of the name map, if ensure_created is true.
- * Note: if the contents are populated, the name of the given ID itself is not added. */
+ * NOTE: if the contents are populated, the name of the given ID itself is not added. */
static UniqueName_Map *get_namemap_for(Main *bmain, ID *id, bool ensure_created)
{
if (id->lib != nullptr) {
@@ -363,3 +368,133 @@ 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);
+ }
+};
+
+static bool main_namemap_validate_and_fix(Main *bmain, const bool do_fix)
+{
+ Set<Uniqueness_Key> id_names_libs;
+ bool is_valid = true;
+ ListBase *lb_iter;
+ FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb_iter) {
+ LISTBASE_FOREACH_MUTABLE (ID *, id_iter, lb_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>");
+ if (do_fix) {
+ /* NOTE: this may imply moving this ID in its listbase, however re-checking it later is
+ * not really an issue. */
+ BKE_id_new_name_validate(
+ bmain, which_libbase(bmain, GS(id_iter->name)), id_iter, nullptr, true);
+ BLI_strncpy(key.name, id_iter->name, MAX_ID_NAME);
+ if (!id_names_libs.add(key)) {
+ CLOG_ERROR(&LOG,
+ "\tID has been renamed to '%s', but it still seems to be already in use",
+ id_iter->name);
+ }
+ else {
+ CLOG_WARN(&LOG, "\tID has been renamed to '%s'", id_iter->name);
+ }
+ }
+ }
+
+ 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_LISTBASE_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);
+
+ if (is_valid || !do_fix) {
+ return is_valid;
+ }
+
+ /* Clear all existing namemaps. */
+ lib = nullptr;
+ UniqueName_Map **name_map_p = &bmain->name_map;
+ do {
+ BLI_assert(name_map_p != nullptr);
+ if (*name_map_p != nullptr) {
+ BKE_main_namemap_destroy(name_map_p);
+ }
+ lib = static_cast<Library *>((lib == nullptr) ? bmain->libraries.first : lib->id.next);
+ name_map_p = (lib != nullptr) ? &lib->runtime.name_map : nullptr;
+ } while (lib != nullptr);
+
+ return is_valid;
+}
+
+bool BKE_main_namemap_validate_and_fix(Main *bmain)
+{
+ const bool is_valid = main_namemap_validate_and_fix(bmain, true);
+ BLI_assert(main_namemap_validate_and_fix(bmain, false));
+ return is_valid;
+}
+
+bool BKE_main_namemap_validate(Main *bmain)
+{
+ return main_namemap_validate_and_fix(bmain, false);
+}