Prechádzať zdrojové kódy

Incomplete attempt at LMDB-like API.

Stefano Cossu 3 rokov pred
rodič
commit
00a755a489
19 zmenil súbory, kde vykonal 450 pridanie a 357 odobranie
  1. 8 6
      Makefile
  2. 17 11
      include/buffer.h
  3. 7 7
      include/core.h
  4. 3 2
      include/graph.h
  5. 66 48
      include/term.h
  6. 7 8
      profile.c
  7. 23 17
      src/buffer.c
  8. 0 4
      src/core.c
  9. 38 23
      src/graph.c
  10. 5 5
      src/htable.c
  11. 1 1
      src/store_mdb.c
  12. 45 36
      src/term.c
  13. 3 3
      src/triple.c
  14. 3 3
      test.c
  15. 29 30
      test/assets.h
  16. 15 5
      test/test_graph.c
  17. 6 4
      test/test_htable.c
  18. 149 97
      test/test_store_mdb.c
  19. 25 47
      test/test_term.c

+ 8 - 6
Makefile

@@ -6,16 +6,18 @@ all: test
 
 check:
 	splint \
-		-Iinclude -Iext/xxHash -Iext/openldap/libraries/liblmdb \
+		-Iinclude -Iext/xxHash -Iext/openldap/libraries/liblmdb -Itest \
 		-D_XOPEN_SOURCE=500 \
-		-preproc \
+		-DUINT_MAX=0xFFFFFFFFUL \
+		-nullpass \
+		-posix-lib \
 		test.c
 
 build:
 	gcc -g -Wall \
-		-std=gnu99 \
+		-std=c99 \
 		-Iinclude -Iext/xxHash -Iext/openldap/libraries/liblmdb \
-		-luuid \
+		-luuid -lpthread \
 		-D_XOPEN_SOURCE=500 \
 		ext/xxHash/xxhash.c ext/openldap/libraries/liblmdb/midl.c \
 		ext/openldap/libraries/liblmdb/mdb.c \
@@ -24,7 +26,7 @@ build:
 
 test:
 	gcc -g -Wall \
-		-std=gnu99 \
+		-std=c99 \
 		-DDEBUG \
 		-Iinclude -Iext/xxHash -Iext/openldap/libraries/liblmdb -Itest \
 		-luuid -lpthread \
@@ -36,7 +38,7 @@ test:
 
 profile:
 	gcc -g -Wall \
-		-std=gnu99 \
+		-std=c99 \
 		-Iinclude -Iext/xxHash -Iext/openldap/libraries/liblmdb \
 		-luuid \
 		-D_XOPEN_SOURCE=500 \

+ 17 - 11
include/buffer.h

@@ -9,32 +9,38 @@ typedef struct LSUP_Buffer {
 } LSUP_Buffer;
 
 
-LSUP_Buffer *LSUP_buffer_new(size_t size);
+LSUP_rc
+LSUP_buffer_new(size_t size, LSUP_Buffer *buf_p);
 
-int LSUP_buffer_init(LSUP_Buffer *buf, size_t size);
+LSUP_rc
+LSUP_buffer_reset(LSUP_Buffer *buf, size_t size);
 
 void LSUP_buffer_print(const LSUP_Buffer *buf);
 
-int LSUP_buffer_copy(LSUP_Buffer *dest, const LSUP_Buffer *src);
+LSUP_rc
+LSUP_buffer_copy(const LSUP_Buffer *src, LSUP_Buffer *dest);
 
-void LSUP_buffer_done(LSUP_Buffer *buf);
+void LSUP_buffer_free(LSUP_Buffer *buf);
+
+
+/** @brief Compare two buffers.
+ *
+ * The return value is the same as memcmp.
+ */
+inline int LSUP_buffer_cmp(const LSUP_Buffer *buf1, const LSUP_Buffer *buf2)
+{ return memcmp(buf1->addr, buf2->addr, max(buf1->size, buf2->size)); }
 
 
 /** @brief Return whether two buffers are equal.
  *
- * This may be faster than LSUP_buffer_cmp because it returns immediately if
+ * This may be faster than #LSUP_buffer_cmp because it returns immediately if
  * the sizes of the buffers differ.
  */
 inline bool LSUP_buffer_eq(const LSUP_Buffer *buf1, const LSUP_Buffer *buf2)
 {
     if (buf1->size != buf2->size) return false;
 
-    return (memcmp(buf1->addr, buf2->addr, buf1->size) == 0) ? true : false;
-}
-
-inline int LSUP_buffer_cmp(const LSUP_Buffer *buf1, const LSUP_Buffer *buf2)
-{
-    return memcmp(buf1->addr, buf2->addr, max(buf1->size, buf2->size));
+    return (LSUP_buffer_cmp(buf1, buf2) == 0) ? true : false;
 }
 
 #endif

+ 7 - 7
include/core.h

@@ -29,7 +29,7 @@
 #define LIKELY(x)       __builtin_expect(!!(x), true)
 #define UNLIKELY(x)     __builtin_expect(!!(x), false)
 // TODO Handle memory errors better.
-#define CRITICAL(exp)   if (UNLIKELY(((exp) == NULL))) { abort(); }
+#define CRITICAL(exp)   if (UNLIKELY ((exp) == NULL)) abort()
 
 #define KLEN sizeof(LSUP_Key)
 #define DBL_KLEN sizeof(LSUP_DoubleKey)
@@ -82,12 +82,9 @@ typedef LSUP_Key LSUP_QuadKey[4];
 
 typedef char uuid_str_t[UUIDSTR_SIZE];
 
-// Don't use MIN and MAX macros: see
-// https://dustri.org/b/min-and-max-macro-considered-harmful.html
-inline int min(int x, int y) { return x < y ? x : y; }
-
-inline int max(int x, int y) { return x > y ? x : y; }
-
+// Yes, a textbook mistake; but writing min and max for all int types is crazy.
+#define min(x, y) (x) < (y) ? (x) : (y)
+#define max(x, y) (x) > (y) ? (x) : (y)
 
 /** @brief Make recursive directories.
  *
@@ -102,4 +99,7 @@ LSUP_rc mkdir_p(const char *path, mode_t mode);
 // Jump if rc is negative (skip warnings).
 #define PCHECK(exp, rc, marker) (rc) = (exp); if ((rc) < LSUP_OK) goto marker
 
+// Return rc if it is of LSUP_rc type and is negative (=error)
+#define RCCK(exp) LSUP_rc _rc = (exp); if (_rc < 0) return _rc;
+
 #endif

+ 3 - 2
include/graph.h

@@ -147,9 +147,10 @@ LSUP_rc
 LSUP_graph_add(
         LSUP_Graph *gr,
         const LSUP_Triple trp[], size_t trp_ct,
-        const LSUP_SerTriple strp[], size_t strp_ct);
+        const LSUP_SerTriple strp[], size_t strp_ct, size_t *inserted);
 
-#define LSUP_graph_add_trp(gr, trp, ct) LSUP_graph_add(gr, trp, ct, NULL, 0)
+#define LSUP_graph_add_trp(gr, trp, ct, ins) \
+    LSUP_graph_add(gr, trp, ct, NULL, 0, ins)
 
 
 /** @brief Delete triples by a matching pattern.

+ 66 - 48
include/term.h

@@ -44,64 +44,85 @@ typedef struct LSUP_Term {
 } LSUP_Term;
 
 
-/*
- * Initialize a pre-allocated term structure.
+/** @brief Create a new term.
+ *
+ * @param type[in] Term type. One of #LSUP_term_type.
+ *
+ * @param data[in] Term data: textual URI, literal value without data type
+ *  or langtag, etc.
+ *
+ * @param datatype[in]: data type for literals.
+ *
+ * @param lang[in]: language tag for string literals.
  *
- * the structure can be an already initialized term, and can be reused
- * without freeing it.
+ * @param term[out] Pointer to a new term, which must be freed with
+ *  #LSUP_term_free after use.
+ *
+ * @return LSUP_OK if successful, LSUP_VALUE_ERR if validation fails.
  */
 LSUP_rc
-LSUP_term_init(
-        LSUP_Term *term, LSUP_term_type type,
-        const char *data, char *datatype, char *lang);
+LSUP_term_new(
+        LSUP_term_type type, const char *data, char *datatype, char *lang,
+        LSUP_Term **term);
 
-/**
- * @brief Shortcut to initialize a URI.
+
+/** @brief Shortcut to create a URI.
+ *
+ * Must be freed with #LSUP_term_free.
+ *
+ * @param data[in] The URI string. If NULL, a UUID4-based URN is generated.
+ *
+ * @param uri[out] The URI to be created.
+ *
+ * @return LSUP_OK if successful, LSUP_VALUE_ERR if validation fails.
  */
 inline LSUP_rc
-LSUP_uri_init(LSUP_Term *term, const char *data)
-{ return LSUP_term_init(term, LSUP_TERM_URI, data, NULL, NULL); }
-
-
-LSUP_Term *
-LSUP_term_new(LSUP_term_type type, const char *data, char *datatype, char *lang);
+LSUP_uri_new(const char *data, LSUP_Term **uri)
+{
+    if (!data) {
+        uuid_t uuid;
+        uuid_generate_random(uuid);
 
-/**
- * @brief Shortcut to create a URI.
- */
-inline LSUP_Term *
-LSUP_uri_new(const char *data)
-{ return LSUP_term_new(LSUP_TERM_URI, data, NULL, NULL); }
+        uuid_str_t uuid_str;
+        uuid_unparse_lower(uuid, uuid_str);
 
+        char uri[UUIDSTR_SIZE + 10];
+        sprintf(uri, "urn:uuid4:%s", uuid_str);
 
-/**
- * Generate a random URN with the format: `urn:lsup:<uuid4>`.
- */
-inline LSUP_Term *
-LSUP_uri_random()
-{
-    uuid_t uuid;
-    uuid_generate_random(uuid);
+        data = uri;
+    }
 
-    uuid_str_t uuid_str;
-    uuid_unparse_lower(uuid, uuid_str);
+    return LSUP_term_new(LSUP_TERM_URI, data, NULL, NULL, uri);
+}
 
-    char uri[UUIDSTR_SIZE + 10];
-    sprintf(uri, "urn:uuid4:%s", uuid_str);
 
-    return LSUP_uri_new(uri);
-}
+/* @brief Reuse a pre-allocated term structure.
+ *
+ * The structure must have been previously created with #LSUP_term_new. It can
+ * be reinitialized multiple times without freeing it. It must be eventually
+ * freed with #LSUP_term_free.
+ */
+LSUP_rc
+LSUP_term_reset(
+        LSUP_Term *term, LSUP_term_type type,
+        const char *data, char *datatype, char *lang);
 
 
+/**
+ * @brief Shortcut to initialize a URI.
+ */
+inline LSUP_rc
+LSUP_uri_reset(LSUP_Term *term, const char *data)
+{ return LSUP_term_reset(term, LSUP_TERM_URI, data, NULL, NULL); }
 
 
-/** Simple ad-hoc serialization function.
+/** @brief Simple ad-hoc serialization function.
  *
- * The resulting term must be freed with #LSUP_term_done after use.
+ * The resulting term must be freed with #LSUP_term_free after use.
  */
-LSUP_rc LSUP_term_serialize(const LSUP_Term *term, LSUP_Buffer *sterm);
+LSUP_rc LSUP_term_serialize(const LSUP_Term *term, LSUP_Buffer **sterm);
 
-LSUP_rc LSUP_term_deserialize(const LSUP_Buffer *sterm, LSUP_Term *term);
+LSUP_rc LSUP_term_deserialize(const LSUP_Buffer *sterm, LSUP_Term **term);
 
 
 inline LSUP_Key
@@ -113,21 +134,21 @@ LSUP_sterm_to_key(const LSUP_Buffer *sterm)
 }
 
 
-/**
- * Hash a term into a key. If NULL is passed, the result is NULL_KEY.
+/** @brief Hash a term into a key.
+ *
+ * If NULL is passed, the result is NULL_KEY.
  */
 inline LSUP_Key
 LSUP_term_to_key(const LSUP_Term *term)
 {
     if (UNLIKELY (term == NULL)) return NULL_KEY;
 
-    LSUP_Buffer sterm_s;
-    LSUP_Buffer *sterm = &sterm_s;
+    LSUP_Buffer *sterm;
 
-    LSUP_term_serialize(term, sterm);
+    LSUP_term_serialize(term, &sterm);
     LSUP_Key key = XXH64(sterm->addr, sterm->size, SEED);
 
-    LSUP_buffer_done(sterm);
+    LSUP_buffer_free(sterm);
 
     return key;
 }
@@ -143,9 +164,6 @@ inline XXH128_hash_t
 LSUP_term_hash128(const LSUP_Term *term);
 */
 
-void
-LSUP_term_done(LSUP_Term *term);
-
 void
 LSUP_term_free(LSUP_Term *term);
 

+ 7 - 8
profile.c

@@ -13,18 +13,17 @@ static int test_graph_add_batch()
     CRITICAL(trp = malloc(nt * sizeof(LSUP_Triple)));
     for (size_t i = 0; i < nt; i++) {
         //printf("i: %lu\n", i);
-        trp[i].s = LSUP_term_new(
-                LSUP_TERM_URI, LSUP_term_gen_random_str(), NULL, NULL);
-        trp[i].p = LSUP_term_new(
-                LSUP_TERM_URI, LSUP_term_gen_random_str(), NULL, NULL);
-        trp[i].o = LSUP_term_new(
-                LSUP_TERM_URI, LSUP_term_gen_random_str(), NULL, NULL);
+        LSUP_uri_new (NULL, trp[i].s);
+        LSUP_uri_new (NULL, trp[i].p);
+        LSUP_uri_new (NULL, trp[i].o);
     }
     TRACE(STR, "Triples generated.");
 
-    LSUP_Graph *gr = LSUP_graph_new(nt, NULL, LSUP_STORE_MEM);
+    LSUP_Graph *gr;
+    LSUP_graph_new(LSUP_STORE_MEM, &gr);
+    LSUP_graph_resize(gr, nt);
 
-    LSUP_graph_add(gr, trp, nt);
+    LSUP_graph_add_trp(gr, trp, nt, NULL);
     TRACE(STR, "Graph populated.");
 
     LSUP_graph_free(gr);

+ 23 - 17
src/buffer.c

@@ -3,28 +3,32 @@
 // Inline extern prototypes
 
 bool LSUP_buffer_eq(const LSUP_Buffer *buf1, const LSUP_Buffer *buf2);
-
 int LSUP_buffer_cmp(const LSUP_Buffer *buf1, const LSUP_Buffer *buf2);
 
 
-LSUP_Buffer *LSUP_buffer_new(size_t size)
+LSUP_rc
+LSUP_buffer_new(size_t size, LSUP_Buffer *buf)
 {
-    LSUP_Buffer *buf;
+    LSUP_Buffer *tmp;
+    CRITICAL(tmp = malloc (sizeof (*tmp)));
+    buf->addr = NULL; // TODO redundant?
+
+    RCCK (LSUP_buffer_reset(buf, size));
 
-    CRITICAL(buf = malloc(sizeof(LSUP_Buffer)));
-    LSUP_buffer_init(buf, size);
+    *buf = *tmp;
 
-    return buf;
+    return LSUP_OK;
 }
 
 
-int LSUP_buffer_init(LSUP_Buffer *buf, size_t size)
+LSUP_rc
+LSUP_buffer_reset(LSUP_Buffer *buf, size_t size)
 {
     //TRACE("Buffer Size: %lu\n", size);
-    CRITICAL(realloc(buf->addr, size * sizeof(char)));
+    CRITICAL (buf->addr = realloc (buf->addr, size));
     buf->size = size;
 
-    return 0;
+    return LSUP_OK;
 }
 
 /**
@@ -46,20 +50,22 @@ void LSUP_buffer_print(const LSUP_Buffer *buf) {
 }
 
 
-int LSUP_buffer_copy(LSUP_Buffer *dest, const LSUP_Buffer *src)
+LSUP_rc
+LSUP_buffer_copy(const LSUP_Buffer *src, LSUP_Buffer *dest)
 {
-    LSUP_buffer_init(dest, src->size);
+    LSUP_Buffer *tmp;
+    RCCK (LSUP_buffer_reset(tmp, src->size));
+
+    memcpy(tmp->addr, src->addr, src->size);
 
-    memcpy(dest->addr, src->addr, src->size);
+    *dest = *tmp;
 
     return LSUP_OK;
 }
 
 
-void LSUP_buffer_done(LSUP_Buffer *buf){
-    if (buf->addr != NULL) {
-        //TRACE(STR, "Freeing buffer.");
-        free(buf->addr);
-    }
+void LSUP_buffer_free(LSUP_Buffer *buf){
+    if (LIKELY (buf)) free(buf->addr);
+    free(buf);
 }
 

+ 0 - 4
src/core.c

@@ -1,9 +1,5 @@
 #include "core.h"
 
-// Extern inline prototypes.
-int min(int x, int y);
-int max(int x, int y);
-
 
 int mkdir_p(const char *path, mode_t mode)
 {

+ 38 - 23
src/graph.c

@@ -94,9 +94,10 @@ LSUP_graph_new(const LSUP_store_type store_type, Graph **gr_p)
 
     // Initialize default context only once per process.
     if(UNLIKELY(!default_ctx)) {
-        LSUP_Term *default_ctx_uri = LSUP_uri_new(default_ctx_label);
-        LSUP_term_serialize(default_ctx_uri, default_ctx);
-        LSUP_term_free(default_ctx_uri);
+        LSUP_Term default_ctx_uri;
+        LSUP_uri_new(default_ctx_label, &default_ctx_uri);
+        LSUP_term_serialize(&default_ctx_uri, default_ctx);
+        LSUP_term_free(&default_ctx_uri);
         atexit(ctx_cleanup);
     }
 
@@ -131,7 +132,7 @@ graph_copy_contents(const LSUP_Graph *src, LSUP_Graph *dest)
 
     while (graph_iter_next_buffer(it, &sspo) != LSUP_END) {
         TRACE("Inserting triple #%lu\n", it->i);
-        LSUP_rc add_rc = LSUP_graph_add(dest, NULL, 0, &sspo, 1);
+        LSUP_rc add_rc = LSUP_graph_add(dest, NULL, 0, &sspo, 1, NULL);
         if (LIKELY (add_rc == LSUP_OK)) rc = LSUP_OK;
         else if (add_rc < 0) return add_rc;
     }
@@ -203,26 +204,22 @@ LSUP_graph_free(LSUP_Graph *gr)
 }
 
 
-LSUP_rc
-LSUP_graph_resize(LSUP_Graph *gr, size_t size)
-{
-    if (gr->store_type == LSUP_STORE_MEM)
-        return LSUP_htstore_resize(gr->ht_store, size);
-
-    return LSUP_VALUE_ERR;
-}
-
-
 LSUP_Term *
 LSUP_graph_uri(const LSUP_Graph *gr) { return gr->uri; }
 
 
 LSUP_rc
 LSUP_graph_set_uri(LSUP_Graph *gr, const char *uri)
+{ return LSUP_uri_new(uri, gr->uri); }
+
+
+LSUP_rc
+LSUP_graph_resize(LSUP_Graph *gr, size_t size)
 {
-    gr->uri = uri ? LSUP_uri_new(uri) : LSUP_uri_random();
+    if (gr->store_type == LSUP_STORE_MEM)
+        return LSUP_htstore_resize(gr->ht_store, size);
 
-    return LSUP_OK;
+    return LSUP_VALUE_ERR;
 }
 
 
@@ -250,10 +247,12 @@ LSUP_rc
 LSUP_graph_add(
         LSUP_Graph *gr,
         const LSUP_Triple trp[], size_t trp_ct,
-        const LSUP_SerTriple strp[], size_t strp_ct)
+        const LSUP_SerTriple strp[], size_t strp_ct, size_t *inserted)
 {
     LSUP_rc rc;
 
+    *inserted = 0;
+
     /*
      * NOTE It is possible to pass both sets of RDF triples and buffer triples.
      */
@@ -280,8 +279,12 @@ LSUP_graph_add(
                 LSUP_term_serialize(trp[i].o, sspo.o);
 
                 TRACE("Inserting triple #%lu\n", i);
-                if (LIKELY(LSUP_htstore_add(gr->ht_store, &sspo) == LSUP_OK))
+                LSUP_rc db_rc = LSUP_htstore_add(gr->ht_store, &sspo);
+                if (LIKELY(db_rc == LSUP_OK)) {
                     rc = LSUP_OK;
+                    (*inserted) ++;
+                }
+                if (UNLIKELY (db_rc < 0)) return db_rc;
             }
 
             LSUP_buffer_done(sspo.s);
@@ -294,8 +297,11 @@ LSUP_graph_add(
             TRACE("Inserting triple #%lu\n", i);
             LSUP_rc db_rc = LSUP_htstore_add(gr->ht_store, strp + i);
 
+            if (LIKELY (db_rc == LSUP_OK)) {
+                rc = LSUP_OK;
+                (*inserted) ++;
+            }
             if (UNLIKELY (db_rc < 0)) return db_rc;
-            if (LIKELY (db_rc == LSUP_OK)) rc = LSUP_OK;
         }
 
         return rc;
@@ -323,8 +329,11 @@ LSUP_graph_add(
                 TRACE("Inserting triple #%lu\n", i);
                 LSUP_rc db_rc = LSUP_mdbstore_add_iter(it, &sspo);
 
+                if (LIKELY (db_rc == LSUP_OK)) {
+                    rc = LSUP_OK;
+                    (*inserted) ++;
+                }
                 if (UNLIKELY(db_rc < 0)) return db_rc;
-                if (LIKELY(db_rc == LSUP_OK)) rc = LSUP_OK;
             }
 
             LSUP_buffer_done(sspo.s);
@@ -337,8 +346,11 @@ LSUP_graph_add(
             TRACE("Inserting triple #%lu\n", i);
             LSUP_rc db_rc = LSUP_mdbstore_add_iter(it, strp + i);
 
+            if (LIKELY (db_rc == LSUP_OK)) {
+                rc = LSUP_OK;
+                (*inserted) ++;
+            }
             if (UNLIKELY (db_rc < 0)) return db_rc;
-            if (LIKELY (db_rc == LSUP_OK)) rc = LSUP_OK;
         }
 
         LSUP_mdbstore_add_done(it, NULL);
@@ -354,7 +366,8 @@ LSUP_graph_remove(Graph *gr, const LSUP_Triple *spo, size_t *ct)
     LSUP_rc rc;
     LSUP_SerTriple sspo_s;
     LSUP_SerTriple *sspo = &sspo_s;
-    LSUP_Buffer *sc;
+    LSUP_Buffer sc_s;
+    LSUP_Buffer *sc = &sc_s;
 
     LSUP_term_serialize(spo->s, sspo->s);
     LSUP_term_serialize(spo->p, sspo->s);
@@ -386,7 +399,8 @@ LSUP_graph_lookup(
 
     LSUP_SerTriple sspo_s;
     LSUP_SerTriple *sspo = &sspo_s;
-    LSUP_Buffer *sc;
+    LSUP_Buffer sc_s;
+    LSUP_Buffer *sc = &sc_s;
 
     LSUP_term_serialize(spo->s, sspo->s);
     LSUP_term_serialize(spo->p, sspo->s);
@@ -422,6 +436,7 @@ graph_iter_next_buffer(GraphIterator *it, LSUP_SerTriple *sspo)
         rc = LSUP_htiter_next(it->ht_iter, sspo);
     else rc = LSUP_mdbiter_next(it->mdb_iter, sspo);
 
+    return rc;
 }
 
 

+ 5 - 5
src/htable.c

@@ -161,13 +161,13 @@ LSUP_htable_copy(const HTable *src, HTable **dest_p)
     dest->nitems = src->nitems;
     dest->divinfo = src->divinfo;
 
-    CRITICAL(dest->buckets = malloc(sizeof(src->buckets)));
-    memcpy(dest->buckets, src->buckets, sizeof(src->buckets));
+    CRITICAL(dest->buckets = malloc(sizeof(bucket_t) * dest->size));
+    memcpy(dest->buckets, src->buckets, sizeof(bucket_t) * dest->size);
 
-    CRITICAL(dest->data = malloc(sizeof(src->data)));
-    memcpy(dest->data, src->data, sizeof(src->data));
+    CRITICAL(dest->data = malloc(dest->size));
+    memcpy(dest->data, src->data, dest->size);
 
-    dest->seed = src->seed ^ random() | (random() << sizeof(ht_hash_t));
+    dest->seed = src->seed ^ (random() | (random() << sizeof(ht_hash_t)));
 
     dest->key_hash_fn = src->key_hash_fn;
     dest->key_eq_fn = src->key_eq_fn;

+ 1 - 1
src/store_mdb.c

@@ -293,7 +293,7 @@ LSUP_mdbstore_new(
     if (default_ctx == NULL) store->default_ctx = NULL;
     else {
         CRITICAL(store->default_ctx = malloc(sizeof(LSUP_Buffer)));
-        LSUP_buffer_copy(store->default_ctx, default_ctx);
+        LSUP_buffer_copy(default_ctx, &store->default_ctx);
     }
 
     // Set map size.

+ 45 - 36
src/term.c

@@ -1,6 +1,5 @@
 #include "term.h"
 
-#define CHR         sizeof(char)
 #define NLEN(str)   (str) == NULL ? 0 : strlen((str))
 
 static regex_t ptn;
@@ -9,8 +8,8 @@ static bool ptn_init = false;
 
 /* Global inline prototypes. */
 
-LSUP_Term *LSUP_uri_new(const char *data);
-LSUP_Term *LSUP_uri_random();
+LSUP_rc LSUP_uri_reset(LSUP_Term *term, const char *data);
+LSUP_rc LSUP_uri_new(const char *data, LSUP_Term **term);
 
 
 /**
@@ -20,7 +19,23 @@ void term_cleanup() { if (ptn_init) regfree(&ptn); }
 
 
 LSUP_rc
-LSUP_term_init(
+LSUP_term_new(
+        LSUP_term_type type, const char *data, char *datatype, char *lang,
+        LSUP_Term **term_p) {
+
+    LSUP_Term *term;
+    CRITICAL (term = malloc (sizeof (*term)));
+    term->data = NULL;
+    term->datatype = NULL;
+
+    *term_p = term;
+
+    return LSUP_term_reset(term, type, data, datatype, lang);
+}
+
+
+LSUP_rc
+LSUP_term_reset(
         LSUP_Term *term, LSUP_term_type type,
         const char *data, char *datatype, char *lang)
 {
@@ -41,11 +56,12 @@ LSUP_term_init(
         }
     }
 
-    CRITICAL(term->data = malloc(strlen(data) + 1));
+    CRITICAL (term->data = realloc (term->data, strlen(data) + 1));
     strcpy(term->data, data);
 
     if (datatype) {
-        term->datatype = malloc(strlen(datatype) + 1);
+        CRITICAL (term->datatype = realloc(
+                    term->datatype, strlen(datatype) + 1));
         strcpy(term->datatype, datatype);
     } else {
         term->datatype = NULL;
@@ -62,19 +78,6 @@ LSUP_term_init(
 }
 
 
-LSUP_Term *
-LSUP_term_new(
-        LSUP_term_type type, const char *data, char *datatype, char *lang) {
-
-    LSUP_Term *term;
-
-    CRITICAL(term = malloc(sizeof(LSUP_Term)));
-    LSUP_term_init(term, type, data, datatype, lang);
-
-    return term;
-}
-
-
 /*
  * This function allocates and returns the following byte sequence:
  *
@@ -115,53 +118,59 @@ LSUP_term_new(
  * type   data        datatype         lang
  */
 LSUP_rc
-LSUP_term_serialize(const LSUP_Term *term, LSUP_Buffer *sterm)
+LSUP_term_serialize(const LSUP_Term *term, LSUP_Buffer **sterm_p)
 {
     size_t size, data_len, datatype_len,
            data_idx, datatype_idx, lang_idx;
 
-    if (UNLIKELY(term == NULL)) return LSUP_NOACTION;
+    if (UNLIKELY (term == NULL)) {
+        *sterm_p = NULL;
+        return LSUP_NOACTION;
+    }
 
-    data_idx = CHR;
-    data_len = strlen(term->data) + CHR;
+    data_idx = 1;
+    data_len = strlen (term->data) + 1;
 
     size = data_idx + data_len;
 
     if (term->datatype != NULL) {
         datatype_idx = size;
-        datatype_len = strlen(term->datatype) + CHR;
+        datatype_len = strlen (term->datatype) + 1;
         size += datatype_len;
 
-        if (strlen(term->lang) > 0) {
+        if (strlen (term->lang) > 0) {
             lang_idx = size;
             size += LANG_SIZE;
         }
     }
 
     //TRACE("Serialized term size: %lu", size);
-    LSUP_buffer_init(sterm, size);
+    LSUP_Buffer *sterm;
+    LSUP_buffer_new (size, &sterm);
 
     // Copy type.
-    memset(sterm->addr, (unsigned char)term->type, CHR);
+    memcpy (sterm->addr, &term->type, 1);
     // Copy data.
-    memcpy(sterm->addr + data_idx, term->data, data_len);
+    memcpy (sterm->addr + data_idx, term->data, data_len);
 
     if (term->datatype != NULL) {
         // Copy data type.
-        memcpy(sterm->addr + datatype_idx, term->datatype, datatype_len);
+        memcpy (sterm->addr + datatype_idx, term->datatype, datatype_len);
 
         if (strlen(term->lang) > 0) {
             // Copy lang tag.
-            memcpy(sterm->addr + lang_idx, term->lang, LANG_SIZE);
+            memcpy (sterm->addr + lang_idx, term->lang, LANG_SIZE);
         }
     }
 
-    return 0;
+    *sterm_p = sterm;
+
+    return LSUP_OK;
 }
 
 
 LSUP_rc
-LSUP_term_deserialize(const LSUP_Buffer *sterm, LSUP_Term *term)
+LSUP_term_deserialize(const LSUP_Buffer *sterm, LSUP_Term **term)
 {
     size_t cur;
     char *data, *datatype = NULL;
@@ -169,13 +178,13 @@ LSUP_term_deserialize(const LSUP_Buffer *sterm, LSUP_Term *term)
 
     char type = ((char*)(sterm->addr))[0];
 
-    cur = CHR;
+    cur = 1;
     data = (char*)sterm->addr + cur;
-    cur += strlen(data) + CHR;
+    cur += strlen(data) + 1;
 
     if (type == LSUP_TERM_LITERAL) {
         datatype = (char*)sterm->addr + cur;
-        cur += strlen(datatype) + CHR;
+        cur += strlen(datatype) + 1;
         if (strlen(datatype) == 0)
             datatype = NULL;
 
@@ -183,7 +192,7 @@ LSUP_term_deserialize(const LSUP_Buffer *sterm, LSUP_Term *term)
             strcpy(lang, sterm->addr + cur);
     }
 
-    LSUP_term_init(term, type, data, datatype, lang);
+    LSUP_term_new(type, data, datatype, lang, term);
 
     return LSUP_OK;
 }

+ 3 - 3
src/triple.c

@@ -42,9 +42,9 @@ LSUP_triple_done(LSUP_Triple *spo)
 {
     if (UNLIKELY(!spo)) return;
 
-    LSUP_term_done(spo->s);
-    LSUP_term_done(spo->p);
-    LSUP_term_done(spo->o);
+    LSUP_term_free(spo->s);
+    LSUP_term_free(spo->p);
+    LSUP_term_free(spo->o);
 }
 
 

+ 3 - 3
test.c

@@ -6,10 +6,10 @@
 int main(int argc, char **argv) {
 
     int result = (
-        //term_tests() |
-        //htable_tests() |
+        term_tests() |
+        htable_tests() |
         store_mdb_test() |
-        //graph_tests() |
+        graph_tests() |
         0);
 
     printf("Test result: %lu\n", (size_t)result);

+ 29 - 30
test/assets.h

@@ -12,36 +12,35 @@ LSUP_Triple *create_triples()
 
     // These constitute overall 10 individual triples, 8 unique.
 
-    trp[0].s = LSUP_term_new(LSUP_TERM_URI, "urn:s:0", NULL, NULL);
-    trp[0].p = LSUP_term_new(LSUP_TERM_URI, "urn:p:0", NULL, NULL);
-    trp[0].o = LSUP_term_new(LSUP_TERM_URI, "urn:o:0", NULL, NULL);
-
-    trp[1].s = LSUP_term_new(LSUP_TERM_URI, "urn:s:1", NULL, NULL);
-    trp[1].p = LSUP_term_new(LSUP_TERM_URI, "urn:p:1", NULL, NULL);
-    trp[1].o = LSUP_term_new(LSUP_TERM_URI, "urn:o:1", NULL, NULL);
-
-    trp[2].s = LSUP_term_new(LSUP_TERM_URI, "urn:s:2", NULL, NULL);
-    trp[2].p = LSUP_term_new(LSUP_TERM_URI, "urn:p:2", NULL, NULL);
-    trp[2].o = LSUP_term_new(LSUP_TERM_URI, "urn:o:2", NULL, NULL);
-
-    trp[3].s = LSUP_term_new(LSUP_TERM_URI, "urn:s:0", NULL, NULL);
-    trp[3].p = LSUP_term_new(LSUP_TERM_URI, "urn:p:1", NULL, NULL);
-    trp[3].o = LSUP_term_new(LSUP_TERM_URI, "urn:o:2", NULL, NULL);
-
-    trp[4].s = LSUP_term_new(LSUP_TERM_URI, "urn:s:0", NULL, NULL);
-    trp[4].p = LSUP_term_new(LSUP_TERM_URI, "urn:p:2", NULL, NULL);
-    trp[4].o = LSUP_term_new(
-            LSUP_TERM_LITERAL, "String 1", NULL, NULL);
-
-    trp[5].s = LSUP_term_new(LSUP_TERM_URI, "urn:s:0", NULL, NULL);
-    trp[5].p = LSUP_term_new(LSUP_TERM_URI, "urn:p:5", NULL, NULL);
-    trp[5].o = LSUP_term_new(
-            LSUP_TERM_LITERAL, "String 1", "xsd:string", NULL);
-
-    trp[6].s = LSUP_term_new(LSUP_TERM_URI, "urn:s:1", NULL, NULL);
-    trp[6].p = LSUP_term_new(LSUP_TERM_URI, "urn:p:6", NULL, NULL);
-    trp[6].o = LSUP_term_new(
-            LSUP_TERM_LITERAL, "String 1", "xsd:string", "es-ES");
+    LSUP_uri_new("urn:s:0", trp[0].s);
+    LSUP_uri_new("urn:p:0", trp[0].p);
+    LSUP_uri_new("urn:o:0", trp[0].o);
+
+    LSUP_uri_new("urn:s:1", trp[1].s);
+    LSUP_uri_new("urn:p:1", trp[1].p);
+    LSUP_uri_new("urn:o:1", trp[1].o);
+
+    LSUP_uri_new("urn:s:2", trp[2].s);
+    LSUP_uri_new("urn:p:2", trp[2].p);
+    LSUP_uri_new("urn:o:2", trp[2].o);
+
+    LSUP_uri_new("urn:s:0", trp[3].s);
+    LSUP_uri_new("urn:p:1", trp[3].p);
+    LSUP_uri_new("urn:o:2", trp[3].o);
+
+    LSUP_uri_new("urn:s:0", trp[4].s);
+    LSUP_uri_new("urn:p:2", trp[4].p);
+    LSUP_term_new(LSUP_TERM_LITERAL, "String 1", NULL, NULL, trp[4].o);
+
+    LSUP_uri_new("urn:s:0", trp[5].s);
+    LSUP_uri_new("urn:p:5", trp[5].p);
+    LSUP_term_new(
+            LSUP_TERM_LITERAL, "String 1", "xsd:string", NULL, trp[5].o);
+
+    LSUP_uri_new("urn:s:1", trp[6].s);
+    LSUP_uri_new("urn:p:6", trp[6].p);
+    LSUP_term_new(
+            LSUP_TERM_LITERAL, "String 1", "xsd:string", "es-ES", trp[6].o);
 
     // Let's reuse pointers. Do not double-free.
     trp[7].s = trp[0].s; // <urn:s:0>

+ 15 - 5
test/test_graph.c

@@ -2,9 +2,16 @@
 #include "graph.h"
 #include "assets.h"
 
-static int test_graph_heap()
+static int test_graph_new()
 {
-    LSUP_Graph *gr = LSUP_graph_new(10, "urn:gr:1", LSUP_STORE_MEM);
+    LSUP_Graph *gr;
+    EXPECT_PASS(LSUP_graph_new(LSUP_STORE_MEM, &gr));
+
+    EXPECT_PASS(LSUP_graph_set_uri(gr, "urn:gr:1"));
+    EXPECT_STR_EQ(LSUP_graph_uri(gr)->data, "urn:gr:1");
+
+    EXPECT_PASS(LSUP_graph_resize(gr, 10));
+    EXPECT_INT_EQ(LSUP_graph_capacity(gr), 10);
 
     ASSERT(strcmp(LSUP_graph_uri(gr)->data, "urn:gr:1") == 0, "Graph URI mismatch!");
     EXPECT_INT_EQ(LSUP_graph_size(gr), 0);
@@ -19,9 +26,12 @@ static int test_graph_add()
 {
     LSUP_Triple *trp = create_triples();
 
-    LSUP_Graph *gr = LSUP_graph_new(NUM_TRP + 2, "urn:gr:2", LSUP_STORE_MEM);
+    LSUP_Graph *gr;
+    LSUP_graph_new(LSUP_STORE_MEM, &gr);
+    LSUP_graph_resize(gr, NUM_TRP + 2);
 
-    LSUP_graph_add(gr, trp, NUM_TRP);
+    size_t ct;
+    LSUP_graph_add_trp(gr, trp, NUM_TRP, &ct);
 
     for (int i = 0; i < sizeof(trp); i++) {
         printf("checking triple #%d... ", i);
@@ -41,7 +51,7 @@ static int test_graph_add()
 
 int graph_tests()
 {
-    RUN(test_graph_heap);
+    RUN(test_graph_new);
     RUN(test_graph_add);
     return 0;
 }

+ 6 - 4
test/test_htable.c

@@ -14,9 +14,10 @@ static int htable_idx()
 {
     LSUP_Key keys[_CT] = {5, 8, 13, 21, 34, 55, 89, 5};
 
-    LSUP_HTable *ht = LSUP_htable_new(
+    LSUP_HTable *ht;
+    LSUP_htable_new(
             _CT, sizeof(LSUP_Key), sizeof(LSUP_Buffer),
-            id_hash_fn, buffer_eq_fn, 0);
+            id_hash_fn, buffer_eq_fn, &ht);
 
     LSUP_Buffer values[_CT];
 
@@ -86,9 +87,10 @@ static int htable_keys()
         {2, 1, 1}, // Duplicate.
     };
 
-    LSUP_HTable *ht = LSUP_htable_new(
+    LSUP_HTable *ht;
+    LSUP_htable_new(
             _CT, sizeof(LSUP_TripleKey), sizeof(LSUP_Buffer),
-            id_hash_fn, buffer_eq_fn, 0);
+            id_hash_fn, buffer_eq_fn, &ht);
 
     LSUP_Buffer values[_CT];
 

+ 149 - 97
test/test_store_mdb.c

@@ -25,14 +25,14 @@ static void rmdb() {
 static int test_triple_store()
 {
     rmdb();
-    EXPECT_PASS(LSUP_store_setup(&path));
+    EXPECT_PASS(LSUP_mdbstore_setup(&path));
 
     LSUP_MDBStore *store;
-    store = LSUP_store_new(path, NULL); // triple store.
+    LSUP_mdbstore_new(path, NULL, &store); // triple store.
     ASSERT(store != NULL, "Error initializing store!");
 
     LSUP_Triple *trp = create_triples();
-    LSUP_SerTerm sterms[NUM_TRP][3];
+    LSUP_Buffer sterms[NUM_TRP][3];
     LSUP_SerTriple ser_trp[NUM_TRP];
 
     for (int i = 0; i < NUM_TRP; i++) {
@@ -41,32 +41,52 @@ static int test_triple_store()
         ser_trp[i].o = sterms[i] + 2;
         for (int j = 0; j < 3; j++) {
             LSUP_term_serialize(
-                    LSUP_triple_term_by_pos(trp + i, j),
-                    LSUP_ser_triple_term_by_pos(ser_trp + i, j));
+                    LSUP_triple_pos(trp + i, j),
+                    LSUP_striple_pos(ser_trp + i, j));
         }
     }
 
     // Test adding.
-    EXPECT_PASS(LSUP_store_add(store, NULL, ser_trp, NUM_TRP));
-    EXPECT_INT_EQ(LSUP_store_size(store), 8);
+    size_t ins;
+    EXPECT_PASS(LSUP_mdbstore_add(store, NULL, ser_trp, NUM_TRP, &ins));
+    EXPECT_INT_EQ(ins, 8);
+    EXPECT_INT_EQ(LSUP_mdbstore_size(store), 8);
 
     // Test lookups.
-    LSUP_SerTerm *lut[12][4] = {
-        {NULL, NULL, NULL, NULL},
-
-        {ser_trp[0].s, NULL, NULL, NULL},
-        {ser_trp[2].s, NULL, NULL, ser_trp[2].s},
-        {NULL, ser_trp[0].p, NULL, NULL},
-        {NULL, ser_trp[0].s, NULL, NULL},
-        {NULL, NULL, ser_trp[6].o, NULL},
-
-        {ser_trp[4].s, ser_trp[4].p, NULL, NULL},
-        {NULL, ser_trp[7].p, ser_trp[7].o, NULL},
-        {ser_trp[5].s, NULL, ser_trp[5].o, NULL},
-        {ser_trp[5].s, NULL, ser_trp[5].o, ser_trp[2].s},
-
-        {ser_trp[4].s, ser_trp[4].p, ser_trp[4].o, NULL},
-        {ser_trp[4].s, ser_trp[4].p, ser_trp[6].o, NULL},
+    LSUP_SerTriple lut[12] = {
+        {NULL, NULL, NULL},
+
+        {ser_trp[0].s, NULL, NULL},
+        {ser_trp[2].s, NULL, NULL},
+        {NULL, ser_trp[0].p, NULL},
+        {NULL, ser_trp[0].s, NULL},
+        {NULL, NULL, ser_trp[6].o},
+
+        {ser_trp[4].s, ser_trp[4].p, NULL},
+        {NULL, ser_trp[7].p, ser_trp[7].o},
+        {ser_trp[5].s, NULL, ser_trp[5].o},
+        {ser_trp[5].s, NULL, ser_trp[5].o},
+
+        {ser_trp[4].s, ser_trp[4].p, ser_trp[4].o},
+        {ser_trp[4].s, ser_trp[4].p, ser_trp[6].o},
+    };
+
+    LSUP_Buffer *luc[12] = {
+        NULL,
+
+        NULL,
+        ser_trp[2].s,
+        NULL,
+        NULL,
+        NULL,
+
+        NULL,
+        NULL,
+        NULL,
+        ser_trp[2].s,
+
+        NULL,
+        NULL,
     };
 
     size_t results[12] = {
@@ -82,10 +102,10 @@ static int test_triple_store()
 
         TRACE("Testing triple lookup #%d.\n", i);
 
-        EXPECT_PASS(LSUP_store_lookup(store, lut[i], &it, &ct));
+        EXPECT_PASS(LSUP_mdbstore_lookup(store, lut + i, luc[i], &it, &ct));
         EXPECT_INT_EQ(ct, results[i]);
 
-        LSUP_store_it_free(it);
+        LSUP_mdbiter_free(it);
     }
 
     for (int i = 0; i < NUM_TRP; i++) {
@@ -94,7 +114,7 @@ static int test_triple_store()
         LSUP_buffer_done(ser_trp[i].o);
     }
 
-    LSUP_store_free(store);
+    LSUP_mdbstore_free(store);
     free_triples(trp);
 
     return 0;
@@ -108,19 +128,20 @@ static int test_triple_store()
 static int test_quad_store()
 {
     rmdb();
-    EXPECT_PASS(LSUP_store_setup(&path));
+    EXPECT_PASS(LSUP_mdbstore_setup(&path));
 
-    LSUP_Term *ctx1 = LSUP_uri_new("urn:c:1");
-    LSUP_SerTerm sc1_s;
-    LSUP_SerTerm *sc1 = &sc1_s;
+    LSUP_Term *ctx1;
+    LSUP_uri_new("urn:c:1", ctx1);
+    LSUP_Buffer sc1_s;
+    LSUP_Buffer *sc1 = &sc1_s;
     LSUP_term_serialize(ctx1, sc1);
 
     LSUP_MDBStore *store;
-    store = LSUP_store_new(path, sc1); // quad store.
+    EXPECT_PASS(LSUP_mdbstore_new(path, sc1, &store)); // quad store.
     ASSERT(store != NULL, "Error initializing store!");
 
     LSUP_Triple *trp = create_triples();
-    LSUP_SerTerm sterms[NUM_TRP][3];
+    LSUP_Buffer sterms[NUM_TRP][3];
     LSUP_SerTriple ser_trp[NUM_TRP];
 
     for (int i = 0; i < NUM_TRP; i++) {
@@ -129,95 +150,126 @@ static int test_quad_store()
         ser_trp[i].o = sterms[i] + 2;
         for (int j = 0; j < 3; j++) {
             LSUP_term_serialize(
-                    LSUP_triple_term_by_pos(trp + i, j),
-                    LSUP_ser_triple_term_by_pos(ser_trp + i, j));
+                    LSUP_triple_pos(trp + i, j),
+                    LSUP_striple_pos(ser_trp + i, j));
         }
     }
 
     // Only triples 0÷5 in default context.
-    EXPECT_PASS(LSUP_store_add(store, NULL, ser_trp, 6));
-
-    LSUP_Term *ctx2 = LSUP_uri_new("urn:c:2");
-    LSUP_SerTerm sc2_s;
-    LSUP_SerTerm *sc2 = &sc2_s;
+    size_t ct;
+    EXPECT_PASS(LSUP_mdbstore_add(store, NULL, ser_trp, 6, &ct));
+    EXPECT_INT_EQ(ct, 6);
+
+    LSUP_Term *ctx2;
+    LSUP_uri_new("urn:c:2", ctx2);
+    LSUP_Buffer sc2_s;
+    LSUP_Buffer *sc2 = &sc2_s;
     LSUP_term_serialize(ctx2, sc2);
 
     // Only triples 4÷9 in default context.
-    EXPECT_PASS(LSUP_store_add(store, &sc2_s, ser_trp + 4, 6));
+    EXPECT_PASS(LSUP_mdbstore_add(store, &sc2_s, ser_trp + 4, 6, &ct));
+    EXPECT_INT_EQ(ct, 4);
 
     // 6 triples in ctx1 + 6 in ctx2 - 2 duplicates
-    EXPECT_INT_EQ(LSUP_store_size(store), 10);
+    EXPECT_INT_EQ(LSUP_mdbstore_size(store), 10);
 
     // Test lookups.
     // This context is not with any triple.
-    LSUP_Term *ctx3 = LSUP_uri_new("urn:c:3");
-    LSUP_SerTerm sc3_s;
-    LSUP_SerTerm *sc3 = &sc3_s;
-    LSUP_term_serialize(ctx3, &sc3_s);
+    LSUP_Term *ctx3;
+    LSUP_uri_new("urn:c:3", ctx3);
+    LSUP_Buffer sc3_s;
+    LSUP_Buffer *sc3 = &sc3_s;
+    LSUP_term_serialize(ctx3, sc3);
 
-    LSUP_SerTerm *lut[41][4] = {
+    LSUP_SerTriple lut[41] = {
         // Any context
-        {NULL, NULL, NULL, NULL},                               // #0
+        {NULL, NULL, NULL},                                 // #0
 
-        {ser_trp[0].s, NULL, NULL, NULL},                       // #1
-        {NULL, ser_trp[0].p, NULL, NULL},                       // #2
-        {NULL, ser_trp[0].s, NULL, NULL},                       // #3
-        {NULL, NULL, ser_trp[6].o, NULL},                       // #4
+        {ser_trp[0].s, NULL, NULL},                         // #1
+        {NULL, ser_trp[0].p, NULL},                         // #2
+        {NULL, ser_trp[0].s, NULL},                         // #3
+        {NULL, NULL, ser_trp[6].o},                         // #4
 
-        {ser_trp[4].s, ser_trp[4].p, NULL, NULL},               // #5
-        {NULL, ser_trp[7].p, ser_trp[7].o, NULL},               // #6
-        {ser_trp[5].s, NULL, ser_trp[5].o, NULL},               // #7
+        {ser_trp[4].s, ser_trp[4].p, NULL},                 // #5
+        {NULL, ser_trp[7].p, ser_trp[7].o},                 // #6
+        {ser_trp[5].s, NULL, ser_trp[5].o},                 // #7
 
-        {ser_trp[4].s, ser_trp[4].p, ser_trp[4].o, NULL},       // #8
-        {ser_trp[2].s, ser_trp[4].p, ser_trp[5].o, NULL},       // #9
+        {ser_trp[4].s, ser_trp[4].p, ser_trp[4].o},         // #8
+        {ser_trp[2].s, ser_trp[4].p, ser_trp[5].o},         // #9
 
         // Context 1 (trp[0÷5])
-        {NULL, NULL, NULL, sc1},                                // #10
+        {NULL, NULL, NULL},                                 // #10
 
-        {ser_trp[0].s, NULL, NULL, sc1},                        // #11
-        {ser_trp[2].s, NULL, NULL, sc1},                        // #12
-        {NULL, ser_trp[0].p, NULL, sc1},                        // #13
-        {NULL, ser_trp[6].p, NULL, sc1},                        // #14
-        {NULL, NULL, ser_trp[6].o, sc1},                        // #15
+        {ser_trp[0].s, NULL, NULL},                         // #11
+        {ser_trp[2].s, NULL, NULL},                         // #12
+        {NULL, ser_trp[0].p, NULL},                         // #13
+        {NULL, ser_trp[6].p, NULL},                         // #14
+        {NULL, NULL, ser_trp[6].o},                         // #15
 
-        {ser_trp[4].s, ser_trp[4].p, NULL, sc1},                // #16
-        {NULL, ser_trp[7].p, ser_trp[7].o, sc1},                // #17
-        {ser_trp[5].s, NULL, ser_trp[5].o, sc1},                // #18
+        {ser_trp[4].s, ser_trp[4].p, NULL},                 // #16
+        {NULL, ser_trp[7].p, ser_trp[7].o},                 // #17
+        {ser_trp[5].s, NULL, ser_trp[5].o},                 // #18
 
-        {ser_trp[4].s, ser_trp[4].p, ser_trp[4].o, sc1},        // #19
-        {ser_trp[6].s, ser_trp[6].p, ser_trp[6].o, sc1},        // #20
+        {ser_trp[4].s, ser_trp[4].p, ser_trp[4].o},         // #19
+        {ser_trp[6].s, ser_trp[6].p, ser_trp[6].o},         // #20
 
 
         // Context 2 (trp[4÷9])
-        {NULL, NULL, NULL, sc2},                                // #21
+        {NULL, NULL, NULL},                                 // #21
 
-        {ser_trp[0].s, NULL, NULL, sc2},                        // #22
-        {NULL, ser_trp[0].p, NULL, sc2},                        // #23
-        {NULL, ser_trp[0].s, NULL, sc2},                        // #24
-        {NULL, NULL, ser_trp[6].o, sc2},                        // #25
+        {ser_trp[0].s, NULL, NULL},                         // #22
+        {NULL, ser_trp[0].p, NULL},                         // #23
+        {NULL, ser_trp[0].s, NULL},                         // #24
+        {NULL, NULL, ser_trp[6].o},                         // #25
 
-        {ser_trp[4].s, ser_trp[4].p, NULL, sc2},                // #26
-        {NULL, ser_trp[7].p, ser_trp[7].o, sc2},                // #27
-        {ser_trp[5].s, NULL, ser_trp[5].o, sc2},                // #28
+        {ser_trp[4].s, ser_trp[4].p, NULL},                 // #26
+        {NULL, ser_trp[7].p, ser_trp[7].o},                 // #27
+        {ser_trp[5].s, NULL, ser_trp[5].o},                 // #28
 
-        {ser_trp[4].s, ser_trp[4].p, ser_trp[4].o, sc2},        // #29
-        {ser_trp[6].s, ser_trp[6].p, ser_trp[6].o, sc2},        // #30
+        {ser_trp[4].s, ser_trp[4].p, ser_trp[4].o},         // #29
+        {ser_trp[6].s, ser_trp[6].p, ser_trp[6].o},         // #30
 
 
         // Non-existing context
-        {NULL, NULL, NULL, sc3},                                // #31
+        {NULL, NULL, NULL},                                 // #31
 
-        {ser_trp[0].s, NULL, NULL, sc3},                        // #32
-        {NULL, ser_trp[0].p, NULL, sc3},                        // #33
-        {NULL, ser_trp[0].s, NULL, sc3},                        // #34
-        {NULL, NULL, ser_trp[6].o, sc3},                        // #35
+        {ser_trp[0].s, NULL, NULL},                         // #32
+        {NULL, ser_trp[0].p, NULL},                         // #33
+        {NULL, ser_trp[0].s, NULL},                         // #34
+        {NULL, NULL, ser_trp[6].o},                         // #35
 
-        {ser_trp[4].s, ser_trp[4].p, NULL, sc3},                // #36
-        {NULL, ser_trp[7].p, ser_trp[7].o, sc3},                // #37
-        {ser_trp[5].s, NULL, ser_trp[5].o, sc3},                // #38
+        {ser_trp[4].s, ser_trp[4].p, NULL},                 // #36
+        {NULL, ser_trp[7].p, ser_trp[7].o},                 // #37
+        {ser_trp[5].s, NULL, ser_trp[5].o},                 // #38
+
+        {ser_trp[4].s, ser_trp[4].p, ser_trp[4].o},         // #39
+        {ser_trp[6].s, ser_trp[6].p, ser_trp[6].o},         // #40
+    };
 
-        {ser_trp[4].s, ser_trp[4].p, ser_trp[4].o, sc3},        // #39
-        {ser_trp[6].s, ser_trp[6].p, ser_trp[6].o, sc3},        // #40
+    LSUP_Buffer *luc[41] = {
+        // Any context
+        NULL,                                               // #0
+        NULL, NULL, NULL, NULL,                             // #1-#4
+        NULL, NULL, NULL,                                   // #5-#7
+        NULL, NULL,                                         // #8-#9
+
+        // Context 1 (trp[0÷5])
+        sc1,                                                // #10
+        sc1, sc1, sc1, sc1, sc1,                            // #11-#15
+        sc1, sc1, sc1,                                      // #16-#18
+        sc1, sc1,                                           // #19-#20
+
+        // Context 2 (trp[4÷9])
+        sc2,                                                // #21
+        sc2, sc2, sc2, sc2,                                 // #22-#25
+        sc2, sc2, sc2,                                      // #26-#28
+        sc2, sc2,                                           // #29-#30
+
+        // Non-existing context
+        sc3,                                                // #31
+        sc3, sc3, sc3, sc3,                                 // #32-#35
+        sc3, sc3, sc3,                                      // #36-#38
+        sc3, sc3,                                           // #39-#40
     };
 
     size_t results[41] = {
@@ -252,26 +304,26 @@ static int test_quad_store()
 
         printf("Testing triple lookup #%d: {", i);
 
-        if(lut[i][0]) LSUP_buffer_print(lut[i][0]);
+        if(lut[i].s) LSUP_buffer_print(lut[i].s);
         else printf("NULL");
-        printf(" ");
+        printf(", ");
 
-        if(lut[i][1]) LSUP_buffer_print(lut[i][1]);
+        if(lut[i].p) LSUP_buffer_print(lut[i].p);
         else printf("NULL");
-        printf(" ");
+        printf(", ");
 
-        if(lut[i][2]) LSUP_buffer_print(lut[i][2]);
+        if(lut[i].o) LSUP_buffer_print(lut[i].o);
         else printf("NULL");
-        printf(" ");
+        printf(", ");
 
-        if(lut[i][3]) LSUP_buffer_print(lut[i][3]);
+        if(luc[i]) LSUP_buffer_print(luc[i]);
         else printf("NULL");
         printf("}\n");
 
-        EXPECT_PASS(LSUP_store_lookup(store, lut[i], &it, &ct));
+        EXPECT_PASS(LSUP_mdbstore_lookup(store, lut + i, luc[i], &it, &ct));
         EXPECT_INT_EQ(ct, results[i]);
 
-        LSUP_store_it_free(it);
+        LSUP_mdbiter_free(it);
     }
 
     for (int i = 0; i < NUM_TRP; i++) {
@@ -286,7 +338,7 @@ static int test_quad_store()
     LSUP_buffer_done(&sc2_s);
     free_triples(trp);
 
-    LSUP_store_free(store);
+    LSUP_mdbstore_free(store);
 
     return 0;
 }

+ 25 - 47
test/test_term.c

@@ -1,41 +1,27 @@
 #include "test.h"
 
 
-static int test_term_stack()
-{
-    TRACE(STR, "Test term, stack-allocated.");
-    LSUP_Term term_s;
-    LSUP_Term *term = &term_s;
-
-    char *data = "http://hello.org";
-
-    LSUP_term_init(
-            term, LSUP_TERM_URI, data, NULL, NULL);
-
-    EXPECT_STR_EQ(term->data, data);
-    ASSERT(term->datatype == NULL,"Term datatype is not NULL!" );
-    ASSERT(strlen(term->lang) == 0, "Term lang incorrect!");
-    TRACE(STR, "freeing term.");
-    LSUP_term_done(term);
-
-    return 0;
-}
-
-static int test_term_heap()
+static int test_term_new()
 {
     char *data = "hello";
     char *datatype = "xsd:string";
     char *lang = "en-US";
 
     TRACE(STR, "Test term, heap-allocated.");
-    LSUP_Term *term = LSUP_term_new(
-            LSUP_TERM_LITERAL, data, datatype, lang);
+    LSUP_Term *term;
+    LSUP_term_new(LSUP_TERM_LITERAL, data, datatype, lang, term);
 
     TRACE("Term data: %s", term->data);
     EXPECT_STR_EQ(term->data, data);
     EXPECT_STR_EQ(term->datatype, datatype);
     EXPECT_STR_EQ(term->lang, lang);
 
+    TRACE(STR, "Reset term.\n");
+
+    char *uri_data = "urn:id:2144564356";
+    LSUP_term_reset(term, LSUP_TERM_URI, uri_data, NULL, NULL);
+    EXPECT_STR_EQ(term->data, uri_data);
+
     LSUP_term_free(term);
 
     return 0;
@@ -43,14 +29,11 @@ static int test_term_heap()
 
 static int test_term_serialize_deserialize()
 {
-    LSUP_Term *uri = LSUP_term_new(
-            LSUP_TERM_URI, "http://hello.org", NULL, NULL);
-    LSUP_Term *lit = LSUP_term_new(
-            LSUP_TERM_LITERAL, "hello", NULL, NULL);
-    LSUP_Term *tlit = LSUP_term_new(
-            LSUP_TERM_LITERAL, "hello", "xsd:string", NULL);
-    LSUP_Term *tllit = LSUP_term_new(
-            LSUP_TERM_LITERAL, "hello", "xsd:string", "en-US");
+    LSUP_Term *uri, *lit, *tlit, *tllit;
+    LSUP_term_new(LSUP_TERM_URI, "http://hello.org", NULL, NULL, uri);
+    LSUP_term_new(LSUP_TERM_LITERAL, "hello", NULL, NULL, lit);
+    LSUP_term_new(LSUP_TERM_LITERAL, "hello", "xsd:string", NULL, tlit);
+    LSUP_term_new(LSUP_TERM_LITERAL, "hello", "xsd:string", "en-US", tllit);
 
     LSUP_Buffer sterm_s;
     LSUP_Buffer *sterm = &sterm_s;
@@ -64,7 +47,7 @@ static int test_term_serialize_deserialize()
     TRACE("%s", "\n");
     LSUP_term_deserialize(sterm, dsterm);
     ASSERT(LSUP_term_equals(dsterm, uri), "URI serialization error!");
-    LSUP_term_done(dsterm);
+    LSUP_term_free(dsterm);
     LSUP_buffer_done(sterm);
     LSUP_term_free(uri);
 
@@ -74,7 +57,7 @@ static int test_term_serialize_deserialize()
     TRACE("%s", "\n");
     LSUP_term_deserialize(sterm, dsterm);
     ASSERT(LSUP_term_equals(dsterm, lit), "lit serialization error!");
-    LSUP_term_done(dsterm);
+    LSUP_term_free(dsterm);
     LSUP_buffer_done(sterm);
     LSUP_term_free(lit);
 
@@ -84,7 +67,7 @@ static int test_term_serialize_deserialize()
     TRACE("%s", "\n");
     LSUP_term_deserialize(sterm, dsterm);
     ASSERT(LSUP_term_equals(dsterm, tlit), "tlit serialization error!");
-    LSUP_term_done(dsterm);
+    LSUP_term_free(dsterm);
     LSUP_buffer_done(sterm);
     LSUP_term_free(tlit);
 
@@ -94,7 +77,7 @@ static int test_term_serialize_deserialize()
     TRACE("%s", "\n");
     LSUP_term_deserialize(sterm, dsterm);
     ASSERT(LSUP_term_equals(dsterm, tllit), "URI serialization error!");
-    LSUP_term_done(dsterm);
+    LSUP_term_free(dsterm);
     LSUP_buffer_done(sterm);
     LSUP_term_free(tllit);
 
@@ -104,16 +87,12 @@ static int test_term_serialize_deserialize()
 
 static int test_term_to_key()
 {
-    LSUP_Term *uri = LSUP_term_new(
-            LSUP_TERM_URI, "http://hello.org", NULL, NULL);
-    LSUP_Term *lit = LSUP_term_new(
-            LSUP_TERM_LITERAL, "hello", NULL, NULL);
-    LSUP_Term *tlit = LSUP_term_new(
-            LSUP_TERM_LITERAL, "hello", "xsd:string", NULL);
-    LSUP_Term *tllit1 = LSUP_term_new(
-            LSUP_TERM_LITERAL, "hello", "xsd:string", "en-US");
-    LSUP_Term *tllit2 = LSUP_term_new(
-            LSUP_TERM_LITERAL, "hello", "xsd:string", "en-GB");
+    LSUP_Term *uri, *lit, *tlit, *tllit1, *tllit2;
+    LSUP_term_new(LSUP_TERM_URI, "http://hello.org", NULL, NULL, uri);
+    LSUP_term_new(LSUP_TERM_LITERAL, "hello", NULL, NULL, lit);
+    LSUP_term_new(LSUP_TERM_LITERAL, "hello", "xsd:string", NULL, tlit);
+    LSUP_term_new(LSUP_TERM_LITERAL, "hello", "xsd:string", "en-US", tllit1);
+    LSUP_term_new(LSUP_TERM_LITERAL, "hello", "xsd:string", "en-GB", tllit2);
 
     LSUP_Key uri_key = LSUP_term_to_key(uri);
     LSUP_Key lit_key = LSUP_term_to_key(lit);
@@ -138,8 +117,7 @@ static int test_term_to_key()
 
 
 int term_tests() {
-    RUN(test_term_stack);
-    RUN(test_term_heap);
+    RUN(test_term_new);
     RUN(test_term_serialize_deserialize);
     RUN(test_term_to_key);