From a2f345468c94e4b8a842ba9a9988237cd5c8194f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 12 Feb 2019 11:43:33 +1100 Subject: DNA: support DNA type & name aliases This allows us to rename struct & struct members in the source code without changing the file format. This is useful because the code becomes increasingly confusing when names such as oops, ipo & dupli aren't used anywhere except DNA headers. dna_rename_defs.h is used to define renaming operations. The renaming it's self will be done separately. --- source/blender/makesdna/intern/CMakeLists.txt | 4 + source/blender/makesdna/intern/dna_genfile.c | 124 ++++++++++++++++++++++- source/blender/makesdna/intern/dna_rename_defs.h | 47 +++++++++ source/blender/makesdna/intern/dna_utils.c | 95 +++++++++++++++++ source/blender/makesdna/intern/dna_utils.h | 10 ++ source/blender/makesdna/intern/makesdna.c | 101 ++++++++++++++++-- 6 files changed, 373 insertions(+), 8 deletions(-) create mode 100644 source/blender/makesdna/intern/dna_rename_defs.h (limited to 'source/blender/makesdna/intern') diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt index 4d6ad4b4389..294fb861912 100644 --- a/source/blender/makesdna/intern/CMakeLists.txt +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -35,7 +35,11 @@ blender_include_dirs( set(SRC dna_utils.c makesdna.c + ../../blenlib/intern/BLI_ghash.c + ../../blenlib/intern/BLI_ghash_utils.c ../../blenlib/intern/BLI_memarena.c + ../../blenlib/intern/BLI_mempool.c + ../../blenlib/intern/hash_mm2a.c # needed by 'BLI_ghash_utils.c', not used directly. ../../../../intern/guardedalloc/intern/mallocn.c ../../../../intern/guardedalloc/intern/mallocn_guarded_impl.c ../../../../intern/guardedalloc/intern/mallocn_lockfree_impl.c diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c index cef152fb45d..078cda2ac16 100644 --- a/source/blender/makesdna/intern/dna_genfile.c +++ b/source/blender/makesdna/intern/dna_genfile.c @@ -156,6 +156,9 @@ void DNA_sdna_free(SDNA *sdna) BLI_memarena_free(sdna->mem_arena); } + MEM_SAFE_FREE(sdna->alias.names); + MEM_SAFE_FREE(sdna->alias.types); + MEM_freeN(sdna); } @@ -311,6 +314,9 @@ static bool init_structDNA( #endif sdna->mem_arena = NULL; + /* Lazy initialize. */ + memset(&sdna->alias, 0, sizeof(sdna->alias)); + /* Struct DNA ('SDNA') */ if (*data != MAKE_ID('S', 'D', 'N', 'A')) { *r_error_message = "SDNA error in SDNA file"; @@ -1387,7 +1393,6 @@ static bool DNA_sdna_patch_struct_nr( BLI_ghash_remove(sdna->structs_map, (void *)sdna->types[sp[0]], NULL, NULL); BLI_ghash_insert(sdna->structs_map, (void *)struct_name_new, POINTER_FROM_INT(struct_name_old_nr)); #endif - // printf("Struct rename: %s -> %s\n", sdna->types[struct_name_old_nr], struct_name_new); sdna->types[sp[0]] = struct_name_new; return true; } @@ -1408,6 +1413,9 @@ bool DNA_sdna_patch_struct( static bool DNA_sdna_patch_struct_member_nr( SDNA *sdna, const int struct_name_nr, const char *elem_old, const char *elem_new) { + /* These names aren't handled here (it's not used). + * Ensure they are never used or we get out of sync arrays. */ + BLI_assert(sdna->alias.names == NULL); const int elem_old_len = strlen(elem_old); const int elem_new_len = strlen(elem_new); BLI_assert(elem_new != NULL); @@ -1454,3 +1462,117 @@ bool DNA_sdna_patch_struct_member( } /** \} */ + + +/* -------------------------------------------------------------------- */ +/** \name Versioning (Forward Compatible) + * + * Versioning that allows new names. + * \{ */ + +/** + * Names are shared between structs which causes problems renaming. + * Make sure every struct member gets it's own name so renaming only ever impacts a single struct. + * + * The resulting SDNA is never written to disk. + */ +static void sdna_expand_names(SDNA *sdna) +{ + int names_expand_len = 0; + for (int struct_nr = 0; struct_nr < sdna->nr_structs; struct_nr++) { + const short *sp = sdna->structs[struct_nr]; + names_expand_len += sp[1]; + } + const char **names_expand = MEM_mallocN(sizeof(*names_expand) * names_expand_len, __func__); + + int names_expand_index = 0; + for (int struct_nr = 0; struct_nr < sdna->nr_structs; struct_nr++) { + /* We can't edit this memory 'sdna->structs' points to (readonly datatoc file). */ + const short *sp = sdna->structs[struct_nr]; + short *sp_expand = BLI_memarena_alloc(sdna->mem_arena, sizeof(short[2]) * (1 + sp[1])); + memcpy(sp_expand, sp, sizeof(short[2]) * (1 + sp[1])); + sdna->structs[struct_nr] = sp_expand; + const int names_len = sp[1]; + sp += 2; + sp_expand += 2; + for (int i = 0; i < names_len; i++, sp += 2, sp_expand += 2) { + names_expand[names_expand_index] = sdna->names[sp[1]]; + BLI_assert(names_expand_index < SHRT_MAX); + sp_expand[1] = names_expand_index; + names_expand_index++; + } + } + MEM_freeN((void *)sdna->names); + sdna->names = names_expand; + sdna->nr_names = names_expand_len; +} + +static const char *dna_sdna_alias_alias_from_static_elem_full( + SDNA *sdna, GHash *elem_map_alias_from_static, + const char *struct_name_static, const char *elem_static_full) +{ + const int elem_static_full_len = strlen(elem_static_full); + char *elem_static = alloca(elem_static_full_len + 1); + const int elem_static_len = DNA_elem_id_strip_copy(elem_static, elem_static_full); + const char *str_pair[2] = {struct_name_static, elem_static}; + const char *elem_alias = BLI_ghash_lookup(elem_map_alias_from_static, str_pair); + if (elem_alias) { + return DNA_elem_id_rename( + sdna->mem_arena, + elem_static, elem_static_len, + elem_alias, strlen(elem_alias), + elem_static_full, elem_static_full_len, + DNA_elem_id_offset_start(elem_static_full)); + } + return NULL; +} + +void DNA_sdna_alias_data_ensure(SDNA *sdna) +{ + if (sdna->mem_arena == NULL) { + sdna->mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + } + + GHash *struct_map_alias_from_static; + GHash *elem_map_alias_from_static; + + DNA_alias_maps( + DNA_RENAME_ALIAS_FROM_STATIC, + &struct_map_alias_from_static, + &elem_map_alias_from_static); + + + if (sdna->alias.types == NULL) { + sdna->alias.types = MEM_mallocN(sizeof(*sdna->alias.types) * sdna->nr_types, __func__); + for (int type_nr = 0; type_nr < sdna->nr_types; type_nr++) { + const char *str = sdna->types[type_nr]; + sdna->alias.types[type_nr] = BLI_ghash_lookup_default( + struct_map_alias_from_static, str, (void *)str); + } + } + + if (sdna->alias.names == NULL) { + sdna_expand_names(sdna); + sdna->alias.names = MEM_mallocN(sizeof(*sdna->alias.names) * sdna->nr_names, __func__); + for (int struct_nr = 0; struct_nr < sdna->nr_structs; struct_nr++) { + const short *sp = sdna->structs[struct_nr]; + const char *struct_name_static = sdna->types[sp[0]]; + const int dna_struct_names_len = sp[1]; + sp += 2; + for (int a = 0; a < dna_struct_names_len; a++, sp += 2) { + const char *elem_alias_full = dna_sdna_alias_alias_from_static_elem_full( + sdna, elem_map_alias_from_static, struct_name_static, sdna->names[sp[1]]); + if (elem_alias_full != NULL) { + sdna->alias.names[sp[1]] = elem_alias_full; + } + else { + sdna->alias.names[sp[1]] = sdna->names[sp[1]]; + } + } + } + } + BLI_ghash_free(struct_map_alias_from_static, NULL, NULL); + BLI_ghash_free(elem_map_alias_from_static, MEM_freeN, NULL); +} + +/** \} */ diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h new file mode 100644 index 00000000000..cdf13e7103d --- /dev/null +++ b/source/blender/makesdna/intern/dna_rename_defs.h @@ -0,0 +1,47 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * DNA handling + */ + +/** \file \ingroup DNA + * + * Defines in this header are only used to define blend file storage. + * This allows us to rename variables & structs without breaking compatibility. + * + * - When renaming the member of a struct which has it's self been renamed + * refer to the newer name, not the original. + * + * - Changes here only change generated code for `makesdna.c` and `makesrna.c` + * without impacting Blender's run-time, besides allowing us to use the new names. + * + * - Renaming something that has already been renamed can be done by editing the existing rename macro. + * All references to the previous destination name can be removed since they're + * never written to disk. + * + * \see versioning_dna.c for a actual version patching. + */ + +/* No include guard (intentional). */ + +/* Match RNA names where possible. */ +#if 0 +DNA_STRUCT_RENAME(Lamp, Light) +DNA_STRUCT_RENAME(SpaceOops, SpaceOutliner) +DNA_STRUCT_RENAME_ELEM(Camera, YF_dofdist, dof_distance) +DNA_STRUCT_RENAME_ELEM(Object, dup_group, instance_collection) +#endif diff --git a/source/blender/makesdna/intern/dna_utils.c b/source/blender/makesdna/intern/dna_utils.c index 44ad13dc669..e696082dee1 100644 --- a/source/blender/makesdna/intern/dna_utils.c +++ b/source/blender/makesdna/intern/dna_utils.c @@ -23,9 +23,12 @@ #include +#include "MEM_guardedalloc.h" + #include "BLI_sys_types.h" #include "BLI_utildefines.h" #include "BLI_assert.h" +#include "BLI_ghash.h" #include "BLI_memarena.h" @@ -185,3 +188,95 @@ char *DNA_elem_id_rename( } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Versioning + * \{ */ + +static uint strhash_pair_p(const void *ptr) +{ + const char * const *pair = ptr; + return (BLI_ghashutil_strhash_p(pair[0]) ^ + BLI_ghashutil_strhash_p(pair[1])); +} + +static bool strhash_pair_cmp(const void *a, const void *b) +{ + const char * const *pair_a = a; + const char * const *pair_b = b; + return (STREQ(pair_a[0], pair_b[0]) && + STREQ(pair_a[1], pair_b[1])) ? false : true; +} + +void DNA_alias_maps( + enum eDNA_RenameDir version_dir, + GHash **r_struct_map, GHash **r_elem_map) +{ + GHash *struct_map_local = NULL; + if (r_struct_map) { + const char *data[][2] = { +#define DNA_STRUCT_RENAME(old, new) {#old, #new}, +#define DNA_STRUCT_RENAME_ELEM(struct_name, old, new) +#include "dna_rename_defs.h" +#undef DNA_STRUCT_RENAME +#undef DNA_STRUCT_RENAME_ELEM + }; + + int elem_key, elem_val; + if (version_dir == DNA_RENAME_ALIAS_FROM_STATIC) { + elem_key = 0; + elem_val = 1; + } + else { + elem_key = 1; + elem_val = 0; + } + GHash *struct_map = BLI_ghash_str_new_ex(__func__, ARRAY_SIZE(data)); + for (int i = 0; i < ARRAY_SIZE(data); i++) { + BLI_ghash_insert(struct_map, (void *)data[i][elem_key], (void *)data[i][elem_val]); + } + *r_struct_map = struct_map; + + /* We know the direction of this, for local use. */ + struct_map_local = BLI_ghash_str_new_ex(__func__, ARRAY_SIZE(data)); + for (int i = 0; i < ARRAY_SIZE(data); i++) { + BLI_ghash_insert(struct_map_local, (void *)data[i][1], (void *)data[i][0]); + } + } + + if (r_elem_map != NULL) { + const char *data[][3] = { +#define DNA_STRUCT_RENAME(old, new) +#define DNA_STRUCT_RENAME_ELEM(struct_name, old, new) {#struct_name, #old, #new}, +#include "dna_rename_defs.h" +#undef DNA_STRUCT_RENAME +#undef DNA_STRUCT_RENAME_ELEM + }; + + int elem_key, elem_val; + if (version_dir == DNA_RENAME_ALIAS_FROM_STATIC) { + elem_key = 1; + elem_val = 2; + } + else { + elem_key = 2; + elem_val = 1; + } + GHash *elem_map = BLI_ghash_new_ex(strhash_pair_p, strhash_pair_cmp, __func__, ARRAY_SIZE(data)); + for (int i = 0; i < ARRAY_SIZE(data); i++) { + const char **str_pair = MEM_mallocN(sizeof(char *) * 2, __func__); + str_pair[0] = BLI_ghash_lookup_default(struct_map_local, data[i][0], (void *)data[i][0]); + str_pair[1] = data[i][elem_key], + BLI_ghash_insert(elem_map, str_pair, (void *)data[i][elem_val]); + } + *r_elem_map = elem_map; + } + + if (struct_map_local) { + BLI_ghash_free(struct_map_local, NULL, NULL); + } +} + +#undef DNA_MAKESDNA + +/** \} */ diff --git a/source/blender/makesdna/intern/dna_utils.h b/source/blender/makesdna/intern/dna_utils.h index d7cf4212971..1a1f5201310 100644 --- a/source/blender/makesdna/intern/dna_utils.h +++ b/source/blender/makesdna/intern/dna_utils.h @@ -21,6 +21,7 @@ #define __DNA_UTILS_H__ struct MemArena; +struct GHash; int DNA_elem_array_size(const char *str); @@ -39,4 +40,13 @@ char *DNA_elem_id_rename( const char *elem_full_src, const int elem_full_src_len, const uint elem_full_offset_start); +/* When requesting version info, support both directions. */ +enum eDNA_RenameDir { + DNA_RENAME_STATIC_FROM_ALIAS = -1, + DNA_RENAME_ALIAS_FROM_STATIC = 1, +}; +void DNA_alias_maps( + enum eDNA_RenameDir version_dir, + struct GHash **r_struct_map, struct GHash **r_elem_map); + #endif /* __DNA_UTILS_H__ */ diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index e8a8bf3fba7..952318482bb 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -43,11 +43,15 @@ #include #include #include +#include #include "MEM_guardedalloc.h" -#include "BLI_sys_types.h" /* for intptr_t support */ +#include "BLI_utildefines.h" +#include "BLI_alloca.h" +#include "BLI_ghash.h" #include "BLI_memarena.h" +#include "BLI_sys_types.h" /* for intptr_t support */ #include "dna_utils.h" @@ -157,6 +161,14 @@ static short *typelens_64; * sp[1] is amount of elements * sp[2] sp[3] is typenr, namenr (etc) */ static short **structs, *structdata; + +/** Versioning data */ +static struct { + GHash *struct_map_alias_from_static; + GHash *struct_map_static_from_alias; + GHash *elem_map_static_from_alias; +} g_version_data = {NULL}; + /** * Variable to control debug output of makesdna. * debugSDNA: @@ -174,7 +186,6 @@ static int additional_slen_offset; /* stub for BLI_abort() */ #ifndef NDEBUG -void BLI_system_backtrace(FILE *fp); void BLI_system_backtrace(FILE *fp) { (void)fp; @@ -242,6 +253,44 @@ void printStructLengths(void); * Make DNA string (write to file). * \{ */ + +static const char *version_struct_static_from_alias(const char *str) +{ + const char *str_test = BLI_ghash_lookup(g_version_data.struct_map_static_from_alias, str); + if (str_test != NULL) { + return str_test; + } + return str; +} + +static const char *version_struct_alias_from_static(const char *str) +{ + const char *str_test = BLI_ghash_lookup(g_version_data.struct_map_alias_from_static, str); + if (str_test != NULL) { + return str_test; + } + return str; +} + +static const char *version_elem_static_from_alias( + const int strct, const char *elem_alias_full) +{ + const uint elem_alias_full_len = strlen(elem_alias_full); + char *elem_alias = alloca(elem_alias_full_len + 1); + const int elem_alias_len = DNA_elem_id_strip_copy(elem_alias, elem_alias_full); + const char *str_pair[2] = {types[strct], elem_alias}; + const char *elem_static = BLI_ghash_lookup(g_version_data.elem_map_static_from_alias, str_pair); + if (elem_static != NULL) { + return DNA_elem_id_rename( + mem_arena, + elem_alias, elem_alias_len, + elem_static, strlen(elem_static), + elem_alias_full, elem_alias_full_len, + DNA_elem_id_offset_start(elem_alias_full)); + } + return elem_alias_full; +} + static int add_type(const char *str, int len) { int nr; @@ -257,6 +306,8 @@ static int add_type(const char *str, int len) return -1; } + str = version_struct_static_from_alias(str); + /* search through type array */ for (nr = 0; nr < nr_types; nr++) { if (strcmp(str, types[nr]) == 0) { @@ -676,8 +727,7 @@ static int convert_include(const char *filename) if (md1[slen - 1] == ';') { md1[slen - 1] = 0; - - name = add_name(md1); + name = add_name(version_elem_static_from_alias(strct, md1)); slen += additional_slen_offset; sp[0] = type; sp[1] = name; @@ -693,8 +743,7 @@ static int convert_include(const char *filename) break; } - - name = add_name(md1); + name = add_name(version_elem_static_from_alias(strct, md1)); slen += additional_slen_offset; sp[0] = type; @@ -1008,6 +1057,16 @@ static int make_structDNA(const char *baseDirectory, FILE *file, FILE *file_offs typelens_64 = MEM_callocN(sizeof(short) * maxnr, "typelens_64"); structs = MEM_callocN(sizeof(short *) * maxnr, "structs"); + /* Build versioning data */ + DNA_alias_maps( + DNA_RENAME_ALIAS_FROM_STATIC, + &g_version_data.struct_map_alias_from_static, + NULL); + DNA_alias_maps( + DNA_RENAME_STATIC_FROM_ALIAS, + &g_version_data.struct_map_static_from_alias, + &g_version_data.elem_map_static_from_alias); + /** * Insertion of all known types. * @@ -1190,12 +1249,36 @@ static int make_structDNA(const char *baseDirectory, FILE *file, FILE *file_offs for (i = 0; i < nr_structs; i++) { const short *structpoin = structs[i]; const int structtype = structpoin[0]; - fprintf(file_offsets, "\t_SDNA_TYPE_%s = %d,\n", types[structtype], i); + fprintf(file_offsets, "\t_SDNA_TYPE_%s = %d,\n", version_struct_alias_from_static(types[structtype]), i); } fprintf(file_offsets, "\tSDNA_TYPE_MAX = %d,\n", nr_structs); fprintf(file_offsets, "};\n"); } + /* Check versioning errors which could cause duplicate names, + * do last because names are stripped. */ + { + GSet *names_unique = BLI_gset_str_new_ex(__func__, 512); + for (int struct_nr = 0; struct_nr < nr_structs; struct_nr++) { + sp = structs[struct_nr]; + const char *struct_name = types[sp[0]]; + const int len = sp[1]; + sp += 2; + for (int a = 0; a < len; a++, sp += 2) { + char *name = names[sp[1]]; + DNA_elem_id_strip(name); + if (!BLI_gset_add(names_unique, name)) { + fprintf(stderr, "Error: duplicate name found '%s.%s', " + "likely cause is 'dna_rename_defs.h'\n", + struct_name, name); + return 1; + } + } + BLI_gset_clear(names_unique, NULL); + } + BLI_gset_free(names_unique, NULL); + } + MEM_freeN(structdata); MEM_freeN(names); MEM_freeN(types); @@ -1206,6 +1289,10 @@ static int make_structDNA(const char *baseDirectory, FILE *file, FILE *file_offs BLI_memarena_free(mem_arena); + BLI_ghash_free(g_version_data.struct_map_alias_from_static, NULL, NULL); + BLI_ghash_free(g_version_data.struct_map_static_from_alias, NULL, NULL); + BLI_ghash_free(g_version_data.elem_map_static_from_alias, MEM_freeN, NULL); + DEBUG_PRINTF(0, "done.\n"); return 0; -- cgit v1.2.3