Explorar o código

ncd: store variable names as strings one after another, instead of with arrays of pointers. Also make
NCDObject_ResolveObjExprCompact() take size_t not int, to be consistent with the newly added NCDObject_ResolveVarExprCompact().

ambrop7 %!s(int64=13) %!d(string=hai) anos
pai
achega
3d71336ec3
Modificáronse 6 ficheiros con 178 adicións e 19 borrados
  1. 120 0
      misc/split_string.h
  2. 28 1
      ncd/NCDObject.c
  3. 2 1
      ncd/NCDObject.h
  4. 15 6
      ncd/NCDPlaceholderDb.c
  5. 3 2
      ncd/NCDPlaceholderDb.h
  6. 10 9
      ncd/ncd.c

+ 120 - 0
misc/split_string.h

@@ -10,6 +10,78 @@
 #include <misc/debug.h>
 #include <misc/expstring.h>
 
+/**
+ * Splits the given string by a character, and returns the result
+ * as a malloc'd array of char pointers, each malloc'd. The array
+ * is terminated by a NULL pointer.
+ * 
+ * @param str string to split
+ * @param del delimiter character
+ * @return pointer to array of strings, or NULL on failure. On success,
+ *         at least one string will always be returned.
+ */
+static char ** split_string (const char *str, char del);
+
+/**
+ * Counts the number of strings in an array (same format as used by
+ * {@link split_string}).
+ * 
+ * @param names pointer to array of strings; must not be NULL.
+ * @return number of strings
+ */
+static size_t count_strings (char **names);
+
+/**
+ * Frees an array of strings (same format as used by
+ * {@link split_string}). This first frees the individual strings,
+ * then the whole array.
+ * 
+ * @param names pointer to array of strings; must not be NULL.
+ */
+static void free_strings (char **names);
+
+/**
+ * Concatenates the given strings, inserting a delimiter character
+ * in between. The result is returned as a newly malloc'd string.
+ * If there are no strings, an empty string is produced.
+ * If there is just one string, this string is copied.
+ * 
+ * @param names pointer to array of strings; must not be NULL.
+ *              Format is as returned by {@link split_string}.
+ * @param del delimiter to insert between strings
+ * @return resulting malloc'd string, or NULL on failure.
+ */
+static char * implode_strings (char **names, char del);
+
+/**
+ * Splits the given string by a character in-place by replacing
+ * all delimiting characters with nulls, and returns the number
+ * of such replacements.
+ * 
+ * @param str string to split in-place; must not be NULL.
+ * @param del delimiter character
+ * @return number of replaced characters, or equivalently, number
+ *         of resulting strings minus one
+ */
+static size_t split_string_inplace2 (char *str, char del);
+
+/**
+ * Concatenates the given strings, inserting a delimiter character
+ * in between. The result is returned as a newly malloc'd string.
+ * If there are no strings, an empty string is produced.
+ * If there is just one string, this string is copied.
+ * 
+ * @param names pointer to a character array containing the
+ *              null-terinated strings one after another, i.e.
+ *              as produced by {@link split_string_inplace2}.
+ *              Must not be NULL.
+ * @param num_names number of strings, e.g. the return value of
+ *                  {@link split_string_inplace2} plus one
+ * @param del delimiter to insert between strings
+ * @return resulting malloc'd string, or NULL on failure.
+ */
+static char * implode_compact_strings (const char *names, size_t num_names, char del);
+
 static char ** split_string (const char *str, char del)
 {
     size_t len = strlen(str);
@@ -123,4 +195,52 @@ fail0:
     return NULL;
 }
 
+static size_t split_string_inplace2 (char *str, char del)
+{
+    ASSERT(str)
+    
+    size_t num_extra_parts = 0;
+    
+    while (*str) {
+        if (*str == del) {
+            *str = '\0';
+            num_extra_parts++;
+        }
+        str++;
+    }
+    
+    return num_extra_parts;
+}
+
+static char * implode_compact_strings (const char *names, size_t num_names, char del)
+{
+    ASSERT(names)
+    
+    ExpString str;
+    if (!ExpString_Init(&str)) {
+        goto fail0;
+    }
+    
+    int is_first = 1;
+    
+    while (num_names > 0) {
+        if (!is_first && !ExpString_AppendChar(&str, del)) {
+            goto fail1;
+        }
+        if (!ExpString_Append(&str, names)) {
+            goto fail1;
+        }
+        names += strlen(names) + 1;
+        num_names--;
+        is_first = 0;
+    }
+    
+    return ExpString_Get(&str);
+    
+fail1:
+    ExpString_Free(&str);
+fail0:
+    return NULL;
+}
+
 #endif

+ 28 - 1
ncd/NCDObject.c

@@ -128,7 +128,7 @@ int NCDObject_ResolveObjExpr (NCDObject *o, char **names, NCDObject *out_object)
     return 1;
 }
 
-int NCDObject_ResolveObjExprCompact (NCDObject *o, const char *names, int num_names, NCDObject *out_object)
+int NCDObject_ResolveObjExprCompact (NCDObject *o, const char *names, size_t num_names, NCDObject *out_object)
 {
     ASSERT(num_names == 0 || names)
     ASSERT(num_names >= 0)
@@ -175,3 +175,30 @@ int NCDObject_ResolveVarExpr (NCDObject *o, char **names, NCDValMem *mem, NCDVal
     
     return NCDObject_GetVar(&object, "", mem, out_value);
 }
+
+int NCDObject_ResolveVarExprCompact (NCDObject *o, const char *names, size_t num_names, NCDValMem *mem, NCDValRef *out_value)
+{
+    ASSERT(names)
+    ASSERT(num_names >= 0)
+    ASSERT(mem)
+    ASSERT(out_value)
+    
+    NCDObject object = dig_into_object(*o);
+    
+    while (num_names > 0) {
+        NCDObject obj2;
+        if (!NCDObject_GetObj(&object, names, &obj2)) {
+            if (num_names == 1 && NCDObject_GetVar(&object, names, mem, out_value)) {
+                return 1;
+            }
+            
+            return 0;
+        }
+        
+        object = dig_into_object(obj2);
+        names += strlen(names) + 1;
+        num_names--;
+    }
+    
+    return NCDObject_GetVar(&object, "", mem, out_value);
+}

+ 2 - 1
ncd/NCDObject.h

@@ -60,7 +60,8 @@ const char * NCDObject_Type (NCDObject *o);
 int NCDObject_GetObj (NCDObject *o, const char *name, NCDObject *out_object) WARN_UNUSED;
 int NCDObject_GetVar (NCDObject *o, const char *name, NCDValMem *mem, NCDValRef *out_value) WARN_UNUSED;
 int NCDObject_ResolveObjExpr (NCDObject *o, char **names, NCDObject *out_object) WARN_UNUSED;
-int NCDObject_ResolveObjExprCompact (NCDObject *o, const char *names, int num_names, NCDObject *out_object) WARN_UNUSED;
+int NCDObject_ResolveObjExprCompact (NCDObject *o, const char *names, size_t num_names, NCDObject *out_object) WARN_UNUSED;
 int NCDObject_ResolveVarExpr (NCDObject *o, char **names, NCDValMem *mem, NCDValRef *out_value) WARN_UNUSED;
+int NCDObject_ResolveVarExprCompact (NCDObject *o, const char *names, size_t num_names, NCDValMem *mem, NCDValRef *out_value) WARN_UNUSED;
 
 #endif

+ 15 - 6
ncd/NCDPlaceholderDb.c

@@ -32,6 +32,7 @@
 
 #include <misc/balloc.h>
 #include <misc/split_string.h>
+#include <misc/strdup.h>
 #include <base/BLog.h>
 
 #include "NCDPlaceholderDb.h"
@@ -54,7 +55,7 @@ int NCDPlaceholderDb_Init (NCDPlaceholderDb *o)
 void NCDPlaceholderDb_Free (NCDPlaceholderDb *o)
 {
     for (size_t i = 0; i < o->count; i++) {
-        free_strings(o->arr[i].varnames);
+        free(o->arr[i].varnames);
     }
     
     BFree(o->arr);
@@ -94,22 +95,30 @@ int NCDPlaceholderDb_AddVariable (NCDPlaceholderDb *o, const char *varname, int
         return 0;
     }
     
-    char **varnames = split_string(varname, '.');
+    char *varnames = b_strdup(varname);
     if (!varnames) {
-        BLog(BLOG_ERROR, "split_string failed");
+        BLog(BLOG_ERROR, "b_strdup failed");
         return 0;
     }
     
+    size_t num_names = split_string_inplace2(varnames, '.') + 1;
+    
     *out_plid = o->count;
-    o->arr[o->count++].varnames = varnames;
+    
+    o->arr[o->count].varnames = varnames;
+    o->arr[o->count].num_names = num_names;
+    o->count++;
     
     return 1;
 }
 
-char ** NCDPlaceholderDb_GetVariable (NCDPlaceholderDb *o, int plid)
+void NCDPlaceholderDb_GetVariable (NCDPlaceholderDb *o, int plid, const char **out_varnames, size_t *out_num_names)
 {
     ASSERT(plid >= 0)
     ASSERT(plid < o->count)
+    ASSERT(out_varnames)
+    ASSERT(out_num_names)
     
-    return o->arr[plid].varnames;
+    *out_varnames = o->arr[plid].varnames;
+    *out_num_names = o->arr[plid].num_names;
 }

+ 3 - 2
ncd/NCDPlaceholderDb.h

@@ -35,7 +35,8 @@
 #include <misc/debug.h>
 
 struct NCDPlaceholderDb__entry {
-    char **varnames;
+    char *varnames;
+    size_t num_names;
 };
 
 /**
@@ -87,6 +88,6 @@ int NCDPlaceholderDb_AddVariable (NCDPlaceholderDb *o, const char *varname, int
  *         database is freed.
  *         Note that there will always be at least one string in the result.
  */
-char ** NCDPlaceholderDb_GetVariable (NCDPlaceholderDb *o, int plid);
+void NCDPlaceholderDb_GetVariable (NCDPlaceholderDb *o, int plid, const char **out_varnames, size_t *out_num_names);
 
 #endif

+ 10 - 9
ncd/ncd.c

@@ -172,7 +172,7 @@ static void process_advance (struct process *p);
 static void process_wait_timer_handler (struct process *p);
 static int process_find_object (struct process *p, int pos, const char *name, NCDObject *out_object);
 static int process_resolve_object_expr (struct process *p, int pos, char **names, NCDObject *out_object);
-static int process_resolve_variable_expr (struct process *p, int pos, char **names, NCDValMem *mem, NCDValRef *out_value);
+static int process_resolve_variable_expr (struct process *p, int pos, const char *names, size_t num_names, NCDValMem *mem, NCDValRef *out_value);
 static void statement_logfunc (struct statement *ps);
 static void statement_log (struct statement *ps, int level, const char *fmt, ...);
 static int statement_allocate_memory (struct statement *ps, int alloc_size);
@@ -979,10 +979,11 @@ int replace_placeholders_callback (void *arg, int plid, NCDValMem *mem, NCDValRe
     ASSERT(mem)
     ASSERT(out)
     
-    char **varnames = NCDPlaceholderDb_GetVariable(&placeholder_db, plid);
-    ASSERT(count_strings(varnames) > 0)
+    const char *varnames;
+    size_t num_names;
+    NCDPlaceholderDb_GetVariable(&placeholder_db, plid, &varnames, &num_names);
     
-    return process_resolve_variable_expr(ps->p, ps->i, varnames, mem, out);
+    return process_resolve_variable_expr(ps->p, ps->i, varnames, num_names, mem, out);
 }
 
 void process_advance (struct process *p)
@@ -1156,28 +1157,28 @@ fail:;
     return 0;
 }
 
-int process_resolve_variable_expr (struct process *p, int pos, char **names, NCDValMem *mem, NCDValRef *out_value)
+int process_resolve_variable_expr (struct process *p, int pos, const char *names, size_t num_names, NCDValMem *mem, NCDValRef *out_value)
 {
     ASSERT(pos >= 0)
     ASSERT(pos <= p->num_statements)
     ASSERT(names)
-    ASSERT(count_strings(names) > 0)
+    ASSERT(num_names > 0)
     ASSERT(mem)
     ASSERT(out_value)
     
     NCDObject object;
-    if (!process_find_object(p, pos, names[0], &object)) {
+    if (!process_find_object(p, pos, names, &object)) {
         goto fail;
     }
     
-    if (!NCDObject_ResolveVarExpr(&object, names + 1, mem, out_value)) {
+    if (!NCDObject_ResolveVarExprCompact(&object, names + strlen(names) + 1, num_names - 1, mem, out_value)) {
         goto fail;
     }
     
     return 1;
     
 fail:;
-    char *name = implode_strings(names, '.');
+    char *name = implode_compact_strings(names, num_names, '.');
     process_log(p, BLOG_ERROR, "failed to resolve variable (%s) from position %zu", (name ? name : ""), pos);
     free(name);
     return 0;