Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenloader/intern/readfile.cc
| Show First 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_blenlib.h" | #include "BLI_blenlib.h" | ||||
| #include "BLI_endian_defines.h" | #include "BLI_endian_defines.h" | ||||
| #include "BLI_endian_switch.h" | #include "BLI_endian_switch.h" | ||||
| #include "BLI_ghash.h" | #include "BLI_ghash.h" | ||||
| #include "BLI_linklist.h" | #include "BLI_linklist.h" | ||||
| #include "BLI_map.hh" | |||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_memarena.h" | #include "BLI_memarena.h" | ||||
| #include "BLI_mempool.h" | #include "BLI_mempool.h" | ||||
| #include "BLI_threads.h" | #include "BLI_threads.h" | ||||
| #include "PIL_time.h" | #include "PIL_time.h" | ||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| ▲ Show 20 Lines • Show All 162 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| return lib->parent ? lib->parent->filepath_abs : "<direct>"; | return lib->parent ? lib->parent->filepath_abs : "<direct>"; | ||||
| } | } | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name OldNewMap API | /** \name OldNewMap API | ||||
| * \{ */ | * \{ */ | ||||
| struct OldNew { | struct NewAddress { | ||||
| const void *oldp; | |||||
| void *newp; | void *newp; | ||||
| /* `nr` is "user count" for data, and ID code for libdata. */ | /* `nr` is "user count" for data, and ID code for libdata. */ | ||||
| int nr; | int nr; | ||||
| }; | }; | ||||
| struct OldNewMap { | struct OldNewMap { | ||||
| /* Array that stores the actual entries. */ | blender::Map<const void *, NewAddress> map; | ||||
| OldNew *entries; | |||||
| int nentries; | |||||
| /* Hash-map that stores indices into the `entries` array. */ | |||||
| int32_t *map; | |||||
| int capacity_exp; | |||||
| }; | }; | ||||
| #define ENTRIES_CAPACITY(onm) (1ll << (onm)->capacity_exp) | |||||
| #define MAP_CAPACITY(onm) (1ll << ((onm)->capacity_exp + 1)) | |||||
| #define SLOT_MASK(onm) (MAP_CAPACITY(onm) - 1) | |||||
| #define DEFAULT_SIZE_EXP 6 | |||||
| #define PERTURB_SHIFT 5 | |||||
| /* based on the probing algorithm used in Python dicts. */ | |||||
| #define ITER_SLOTS(onm, KEY, SLOT_NAME, INDEX_NAME) \ | |||||
| uint32_t hash = BLI_ghashutil_ptrhash(KEY); \ | |||||
| uint32_t mask = SLOT_MASK(onm); \ | |||||
| uint perturb = hash; \ | |||||
| int SLOT_NAME = mask & hash; \ | |||||
| int INDEX_NAME = onm->map[SLOT_NAME]; \ | |||||
| for (;; SLOT_NAME = mask & ((5 * SLOT_NAME) + 1 + perturb), \ | |||||
| perturb >>= PERTURB_SHIFT, \ | |||||
| INDEX_NAME = onm->map[SLOT_NAME]) | |||||
| static void oldnewmap_insert_index_in_map(OldNewMap *onm, const void *ptr, int index) | |||||
| { | |||||
| ITER_SLOTS (onm, ptr, slot, stored_index) { | |||||
| if (stored_index == -1) { | |||||
| onm->map[slot] = index; | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| static void oldnewmap_insert_or_replace(OldNewMap *onm, OldNew entry) | |||||
| { | |||||
| ITER_SLOTS (onm, entry.oldp, slot, index) { | |||||
| if (index == -1) { | |||||
| onm->entries[onm->nentries] = entry; | |||||
| onm->map[slot] = onm->nentries; | |||||
| onm->nentries++; | |||||
| break; | |||||
| } | |||||
| if (onm->entries[index].oldp == entry.oldp) { | |||||
| onm->entries[index] = entry; | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| static OldNew *oldnewmap_lookup_entry(const OldNewMap *onm, const void *addr) | |||||
| { | |||||
| ITER_SLOTS (onm, addr, slot, index) { | |||||
| if (index >= 0) { | |||||
| OldNew *entry = &onm->entries[index]; | |||||
| if (entry->oldp == addr) { | |||||
| return entry; | |||||
| } | |||||
| } | |||||
| else { | |||||
| return nullptr; | |||||
| } | |||||
| } | |||||
| } | |||||
| static void oldnewmap_clear_map(OldNewMap *onm) | |||||
| { | |||||
| memset(onm->map, 0xFF, MAP_CAPACITY(onm) * sizeof(*onm->map)); | |||||
| } | |||||
| static void oldnewmap_increase_size(OldNewMap *onm) | |||||
| { | |||||
| onm->capacity_exp++; | |||||
| onm->entries = static_cast<OldNew *>( | |||||
| MEM_reallocN(onm->entries, sizeof(*onm->entries) * ENTRIES_CAPACITY(onm))); | |||||
| onm->map = static_cast<int32_t *>(MEM_reallocN(onm->map, sizeof(*onm->map) * MAP_CAPACITY(onm))); | |||||
| oldnewmap_clear_map(onm); | |||||
| for (int i = 0; i < onm->nentries; i++) { | |||||
| oldnewmap_insert_index_in_map(onm, onm->entries[i].oldp, i); | |||||
| } | |||||
| } | |||||
| /* Public OldNewMap API */ | |||||
| static void oldnewmap_init_data(OldNewMap *onm, const int capacity_exp) | |||||
| { | |||||
| memset(onm, 0x0, sizeof(*onm)); | |||||
| onm->capacity_exp = capacity_exp; | |||||
| onm->entries = static_cast<OldNew *>( | |||||
| MEM_malloc_arrayN(ENTRIES_CAPACITY(onm), sizeof(*onm->entries), "OldNewMap.entries")); | |||||
| onm->map = static_cast<int32_t *>( | |||||
| MEM_malloc_arrayN(MAP_CAPACITY(onm), sizeof(*onm->map), "OldNewMap.map")); | |||||
| oldnewmap_clear_map(onm); | |||||
| } | |||||
| static OldNewMap *oldnewmap_new() | static OldNewMap *oldnewmap_new() | ||||
| { | { | ||||
| OldNewMap *onm = static_cast<OldNewMap *>(MEM_mallocN(sizeof(*onm), "OldNewMap")); | return MEM_new<OldNewMap>(__func__); | ||||
| oldnewmap_init_data(onm, DEFAULT_SIZE_EXP); | |||||
| return onm; | |||||
| } | } | ||||
| static void oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr) | static void oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr) | ||||
| { | { | ||||
| if (oldaddr == nullptr || newaddr == nullptr) { | if (oldaddr == nullptr || newaddr == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (UNLIKELY(onm->nentries == ENTRIES_CAPACITY(onm))) { | onm->map.add_overwrite(oldaddr, NewAddress{newaddr, nr}); | ||||
| oldnewmap_increase_size(onm); | |||||
| } | |||||
| OldNew entry; | |||||
| entry.oldp = oldaddr; | |||||
| entry.newp = newaddr; | |||||
| entry.nr = nr; | |||||
| oldnewmap_insert_or_replace(onm, entry); | |||||
| } | } | ||||
| static void oldnewmap_lib_insert(FileData *fd, const void *oldaddr, ID *newaddr, int nr) | static void oldnewmap_lib_insert(FileData *fd, const void *oldaddr, ID *newaddr, int nr) | ||||
| { | { | ||||
| oldnewmap_insert(fd->libmap, oldaddr, newaddr, nr); | oldnewmap_insert(fd->libmap, oldaddr, newaddr, nr); | ||||
| } | } | ||||
| void blo_do_versions_oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr) | void blo_do_versions_oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr) | ||||
| { | { | ||||
| oldnewmap_insert(onm, oldaddr, newaddr, nr); | oldnewmap_insert(onm, oldaddr, newaddr, nr); | ||||
| } | } | ||||
| static void *oldnewmap_lookup_and_inc(OldNewMap *onm, const void *addr, bool increase_users) | static void *oldnewmap_lookup_and_inc(OldNewMap *onm, const void *addr, bool increase_users) | ||||
| { | { | ||||
| OldNew *entry = oldnewmap_lookup_entry(onm, addr); | NewAddress *entry = onm->map.lookup_ptr(addr); | ||||
| if (entry == nullptr) { | if (entry == nullptr) { | ||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| if (increase_users) { | if (increase_users) { | ||||
| entry->nr++; | entry->nr++; | ||||
| } | } | ||||
| return entry->newp; | return entry->newp; | ||||
| } | } | ||||
| /* for libdata, OldNew.nr has ID code, no increment */ | /* for libdata, NewAddress.nr has ID code, no increment */ | ||||
| static void *oldnewmap_liblookup(OldNewMap *onm, const void *addr, const void *lib) | static void *oldnewmap_liblookup(OldNewMap *onm, const void *addr, const void *lib) | ||||
| { | { | ||||
| if (addr == nullptr) { | if (addr == nullptr) { | ||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| ID *id = static_cast<ID *>(oldnewmap_lookup_and_inc(onm, addr, false)); | ID *id = static_cast<ID *>(oldnewmap_lookup_and_inc(onm, addr, false)); | ||||
| if (id == nullptr) { | if (id == nullptr) { | ||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| if (!lib || id->lib) { | if (!lib || id->lib) { | ||||
| return id; | return id; | ||||
| } | } | ||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| static void oldnewmap_clear(OldNewMap *onm) | static void oldnewmap_clear(OldNewMap *onm) | ||||
| { | { | ||||
| /* Free unused data. */ | /* Free unused data. */ | ||||
| for (int i = 0; i < onm->nentries; i++) { | for (NewAddress &new_addr : onm->map.values()) { | ||||
| OldNew *entry = &onm->entries[i]; | if (new_addr.nr == 0) { | ||||
| if (entry->nr == 0) { | MEM_freeN(new_addr.newp); | ||||
| MEM_freeN(entry->newp); | |||||
| entry->newp = nullptr; | |||||
| } | } | ||||
| } | } | ||||
| onm->map.clear(); | |||||
| MEM_freeN(onm->entries); | |||||
| MEM_freeN(onm->map); | |||||
| oldnewmap_init_data(onm, DEFAULT_SIZE_EXP); | |||||
| } | } | ||||
| static void oldnewmap_free(OldNewMap *onm) | static void oldnewmap_free(OldNewMap *onm) | ||||
| { | { | ||||
| MEM_freeN(onm->entries); | MEM_delete(onm); | ||||
| MEM_freeN(onm->map); | |||||
| MEM_freeN(onm); | |||||
| } | } | ||||
| #undef ENTRIES_CAPACITY | |||||
| #undef MAP_CAPACITY | |||||
| #undef SLOT_MASK | |||||
| #undef DEFAULT_SIZE_EXP | |||||
| #undef PERTURB_SHIFT | |||||
| #undef ITER_SLOTS | |||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Helper Functions | /** \name Helper Functions | ||||
| * \{ */ | * \{ */ | ||||
| static void add_main_to_main(Main *mainvar, Main *from) | static void add_main_to_main(Main *mainvar, Main *from) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 1,108 Lines • ▼ Show 20 Lines | void *blo_do_versions_newlibadr(FileData *fd, const void *lib, const void *adr) | ||||
| return newlibadr(fd, lib, adr); | return newlibadr(fd, lib, adr); | ||||
| } | } | ||||
| /* increases user number */ | /* increases user number */ | ||||
| static void change_link_placeholder_to_real_ID_pointer_fd(FileData *fd, | static void change_link_placeholder_to_real_ID_pointer_fd(FileData *fd, | ||||
| const void *old, | const void *old, | ||||
| void *newp) | void *newp) | ||||
| { | { | ||||
| for (int i = 0; i < fd->libmap->nentries; i++) { | for (NewAddress &entry : fd->libmap->map.values()) { | ||||
| OldNew *entry = &fd->libmap->entries[i]; | if (old == entry.newp && entry.nr == ID_LINK_PLACEHOLDER) { | ||||
| entry.newp = newp; | |||||
| if (old == entry->newp && entry->nr == ID_LINK_PLACEHOLDER) { | |||||
| entry->newp = newp; | |||||
| if (newp) { | if (newp) { | ||||
| entry->nr = GS(((ID *)newp)->name); | entry.nr = GS(((ID *)newp)->name); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void change_link_placeholder_to_real_ID_pointer(ListBase *mainlist, | static void change_link_placeholder_to_real_ID_pointer(ListBase *mainlist, | ||||
| FileData *basefd, | FileData *basefd, | ||||
| void *old, | void *old, | ||||
| ▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | LISTBASE_FOREACH (Library *, lib, &oldmain->libraries) { | ||||
| if (lib->packedfile) { | if (lib->packedfile) { | ||||
| insert_packedmap(fd, lib->packedfile); | insert_packedmap(fd, lib->packedfile); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void blo_end_packed_pointer_map(FileData *fd, Main *oldmain) | void blo_end_packed_pointer_map(FileData *fd, Main *oldmain) | ||||
| { | { | ||||
| OldNew *entry = fd->packedmap->entries; | |||||
| /* used entries were restored, so we put them to zero */ | /* used entries were restored, so we put them to zero */ | ||||
| for (int i = 0; i < fd->packedmap->nentries; i++, entry++) { | for (NewAddress &entry : fd->packedmap->map.values()) { | ||||
| if (entry->nr > 0) { | if (entry.nr > 0) { | ||||
| entry->newp = nullptr; | entry.newp = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| LISTBASE_FOREACH (Image *, ima, &oldmain->images) { | LISTBASE_FOREACH (Image *, ima, &oldmain->images) { | ||||
| ima->packedfile = static_cast<PackedFile *>(newpackedadr(fd, ima->packedfile)); | ima->packedfile = static_cast<PackedFile *>(newpackedadr(fd, ima->packedfile)); | ||||
| LISTBASE_FOREACH (ImagePackedFile *, imapf, &ima->packedfiles) { | LISTBASE_FOREACH (ImagePackedFile *, imapf, &ima->packedfiles) { | ||||
| imapf->packedfile = static_cast<PackedFile *>(newpackedadr(fd, imapf->packedfile)); | imapf->packedfile = static_cast<PackedFile *>(newpackedadr(fd, imapf->packedfile)); | ||||
| ▲ Show 20 Lines • Show All 3,557 Lines • Show Last 20 Lines | |||||