Blender  V2.93
main_idmap.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #include <stdlib.h>
18 #include <string.h>
19 
20 #include "MEM_guardedalloc.h"
21 
22 #include "BLI_ghash.h"
23 #include "BLI_listbase.h"
24 #include "BLI_utildefines.h"
25 
26 #include "DNA_ID.h"
27 
28 #include "BKE_idtype.h"
29 #include "BKE_lib_id.h"
30 #include "BKE_main.h"
31 #include "BKE_main_idmap.h" /* own include */
32 
39 /* -------------------------------------------------------------------- */
51 struct IDNameLib_Key {
53  const char *name;
55  const Library *lib;
56 };
57 
60  short id_type;
61  /* only for storage of keys in the ghash, avoid many single allocs */
63 };
64 
68 struct IDNameLib_Map {
70  struct GHash *uuid_map;
71  struct Main *bmain;
74 };
75 
77  short id_type)
78 {
79  if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) {
80  for (int i = 0; i < INDEX_ID_MAX; i++) {
81  if (id_map->type_maps[i].id_type == id_type) {
82  return &id_map->type_maps[i];
83  }
84  }
85  }
86  return NULL;
87 }
88 
102  const bool create_valid_ids_set,
103  struct Main *old_bmain,
104  const int idmap_types)
105 {
106  struct IDNameLib_Map *id_map = MEM_mallocN(sizeof(*id_map), __func__);
107  id_map->bmain = bmain;
108  id_map->idmap_types = idmap_types;
109 
110  int index = 0;
111  while (index < INDEX_ID_MAX) {
112  struct IDNameLib_TypeMap *type_map = &id_map->type_maps[index];
113  type_map->map = NULL;
114  type_map->id_type = BKE_idtype_idcode_iter_step(&index);
115  BLI_assert(type_map->id_type != 0);
116  }
117  BLI_assert(index == INDEX_ID_MAX);
118 
119  if (idmap_types & MAIN_IDMAP_TYPE_UUID) {
120  ID *id;
121  id_map->uuid_map = BLI_ghash_int_new(__func__);
122  FOREACH_MAIN_ID_BEGIN (bmain, id) {
124  void **id_ptr_v;
125  const bool existing_key = BLI_ghash_ensure_p(
126  id_map->uuid_map, POINTER_FROM_UINT(id->session_uuid), &id_ptr_v);
127  BLI_assert(existing_key == false);
128  UNUSED_VARS_NDEBUG(existing_key);
129 
130  *id_ptr_v = id;
131  }
133  }
134  else {
135  id_map->uuid_map = NULL;
136  }
137 
138  if (create_valid_ids_set) {
139  id_map->valid_id_pointers = BKE_main_gset_create(bmain, NULL);
140  if (old_bmain != NULL) {
141  id_map->valid_id_pointers = BKE_main_gset_create(old_bmain, id_map->valid_id_pointers);
142  }
143  }
144  else {
145  id_map->valid_id_pointers = NULL;
146  }
147 
148  return id_map;
149 }
150 
152 {
153  return id_map->bmain;
154 }
155 
156 static unsigned int idkey_hash(const void *ptr)
157 {
158  const struct IDNameLib_Key *idkey = ptr;
159  unsigned int key = BLI_ghashutil_strhash(idkey->name);
160  if (idkey->lib) {
161  key ^= BLI_ghashutil_ptrhash(idkey->lib);
162  }
163  return key;
164 }
165 
166 static bool idkey_cmp(const void *a, const void *b)
167 {
168  const struct IDNameLib_Key *idkey_a = a;
169  const struct IDNameLib_Key *idkey_b = b;
170  return !STREQ(idkey_a->name, idkey_b->name) || (idkey_a->lib != idkey_b->lib);
171 }
172 
174  short id_type,
175  const char *name,
176  const Library *lib)
177 {
179 
180  if (UNLIKELY(type_map == NULL)) {
181  return NULL;
182  }
183 
184  /* lazy init */
185  if (type_map->map == NULL) {
186  ListBase *lb = which_libbase(id_map->bmain, id_type);
187  const int lb_len = BLI_listbase_count(lb);
188  if (lb_len == 0) {
189  return NULL;
190  }
191  type_map->map = BLI_ghash_new_ex(idkey_hash, idkey_cmp, __func__, lb_len);
192  type_map->keys = MEM_mallocN(sizeof(struct IDNameLib_Key) * lb_len, __func__);
193 
194  GHash *map = type_map->map;
195  struct IDNameLib_Key *key = type_map->keys;
196 
197  for (ID *id = lb->first; id; id = id->next, key++) {
198  key->name = id->name + 2;
199  key->lib = id->lib;
200  BLI_ghash_insert(map, key, id);
201  }
202  }
203 
204  const struct IDNameLib_Key key_lookup = {name, lib};
205  return BLI_ghash_lookup(type_map->map, &key_lookup);
206 }
207 
209 {
210  /* When used during undo/redo, this function cannot assume that given id points to valid memory
211  * (i.e. has not been freed),
212  * so it has to check that it does exist in 'old' (aka current) Main database.
213  * Otherwise, we cannot provide new ID pointer that way (would crash accessing freed memory
214  * when trying to get ID name).
215  */
216  if (id_map->valid_id_pointers == NULL || BLI_gset_haskey(id_map->valid_id_pointers, id)) {
217  return BKE_main_idmap_lookup_name(id_map, GS(id->name), id->name + 2, id->lib);
218  }
219  return NULL;
220 }
221 
223 {
224  if (id_map->idmap_types & MAIN_IDMAP_TYPE_UUID) {
225  return BLI_ghash_lookup(id_map->uuid_map, POINTER_FROM_UINT(session_uuid));
226  }
227  return NULL;
228 }
229 
231 {
232  if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) {
233  struct IDNameLib_TypeMap *type_map = id_map->type_maps;
234  for (int i = 0; i < INDEX_ID_MAX; i++, type_map++) {
235  if (type_map->map) {
236  BLI_ghash_free(type_map->map, NULL, NULL);
237  type_map->map = NULL;
238  MEM_freeN(type_map->keys);
239  }
240  }
241  }
242  if (id_map->idmap_types & MAIN_IDMAP_TYPE_UUID) {
243  BLI_ghash_free(id_map->uuid_map, NULL, NULL);
244  }
245 
246  if (id_map->valid_id_pointers != NULL) {
247  BLI_gset_free(id_map->valid_id_pointers, NULL);
248  }
249 
250  MEM_freeN(id_map);
251 }
252 
short BKE_idtype_idcode_iter_step(int *index)
Definition: idtype.c:472
#define MAIN_ID_SESSION_UUID_UNSET
Definition: BKE_lib_id.h:73
#define FOREACH_MAIN_ID_END
Definition: BKE_main.h:250
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition: BKE_main.h:244
struct ListBase * which_libbase(struct Main *bmain, short type)
Definition: main.c:447
struct GSet * BKE_main_gset_create(struct Main *bmain, struct GSet *gset)
Definition: main.c:342
@ MAIN_IDMAP_TYPE_UUID
@ MAIN_IDMAP_TYPE_NAME
#define BLI_assert(a)
Definition: BLI_assert.h:58
struct GSet GSet
Definition: BLI_ghash.h:189
GHash * BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:707
unsigned int BLI_ghashutil_ptrhash(const void *key)
GHash * BLI_ghash_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
bool BLI_gset_haskey(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1216
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:756
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
#define BLI_ghashutil_strhash(key)
Definition: BLI_ghash.h:350
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1253
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:851
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED_VARS_NDEBUG(...)
#define UNLIKELY(x)
#define POINTER_FROM_UINT(i)
#define STREQ(a, b)
ID and Library types, which are fundamental for sdna.
@ INDEX_ID_MAX
Definition: DNA_ID.h:859
Read Guarded memory(de)allocation.
DRWShaderLibrary * lib
#define GS(x)
Definition: iris.c:241
ID * BKE_main_idmap_lookup_uuid(struct IDNameLib_Map *id_map, const uint session_uuid)
Definition: main_idmap.c:222
static bool idkey_cmp(const void *a, const void *b)
Definition: main_idmap.c:166
void BKE_main_idmap_destroy(struct IDNameLib_Map *id_map)
Definition: main_idmap.c:230
struct Main * BKE_main_idmap_main_get(struct IDNameLib_Map *id_map)
Definition: main_idmap.c:151
ID * BKE_main_idmap_lookup_id(struct IDNameLib_Map *id_map, const ID *id)
Definition: main_idmap.c:208
ID * BKE_main_idmap_lookup_name(struct IDNameLib_Map *id_map, short id_type, const char *name, const Library *lib)
Definition: main_idmap.c:173
static struct IDNameLib_TypeMap * main_idmap_from_idcode(struct IDNameLib_Map *id_map, short id_type)
Definition: main_idmap.c:76
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:101
static unsigned int idkey_hash(const void *ptr)
Definition: main_idmap.c:156
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static unsigned a[3]
Definition: RandGen.cpp:92
const Library * lib
Definition: main_idmap.c:55
const char * name
Definition: main_idmap.c:53
struct Main * bmain
Definition: main_idmap.c:71
struct GSet * valid_id_pointers
Definition: main_idmap.c:72
struct IDNameLib_TypeMap type_maps[INDEX_ID_MAX]
Definition: main_idmap.c:69
struct GHash * uuid_map
Definition: main_idmap.c:70
struct IDNameLib_Key * keys
Definition: main_idmap.c:62
Definition: DNA_ID.h:273
struct Library * lib
Definition: DNA_ID.h:277
unsigned int session_uuid
Definition: DNA_ID.h:312
void * next
Definition: DNA_ID.h:274
char name[66]
Definition: DNA_ID.h:283
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
PointerRNA * ptr
Definition: wm_files.c:3157