Blender  V3.3
main_idmap.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <stdlib.h>
4 #include <string.h>
5 
6 #include "MEM_guardedalloc.h"
7 
8 #include "BLI_ghash.h"
9 #include "BLI_listbase.h"
10 #include "BLI_mempool.h"
11 #include "BLI_utildefines.h"
12 
13 #include "DNA_ID.h"
14 
15 #include "BKE_idtype.h"
16 #include "BKE_lib_id.h"
17 #include "BKE_main.h"
18 #include "BKE_main_idmap.h" /* own include */
19 
26 /* -------------------------------------------------------------------- */
38 struct IDNameLib_Key {
40  const char *name;
42  const Library *lib;
43 };
44 
47  short id_type;
48 };
49 
53 struct IDNameLib_Map {
55  struct GHash *uuid_map;
56  struct Main *bmain;
59 
60  /* For storage of keys for the TypeMap ghash, avoids many single allocs. */
62 };
63 
65  short id_type)
66 {
67  if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) {
68  for (int i = 0; i < INDEX_ID_MAX; i++) {
69  if (id_map->type_maps[i].id_type == id_type) {
70  return &id_map->type_maps[i];
71  }
72  }
73  }
74  return NULL;
75 }
76 
78  const bool create_valid_ids_set,
79  struct Main *old_bmain,
80  const int idmap_types)
81 {
82  struct IDNameLib_Map *id_map = MEM_mallocN(sizeof(*id_map), __func__);
83  id_map->bmain = bmain;
84  id_map->idmap_types = idmap_types;
85 
86  int index = 0;
87  while (index < INDEX_ID_MAX) {
88  struct IDNameLib_TypeMap *type_map = &id_map->type_maps[index];
89  type_map->map = NULL;
90  type_map->id_type = BKE_idtype_idcode_iter_step(&index);
91  BLI_assert(type_map->id_type != 0);
92  }
93  BLI_assert(index == INDEX_ID_MAX);
94  id_map->type_maps_keys_pool = NULL;
95 
96  if (idmap_types & MAIN_IDMAP_TYPE_UUID) {
97  ID *id;
98  id_map->uuid_map = BLI_ghash_int_new(__func__);
99  FOREACH_MAIN_ID_BEGIN (bmain, id) {
101  void **id_ptr_v;
102  const bool existing_key = BLI_ghash_ensure_p(
103  id_map->uuid_map, POINTER_FROM_UINT(id->session_uuid), &id_ptr_v);
104  BLI_assert(existing_key == false);
105  UNUSED_VARS_NDEBUG(existing_key);
106 
107  *id_ptr_v = id;
108  }
110  }
111  else {
112  id_map->uuid_map = NULL;
113  }
114 
115  if (create_valid_ids_set) {
116  id_map->valid_id_pointers = BKE_main_gset_create(bmain, NULL);
117  if (old_bmain != NULL) {
118  id_map->valid_id_pointers = BKE_main_gset_create(old_bmain, id_map->valid_id_pointers);
119  }
120  }
121  else {
122  id_map->valid_id_pointers = NULL;
123  }
124 
125  return id_map;
126 }
127 
129 {
130  if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) {
131  const short id_type = GS(id->name);
133 
134  /* No need to do anything if map has not been lazily created yet. */
135  if (LIKELY(type_map != NULL) && type_map->map != NULL) {
136  BLI_assert(id_map->type_maps_keys_pool != NULL);
137 
138  struct IDNameLib_Key *key = BLI_mempool_alloc(id_map->type_maps_keys_pool);
139  key->name = id->name + 2;
140  key->lib = id->lib;
141  BLI_ghash_insert(type_map->map, key, id);
142  }
143  }
144 
145  if (id_map->idmap_types & MAIN_IDMAP_TYPE_UUID) {
146  BLI_assert(id_map->uuid_map != NULL);
148  void **id_ptr_v;
149  const bool existing_key = BLI_ghash_ensure_p(
150  id_map->uuid_map, POINTER_FROM_UINT(id->session_uuid), &id_ptr_v);
151  BLI_assert(existing_key == false);
152  UNUSED_VARS_NDEBUG(existing_key);
153 
154  *id_ptr_v = id;
155  }
156 }
157 
159 {
160  if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) {
161  const short id_type = GS(id->name);
163 
164  /* No need to do anything if map has not been lazily created yet. */
165  if (LIKELY(type_map != NULL) && type_map->map != NULL) {
166  BLI_assert(id_map->type_maps_keys_pool != NULL);
167 
168  /* NOTE: We cannot free the key from the MemPool here, would need new API from GHash to also
169  * retrieve key pointer. Not a big deal for now */
170  BLI_ghash_remove(type_map->map, &(struct IDNameLib_Key){id->name + 2, id->lib}, NULL, NULL);
171  }
172  }
173 
174  if (id_map->idmap_types & MAIN_IDMAP_TYPE_UUID) {
175  BLI_assert(id_map->uuid_map != NULL);
177 
179  }
180 }
181 
183 {
184  return id_map->bmain;
185 }
186 
187 static unsigned int idkey_hash(const void *ptr)
188 {
189  const struct IDNameLib_Key *idkey = ptr;
190  unsigned int key = BLI_ghashutil_strhash(idkey->name);
191  if (idkey->lib) {
192  key ^= BLI_ghashutil_ptrhash(idkey->lib);
193  }
194  return key;
195 }
196 
197 static bool idkey_cmp(const void *a, const void *b)
198 {
199  const struct IDNameLib_Key *idkey_a = a;
200  const struct IDNameLib_Key *idkey_b = b;
201  return !STREQ(idkey_a->name, idkey_b->name) || (idkey_a->lib != idkey_b->lib);
202 }
203 
205  short id_type,
206  const char *name,
207  const Library *lib)
208 {
210 
211  if (UNLIKELY(type_map == NULL)) {
212  return NULL;
213  }
214 
215  /* Lazy init. */
216  if (type_map->map == NULL) {
217  if (id_map->type_maps_keys_pool == NULL) {
218  id_map->type_maps_keys_pool = BLI_mempool_create(
219  sizeof(struct IDNameLib_Key), 1024, 1024, BLI_MEMPOOL_NOP);
220  }
221 
222  GHash *map = type_map->map = BLI_ghash_new(idkey_hash, idkey_cmp, __func__);
223  ListBase *lb = which_libbase(id_map->bmain, id_type);
224  for (ID *id = lb->first; id; id = id->next) {
225  struct IDNameLib_Key *key = BLI_mempool_alloc(id_map->type_maps_keys_pool);
226  key->name = id->name + 2;
227  key->lib = id->lib;
228  BLI_ghash_insert(map, key, id);
229  }
230  }
231 
232  const struct IDNameLib_Key key_lookup = {name, lib};
233  return BLI_ghash_lookup(type_map->map, &key_lookup);
234 }
235 
237 {
238  /* When used during undo/redo, this function cannot assume that given id points to valid memory
239  * (i.e. has not been freed),
240  * so it has to check that it does exist in 'old' (aka current) Main database.
241  * Otherwise, we cannot provide new ID pointer that way (would crash accessing freed memory
242  * when trying to get ID name).
243  */
244  if (id_map->valid_id_pointers == NULL || BLI_gset_haskey(id_map->valid_id_pointers, id)) {
245  return BKE_main_idmap_lookup_name(id_map, GS(id->name), id->name + 2, id->lib);
246  }
247  return NULL;
248 }
249 
251 {
252  if (id_map->idmap_types & MAIN_IDMAP_TYPE_UUID) {
253  return BLI_ghash_lookup(id_map->uuid_map, POINTER_FROM_UINT(session_uuid));
254  }
255  return NULL;
256 }
257 
259 {
260  if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) {
261  struct IDNameLib_TypeMap *type_map = id_map->type_maps;
262  for (int i = 0; i < INDEX_ID_MAX; i++, type_map++) {
263  if (type_map->map) {
264  BLI_ghash_free(type_map->map, NULL, NULL);
265  type_map->map = NULL;
266  }
267  }
268  if (id_map->type_maps_keys_pool != NULL) {
269  BLI_mempool_destroy(id_map->type_maps_keys_pool);
270  id_map->type_maps_keys_pool = NULL;
271  }
272  }
273  if (id_map->idmap_types & MAIN_IDMAP_TYPE_UUID) {
274  BLI_ghash_free(id_map->uuid_map, NULL, NULL);
275  }
276 
277  BLI_assert(id_map->type_maps_keys_pool == NULL);
278 
279  if (id_map->valid_id_pointers != NULL) {
280  BLI_gset_free(id_map->valid_id_pointers, NULL);
281  }
282 
283  MEM_freeN(id_map);
284 }
285 
short BKE_idtype_idcode_iter_step(int *index)
Definition: idtype.c:442
#define MAIN_ID_SESSION_UUID_UNSET
Definition: BKE_lib_id.h:82
#define FOREACH_MAIN_ID_END
Definition: BKE_main.h:367
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition: BKE_main.h:361
struct ListBase * which_libbase(struct Main *bmain, short type)
Definition: main.c:567
struct GSet * BKE_main_gset_create(struct Main *bmain, struct GSet *gset)
Definition: main.c:346
@ MAIN_IDMAP_TYPE_UUID
@ MAIN_IDMAP_TYPE_NAME
#define BLI_assert(a)
Definition: BLI_assert.h:46
struct GSet GSet
Definition: BLI_ghash.h:340
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1007
unsigned int BLI_ghashutil_ptrhash(const void *key)
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:689
GHash * BLI_ghash_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:734
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:790
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:710
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:863
#define BLI_ghashutil_strhash(key)
Definition: BLI_ghash.h:573
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1037
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:755
@ BLI_MEMPOOL_NOP
Definition: BLI_mempool.h:99
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
Definition: BLI_mempool.c:253
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
Definition: BLI_mempool.c:319
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
Definition: BLI_mempool.c:707
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED_VARS_NDEBUG(...)
#define UNLIKELY(x)
#define POINTER_FROM_UINT(i)
#define STREQ(a, b)
#define LIKELY(x)
ID and Library types, which are fundamental for sdna.
@ INDEX_ID_MAX
Definition: DNA_ID.h:1058
Read Guarded memory(de)allocation.
Definition: id_map.h:23
DRWShaderLibrary * lib
#define GS(x)
Definition: iris.c:225
ID * BKE_main_idmap_lookup_uuid(struct IDNameLib_Map *id_map, const uint session_uuid)
Definition: main_idmap.c:250
void BKE_main_idmap_insert_id(struct IDNameLib_Map *id_map, ID *id)
Definition: main_idmap.c:128
static bool idkey_cmp(const void *a, const void *b)
Definition: main_idmap.c:197
void BKE_main_idmap_remove_id(struct IDNameLib_Map *id_map, ID *id)
Definition: main_idmap.c:158
void BKE_main_idmap_destroy(struct IDNameLib_Map *id_map)
Definition: main_idmap.c:258
struct Main * BKE_main_idmap_main_get(struct IDNameLib_Map *id_map)
Definition: main_idmap.c:182
ID * BKE_main_idmap_lookup_id(struct IDNameLib_Map *id_map, const ID *id)
Definition: main_idmap.c:236
ID * BKE_main_idmap_lookup_name(struct IDNameLib_Map *id_map, short id_type, const char *name, const Library *lib)
Definition: main_idmap.c:204
static struct IDNameLib_TypeMap * main_idmap_from_idcode(struct IDNameLib_Map *id_map, short id_type)
Definition: main_idmap.c:64
struct IDNameLib_Map * BKE_main_idmap_create(struct Main *bmain, const bool create_valid_ids_set, struct Main *old_bmain, const int idmap_types)
Definition: main_idmap.c:77
static unsigned int idkey_hash(const void *ptr)
Definition: main_idmap.c:187
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static unsigned a[3]
Definition: RandGen.cpp:78
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
SocketIndexByIdentifierMap * map
const Library * lib
Definition: main_idmap.c:42
const char * name
Definition: main_idmap.c:40
struct Main * bmain
Definition: main_idmap.c:56
BLI_mempool * type_maps_keys_pool
Definition: main_idmap.c:61
struct GSet * valid_id_pointers
Definition: main_idmap.c:57
struct IDNameLib_TypeMap type_maps[INDEX_ID_MAX]
Definition: main_idmap.c:54
struct GHash * uuid_map
Definition: main_idmap.c:55
Definition: DNA_ID.h:368
struct Library * lib
Definition: DNA_ID.h:372
unsigned int session_uuid
Definition: DNA_ID.h:407
void * next
Definition: DNA_ID.h:369
char name[66]
Definition: DNA_ID.h:378
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
PointerRNA * ptr
Definition: wm_files.c:3480