Browse Source

Merge branch 'simplify_lmap' into lua

scossu 4 days ago
parent
commit
c00d8a3d74
9 changed files with 174 additions and 27 deletions
  1. 2 1
      include/codec.h
  2. 1 4
      include/graph.h
  3. 5 2
      include/term.h
  4. 1 1
      src/codec/codec_ttl.c
  5. 9 6
      src/codec/grammar_ttl.y
  6. 3 4
      src/graph.c
  7. 16 8
      src/term.c
  8. 12 1
      test/assets/triples.h
  9. 125 0
      test/test_graph.c

+ 2 - 1
include/codec.h

@@ -21,10 +21,11 @@ typedef struct codec_t LSUP_Codec;
 
 
 /// Parser state.
-typedef struct {
+typedef struct ttl_parser_state {
     LSUP_GraphIterator *    it;     ///< Iterator used to build the graph.
     LSUP_NSMap *            nsm;    ///< NS map used in the document.
     LSUP_Term *             base;   ///< Base IRI used in the document.
+    LSUP_Term *             lms;    ///< Link map subject.
     size_t                  ct;     ///< Statements parsed.
     LSUP_rc                 rc;     ///< Internal return code.
 } LSUP_TTLParserState;

+ 1 - 4
include/graph.h

@@ -474,15 +474,12 @@ LSUP_graph_unique_terms (const LSUP_Graph *gr, LSUP_TriplePos pos);
  *
  * @param[in] it Graph iterator obtained with #LSUP_graph_add_init_txn().
  *
- * @param[in] t Term to be associated with the collection list.
- *
  * @param[in] lm Link map.
  *
  * @return Number of triples parsed on success, or <0 (LSUP_*_ERR) on error.
  */
 size_t
-LSUP_graph_add_link_map (
-        LSUP_GraphIterator *it, LSUP_Term *t, LSUP_LinkMap *cl);
+LSUP_graph_add_link_map ( LSUP_GraphIterator *it, LSUP_LinkMap *lm);
 
 
 /** @brief Add triples for an anonymous collection to a graph.

+ 5 - 2
include/term.h

@@ -553,13 +553,16 @@ LSUP_term_set_next (LSUP_TermSet *ts, size_t *i, LSUP_Term **term);
  *
  * Terms can be added to a link map with #LSUP_term_set_add().
  *
+ * @param[in] linked_term Term to be linked to map. The term is copied and may
+ *  be freed after this function call.
+ *
  * @param[in] type Type of links that the link map shall contain.
  * @sa #LSUP_LinkType
  *
  * @return a new empty link map.
  */
 LSUP_LinkMap *
-LSUP_link_map_new (LSUP_LinkType type);
+LSUP_link_map_new (const LSUP_Term *linked_term, LSUP_LinkType type);
 
 
 /** @brief Free a link map.
@@ -609,7 +612,7 @@ LSUP_link_map_add (
  * @param[in] lmap Map handle to iterate.
  */
 LSUP_LinkMapIterator *
-LSUP_link_map_iter_new (const LSUP_LinkMap *lmap, LSUP_Term *ext);
+LSUP_link_map_iter_new (const LSUP_LinkMap *lmap);
 
 
 /** @brief Iterate through a link map.

+ 1 - 1
src/codec/codec_ttl.c

@@ -249,7 +249,7 @@ gr_to_ttl_iter (void *h, char **res_p) {
     LSUP_LinkMap *lmap = LSUP_graph_connections (
             it->gr, s, LSUP_LINK_OUTBOUND);
 
-    LSUP_LinkMapIterator *lmit = LSUP_link_map_iter_new (lmap, s);
+    LSUP_LinkMapIterator *lmit = LSUP_link_map_iter_new (lmap);
     LSUP_Term *p = NULL;
     LSUP_TermSet *o_ts = NULL;
     char *p_join = " ";

+ 9 - 6
src/codec/grammar_ttl.y

@@ -79,7 +79,8 @@ base        ::= BASE WS IRIREF(D) PERIOD . {
             }
 
 triples 	::= subject(S) ows predObjList(L) PERIOD . {
-                size_t ct = LSUP_graph_add_link_map (state->it, S, L);
+                state->lms = S;
+                size_t ct = LSUP_graph_add_link_map (state->it, L);
                 state->ct += ct;
                 state->rc = LSUP_OK;
                 LOG_TRACE("Added %lu triples.", ct);
@@ -88,7 +89,8 @@ triples 	::= subject(S) ows predObjList(L) PERIOD . {
                 LSUP_link_map_free (L);
             }
 triples 	::= subject(S) ows predObjList(L) SEMICOLON PERIOD . [PERIOD] {
-                size_t ct = LSUP_graph_add_link_map (state->it, S, L);
+                state->lms = S;
+                size_t ct = LSUP_graph_add_link_map (state->it, L);
                 state->ct += ct;
                 state->rc = LSUP_OK;
                 LOG_TRACE("Added %lu triples.", ct);
@@ -100,7 +102,7 @@ triples 	::= subject(S) ows predObjList(L) SEMICOLON PERIOD . [PERIOD] {
 %type predObjList       { LSUP_LinkMap * }
 %destructor predObjList { LSUP_link_map_free ($$); }
 predObjList(A) ::= predicate(P) ows objectList(O) . [SEMICOLON] {
-                A = LSUP_link_map_new (LSUP_LINK_OUTBOUND);
+                A = LSUP_link_map_new (state->lms, LSUP_LINK_OUTBOUND);
                 LSUP_link_map_add (A, P, O);
             }
 predObjList(A) ::= predObjList(L) SEMICOLON predicate(P) ows objectList(O) . {
@@ -122,8 +124,8 @@ objectList(A) ::= object(O) . [IRIREF] {
 
 %type subject { LSUP_Term * }
 %destructor subject { LSUP_term_free ($$); }
-subject 	::= resource .
-subject 	::= blank .
+subject 	::= resource(D) . { state->lms = D; }
+subject 	::= blank(D) . { state->lms = D; }
 
 %type predicate { LSUP_Term * }
 %destructor predicate { LSUP_term_free ($$); }
@@ -216,7 +218,8 @@ blank(A)    ::= LBRACKET RBRACKET . [BNODE_ID] {
             }
 blank(A)    ::= LBRACKET predObjList(L) RBRACKET . [BNODE_ID] {
                 A = LSUP_term_new (LSUP_TERM_BNODE, NULL, NULL);
-                state->ct += LSUP_graph_add_link_map (state->it, A, L);
+                state->lms = A;
+                state->ct += LSUP_graph_add_link_map (state->it, L);
                 LOG_TRACE("Created list BN: _:%s", A->data);
 
                 LSUP_link_map_free (L);

+ 3 - 4
src/graph.c

@@ -722,7 +722,7 @@ LSUP_graph_connections (
     }
     LSUP_graph_iter_free(it);
 
-    LSUP_LinkMap *ret = LSUP_link_map_new (type);
+    LSUP_LinkMap *ret = LSUP_link_map_new (t, type);
     size_t i = 0;
     LSUP_Term *lt;
     while (LSUP_term_set_next (lts, &i, &lt) != LSUP_END) {
@@ -792,12 +792,11 @@ LSUP_graph_unique_terms (const LSUP_Graph *gr, LSUP_TriplePos pos)
 
 
 size_t
-LSUP_graph_add_link_map (
-        LSUP_GraphIterator *it, LSUP_Term *t, LSUP_LinkMap *lmap)
+LSUP_graph_add_link_map (LSUP_GraphIterator *it, LSUP_LinkMap *lm)
 {
     LSUP_Triple *spo = TRP_DUMMY;
     size_t ct = 0;
-    LSUP_LinkMapIterator *lmit = LSUP_link_map_iter_new (lmap, t);
+    LSUP_LinkMapIterator *lmit = LSUP_link_map_iter_new (lm);
 
     while (LSUP_link_map_triples (lmit, spo) != LSUP_END) {
         LSUP_rc rc = LSUP_graph_add_iter (it, spo);

+ 16 - 8
src/term.c

@@ -55,7 +55,6 @@ struct link_map_iter {
     const LSUP_LinkMap *map;        ///< Link map to iterate.
     size_t              i;          ///< Linking term loop cursor.
     size_t              j;          ///< Term set loop cursor.
-    LSUP_Term *         ext;        ///< External link to look for connections.
     Link *              link;       ///< Current link being retrieved.
 };
 
@@ -64,13 +63,16 @@ struct link_map_iter {
  * A link map is thus nested:
  *
  * - A link map contains a hash map of Link instances (link).
+ * - It also contains the single term that the other terms are related to
+ *    (linked_t).
  * - Each Link contains a KeyedTerm (term) and a TermSet (tset).
  * - Each term set is a hash map of KeyedTerm instances.
  * - Each KeyedTerm contains a Term and its hash.
  */
 typedef struct link_map {
     LSUP_LinkType       type;       ///< Link type.
-    struct hashmap *    links;      ///< Map of #Link instances.
+    LSUP_Term          *linked_t;   ///< Linked term.
+    struct hashmap     *links;      ///< Map of #Link instances.
 } LSUP_LinkMap;
 
 
@@ -603,7 +605,7 @@ LSUP_term_set_free (LSUP_TermSet *ts)
 
 
 LSUP_LinkMap *
-LSUP_link_map_new (LSUP_LinkType type)
+LSUP_link_map_new (const LSUP_Term *linked_term, LSUP_LinkType type)
 {
     LSUP_LinkMap *lm;
     MALLOC_GUARD (lm, NULL);
@@ -611,6 +613,12 @@ LSUP_link_map_new (LSUP_LinkType type)
     lm->links = hashmap_new (
             sizeof (Link), 0, LSUP_HASH_SEED, 0,
             link_map_hash_fn, link_map_cmp_fn, link_map_free_fn, NULL);
+    if (!linked_term) {
+        log_error ("term must not be NULL.");
+        free (lm);
+        return NULL;
+    }
+    lm->linked_t = LSUP_term_copy (linked_term);
 
     return lm;
 }
@@ -620,6 +628,7 @@ void
 LSUP_link_map_free (LSUP_LinkMap *lm)
 {
     hashmap_free (lm->links);
+    LSUP_term_free (lm->linked_t);
     free (lm);
 }
 
@@ -674,12 +683,11 @@ LSUP_link_map_add (
 
 
 LSUP_LinkMapIterator *
-LSUP_link_map_iter_new (const LSUP_LinkMap *lmap, LSUP_Term *ext)
+LSUP_link_map_iter_new (const LSUP_LinkMap *lmap)
 {
     LSUP_LinkMapIterator *it;
     CALLOC_GUARD (it, NULL);
     it->map = lmap;
-    it->ext = ext;
 
     return it;
 }
@@ -710,10 +718,10 @@ LSUP_link_map_triples (
 {
     // Assign external (related) term.
     if (it->map->type == LSUP_LINK_INBOUND)
-        spo->o = it->ext;
+        spo->o = it->map->linked_t;
     else if (it->map->type == LSUP_LINK_OUTBOUND)
-        spo->s = it->ext;
-    else spo->p = it->ext;
+        spo->s = it->map->linked_t;
+    else spo->p = it->map->linked_t;
 
     KeyedTerm *kt;
 

+ 12 - 1
test/assets/triples.h

@@ -5,6 +5,17 @@
 
 #define NUM_TRP 10
 
+/*
+ * This results in the following set:
+ * <urn:s:0> <urn:p:0> <urn:o:0> .
+ * <urn:s:1> <urn:p:1> <urn:o:1> .
+ * <urn:s:2> <urn:p:2> <urn:o:2> .
+ * <urn:s:0> <urn:p:1> <urn:o:2> .
+ * <urn:s:0> <urn:p:2> "String 1" .
+ * <urn:s:0> <urn:p:5> "String 1"^^<urn:mydatatype:string> .
+ * <urn:s:1> <urn:p:6> "String 1"@es-ES .
+ * <urn:s:0> <urn:p:2> "String 1"^^<urn:mydatatype:string> .
+ */
 LSUP_Triple **create_triples()
 {
     LSUP_NSMap *nsm = LSUP_nsmap_new ();
@@ -20,7 +31,7 @@ LSUP_Triple **create_triples()
                     "String 1",
                     LSUP_iriref_new ("urn:mydatatype:string", NULL));
 
-    LSUP_Triple **trp = calloc (sizeof (LSUP_Triple), NUM_TRP + 1);
+    LSUP_Triple **trp = calloc (sizeof (*trp), NUM_TRP + 1);
     trp[0] = LSUP_triple_new (
             s0,
             LSUP_iriref_new ("urn:p:0", NULL),

+ 125 - 0
test/test_graph.c

@@ -124,6 +124,8 @@ _graph_get (LSUP_StoreType type)
     }
     LSUP_graph_add_done (it2);
 
+    free_triples (trp);
+
     EXPECT_INT_EQ (LSUP_graph_size (gr1), 5);
     EXPECT_INT_EQ (LSUP_graph_size (gr2), 3);
 
@@ -144,7 +146,119 @@ _graph_get (LSUP_StoreType type)
     LSUP_graph_free (gr2);
     LSUP_graph_free (gr3);
     LSUP_graph_free (gr4);
+    if (type != LSUP_STORE_HTABLE) LSUP_store_free (store);
+
+    return 0;
+}
+
+
+static int
+_graph_link_map (LSUP_StoreType type)
+{
+    const LSUP_StoreInt *sif = LSUP_store_int (type);
+
+    if (sif->setup_fn) sif->setup_fn (NULL, true);
+
+    LSUP_Triple **trp = create_triples();
+
+    LSUP_Store *store = LSUP_store_new (type, NULL, 0);
+    LSUP_Graph *gr = LSUP_graph_new (store, NULL, NULL);
+
+    size_t ct;
+    LSUP_graph_add (gr, trp, &ct);
+
+    LSUP_LinkMap *lmap;
+    LSUP_LinkMapIterator *lmit ;
+    //LSUP_Term *k = NULL;
+    LSUP_TermSet *ts = NULL;  // Term set being iterated in link map loop.
+    LSUP_Term *k_res[9] = {NULL};  // Collected keys.
+    LSUP_Term *ts_res[9] = {NULL};  // Collected terms in term set in loop.
+    size_t i = 0, j = 0;
+
+    LSUP_Term *po[6][4] = {
+        {trp[0]->p, trp[0]->o, NULL},
+        {trp[3]->p, trp[3]->o, NULL},
+        {trp[4]->p, trp[4]->o, trp[7]->o, NULL},
+        {trp[5]->p, trp[5]->o, NULL},
+        {NULL}
+    };
+
+    // terms connected to subject, urn:s:0
+    lmap = LSUP_graph_connections (gr, trp[0]->s, LSUP_LINK_OUTBOUND);
+    lmit = LSUP_link_map_iter_new (lmap);
+    while (LSUP_link_map_next (lmit, k_res + i, &ts) == LSUP_OK) {
+        while (LSUP_term_set_next (ts, &j, ts_res + j) == LSUP_OK);
+        /*
+        // TODO test exact terms. This requires a cross-check.
+        ASSERT (
+                LSUP_term_equals (k_res[i], po[i][0]),
+                "Wrong term in link map!");
+        for (size_t k = 1; po[i][k]; k++)
+            ASSERT (
+                    LSUP_term_equals (ts_res[k - 1], po[i][k]),
+                    "Wrong term in term set!");
+        */
+        i++;
+    }
+    LSUP_link_map_iter_free (lmit);
+    LSUP_link_map_free (lmap);
+    EXPECT_INT_EQ (i, 4);
+
+    i = 0; j = 0;
+    memset (k_res, 0, sizeof (k_res));
+    memset (ts_res, 0, sizeof (ts_res));
+    LSUP_Term *so[3][3] = {
+        {trp[1]->s, trp[1]->o, NULL},
+        {trp[3]->s, trp[3]->o, NULL},
+    };
+    // terms connected to predicate, urn:p:1
+    lmap = LSUP_graph_connections (gr, trp[1]->p, LSUP_LINK_EDGE);
+    lmit = LSUP_link_map_iter_new (lmap);
+    while (LSUP_link_map_next (lmit, k_res + i, &ts) == LSUP_OK) {
+        while (LSUP_term_set_next (ts, &j, ts_res + j) == LSUP_OK);
+        /*
+        ASSERT (
+                LSUP_term_equals (k_res[i], so[i][0]),
+                "Wrong term in link map!");
+        for (size_t k = 1; so[i][k]; k++)
+            ASSERT (
+                    LSUP_term_equals (ts_res[k - 1], so[i][k]),
+                    "Wrong term in term set!");
+        */
+        i++;
+    }
+    LSUP_link_map_iter_free (lmit);
+    LSUP_link_map_free (lmap);
+    EXPECT_INT_EQ (i, 2);
+
+    i = 0; j = 0;
+    memset (k_res, 0, sizeof (k_res));
+    memset (ts_res, 0, sizeof (ts_res));
+    LSUP_Term *sp[1][3] = {
+        {trp[6]->s, trp[6]->p, NULL},
+    };
+    // terms connected to object, "String 1"@es-ES
+    lmap = LSUP_graph_connections (gr, trp[6]->o, LSUP_LINK_INBOUND);
+    lmit = LSUP_link_map_iter_new (lmap);
+    while (LSUP_link_map_next (lmit, k_res + i, &ts) == LSUP_OK) {
+        while (LSUP_term_set_next (ts, &j, ts_res + j) == LSUP_OK);
+        /*
+        ASSERT (
+                LSUP_term_equals (k_res[i], sp[i][0]),
+                "Wrong term in link map!");
+        for (size_t k = 1; sp[i][k]; k++)
+            ASSERT (
+                    LSUP_term_equals (ts_res[k - 1], sp[i][k]),
+                    "Wrong term in term set!");
+        */
+        i++;
+    }
+    LSUP_link_map_iter_free (lmit);
+    LSUP_link_map_free (lmap);
+    EXPECT_INT_EQ (i, 1);
+
     free_triples (trp);
+    LSUP_graph_free (gr);
     if (type != LSUP_STORE_HTABLE) LSUP_store_free (store);
 
     return 0;
@@ -579,6 +693,16 @@ BACKEND_TBL
 }
 
 
+static int test_graph_link_map() {
+#define ENTRY(a, b) \
+    if (_graph_link_map (LSUP_STORE_##a) != 0) return -1;
+BACKEND_TBL
+#undef ENTRY
+
+    return 0;
+}
+
+
 static int test_graph_bool_ops() {
 #define ENTRY(a, b) \
     if (_graph_bool_ops (LSUP_STORE_##a) != 0) return -1;
@@ -685,6 +809,7 @@ int graph_tests()
     RUN (test_graph_new);
     RUN (test_graph_add);
     RUN (test_graph_get);
+    RUN (test_graph_link_map);
     RUN (test_graph_bool_ops);
     RUN (test_graph_lookup);
     RUN (test_graph_remove);