Blender V4.3
main_idmap.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
5#include <cstdlib>
6#include <cstring>
7
8#include "MEM_guardedalloc.h"
9
10#include "BLI_ghash.h"
11#include "BLI_mempool.h"
12#include "BLI_utildefines.h"
13
14#include "DNA_ID.h"
15
16#include "BKE_idtype.hh"
17#include "BKE_lib_id.hh"
18#include "BKE_main.hh"
19#include "BKE_main_idmap.hh" /* own include */
20
27/* -------------------------------------------------------------------- */
41 const char *name;
43 const Library *lib;
44};
45
50
60
61 /* For storage of keys for the #TypeMap #GHash, avoids many single allocations. */
63};
64
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 nullptr;
75}
76
78 const bool create_valid_ids_set,
79 Main *old_bmain,
80 const int idmap_types)
81{
82 IDNameLib_Map *id_map = static_cast<IDNameLib_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 IDNameLib_TypeMap *type_map = &id_map->type_maps[index];
89 type_map->map = nullptr;
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 = nullptr;
95
96 if (idmap_types & MAIN_IDMAP_TYPE_UID) {
97 ID *id;
98 id_map->uid_map = BLI_ghash_int_new(__func__);
99 FOREACH_MAIN_ID_BEGIN (bmain, id) {
100 BLI_assert(id->session_uid != MAIN_ID_SESSION_UID_UNSET);
101 void **id_ptr_v;
102 const bool existing_key = BLI_ghash_ensure_p(
103 id_map->uid_map, POINTER_FROM_UINT(id->session_uid), &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->uid_map = nullptr;
113 }
114
115 if (create_valid_ids_set) {
116 id_map->valid_id_pointers = BKE_main_gset_create(bmain, nullptr);
117 if (old_bmain != nullptr) {
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 = nullptr;
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);
132 IDNameLib_TypeMap *type_map = main_idmap_from_idcode(id_map, id_type);
133
134 /* No need to do anything if map has not been lazily created yet. */
135 if (LIKELY(type_map != nullptr) && type_map->map != nullptr) {
136 BLI_assert(id_map->type_maps_keys_pool != nullptr);
137
138 IDNameLib_Key *key = static_cast<IDNameLib_Key *>(
139 BLI_mempool_alloc(id_map->type_maps_keys_pool));
140 key->name = id->name + 2;
141 key->lib = id->lib;
142 BLI_ghash_insert(type_map->map, key, id);
143 }
144 }
145
146 if (id_map->idmap_types & MAIN_IDMAP_TYPE_UID) {
147 BLI_assert(id_map->uid_map != nullptr);
148 BLI_assert(id->session_uid != MAIN_ID_SESSION_UID_UNSET);
149 void **id_ptr_v;
150 const bool existing_key = BLI_ghash_ensure_p(
151 id_map->uid_map, POINTER_FROM_UINT(id->session_uid), &id_ptr_v);
152 BLI_assert(existing_key == false);
153 UNUSED_VARS_NDEBUG(existing_key);
154
155 *id_ptr_v = id;
156 }
157}
158
160{
161 if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) {
162 const short id_type = GS(id->name);
163 IDNameLib_TypeMap *type_map = main_idmap_from_idcode(id_map, id_type);
164
165 /* No need to do anything if map has not been lazily created yet. */
166 if (LIKELY(type_map != nullptr) && type_map->map != nullptr) {
167 BLI_assert(id_map->type_maps_keys_pool != nullptr);
168
169 /* NOTE: We cannot free the key from the MemPool here, would need new API from GHash to also
170 * retrieve key pointer. Not a big deal for now */
171 IDNameLib_Key key{id->name + 2, id->lib};
172 BLI_ghash_remove(type_map->map, &key, nullptr, nullptr);
173 }
174 }
175
176 if (id_map->idmap_types & MAIN_IDMAP_TYPE_UID) {
177 BLI_assert(id_map->uid_map != nullptr);
178 BLI_assert(id->session_uid != MAIN_ID_SESSION_UID_UNSET);
179
180 BLI_ghash_remove(id_map->uid_map, POINTER_FROM_UINT(id->session_uid), nullptr, nullptr);
181 }
182}
183
188
189static uint idkey_hash(const void *ptr)
190{
191 const IDNameLib_Key *idkey = static_cast<const IDNameLib_Key *>(ptr);
192 uint key = BLI_ghashutil_strhash(idkey->name);
193 if (idkey->lib) {
194 key ^= BLI_ghashutil_ptrhash(idkey->lib);
195 }
196 return key;
197}
198
199static bool idkey_cmp(const void *a, const void *b)
200{
201 const IDNameLib_Key *idkey_a = static_cast<const IDNameLib_Key *>(a);
202 const IDNameLib_Key *idkey_b = static_cast<const IDNameLib_Key *>(b);
203 return !STREQ(idkey_a->name, idkey_b->name) || (idkey_a->lib != idkey_b->lib);
204}
205
207 short id_type,
208 const char *name,
209 const Library *lib)
210{
211 IDNameLib_TypeMap *type_map = main_idmap_from_idcode(id_map, id_type);
212
213 if (UNLIKELY(type_map == nullptr)) {
214 return nullptr;
215 }
216
217 /* Lazy init. */
218 if (type_map->map == nullptr) {
219 if (id_map->type_maps_keys_pool == nullptr) {
220 id_map->type_maps_keys_pool = BLI_mempool_create(
221 sizeof(IDNameLib_Key), 1024, 1024, BLI_MEMPOOL_NOP);
222 }
223
224 GHash *map = type_map->map = BLI_ghash_new(idkey_hash, idkey_cmp, __func__);
225 ListBase *lb = which_libbase(id_map->bmain, id_type);
226 for (ID *id = static_cast<ID *>(lb->first); id; id = static_cast<ID *>(id->next)) {
227 IDNameLib_Key *key = static_cast<IDNameLib_Key *>(
228 BLI_mempool_alloc(id_map->type_maps_keys_pool));
229 key->name = id->name + 2;
230 key->lib = id->lib;
231 BLI_ghash_insert(map, key, id);
232 }
233 }
234
235 const IDNameLib_Key key_lookup = {name, lib};
236 return static_cast<ID *>(BLI_ghash_lookup(type_map->map, &key_lookup));
237}
238
240{
241 /* When used during undo/redo, this function cannot assume that given id points to valid memory
242 * (i.e. has not been freed),
243 * so it has to check that it does exist in 'old' (aka current) Main database.
244 * Otherwise, we cannot provide new ID pointer that way (would crash accessing freed memory
245 * when trying to get ID name).
246 */
247 if (id_map->valid_id_pointers == nullptr || BLI_gset_haskey(id_map->valid_id_pointers, id)) {
248 return BKE_main_idmap_lookup_name(id_map, GS(id->name), id->name + 2, id->lib);
249 }
250 return nullptr;
251}
252
254{
255 if (id_map->idmap_types & MAIN_IDMAP_TYPE_UID) {
256 return static_cast<ID *>(BLI_ghash_lookup(id_map->uid_map, POINTER_FROM_UINT(session_uid)));
257 }
258 return nullptr;
259}
260
262{
263 if (id_map.idmap_types & MAIN_IDMAP_TYPE_NAME) {
264 for (IDNameLib_TypeMap &type_map : id_map.type_maps) {
265 if (type_map.map) {
266 BLI_ghash_clear(type_map.map, nullptr, nullptr);
267 }
268 }
269 }
270 if (id_map.idmap_types & MAIN_IDMAP_TYPE_UID) {
271 BLI_ghash_clear(id_map.uid_map, nullptr, nullptr);
272 }
273
274 if (id_map.valid_id_pointers != nullptr) {
275 BLI_gset_clear(id_map.valid_id_pointers, nullptr);
276 }
277}
278
280{
281 if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) {
282 for (IDNameLib_TypeMap &type_map : id_map->type_maps) {
283 if (type_map.map) {
284 BLI_ghash_free(type_map.map, nullptr, nullptr);
285 type_map.map = nullptr;
286 }
287 }
288 if (id_map->type_maps_keys_pool != nullptr) {
289 BLI_mempool_destroy(id_map->type_maps_keys_pool);
290 id_map->type_maps_keys_pool = nullptr;
291 }
292 }
293 if (id_map->idmap_types & MAIN_IDMAP_TYPE_UID) {
294 BLI_ghash_free(id_map->uid_map, nullptr, nullptr);
295 }
296
297 BLI_assert(id_map->type_maps_keys_pool == nullptr);
298
299 if (id_map->valid_id_pointers != nullptr) {
300 BLI_gset_free(id_map->valid_id_pointers, nullptr);
301 }
302
304}
305
short BKE_idtype_idcode_iter_step(int *idtype_index)
Definition idtype.cc:379
#define MAIN_ID_SESSION_UID_UNSET
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:500
ListBase * which_libbase(Main *bmain, short type)
Definition main.cc:842
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:494
GSet * BKE_main_gset_create(Main *bmain, GSet *gset)
Definition main.cc:615
@ MAIN_IDMAP_TYPE_UID
@ MAIN_IDMAP_TYPE_NAME
#define BLI_assert(a)
Definition BLI_assert.h:50
struct GSet GSet
Definition BLI_ghash.h:341
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:1004
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:855
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:686
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1029
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:787
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
#define BLI_ghashutil_strhash(key)
Definition BLI_ghash.h:574
GHash * BLI_ghash_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1034
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:752
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
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
@ BLI_MEMPOOL_NOP
Definition BLI_mempool.h:86
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
unsigned int uint
#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.
#define INDEX_ID_MAX
Definition DNA_ID.h:1328
Read Guarded memory(de)allocation.
local_group_size(16, 16) .push_constant(Type b
#define GS(x)
Definition iris.cc:202
IDNameLib_Map * BKE_main_idmap_create(Main *bmain, const bool create_valid_ids_set, Main *old_bmain, const int idmap_types)
Definition main_idmap.cc:77
Main * BKE_main_idmap_main_get(IDNameLib_Map *id_map)
static bool idkey_cmp(const void *a, const void *b)
void BKE_main_idmap_remove_id(IDNameLib_Map *id_map, const ID *id)
static IDNameLib_TypeMap * main_idmap_from_idcode(IDNameLib_Map *id_map, short id_type)
Definition main_idmap.cc:65
static uint idkey_hash(const void *ptr)
void BKE_main_idmap_clear(IDNameLib_Map &id_map)
ID * BKE_main_idmap_lookup_name(IDNameLib_Map *id_map, short id_type, const char *name, const Library *lib)
ID * BKE_main_idmap_lookup_id(IDNameLib_Map *id_map, const ID *id)
ID * BKE_main_idmap_lookup_uid(IDNameLib_Map *id_map, const uint session_uid)
void BKE_main_idmap_insert_id(IDNameLib_Map *id_map, ID *id)
void BKE_main_idmap_destroy(IDNameLib_Map *id_map)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
const Library * lib
Definition main_idmap.cc:43
const char * name
Definition main_idmap.cc:41
IDNameLib_TypeMap type_maps[INDEX_ID_MAX]
Definition main_idmap.cc:55
BLI_mempool * type_maps_keys_pool
Definition main_idmap.cc:62
GSet * valid_id_pointers
Definition main_idmap.cc:58
GHash * uid_map
Definition main_idmap.cc:56
Definition DNA_ID.h:413
void * first
static DynamicLibrary lib
PointerRNA * ptr
Definition wm_files.cc:4126