scossu 1 неделя назад
Родитель
Сommit
94a83ed963
3 измененных файлов с 48 добавлено и 19 удалено
  1. 1 1
      ext/volksdata
  2. 39 12
      src/lua_term.c
  3. 8 6
      test.lua

+ 1 - 1
ext/volksdata

@@ -1 +1 @@
-Subproject commit 49a2cb38709bbdc9e3a6b429a6c9b2b36473ff76
+Subproject commit c37110fba218d23c489ddd74f9e35776595cc293

+ 39 - 12
src/lua_term.c

@@ -49,9 +49,10 @@ static int
 tset_iter_next (lua_State *L)
 {
     VOLK_TermSet *ts;
+    // light userdata coming from a link map is not garbage collected.
     if (lua_islightuserdata (L, lua_upvalueindex (1)))
         ts = lua_touserdata (L, lua_upvalueindex (1));
-    else ts = check_term_set(L, lua_upvalueindex (1));
+    else ts = check_term_set (L, lua_upvalueindex (1));
     size_t i = luaL_checkinteger (L, lua_upvalueindex (2));
     LOG_DEBUG ("TS Iteration #%zu", i);
     VOLK_Term *tmp = NULL;
@@ -409,10 +410,20 @@ static int l_term_set_attr (lua_State *L)
  * Link map.
  */
 
+/** @brief iterate over a link map.
+ *
+ * @param[in] copy If `false` (default), the iteration yields the linked term,
+ *  a term set iterator, and its size. This avoids copying the term set into a
+ *  new table, but the returned object can only be iterated once, and random
+ *  access via `contains` is not allowed. If `true`, the iteration yields the
+ *  linked term and a full term set table with a copy of the term set, that is
+ *  separately garbage-collected.
+ */
 static int lmap_iter_next (lua_State *L)
 {
     VOLK_LinkMapIterator *it =
         *(VOLK_LinkMapIterator **)lua_touserdata (L, lua_upvalueindex (1));
+    bool copy = lua_toboolean (L, 1);
 
     VOLK_TermSet *ts = NULL;
     VOLK_Term *tmp = NULL;
@@ -426,14 +437,30 @@ static int lmap_iter_next (lua_State *L)
     LUA_NLCHECK (link_p, "Error allocating term.");
     *link_p = VOLK_term_copy (tmp);
 
-    lua_pushlightuserdata (L, ts);
-    lua_pushinteger (L, 0);
-    stack_dump (L, "LM set up TS iter closure");
-    lua_pushcclosure (L, tset_iter_next, 2);
-    stack_dump (L, "LM TS iter init");
-
-    // linked term + term set.
-    return 2;
+    if (copy) {
+        // Deep copy of the term set as a full userdata object.
+        VOLK_TermSet *ts2 = VOLK_term_set_new ();
+        size_t i = 0;
+        VOLK_Term *tmp = NULL;
+        VOLK_rc cp_rc = VOLK_NORESULT;
+        while ((cp_rc = VOLK_term_set_next (ts, &i, &tmp)) == VOLK_OK)
+            VOLK_term_set_add (ts2, VOLK_term_copy (tmp), NULL);
+        LUA_PCHECK (cp_rc, "Error copying term set from link map.");
+
+        cp_rc = tset_to_udata (L, ts2);
+        return cp_rc == 1 ? 2 : 0;
+
+    } else {
+        // Second yielded value is a term set iterator. Random access methods
+        // are not allowed.
+        lua_pushlightuserdata (L, ts);
+        lua_pushinteger (L, 0);
+        lua_pushcclosure (L, tset_iter_next, 2);
+        lua_pushinteger (L, VOLK_term_set_size (ts));
+
+        // linked term, term set, size.
+        return 3;
+    }
 }
 
 
@@ -594,18 +621,18 @@ int luaopen_volksdata_term (lua_State *L)
     lua_pushcfunction (L, tset_size);
     lua_setfield (L, -2, "__len");
     lua_pushcfunction (L, tset_iter_init);
-    lua_setfield (L, -2, "__pairs");
-    lua_pushcfunction (L, tset_iter_init);
     lua_setfield (L, -2, "iter");
     lua_pushcfunction (L, tset_contains);
     lua_setfield (L, -2, "contains");
 
     // Link map.
     luaL_newmetatable (L, "VOLK.LinkMap");
+    lua_pushvalue (L, -1);
+    lua_setfield (L, -2, "__index");
     lua_pushcfunction (L, link_map_gc);
     lua_setfield (L, -2, "__gc");
     lua_pushcfunction (L, l_lmap_iter_init);
-    lua_setfield (L, -2, "__pairs");
+    lua_setfield (L, -2, "iter");
 
     // Link map iterator.
     luaL_newmetatable (L, "VOLK.LMapIterator");

+ 8 - 6
test.lua

@@ -44,27 +44,28 @@ for i in gr1:lookup(t1) do print(i) end
 ---[[
 print("Terms connected to t1 t2:")
 tset = gr1:term_set(t2, triple.POS_P, t1, triple.POS_S)
-for t in pairs(tset) do print(t) end
+for t in tset:iter() do print(t) end
 --]]
 
 ---[[
 lm = gr1:connections(t1, term.LINK_OUTBOUND)
 print("Connections")
-for t1, tsiter in pairs(lm) do
-    for t2 in tsiter do print(t1, t2) end
+for t1, tsit, size in lm:iter() do
+    assert (size == 3)
+    for t2 in tsit do print(t1, t2) end
 end
 --]]
 
 ---[[
 unique_t = gr1:unique_terms(triple.POS_S)
 print("Unique subjects")
-for t in pairs(unique_t) do print(t) end
+for t in unique_t:iter() do print(t) end
 print("Unique predicates")
 unique_t = gr1:unique_terms(triple.POS_P)
-for t in pairs(unique_t) do print(t) end
+for t in unique_t:iter() do print(t) end
 print("Unique objects")
 unique_t = gr1:unique_terms(triple.POS_O)
-for t in pairs(unique_t) do print(t) end
+for t in unique_t:iter() do print(t) end
 --]]
 
 namespace.add("ns1", "urn:ns:1#")
@@ -92,6 +93,7 @@ assert(#idx == 3)
 
 attr = mdb_gr2:attr(t1, t2)
 assert (#attr == 3)
+-- A new term can match a distinct but equivalent one in the set.
 assert(attr:contains(term.new_lit("Hola", nil, "es_ES")))
 print("Attributes:")
 for a in attr:iter() do print(a) end