dna_genfile: add SDNA struct/elem queries that use alias names
authorCampbell Barton <ideasman42@gmail.com>
Tue, 21 May 2019 23:15:06 +0000 (09:15 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 21 May 2019 23:19:05 +0000 (09:19 +1000)
Allow versioning code to use checks which use run-time naming
instead of the old names which are only listed in dna_rename_defs.h.

Addresses T64791.

source/blender/makesdna/DNA_genfile.h
source/blender/makesdna/DNA_sdna_types.h
source/blender/makesdna/intern/dna_genfile.c

index 6a9d50e..dc4f551 100644 (file)
@@ -121,4 +121,15 @@ bool DNA_sdna_patch_struct_member(struct SDNA *sdna,
 
 void DNA_sdna_alias_data_ensure(struct SDNA *sdna);
 
+/* Alias lookups (using runtime struct member names). */
+int DNA_struct_alias_find_nr_ex(const struct SDNA *sdna,
+                                const char *str,
+                                unsigned int *index_last);
+int DNA_struct_alias_find_nr(const struct SDNA *sdna, const char *str);
+bool DNA_struct_alias_elem_find(const struct SDNA *sdna,
+                                const char *stype,
+                                const char *vartype,
+                                const char *name);
+void DNA_sdna_alias_data_ensure_structs_map(struct SDNA *sdna);
+
 #endif /* __DNA_GENFILE_H__ */
index efd3dbe..efa7a30 100644 (file)
@@ -75,6 +75,8 @@ typedef struct SDNA {
     const char **names;
     /** Aligned with #SDNA.types, same pointers when unchanged. */
     const char **types;
+    /** A version of #SDNA.structs_map that uses #SDNA.alias.types for it's keys. */
+    struct GHash *structs_map;
   } alias;
 } SDNA;
 
index 2e89629..82c356a 100644 (file)
@@ -39,9 +39,7 @@
 #include "BLI_memarena.h"
 #include "BLI_string.h"
 
-#ifdef WITH_DNA_GHASH
-#  include "BLI_ghash.h"
-#endif
+#include "BLI_ghash.h"
 
 #include "DNA_genfile.h"
 #include "DNA_sdna_types.h"  // for SDNA ;-)
@@ -161,6 +159,11 @@ void DNA_sdna_free(SDNA *sdna)
 
   MEM_SAFE_FREE(sdna->alias.names);
   MEM_SAFE_FREE(sdna->alias.types);
+#ifdef WITH_DNA_GHASH
+  if (sdna->alias.structs_map) {
+    BLI_ghash_free(sdna->alias.structs_map, NULL, NULL);
+  }
+#endif
 
   MEM_freeN(sdna);
 }
@@ -222,18 +225,29 @@ static void printstruct(SDNA *sdna, short strnr)
 /**
  * Returns the index of the struct info for the struct with the specified name.
  */
-int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last)
+static int dna_struct_find_nr_ex_impl(
+    /* From SDNA struct. */
+    const char **types,
+    const int UNUSED(types_len),
+    short **const structs,
+    const int structs_len,
+#ifdef WITH_DNA_GHASH
+    GHash *structs_map,
+#endif
+    /* Regular args. */
+    const char *str,
+    unsigned int *index_last)
 {
-  if (*index_last < sdna->structs_len) {
-    const short *sp = sdna->structs[*index_last];
-    if (STREQ(sdna->types[sp[0]], str)) {
+  if (*index_last < structs_len) {
+    const short *sp = structs[*index_last];
+    if (STREQ(types[sp[0]], str)) {
       return *index_last;
     }
   }
 
 #ifdef WITH_DNA_GHASH
   {
-    void **index_p = BLI_ghash_lookup_p(sdna->structs_map, str);
+    void **index_p = BLI_ghash_lookup_p(structs_map, str);
     if (index_p) {
       const int index = POINTER_AS_INT(*index_p);
       *index_last = index;
@@ -242,9 +256,9 @@ int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index
   }
 #else
   {
-    for (int index = 0; index < sdna->structs_len; index++) {
-      const short *sp = sdna->structs[index];
-      if (STREQ(sdna->types[sp[0]], str)) {
+    for (int index = 0; index < structs_len; index++) {
+      const short *sp = structs[index];
+      if (STREQ(types[sp[0]], str)) {
         *index_last = index;
         return index;
       }
@@ -254,12 +268,58 @@ int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index
   return -1;
 }
 
+/**
+ * Returns the index of the struct info for the struct with the specified name.
+ */
+int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last)
+{
+  return dna_struct_find_nr_ex_impl(
+      /* Expand SDNA. */
+      sdna->types,
+      sdna->types_len,
+      sdna->structs,
+      sdna->structs_len,
+#ifdef WITH_DNA_GHASH
+      sdna->structs_map,
+#endif
+      /* Regular args. */
+      str,
+      index_last);
+}
+
+/** \note requires #DNA_sdna_alias_data_ensure_structs_map to be called. */
+int DNA_struct_alias_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last)
+{
+#ifdef WITH_DNA_GHASH
+  BLI_assert(sdna->alias.structs_map != NULL);
+#endif
+  return dna_struct_find_nr_ex_impl(
+      /* Expand SDNA. */
+      sdna->alias.types,
+      sdna->types_len,
+      sdna->structs,
+      sdna->structs_len,
+#ifdef WITH_DNA_GHASH
+      sdna->alias.structs_map,
+#endif
+      /* Regular args. */
+      str,
+      index_last);
+}
+
 int DNA_struct_find_nr(const SDNA *sdna, const char *str)
 {
   unsigned int index_last_dummy = UINT_MAX;
   return DNA_struct_find_nr_ex(sdna, str, &index_last_dummy);
 }
 
+/** \note requires #DNA_sdna_alias_data_ensure_structs_map to be called. */
+int DNA_struct_alias_find_nr(const SDNA *sdna, const char *str)
+{
+  unsigned int index_last_dummy = UINT_MAX;
+  return DNA_struct_alias_find_nr_ex(sdna, str, &index_last_dummy);
+}
+
 /* ************************* END DIV ********************** */
 
 /* ************************* READ DNA ********************** */
@@ -909,7 +969,14 @@ static int elem_strcmp(const char *name, const char *oname)
  * \param old: Pointer to struct information in sdna
  * \return true when existing, false otherwise.
  */
-static bool elem_exists(const SDNA *sdna, const char *type, const char *name, const short *old)
+static bool elem_exists_impl(
+    /* Expand SDNA. */
+    const char **types,
+    const char **names,
+    /* Regular args. */
+    const char *type,
+    const char *name,
+    const short *old)
 {
   int a, elemcount;
   const char *otype, *oname;
@@ -918,8 +985,8 @@ static bool elem_exists(const SDNA *sdna, const char *type, const char *name, co
   elemcount = old[1];
   old += 2;
   for (a = 0; a < elemcount; a++, old += 2) {
-    otype = sdna->types[old[0]];
-    oname = sdna->names[old[1]];
+    otype = types[old[0]];
+    oname = names[old[1]];
 
     if (elem_strcmp(name, oname) == 0) { /* name equal */
       return strcmp(type, otype) == 0;   /* type equal */
@@ -928,6 +995,33 @@ static bool elem_exists(const SDNA *sdna, const char *type, const char *name, co
   return false;
 }
 
+static bool elem_exists(const SDNA *sdna, const char *type, const char *name, const short *old)
+{
+  return elem_exists_impl(
+      /* Expand SDNA. */
+      sdna->types,
+      sdna->names,
+      /* Regular args. */
+      type,
+      name,
+      old);
+}
+
+static bool elem_exists_alias(const SDNA *sdna,
+                              const char *type,
+                              const char *name,
+                              const short *old)
+{
+  return elem_exists_impl(
+      /* Expand SDNA. */
+      sdna->alias.types,
+      sdna->alias.names,
+      /* Regular args. */
+      type,
+      name,
+      old);
+}
+
 /**
  * Returns the address of the data for the specified field within olddata
  * according to the struct format pointed to by old, or NULL if no such
@@ -1384,6 +1478,25 @@ bool DNA_struct_elem_find(const SDNA *sdna,
   return false;
 }
 
+/** \note requires #DNA_sdna_alias_data_ensure_structs_map to be called. */
+bool DNA_struct_alias_elem_find(const SDNA *sdna,
+                                const char *stype,
+                                const char *vartype,
+                                const char *name)
+{
+  const int SDNAnr = DNA_struct_alias_find_nr(sdna, stype);
+
+  if (SDNAnr != -1) {
+    const short *const spo = sdna->structs[SDNAnr];
+    const bool found = elem_exists_alias(sdna, vartype, name, spo);
+
+    if (found) {
+      return true;
+    }
+  }
+  return false;
+}
+
 /**
  * Returns the size in bytes of a primitive type.
  */
@@ -1629,4 +1742,24 @@ void DNA_sdna_alias_data_ensure(SDNA *sdna)
   BLI_ghash_free(elem_map_alias_from_static, MEM_freeN, NULL);
 }
 
+/**
+ * Separated from #DNA_sdna_alias_data_ensure because it's not needed
+ * unless we want to lookup aliased struct names (#DNA_struct_alias_find_nr and friends).
+ */
+void DNA_sdna_alias_data_ensure_structs_map(SDNA *sdna)
+{
+  DNA_sdna_alias_data_ensure(sdna);
+#ifdef WITH_DNA_GHASH
+  /* create a ghash lookup to speed up */
+  struct GHash *structs_map = BLI_ghash_str_new_ex(__func__, sdna->structs_len);
+  for (intptr_t nr = 0; nr < sdna->structs_len; nr++) {
+    const short *sp = sdna->structs[nr];
+    BLI_ghash_insert(structs_map, (void *)sdna->alias.types[sp[0]], POINTER_FROM_INT(nr));
+  }
+  sdna->alias.structs_map = structs_map;
+#else
+  UNUSED_VARS(sdna);
+#endif
+}
+
 /** \} */