lua_graph.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. #include "lua_lsup.h"
  2. #define check_graph(L) \
  3. *(LSUP_Graph **)luaL_checkudata(L, 1, "LSUP.Graph")
  4. static LSUP_Graph **allocate_graph (lua_State *L)
  5. {
  6. LSUP_Graph **gp = lua_newuserdatauv (L, sizeof (*gp), 1);
  7. luaL_getmetatable (L, "LSUP.Graph");
  8. lua_setmetatable (L, -2);
  9. return gp;
  10. }
  11. static int l_graph_new (lua_State *L)
  12. {
  13. LSUP_Store *store;
  14. if (!lua_isnoneornil (L, 1))
  15. store = *(LSUP_Store **)luaL_checkudata (L, 1, "LSUP.Store");
  16. else store = NULL;
  17. const char *uri_str = lua_tostring (L, 2);
  18. LSUP_Graph **gp = allocate_graph (L);
  19. // TODO Make store ID, nsm and initial size accessible.
  20. *gp = LSUP_graph_new (store, uri_str, NULL);
  21. LUA_NLCHECK (*gp, "Error creating graph.");
  22. return 1;
  23. }
  24. static int l_graph_list (lua_State *L)
  25. {
  26. const LSUP_Store *store = *(LSUP_Store **)luaL_checkudata (
  27. L, 1, "LSUP.Store");
  28. LSUP_TermSet **ts_p = lua_newuserdata (L, sizeof *ts_p);
  29. luaL_getmetatable (L, "LSUP.TermSet");
  30. lua_setmetatable (L, -2);
  31. *ts_p = LSUP_graph_list (store);
  32. LUA_NLCHECK (ts_p, "Error retrieving context list.");
  33. return 1;
  34. }
  35. /*
  36. * Class methods.
  37. */
  38. static int l_graph_gc (lua_State *L)
  39. {
  40. LSUP_Graph **gp = luaL_checkudata(L, 1, "LSUP.Graph");
  41. LOG_DEBUG ("Garbage collecting graph @%p", *gp);
  42. LSUP_graph_free (*gp);
  43. *gp = NULL;
  44. return 0;
  45. }
  46. static int l_graph_to_string (lua_State *L)
  47. {
  48. const LSUP_Graph *gr = check_graph (L);
  49. lua_pushfstring (
  50. L, "LSUP.Graph @%p <%s>: %d triples",
  51. gr, LSUP_graph_uri (gr)->data, LSUP_graph_size (gr));
  52. return 1;
  53. }
  54. static int l_graph_len (lua_State *L)
  55. {
  56. const LSUP_Graph *gr = check_graph (L);
  57. lua_pushinteger (L, LSUP_graph_size (gr));
  58. return 1;
  59. }
  60. static int l_graph_copy (lua_State *L)
  61. {
  62. const LSUP_Graph *src = check_graph (L);
  63. LSUP_Graph *dest = *(LSUP_Graph **)luaL_checkudata(L, 2, "LSUP.Graph");
  64. LUA_PCHECK (LSUP_graph_copy (src, dest), "Error copying graph");
  65. return 1;
  66. }
  67. static int l_graph_copy_contents (lua_State *L)
  68. {
  69. const LSUP_Graph *src = check_graph (L);
  70. LSUP_Graph *dest = *(LSUP_Graph **)luaL_checkudata (L, 2, "LSUP.Graph");
  71. const LSUP_Term *s, *p, *o;
  72. if lua_isnoneornil (L, 3) s = NULL;
  73. else s = *(LSUP_Term **)luaL_checkudata (L, 3, "LSUP.Term");
  74. if lua_isnoneornil (L, 4) p = NULL;
  75. else p = *(LSUP_Term **)luaL_checkudata (L, 4, "LSUP.Term");
  76. if lua_isnoneornil (L, 5) o = NULL;
  77. else o = *(LSUP_Term **)luaL_checkudata (L, 5, "LSUP.Term");
  78. LUA_PCHECK (LSUP_graph_copy_contents (
  79. src, dest, s, p, o), "Error copying graph.");
  80. return 1;
  81. }
  82. static int l_graph_equals (lua_State *L)
  83. {
  84. const LSUP_Graph *gr1 = check_graph (L);
  85. const LSUP_Graph *gr2 =
  86. *(LSUP_Graph **)luaL_checkudata (L, 2, "LSUP.Graph");
  87. LOG_DEBUG ("Comparing graphs %p %p", gr1, gr2);
  88. int eq_rc = LSUP_graph_equals (gr1, gr2);
  89. lua_pushboolean (L, eq_rc);
  90. return 1;
  91. }
  92. static int l_graph_contains (lua_State *L)
  93. {
  94. const LSUP_Graph *gr = check_graph (L);
  95. const LSUP_Triple *spo =
  96. *(LSUP_Triple **)luaL_checkudata (L, 2, "LSUP.Triple");
  97. lua_pushboolean (L, LSUP_graph_contains (gr, spo));
  98. return 1;
  99. }
  100. static int l_graph_add (lua_State *L)
  101. {
  102. LSUP_Graph *gr = check_graph (L);
  103. int rc;
  104. LSUP_rc lsup_rc= LSUP_NOACTION;
  105. size_t i = 0, ct = 0;
  106. LSUP_GraphIterator *it = LSUP_graph_add_init (gr);
  107. while ((rc = lua_rawgeti (L, 2, ++i)) != LUA_TNIL) {
  108. //LOG_DEBUG ("Triple type: %s", lua_typename (L, rc));
  109. const LSUP_Triple *spo =
  110. *(LSUP_Triple **)luaL_checkudata (L, -1, "LSUP.Triple");
  111. LOG_DEBUG (
  112. "Got triple %d: {%s %s %s}\n",
  113. i, spo->s->data, spo->p->data, spo->o->data);
  114. lsup_rc = LSUP_graph_add_iter (it, spo);
  115. if (lsup_rc < LSUP_OK) break;
  116. if (lsup_rc == LSUP_OK) ct++;
  117. };
  118. LSUP_graph_add_done (it);
  119. lua_pushinteger (L, ct);
  120. if (UNLIKELY (lsup_rc < LSUP_OK)) return luaL_error (
  121. L, "Error adding triple at position %d: %s",
  122. i, LSUP_strerror (lsup_rc));
  123. else return 1;
  124. }
  125. static int l_graph_remove (lua_State *L)
  126. {
  127. LSUP_Graph *gr = check_graph (L);
  128. const LSUP_Term *s, *p, *o;
  129. if lua_isnoneornil (L, 2) s = NULL;
  130. else s = *(LSUP_Term **)luaL_checkudata (L, 2, "LSUP.Term");
  131. if lua_isnoneornil (L, 3) p = NULL;
  132. else p = *(LSUP_Term **)luaL_checkudata (L, 3, "LSUP.Term");
  133. if lua_isnoneornil (L, 4) o = NULL;
  134. else o = *(LSUP_Term **)luaL_checkudata (L, 4, "LSUP.Term");
  135. size_t ct;
  136. LSUP_rc rc = LSUP_graph_remove (gr, s, p, o, &ct);
  137. LUA_PCHECK (rc, "Error removing triples from graph.");
  138. lua_pushinteger (L, ct);
  139. return 1;
  140. }
  141. static int graph_iter_next (lua_State *L)
  142. {
  143. LSUP_GraphIterator **it_p = lua_touserdata (L, lua_upvalueindex (1));
  144. LSUP_Triple **spo_p = lua_newuserdatauv (L, sizeof (*spo_p), 1);
  145. luaL_getmetatable (L, "LSUP.Triple");
  146. lua_setmetatable (L, -2);
  147. *spo_p = NULL;
  148. LSUP_rc rc = LSUP_graph_iter_next (*it_p, spo_p);
  149. if (rc != LSUP_OK) {
  150. LSUP_graph_iter_free (*it_p);
  151. *it_p = NULL;
  152. if (rc == LSUP_END) {
  153. lua_pushnil (L);
  154. lua_pushstring (L, "End of lookup results.");
  155. return 2;
  156. }
  157. LUA_PCHECK (rc, "Error retrieving a lookup result.");
  158. }
  159. return 1;
  160. }
  161. static int l_graph_lookup (lua_State *L)
  162. {
  163. const LSUP_Graph *gr = check_graph (L);
  164. const LSUP_Term *s, *p, *o;
  165. if lua_isnoneornil (L, 2) s = NULL;
  166. else s = *(LSUP_Term **)luaL_checkudata (L, 2, "LSUP.Term");
  167. if lua_isnoneornil (L, 3) p = NULL;
  168. else p = *(LSUP_Term **)luaL_checkudata (L, 3, "LSUP.Term");
  169. if lua_isnoneornil (L, 4) o = NULL;
  170. else o = *(LSUP_Term **)luaL_checkudata (L, 4, "LSUP.Term");
  171. LSUP_GraphIterator **it_p =
  172. (LSUP_GraphIterator **)lua_newuserdata (L, sizeof *it_p);
  173. *it_p = NULL;
  174. luaL_getmetatable (L, "LSUP.GraphIterator");
  175. lua_setmetatable (L, -2);
  176. size_t ct;
  177. *it_p = LSUP_graph_lookup (gr, s, p, o, &ct);
  178. LUA_NLCHECK (*it_p, "Error creating graph iterator.");
  179. LOG_DEBUG ("Found triples: %d", ct);
  180. lua_pushcclosure (L, graph_iter_next, 1);
  181. return 1;
  182. }
  183. /** @brief Free an iterator handle.
  184. *
  185. * This is only called if the iterator is abandoned before the
  186. * iteration cycle is over (either by end of loop or error).
  187. *
  188. * @note A new iterator should not be started without first garbage-collecting
  189. * an incomplete one. That would cause a MDB_BAD_RSLOT error on an LMDB-backed
  190. * graph, because it attempts to open a new read transaction while the old
  191. * iterator is keeping the old one open.
  192. */
  193. static int graph_iter_gc (lua_State *L)
  194. {
  195. LSUP_GraphIterator **it_p = lua_touserdata (L, 1);
  196. if (UNLIKELY (!it_p || !*it_p)) return 0;
  197. LOG_DEBUG ("Garbage collecting iterator @%p", it_p);
  198. LSUP_graph_iter_free (*it_p);
  199. *it_p = NULL;
  200. return 0;
  201. }
  202. /** Returns a LinkMap that can be iterated over with iter().
  203. */
  204. static int l_graph_connections (lua_State *L)
  205. {
  206. const LSUP_Graph *gr = check_graph (L);
  207. LSUP_Term *t = *(LSUP_Term **)luaL_checkudata (L, 2, "LSUP.Term");
  208. const LSUP_LinkType type = luaL_checkinteger (L, 3);
  209. LOG_DEBUG ("Adding term for connections: @%p", *t);
  210. LSUP_LinkMap **lm_p = lua_newuserdata (L, sizeof *lm_p);
  211. *lm_p = LSUP_graph_connections (gr, t, type);
  212. LUA_NLCHECK (*lm_p, "Error creating Link map.");
  213. luaL_getmetatable (L, "LSUP.LinkMap");
  214. lua_setmetatable (L, -2);
  215. return 1;
  216. }
  217. static int l_graph_term_set (lua_State *L)
  218. {
  219. const LSUP_Graph *gr = check_graph (L);
  220. const LSUP_Term *t1 = *(LSUP_Term **)luaL_checkudata (L, 2, "LSUP.Term");
  221. const LSUP_TriplePos t1_pos = luaL_checkinteger (L, 3);
  222. const LSUP_Term *t2 = *(LSUP_Term **)luaL_checkudata (L, 4, "LSUP.Term");
  223. const LSUP_TriplePos t2_pos = luaL_checkinteger (L, 5);
  224. LSUP_TermSet **ts_p = lua_newuserdata (L, sizeof *ts_p);
  225. luaL_getmetatable (L, "LSUP.TermSet");
  226. lua_setmetatable (L, -2);
  227. *ts_p = LSUP_graph_term_set (gr, t1, t1_pos, t2, t2_pos);
  228. LUA_NLCHECK (*ts_p, "Error creating term set.");
  229. return 1;
  230. }
  231. static int l_graph_unique_terms (lua_State *L)
  232. {
  233. const LSUP_Graph *gr = check_graph (L);
  234. const LSUP_TriplePos pos = luaL_checkinteger (L, 2);
  235. LSUP_TermSet **ts_p = lua_newuserdata (L, sizeof *ts_p);
  236. luaL_getmetatable (L, "LSUP.TermSet");
  237. lua_setmetatable (L, -2);
  238. *ts_p = LSUP_graph_unique_terms (gr, pos);
  239. LUA_NLCHECK (*ts_p, "Error creating term set.");
  240. return 1;
  241. }
  242. /*
  243. * Library setup.
  244. */
  245. static const luaL_Reg graph_lib_fn [] = {
  246. {"new", l_graph_new},
  247. {"list", l_graph_list},
  248. {NULL}
  249. };
  250. /*
  251. static const luaL_Reg graph_getters [] = {
  252. {"uri", l_graph_get_uri},
  253. {"namespace", l_graph_get_nsm},
  254. {NULL}
  255. };
  256. */
  257. /*
  258. static const luaL_Reg graph_setters [] = {
  259. {"uri", l_graph_set_uri},
  260. {NULL}
  261. };
  262. */
  263. static const luaL_Reg graph_lib_meth [] = {
  264. {"__eq", l_graph_equals},
  265. {"__gc", l_graph_gc},
  266. //{"__index", get_attr},
  267. //{"__newindex", set_attr},
  268. {"__tostring", l_graph_to_string},
  269. {"__len", l_graph_len},
  270. {"copy", l_graph_copy},
  271. {"copy_contents", l_graph_copy_contents},
  272. {"add", l_graph_add},
  273. {"remove", l_graph_remove},
  274. {"lookup", l_graph_lookup},
  275. {"contains", l_graph_contains},
  276. {"connections", l_graph_connections},
  277. {"term_set", l_graph_term_set},
  278. {"unique_terms", l_graph_unique_terms},
  279. //{"to_n3", l_graph_to_n3},
  280. {NULL}
  281. };
  282. static const LEnumConst graph_enums[] = {
  283. {NULL, 0}
  284. };
  285. int luaopen_lsup_graph (lua_State *L)
  286. {
  287. LSUP_init(); // This is idempotent: no problem calling it multiple times.
  288. luaL_newmetatable (L, "LSUP.Graph");
  289. lua_pushvalue (L, -1);
  290. lua_setfield (L, -2, "__index");
  291. luaL_setfuncs (L, graph_lib_meth, 0);
  292. // Metatables for ancillary types.
  293. luaL_newmetatable (L, "LSUP.GraphIterator");
  294. lua_pushcfunction (L, graph_iter_gc);
  295. lua_setfield (L, -2, "__gc");
  296. /*
  297. // Getters table.
  298. lua_newtable (L);
  299. for (int i = 0; graph_getters[i].name != NULL; i++) {
  300. lua_pushcfunction (L, graph_getters[i].func);
  301. lua_setfield (L, -2, graph_getters[i].name);
  302. }
  303. // Set getters table as a value for the Graph metatable.
  304. lua_setfield (L, -2, "getters");
  305. */
  306. luaL_newlib (L, graph_lib_fn);
  307. // Module-level constants.
  308. push_int_const (L, graph_enums);
  309. return 1;
  310. }