ソースを参照

ncd: NCDVal: implement ID-strings

ambrop7 13 年 前
コミット
0e1f201d99
4 ファイル変更161 行追加11 行削除
  1. 35 1
      examples/ncdval_test.c
  2. 6 3
      ncd/CMakeLists.txt
  3. 81 7
      ncd/NCDVal.c
  4. 39 0
      ncd/NCDVal.h

+ 35 - 1
examples/ncdval_test.c

@@ -30,6 +30,8 @@
 #include <stdio.h>
 
 #include <ncd/NCDVal.h>
+#include <ncd/NCDStringIndex.h>
+#include <ncd/static_strings.h>
 #include <base/BLog.h>
 #include <misc/debug.h>
 
@@ -86,6 +88,9 @@ int main ()
 {
     BLog_InitStdout();
     
+    NCDStringIndex string_index;
+    FORCE( NCDStringIndex_Init(&string_index) )
+    
     // Some basic usage of values.
     
     NCDValMem mem;
@@ -93,6 +98,9 @@ int main ()
     
     NCDValRef s1 = NCDVal_NewString(&mem, "Hello World");
     FORCE( !NCDVal_IsInvalid(s1) )
+    ASSERT( NCDVal_IsString(s1) )
+    ASSERT( !NCDVal_IsIdString(s1) )
+    ASSERT( NCDVal_Type(s1) == NCDVAL_STRING )
     
     NCDValRef s2 = NCDVal_NewString(&mem, "This is reeeeeeeeeeeeeallllllllyyyyy fun!");
     FORCE( !NCDVal_IsInvalid(s2) )
@@ -119,14 +127,38 @@ int main ()
     NCDValRef v2 = NCDVal_NewString(&mem, "V2");
     FORCE( !NCDVal_IsInvalid(v2) )
     
-    NCDValRef m1 = NCDVal_NewMap(&mem, 2);
+    NCDValRef m1 = NCDVal_NewMap(&mem, 3);
     FORCE( !NCDVal_IsInvalid(m1) )
     
     FORCE( NCDVal_MapInsert(m1, k1, v1) )
     FORCE( NCDVal_MapInsert(m1, k2, v2) )
     
+    NCDValRef ids1 = NCDVal_NewIdString(&mem, NCD_STRING_ARG1, &string_index);
+    FORCE( !NCDVal_IsInvalid(ids1) )
+    ASSERT( !strcmp(NCDVal_StringValue(ids1), "_arg1") )
+    ASSERT( NCDVal_StringLength(ids1) == 5 )
+    ASSERT( !NCDVal_StringHasNulls(ids1) )
+    ASSERT( NCDVal_StringEquals(ids1, "_arg1") )
+    ASSERT( NCDVal_Type(ids1) == NCDVAL_STRING )
+    ASSERT( NCDVal_IsIdString(ids1) )
+    
+    NCDValRef ids2 = NCDVal_NewIdString(&mem, NCD_STRING_ARG2, &string_index);
+    FORCE( !NCDVal_IsInvalid(ids2) )
+    ASSERT( !strcmp(NCDVal_StringValue(ids2), "_arg2") )
+    ASSERT( NCDVal_StringLength(ids2) == 5 )
+    ASSERT( !NCDVal_StringHasNulls(ids2) )
+    ASSERT( NCDVal_StringEquals(ids2, "_arg2") )
+    ASSERT( NCDVal_Type(ids2) == NCDVAL_STRING )
+    ASSERT( NCDVal_IsIdString(ids2) )
+    
+    FORCE( NCDVal_MapInsert(m1, ids1, ids2) )
+    
     print_value(m1, 0);
     
+    NCDValRef copy = NCDVal_NewCopy(&mem, m1);
+    FORCE( !NCDVal_IsInvalid(copy) )
+    ASSERT( NCDVal_Compare(copy, m1) == 0 )
+    
     NCDValMem_Free(&mem);
     
     // Try to make copies of a string within the same memory object.
@@ -157,5 +189,7 @@ int main ()
     
     NCDValMem_Free(&mem);
     
+    NCDStringIndex_Free(&string_index);
+    
     return 0;
 }

+ 6 - 3
ncd/CMakeLists.txt

@@ -26,10 +26,14 @@ add_library(ncdtokenizer
 )
 target_link_libraries(ncdtokenizer base)
 
+add_library(ncdstringindex
+    NCDStringIndex.c
+)
+
 add_library(ncdval
     NCDVal.c
 )
-target_link_libraries(ncdval base)
+target_link_libraries(ncdval base ncdstringindex)
 
 add_library(ncdvalgenerator
     NCDValGenerator.c
@@ -80,7 +84,6 @@ add_executable(badvpn-ncd
     NCDInterpProg.c
     NCDPlaceholderDb.c
     NCDMethodIndex.c
-    NCDStringIndex.c
     BEventLock.c
     modules/command_template.c
     modules/event_template.c
@@ -151,7 +154,7 @@ add_executable(badvpn-ncd
     ${NCD_ADDITIONAL_SOURCES}
 )
 target_link_libraries(badvpn-ncd
-    system flow flowextra dhcpclient arpprobe ncdval ncdvalgenerator
+    system flow flowextra dhcpclient arpprobe ncdval ncdstringindex ncdvalgenerator
     ncdvalparser ncdconfigparser ncdsugar udevmonitor ncdinterfacemonitor ncdrequest
     badvpn_random
 )

+ 81 - 7
ncd/NCDVal.c

@@ -41,6 +41,9 @@
 
 #include <generated/blog_channel_NCDVal.h>
 
+#define EXTERNAL_TYPE_MASK ((1 << 3) - 1)
+#define IDSTRING_TYPE (NCDVAL_STRING | (1 << 3))
+
 static void * NCDValMem__BufAt (NCDValMem *o, NCDVal__idx idx)
 {
     ASSERT(idx >= 0)
@@ -160,6 +163,12 @@ static void NCDVal__AssertValOnly (NCDValMem *mem, NCDVal__idx idx)
             ASSERT(map_e->count <= map_e->maxcount)
             ASSERT(idx + sizeof(struct NCDVal__map) + map_e->maxcount * sizeof(struct NCDVal__mapelem) <= mem->used)
         } break;
+        case IDSTRING_TYPE: {
+            ASSERT(idx + sizeof(struct NCDVal__idstring) <= mem->used)
+            struct NCDVal__idstring *ids_e = NCDValMem__BufAt(mem, idx);
+            ASSERT(ids_e->string_id >= 0)
+            ASSERT(ids_e->string_index)
+        } break;
         default: ASSERT(0);
     }
 #endif
@@ -299,7 +308,7 @@ int NCDVal_Type (NCDValRef val)
     
     int *type_ptr = NCDValMem__BufAt(val.mem, val.idx);
     
-    return *type_ptr;
+    return (*type_ptr & EXTERNAL_TYPE_MASK);
 }
 
 NCDValRef NCDVal_NewInvalid (void)
@@ -330,7 +339,13 @@ NCDValRef NCDVal_NewCopy (NCDValMem *mem, NCDValRef val)
     NCDVal__AssertMem(mem);
     NCDVal__AssertVal(val);
     
-    switch (NCDVal_Type(val)) {
+    if (val.idx < -1) {
+        return NCDVal_NewPlaceholder(mem, NCDVal_PlaceholderId(val));
+    }
+    
+    void *ptr = NCDValMem__BufAt(val.mem, val.idx);
+    
+    switch (*(int *)ptr) {
         case NCDVAL_STRING: {
             size_t len = NCDVal_StringLength(val);
             
@@ -386,8 +401,10 @@ NCDValRef NCDVal_NewCopy (NCDValMem *mem, NCDValRef val)
             return copy;
         } break;
         
-        case NCDVAL_PLACEHOLDER: {
-            return NCDVal_NewPlaceholder(mem, NCDVal_PlaceholderId(val));
+        case IDSTRING_TYPE: {
+            struct NCDVal__idstring *ids_e = ptr;
+            
+            return NCDVal_NewIdString(mem, ids_e->string_id, ids_e->string_index);
         } break;
         
         default: ASSERT(0);
@@ -521,6 +538,13 @@ int NCDVal_IsString (NCDValRef val)
     return NCDVal_Type(val) == NCDVAL_STRING;
 }
 
+int NCDVal_IsIdString (NCDValRef val)
+{
+    NCDVal__AssertVal(val);
+    
+    return !(val.idx < -1) && *(int *)NCDValMem__BufAt(val.mem, val.idx) == IDSTRING_TYPE;
+}
+
 int NCDVal_IsStringNoNulls (NCDValRef val)
 {
     NCDVal__AssertVal(val);
@@ -592,12 +616,42 @@ fail:
     return NCDVal_NewInvalid();
 }
 
+NCDValRef NCDVal_NewIdString (NCDValMem *mem, NCD_string_id_t string_id, NCDStringIndex *string_index)
+{
+    NCDVal__AssertMem(mem);
+    ASSERT(string_id >= 0)
+    ASSERT(string_index)
+    
+    bsize_t size = bsize_fromsize(sizeof(struct NCDVal__idstring));
+    NCDVal__idx idx = NCDValMem__Alloc(mem, size, __alignof(struct NCDVal__idstring));
+    if (idx < 0) {
+        goto fail;
+    }
+    
+    struct NCDVal__idstring *ids_e = NCDValMem__BufAt(mem, idx);
+    ids_e->type = IDSTRING_TYPE;
+    ids_e->string_id = string_id;
+    ids_e->string_index = string_index;
+    
+    return NCDVal__Ref(mem, idx);
+    
+fail:
+    return NCDVal_NewInvalid();
+}
+
 const char * NCDVal_StringValue (NCDValRef string)
 {
     ASSERT(NCDVal_IsString(string))
     
-    struct NCDVal__string *str_e = NCDValMem__BufAt(string.mem, string.idx);
+    void *ptr = NCDValMem__BufAt(string.mem, string.idx);
     
+    if (*(int *)ptr == IDSTRING_TYPE) {
+        struct NCDVal__idstring *ids_e = ptr;
+        const char *value = NCDStringIndex_Value(ids_e->string_index, ids_e->string_id);
+        return value;
+    }
+    
+    struct NCDVal__string *str_e = ptr;
     return str_e->data;
 }
 
@@ -605,11 +659,30 @@ size_t NCDVal_StringLength (NCDValRef string)
 {
     ASSERT(NCDVal_IsString(string))
     
-    struct NCDVal__string *str_e = NCDValMem__BufAt(string.mem, string.idx);
+    void *ptr = NCDValMem__BufAt(string.mem, string.idx);
     
+    if (*(int *)ptr == IDSTRING_TYPE) {
+        struct NCDVal__idstring *ids_e = ptr;
+        const char *value = NCDStringIndex_Value(ids_e->string_index, ids_e->string_id);
+        return strlen(value);
+    }
+    
+    struct NCDVal__string *str_e = ptr;;
     return str_e->length;
 }
 
+void NCDVal_IdStringGet (NCDValRef idstring, NCD_string_id_t *out_string_id,
+                         NCDStringIndex **out_string_index)
+{
+    ASSERT(NCDVal_IsIdString(idstring))
+    ASSERT(out_string_id)
+    ASSERT(out_string_index)
+    
+    struct NCDVal__idstring *ids_e = NCDValMem__BufAt(idstring.mem, idstring.idx);
+    *out_string_id = ids_e->string_id;
+    *out_string_index = ids_e->string_index;
+}
+
 int NCDVal_StringHasNulls (NCDValRef string)
 {
     ASSERT(NCDVal_IsString(string))
@@ -930,7 +1003,8 @@ static void replaceprog_build_recurser (NCDValMem *mem, NCDVal__idx idx, size_t
     struct NCDVal__instr instr;
     
     switch (*((int *)(ptr))) {
-        case NCDVAL_STRING: {
+        case NCDVAL_STRING:
+        case IDSTRING_TYPE: {
         } break;
         
         case NCDVAL_LIST: {

+ 39 - 0
ncd/NCDVal.h

@@ -35,6 +35,7 @@
 
 #include <misc/debug.h>
 #include <structure/CAvl.h>
+#include <ncd/NCDStringIndex.h>
 
 // these are implementation details. The interface is defined below.
 
@@ -83,6 +84,12 @@ struct NCDVal__mapelem {
     int8_t tree_balance;
 };
 
+struct NCDVal__idstring {
+    int type;
+    NCD_string_id_t string_id;
+    NCDStringIndex *string_index;
+};
+
 typedef struct NCDVal__mapelem NCDVal__maptree_entry;
 typedef NCDValMem *NCDVal__maptree_arg;
 
@@ -273,6 +280,13 @@ NCDValRef NCDVal_Moved (NCDValMem *mem, NCDValRef val);
  */
 int NCDVal_IsString (NCDValRef val);
 
+/**
+ * Determines if a value is an ID-string value. See {@link NCDVal_NewIdString}
+ * for an explanation of ID-string values.
+ * The value reference must not be an invalid reference.
+ */
+int NCDVal_IsIdString (NCDValRef val);
+
 /**
  * Determines if a value is a string value which has no null bytes.
  * The value reference must not be an invalid reference.
@@ -308,6 +322,22 @@ NCDValRef NCDVal_NewStringBin (NCDValMem *mem, const uint8_t *data, size_t len);
  */
 NCDValRef NCDVal_NewStringUninitialized (NCDValMem *mem, size_t len);
 
+/**
+ * Builds a new ID-string value.
+ * Returns a reference to the new value, or an invalid reference
+ * on out of memory.
+ * 
+ * An ID-string value is a special kind of string value which is represented
+ * efficiently as a string identifier via {@link NCDStringIndex}. An ID-string
+ * is also a string and is transparent for use. For example, for an ID-string,
+ * {@link NCDVal_Type} still returns NCDVAL_STRING, {@link NCDVal_IsString}
+ * returns 1, and {@link NCDVal_StringValue} and {@link NCDVal_StringLength}
+ * both work. The only way to distinguish an ID-string from a non-ID string is
+ * by calling {@link NCDVal_IsIdString}.
+ */
+NCDValRef NCDVal_NewIdString (NCDValMem *mem, NCD_string_id_t string_id,
+                              NCDStringIndex *string_index);
+
 /**
  * Returns a pointer to the data of a string value. An extra null byte
  * is always appended to the actual contents of the string.
@@ -322,6 +352,15 @@ const char * NCDVal_StringValue (NCDValRef string);
  */
 size_t NCDVal_StringLength (NCDValRef string);
 
+/**
+ * Returns the string ID and the string index of an ID-string.
+ * The value given must be an ID-string value (which can be determined via
+ * {@link NCDVal_IsIdString}). Both the \a out_string_id and \a out_string_index
+ * pointers must be non-NULL.
+ */
+void NCDVal_IdStringGet (NCDValRef idstring, NCD_string_id_t *out_string_id,
+                         NCDStringIndex **out_string_index);
+
 /**
  * Determines if the string value has any null bytes in its contents,
  * i.e. that length > strlen().