Blender V4.3
main_namemap.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BKE_idtype.hh"
10#include "BKE_lib_id.hh"
11#include "BKE_main.hh"
12#include "BKE_main_namemap.hh"
13
14#include "BLI_assert.h"
15#include "BLI_bitmap.h"
16#include "BLI_ghash.h"
17#include "BLI_listbase.h"
18#include "BLI_map.hh"
19#include "BLI_math_base.hh"
20#include "BLI_set.hh"
21#include "BLI_string.h"
22#include "BLI_string_utf8.h"
23#include "BLI_string_utils.hh"
24
25#include "DNA_ID.h"
26
27#include "MEM_guardedalloc.h"
28
29#include "CLG_log.h"
30
31static CLG_LogRef LOG = {"bke.main_namemap"};
32
33// #define DEBUG_PRINT_MEMORY_USAGE
34
35using namespace blender;
36
37/* Assumes and ensure that the suffix number can never go beyond 1 billion. */
38#define MAX_NUMBER 1000000000
39/* We do not want to get "name.000", so minimal number is 1. */
40#define MIN_NUMBER 1
41
50static bool id_name_final_build(char *name, char *base_name, size_t base_name_len, int number)
51{
52 char number_str[11]; /* Dot + nine digits + null terminator. */
53 size_t number_str_len = SNPRINTF_RLEN(number_str, ".%.3d", number);
54
55 /* If the number would lead to an overflow of the maximum ID name length, we need to truncate
56 * the base name part and do all the number checks again. */
57 if (base_name_len + number_str_len >= MAX_NAME || number >= MAX_NUMBER) {
58 if (base_name_len + number_str_len >= MAX_NAME) {
59 base_name_len = MAX_NAME - number_str_len - 1;
60 }
61 else {
62 base_name_len--;
63 }
64 base_name[base_name_len] = '\0';
65
66 /* Code above may have generated invalid utf-8 string, due to raw truncation.
67 * Ensure we get a valid one now. */
68 base_name_len -= size_t(BLI_str_utf8_invalid_strip(base_name, base_name_len));
69
70 /* Also truncate orig name, and start the whole check again. */
71 name[base_name_len] = '\0';
72 return false;
73 }
74
75 /* We have our final number, we can put it in name and exit the function. */
76 BLI_strncpy(name + base_name_len, number_str, number_str_len + 1);
77 return true;
78}
79
80/* Key used in set/map lookups: just a string name. */
82 char name[MAX_NAME];
83 uint64_t hash() const
84 {
86 }
87 bool operator==(const UniqueName_Key &o) const
88 {
89 return !BLI_ghashutil_strcmp(name, o.name);
90 }
91};
92
93/* Tracking of used numeric suffixes. For each base name:
94 *
95 * - Exactly track which of the lowest 1024 suffixes are in use,
96 * whenever there is a name collision we pick the lowest "unused"
97 * one. This is done with a bit map.
98 * - Above 1024, do not track them exactly, just track the maximum
99 * suffix value seen so far. Upon collision, assign number that is
100 * one larger.
101 */
103 static constexpr uint max_exact_tracking = 1024;
105 int max_value = 0;
106
107 void mark_used(int number)
108 {
109 if (number >= 0 && number < max_exact_tracking) {
110 BLI_BITMAP_ENABLE(mask, number);
111 }
112 if (number < MAX_NUMBER) {
114 }
115 }
116
117 void mark_unused(int number)
118 {
119 if (number >= 0 && number < max_exact_tracking) {
120 BLI_BITMAP_DISABLE(mask, number);
121 }
122 if (number > 0 && number == max_value) {
123 --max_value;
124 }
125 }
126
127 bool use_if_unused(int number)
128 {
129 if (number >= 0 && number < max_exact_tracking) {
130 if (!BLI_BITMAP_TEST_BOOL(mask, number)) {
131 BLI_BITMAP_ENABLE(mask, number);
133 return true;
134 }
135 }
136 return false;
137 }
138
140 {
141 /* Find the smallest available one <1k.
142 * However we never want to pick zero ("none") suffix, even if it is
143 * available, e.g. if Foo.001 was used and we want to create another
144 * Foo.001, we should return Foo.002 and not Foo.
145 * So while searching, mark #0 as "used" to make sure we don't find it,
146 * and restore the value afterwards. */
147
148 BLI_bitmap prev_first = mask[0];
149 mask[0] |= 1;
151 if (result >= 0) {
152 BLI_BITMAP_ENABLE(mask, result);
154 }
155 mask[0] |= prev_first & 1; /* Restore previous value of #0 bit. */
156 return result;
157 }
158};
159
160/* Tracking of names for a single ID type. */
162 /* Set of full names that are in use. */
164 /* For each base name (i.e. without numeric suffix), track the
165 * numeric suffixes that are in use. */
167};
168
171
173 {
174 int index = BKE_idtype_idcode_to_index(id_type);
175 return index >= 0 ? &type_maps[index] : nullptr;
176 }
177};
178
180{
181 UniqueName_Map *map = MEM_new<UniqueName_Map>(__func__);
182 return map;
183}
184
186{
187#ifdef DEBUG_PRINT_MEMORY_USAGE
188 int64_t size_sets = 0;
189 int64_t size_maps = 0;
190 for (const UniqueName_TypeMap &type_map : (*r_name_map)->type_maps) {
191 size_sets += type_map.full_names.size_in_bytes();
192 size_maps += type_map.base_name_to_num_suffix.size_in_bytes();
193 }
194 printf(
195 "NameMap memory usage: sets %.1fKB, maps %.1fKB\n", size_sets / 1024.0, size_maps / 1024.0);
196#endif
197 MEM_delete<UniqueName_Map>(*r_name_map);
198 *r_name_map = nullptr;
199}
200
202{
203 for (Main *bmain_iter = bmain; bmain_iter != nullptr; bmain_iter = bmain_iter->next) {
204 if (bmain_iter->name_map != nullptr) {
205 BKE_main_namemap_destroy(&bmain_iter->name_map);
206 }
207 if (bmain_iter->name_map_global != nullptr) {
208 BKE_main_namemap_destroy(&bmain_iter->name_map_global);
209 }
210 for (Library *lib_iter = static_cast<Library *>(bmain_iter->libraries.first);
211 lib_iter != nullptr;
212 lib_iter = static_cast<Library *>(lib_iter->id.next))
213 {
214 if (lib_iter->runtime.name_map != nullptr) {
215 BKE_main_namemap_destroy(&lib_iter->runtime.name_map);
216 }
217 }
218 }
219}
220
221/* `do_global` will generate a namemap for all IDs in current Main, regardless of their library.
222 * Note that duplicates (e.g.local ID and linked ID with same name) will only generate a single
223 * entry in the map then. */
225 UniqueName_Map *name_map, Main *bmain, Library *library, ID *ignore_id, const bool do_global)
226{
227 BLI_assert_msg(name_map != nullptr, "name_map should not be null");
228 for (UniqueName_TypeMap &type_map : name_map->type_maps) {
229 type_map.base_name_to_num_suffix.clear();
230 }
231 ID *id;
232 FOREACH_MAIN_ID_BEGIN (bmain, id) {
233 if ((id == ignore_id) || (!do_global && (id->lib != library))) {
234 continue;
235 }
236 UniqueName_TypeMap *type_map = name_map->find_by_type(GS(id->name));
237 BLI_assert(type_map != nullptr);
238
239 /* Insert the full name into the set. */
240 UniqueName_Key key;
241 STRNCPY(key.name, id->name + 2);
242 if (!type_map->full_names.add(key)) {
243 /* Do not assert, this code is also used by #BKE_main_namemap_validate_and_fix, where
244 * duplicates are expected. */
245#if 0
246 BLI_assert_msg(do_global,
247 "The key (name) already exists in the namemap, should only happen when "
248 "`do_global` is true.");
249#endif
250 continue;
251 }
252
253 /* Get the name and number parts ("name.number"). */
254 int number = MIN_NUMBER;
255 BLI_string_split_name_number(id->name + 2, '.', key.name, &number);
256
257 /* Get and update the entry for this base name. */
259 val.mark_used(number);
260 }
262}
263
264/* Get the name map object used for the given Main/ID.
265 * Lazily creates and populates the contents of the name map, if ensure_created is true.
266 * NOTE: if the contents are populated, the name of the given ID itself is not added. */
268 ID *id,
269 const bool ensure_created,
270 const bool do_global)
271{
272 if (do_global) {
273 if (ensure_created && bmain->name_map_global == nullptr) {
275 main_namemap_populate(bmain->name_map_global, bmain, id->lib, id, true);
276 }
277 return bmain->name_map_global;
278 }
279
280 if (id->lib != nullptr) {
281 if (ensure_created && id->lib->runtime.name_map == nullptr) {
282 id->lib->runtime.name_map = BKE_main_namemap_create();
283 main_namemap_populate(id->lib->runtime.name_map, bmain, id->lib, id, false);
284 }
285 return id->lib->runtime.name_map;
286 }
287 if (ensure_created && bmain->name_map == nullptr) {
289 main_namemap_populate(bmain->name_map, bmain, id->lib, id, false);
290 }
291 return bmain->name_map;
292}
293
294/* Tries to add given name to the given name_map, returns `true` if added, `false` if it was
295 * already in the namemap. */
296static bool namemap_add_name(UniqueName_Map *name_map, ID *id, const char *name, const int number)
297{
298 BLI_assert(strlen(name) < MAX_NAME);
299 UniqueName_TypeMap *type_map = name_map->find_by_type(GS(id->name));
300 BLI_assert(type_map != nullptr);
301
302 UniqueName_Key key;
303 /* Remove full name from the set. */
304 STRNCPY(key.name, name);
305 if (!type_map->full_names.add(key)) {
306 /* Name already in this namemap, nothing else to do. */
307 return false;
308 }
309
311 val.mark_used(number);
312 return true;
313}
314
315bool BKE_main_namemap_get_name(Main *bmain, ID *id, char *name, const bool do_unique_in_bmain)
316{
317#ifndef __GNUC__ /* GCC warns with `nonull-compare`. */
318 BLI_assert(bmain != nullptr);
319 BLI_assert(id != nullptr);
320#endif
321 UniqueName_Map *name_map = get_namemap_for(bmain, id, true, do_unique_in_bmain);
322 UniqueName_Map *name_map_other = get_namemap_for(bmain, id, false, !do_unique_in_bmain);
323 BLI_assert(name_map != nullptr);
324 BLI_assert(strlen(name) < MAX_NAME);
325 UniqueName_TypeMap *type_map = name_map->find_by_type(GS(id->name));
326 BLI_assert(type_map != nullptr);
327
328 bool is_name_changed = false;
329
330 UniqueName_Key key;
331 while (true) {
332 /* Check if the full original name has a duplicate. */
333 STRNCPY(key.name, name);
334 const bool has_dup = type_map->full_names.contains(key);
335
336 /* Get the name and number parts ("name.number"). */
337 int number = MIN_NUMBER;
338 size_t base_name_len = BLI_string_split_name_number(name, '.', key.name, &number);
339
340 bool added_new = false;
341 UniqueName_Value &val = type_map->base_name_to_num_suffix.lookup_or_add_cb(key, [&]() {
342 added_new = true;
343 return UniqueName_Value();
344 });
345 if (added_new || !has_dup) {
346 /* This base name is not used at all yet, or the full original
347 * name has no duplicates. The latter could happen if splitting
348 * by number would produce the same values, for different name
349 * strings (e.g. Foo.001 and Foo.1). */
350 val.mark_used(number);
351
352 if (!has_dup) {
353 STRNCPY(key.name, name);
354 type_map->full_names.add(key);
355 }
356 if (name_map_other != nullptr) {
357 namemap_add_name(name_map_other, id, name, number);
358 }
359 return is_name_changed;
360 }
361
362 /* At this point, if this is the first iteration, the initially given name is colliding with an
363 * existing ID name, and has to be modified. If this is a later iteration, the given name has
364 * already been modified one way or another. */
365 is_name_changed = true;
366
367 /* The base name is already used. But our number suffix might not be used yet. */
368 int number_to_use = -1;
369 if (val.use_if_unused(number)) {
370 /* Our particular number suffix is not used yet: use it. */
371 number_to_use = number;
372 }
373 else {
374 /* Find lowest free under 1k and use it. */
375 number_to_use = val.use_smallest_unused();
376
377 /* Did not find one under 1k. */
378 if (number_to_use == -1) {
379 if (number >= MIN_NUMBER && number > val.max_value) {
380 val.max_value = number;
381 number_to_use = number;
382 }
383 else {
384 val.max_value++;
385 number_to_use = val.max_value;
386 }
387 }
388 }
389
390 /* Try to build final name from the current base name and the number.
391 * Note that this can fail due to too long base name, or a too large number,
392 * in which case it will shorten the base name, and we'll start again. */
393 BLI_assert(number_to_use >= MIN_NUMBER);
394 if (id_name_final_build(name, key.name, base_name_len, number_to_use)) {
395 /* All good, add final name to the set. */
396 STRNCPY(key.name, name);
397 type_map->full_names.add(key);
398 if (name_map_other != nullptr) {
399 namemap_add_name(name_map_other, id, name, number);
400 }
401 break;
402 }
403 }
404
405 return is_name_changed;
406}
407
408static void namemap_remove_name(UniqueName_Map *name_map, ID *id, const char *name)
409{
410 BLI_assert(strlen(name) < MAX_NAME);
411 UniqueName_TypeMap *type_map = name_map->find_by_type(GS(id->name));
412 BLI_assert(type_map != nullptr);
413
414 UniqueName_Key key;
415 /* Remove full name from the set. */
416 STRNCPY(key.name, name);
417 type_map->full_names.remove(key);
418
419 int number = MIN_NUMBER;
420 BLI_string_split_name_number(name, '.', key.name, &number);
422 if (val == nullptr) {
423 return;
424 }
425 if (number == 0 && val->max_value == 0) {
426 /* This was the only base name usage, remove whole key. */
427 type_map->base_name_to_num_suffix.remove(key);
428 return;
429 }
430 val->mark_unused(number);
431}
432
433void BKE_main_namemap_remove_name(Main *bmain, ID *id, const char *name)
434{
435#ifndef __GNUC__ /* GCC warns with `nonull-compare`. */
436 BLI_assert(bmain != nullptr);
437 BLI_assert(id != nullptr);
438 BLI_assert(name != nullptr);
439#endif
440 /* Name is empty or not initialized yet, nothing to remove. */
441 if (name[0] == '\0') {
442 return;
443 }
444
445 UniqueName_Map *name_map_local = get_namemap_for(bmain, id, false, false);
446 if (name_map_local != nullptr) {
447 namemap_remove_name(name_map_local, id, name);
448 }
449
450 UniqueName_Map *name_map_global = get_namemap_for(bmain, id, false, true);
451 if (name_map_global != nullptr) {
452 namemap_remove_name(name_map_global, id, name);
453 }
454}
455
457 char name[MAX_ID_NAME];
464 bool operator==(const Uniqueness_Key &o) const
465 {
466 return lib == o.lib && !BLI_ghashutil_strcmp(name, o.name);
467 }
468};
469
470static bool main_namemap_validate_and_fix(Main *bmain, const bool do_fix)
471{
472 Set<Uniqueness_Key> id_names_libs;
473 Set<ID *> id_validated;
474 bool is_valid = true;
475 ListBase *lb_iter;
476 FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb_iter) {
477 LISTBASE_FOREACH_MUTABLE (ID *, id_iter, lb_iter) {
478 if (id_validated.contains(id_iter)) {
479 /* Do not re-check an already validated ID. */
480 continue;
481 }
482
483 Uniqueness_Key key;
484 STRNCPY(key.name, id_iter->name);
485 key.lib = id_iter->lib;
486 if (!id_names_libs.add(key)) {
487 is_valid = false;
488 if (do_fix) {
489 CLOG_WARN(&LOG,
490 "ID name '%s' (from library '%s') is found more than once",
491 id_iter->name,
492 id_iter->lib != nullptr ? id_iter->lib->filepath : "<None>");
493 /* NOTE: this may imply moving this ID in its listbase. The logic below will add the ID
494 * to the validated set if it can now be added to `id_names_libs`, and will prevent
495 * further checking (which would fail again, since the new ID name/lib key has already
496 * been added to `id_names_libs`). */
498 *which_libbase(bmain, GS(id_iter->name)),
499 *id_iter,
500 nullptr,
502 true);
503 STRNCPY(key.name, id_iter->name);
504 if (!id_names_libs.add(key)) {
505 /* This is a serious error, very likely a bug, keep it as CLOG_ERROR even when doing
506 * fixes. */
508 "\tID has been renamed to '%s', but it still seems to be already in use",
509 id_iter->name);
510 }
511 else {
512 CLOG_WARN(&LOG, "\tID has been renamed to '%s'", id_iter->name);
513 id_validated.add(id_iter);
514 }
515 }
516 else {
518 "ID name '%s' (from library '%s') is found more than once",
519 id_iter->name,
520 id_iter->lib != nullptr ? id_iter->lib->filepath : "<None>");
521 }
522 }
523
524 UniqueName_Map *name_map = get_namemap_for(bmain, id_iter, false, false);
525 if (name_map == nullptr) {
526 continue;
527 }
528 UniqueName_TypeMap *type_map = name_map->find_by_type(GS(id_iter->name));
529 BLI_assert(type_map != nullptr);
530
531 UniqueName_Key key_namemap;
532 /* Remove full name from the set. */
533 STRNCPY(key_namemap.name, id_iter->name + 2);
534 if (!type_map->full_names.contains(key_namemap)) {
535 is_valid = false;
536 if (do_fix) {
537 CLOG_INFO(
538 &LOG,
539 3,
540 "ID name '%s' (from library '%s') exists in current Main, but is not listed in "
541 "the namemap",
542 id_iter->name,
543 id_iter->lib != nullptr ? id_iter->lib->filepath : "<None>");
544 }
545 else {
547 &LOG,
548 "ID name '%s' (from library '%s') exists in current Main, but is not listed in "
549 "the namemap",
550 id_iter->name,
551 id_iter->lib != nullptr ? id_iter->lib->filepath : "<None>");
552 }
553 }
554 }
555 }
557
558 Library *lib = nullptr;
559 UniqueName_Map *name_map = bmain->name_map;
560 do {
561 if (name_map != nullptr) {
562 int i = 0;
563 for (short idcode = BKE_idtype_idcode_iter_step(&i); idcode != 0;
564 idcode = BKE_idtype_idcode_iter_step(&i))
565 {
566 UniqueName_TypeMap *type_map = name_map->find_by_type(idcode);
567 if (type_map != nullptr) {
568 for (const UniqueName_Key &id_name : type_map->full_names) {
569 Uniqueness_Key key;
570 *(reinterpret_cast<short *>(key.name)) = idcode;
571 BLI_strncpy(key.name + 2, id_name.name, MAX_NAME);
572 key.lib = lib;
573 if (!id_names_libs.contains(key)) {
574 is_valid = false;
575 if (do_fix) {
576 CLOG_INFO(
577 &LOG,
578 3,
579 "ID name '%s' (from library '%s') is listed in the namemap, but does not "
580 "exists in current Main",
581 key.name,
582 lib != nullptr ? lib->filepath : "<None>");
583 }
584 else {
586 &LOG,
587 "ID name '%s' (from library '%s') is listed in the namemap, but does not "
588 "exists in current Main",
589 key.name,
590 lib != nullptr ? lib->filepath : "<None>");
591 }
592 }
593 }
594 }
595 }
596 }
597 lib = static_cast<Library *>((lib == nullptr) ? bmain->libraries.first : lib->id.next);
598 name_map = (lib != nullptr) ? lib->runtime.name_map : nullptr;
599 } while (lib != nullptr);
600
601 if (is_valid || !do_fix) {
602 return is_valid;
603 }
604
605 /* Clear all existing name-maps. */
607
608 return is_valid;
609}
610
612{
613 const bool is_valid = main_namemap_validate_and_fix(bmain, true);
615 return is_valid;
616}
617
619{
620 return main_namemap_validate_and_fix(bmain, false);
621}
int BKE_idtype_idcode_to_index(short idcode)
Definition idtype.cc:232
short BKE_idtype_idcode_iter_step(int *idtype_index)
Definition idtype.cc:379
IDNewNameResult BKE_id_new_name_validate(Main &bmain, ListBase &lb, ID &id, const char *newname, IDNewNameMode mode, bool do_linked_data)
Definition lib_id.cc:1850
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:500
ListBase * which_libbase(Main *bmain, short type)
Definition main.cc:842
#define FOREACH_MAIN_LISTBASE_END
Definition BKE_main.hh:481
#define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb)
Definition BKE_main.hh:474
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:494
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition BLI_bitmap.h:82
#define BLI_BITMAP_DISABLE(_bitmap, _index)
Definition BLI_bitmap.h:89
int BLI_bitmap_find_first_unset(const BLI_bitmap *bitmap, size_t bits)
Definition bitmap.c:52
#define BLI_BITMAP_TEST_BOOL(_bitmap, _index)
Definition BLI_bitmap.h:75
unsigned int BLI_bitmap
Definition BLI_bitmap.h:17
bool BLI_ghashutil_strcmp(const void *a, const void *b)
size_t BLI_ghashutil_combine_hash(size_t hash_a, size_t hash_b)
unsigned int BLI_ghashutil_strhash_n(const char *key, size_t n)
unsigned int BLI_ghashutil_ptrhash(const void *key)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF_RLEN(dst, format,...)
Definition BLI_string.h:598
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
int BLI_str_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL(1)
size_t BLI_string_split_name_number(const char *name, char delim, char *r_name_left, int *r_number) ATTR_NONNULL(1
unsigned int uint
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
ID and Library types, which are fundamental for SDNA.
#define MAX_ID_NAME
Definition DNA_ID.h:377
#define INDEX_ID_MAX
Definition DNA_ID.h:1328
#define MAX_NAME
Definition DNA_defs.h:50
Read Guarded memory(de)allocation.
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:484
Value & lookup_or_add_default(const Key &key)
Definition BLI_map.hh:601
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition BLI_map.hh:582
bool remove(const Key &key)
Definition BLI_map.hh:344
Value & lookup_or_add(const Key &key, const Value &value)
Definition BLI_map.hh:551
bool contains(const Key &key) const
Definition BLI_set.hh:291
bool add(const Key &key)
Definition BLI_set.hh:248
bool remove(const Key &key)
Definition BLI_set.hh:366
std::string id_name(void *id)
#define printf
#define GS(x)
Definition iris.cc:202
void BKE_main_namemap_destroy(UniqueName_Map **r_name_map)
bool BKE_main_namemap_get_name(Main *bmain, ID *id, char *name, const bool do_unique_in_bmain)
bool BKE_main_namemap_validate_and_fix(Main *bmain)
static bool namemap_add_name(UniqueName_Map *name_map, ID *id, const char *name, const int number)
static UniqueName_Map * get_namemap_for(Main *bmain, ID *id, const bool ensure_created, const bool do_global)
#define MIN_NUMBER
void BKE_main_namemap_remove_name(Main *bmain, ID *id, const char *name)
UniqueName_Map * BKE_main_namemap_create()
static bool id_name_final_build(char *name, char *base_name, size_t base_name_len, int number)
void BKE_main_namemap_clear(Main *bmain)
bool BKE_main_namemap_validate(Main *bmain)
static void main_namemap_populate(UniqueName_Map *name_map, Main *bmain, Library *library, ID *ignore_id, const bool do_global)
static bool main_namemap_validate_and_fix(Main *bmain, const bool do_fix)
static void namemap_remove_name(UniqueName_Map *name_map, ID *id, const char *name)
#define MAX_NUMBER
static CLG_LogRef LOG
void max_inplace(T &a, const T &b)
__int64 int64_t
Definition stdint.h:89
unsigned __int64 uint64_t
Definition stdint.h:90
Definition DNA_ID.h:413
void * first
UniqueName_Map * name_map_global
Definition BKE_main.hh:270
UniqueName_Map * name_map
Definition BKE_main.hh:266
ListBase libraries
Definition BKE_main.hh:211
Main * next
Definition BKE_main.hh:123
uint64_t hash() const
char name[MAX_NAME]
bool operator==(const UniqueName_Key &o) const
UniqueName_TypeMap * find_by_type(short id_type)
UniqueName_TypeMap type_maps[INDEX_ID_MAX]
Set< UniqueName_Key > full_names
Map< UniqueName_Key, UniqueName_Value > base_name_to_num_suffix
static constexpr uint max_exact_tracking
void mark_used(int number)
BLI_BITMAP_DECLARE(mask, max_exact_tracking)
void mark_unused(int number)
bool use_if_unused(int number)
uint64_t hash() const
bool operator==(const Uniqueness_Key &o) const
char name[MAX_ID_NAME]
static DynamicLibrary lib