|
@@ -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");
|