Skip to content
Snippets Groups Projects
Commit 28704d00 authored by Roman Tsisyk's avatar Roman Tsisyk
Browse files

Add Lua/C version of index:pairs()

A part of #863
parent e8c3d433
No related branches found
No related tags found
No related merge requests found
......@@ -42,6 +42,8 @@
/** {{{ box.index Lua library: access to spaces and indexes
*/
static int CTID_STRUCT_ITERATOR_REF = 0;
static inline Index *
check_index(uint32_t space_id, uint32_t index_id)
{
......@@ -307,6 +309,30 @@ boxffi_index_iterator(uint32_t space_id, uint32_t index_id, int type,
}
}
static int
lbox_index_iterator(lua_State *L)
{
if (lua_gettop(L) != 4 || !lua_isnumber(L, 1) || !lua_isnumber(L, 2) ||
!lua_isnumber(L, 3))
return luaL_error(L, "usage index.iterator(space_id, index_id, type, key)");
uint32_t space_id = lua_tointeger(L, 1);
uint32_t index_id = lua_tointeger(L, 2);
uint32_t iterator = lua_tointeger(L, 3);
/* const char *key = lbox_tokey(L, 4); */
const char *mpkey = lua_tolstring(L, 4, NULL); /* Key encoded by Lua */
struct iterator *it = boxffi_index_iterator(space_id, index_id,
iterator, mpkey);
if (it == NULL)
return lbox_error(L);
assert(CTID_STRUCT_ITERATOR_REF != 0);
struct iterator **ptr = (struct iterator **) luaL_pushcdata(L,
CTID_STRUCT_ITERATOR_REF, sizeof(struct iterator *));
*ptr = it; /* NULL handled by Lua, gc also set by Lua */
return 1;
}
struct tuple*
boxffi_iterator_next(struct iterator *itr)
{
......@@ -333,11 +359,36 @@ boxffi_iterator_next(struct iterator *itr)
}
}
static int
lbox_iterator_next(lua_State *L)
{
/* first argument is key buffer */
if (lua_gettop(L) < 1 || lua_type(L, 1) != LUA_TCDATA)
return luaL_error(L, "usage: next(state)");
assert(CTID_STRUCT_ITERATOR_REF != 0);
uint32_t ctypeid;
void *data = luaL_checkcdata(L, 1, &ctypeid);
if (ctypeid != CTID_STRUCT_ITERATOR_REF)
return luaL_error(L, "usage: next(state)");
struct iterator *itr = *(struct iterator **) data;
struct tuple *tuple = boxffi_iterator_next(itr);
return lbox_returntuple(L, tuple);
}
/* }}} */
void
box_lua_index_init(struct lua_State *L)
{
/* Get CTypeIDs */
int rc = luaL_cdef(L, "struct iterator;");
assert(rc == 0);
(void) rc;
CTID_STRUCT_ITERATOR_REF = luaL_ctypeid(L, "struct iterator&");
assert(CTID_STRUCT_ITERATOR_REF != 0);
static const struct luaL_reg indexlib [] = {
{NULL, NULL}
};
......@@ -353,6 +404,8 @@ box_lua_index_init(struct lua_State *L)
{"min", lbox_index_min},
{"max", lbox_index_max},
{"count", lbox_index_count},
{"iterator", lbox_index_iterator},
{"iterator_next", lbox_iterator_next},
{NULL, NULL}
};
......
-- schema.lua (internal file)
--
local ffi = require('ffi')
local msgpack = require('msgpack')
local msgpackffi = require('msgpackffi')
local fun = require('fun')
local session = box.session
......@@ -524,7 +525,7 @@ local iterator_gen = function(param, state)
information.
--]]
if not ffi.istype(iterator_t, state) then
error('usage gen(param, state)')
error('usage: next(param, state)')
end
-- next() modifies state in-place
local tuple = builtin.boxffi_iterator_next(state)
......@@ -537,6 +538,15 @@ local iterator_gen = function(param, state)
end
end
local iterator_gen_luac = function(param, state)
local tuple = internal.iterator_next(state)
if tuple ~= nil then
return state, tuple -- new state, value
else
return nil
end
end
local iterator_cdata_gc = function(iterator)
return iterator.free(iterator)
end
......@@ -650,7 +660,7 @@ function box.schema.space.bless(space)
return internal.random(index.space_id, index.id, rnd);
end
-- iteration
index_mt.pairs = function(index, key, opts)
index_mt.pairs_ffi = function(index, key, opts)
local pkey, pkey_end = msgpackffi.encode_tuple(key)
local itype = check_iterator_type(opts, pkey + 1 >= pkey_end);
......@@ -660,11 +670,18 @@ function box.schema.space.bless(space)
if cdata == nil then
box.error()
end
return fun.wrap(iterator_gen, keybuf, ffi.gc(cdata, iterator_cdata_gc))
end
index_mt.__pairs = index_mt.pairs -- Lua 5.2 compatibility
index_mt.__ipairs = index_mt.pairs -- Lua 5.2 compatibility
index_mt.pairs_luac = function(index, key, opts)
key = keify(key)
local itype = check_iterator_type(opts, #key == 0);
local keymp = msgpack.encode(key)
local keybuf = ffi.string(keymp, #keymp)
local cdata = internal.iterator(index.space_id, index.id, itype, keymp);
return fun.wrap(iterator_gen_luac, keybuf,
ffi.gc(cdata, iterator_cdata_gc))
end
-- index subtree size
index_mt.count_ffi = function(index, key, opts)
local pkey, pkey_end = msgpackffi.encode_tuple(key)
......@@ -764,7 +781,7 @@ function box.schema.space.bless(space)
-- true if reading operations may yield
local read_yields = space.engine == 'sophia'
local read_ops = {'select', 'get', 'min', 'max', 'count', 'random'}
local read_ops = {'select', 'get', 'min', 'max', 'count', 'random', 'pairs'}
for _, op in ipairs(read_ops) do
if read_yields then
-- use Lua/C implmenetation
......@@ -774,6 +791,8 @@ function box.schema.space.bless(space)
index_mt[op] = index_mt[op .. "_ffi"]
end
end
index_mt.__pairs = index_mt.pairs -- Lua 5.2 compatibility
index_mt.__ipairs = index_mt.pairs -- Lua 5.2 compatibility
--
local space_mt = {}
space_mt.len = function(space)
......
......@@ -96,6 +96,23 @@ luaL_ctypeid(struct lua_State *L, const char *ctypename)
return ctypeid;
}
int
luaL_cdef(struct lua_State *L, const char *what)
{
int idx = lua_gettop(L);
/* This function calls ffi.cdef */
/* Get ffi.typeof function */
luaL_loadstring(L, "return require('ffi').cdef");
lua_call(L, 0, 1);
/* FFI must exist */
assert(lua_gettop(L) == idx + 1 && lua_isfunction(L, idx + 1));
/* Push the argument to ffi.cdef */
lua_pushstring(L, what);
/* Call ffi.cdef() */
return lua_pcall(L, 1, 0, 0);
}
int
luaL_setcdatagc(struct lua_State *L, int idx)
{
......
......@@ -101,6 +101,17 @@ luaL_setcdatagc(struct lua_State *L, int idx);
LUA_API uint32_t
luaL_ctypeid(struct lua_State *L, const char *ctypename);
/**
* @brief Declare symbols for FFI
* @param L Lua State
* @param what C definitions
* @sa ffi.cdef(def)
* @retval 0 on success
* @retval LUA_ERRRUN, LUA_ERRMEM, LUA_ERRERR otherwise
*/
LUA_API int
luaL_cdef(struct lua_State *L, const char *ctypename);
/** \endcond public */
static inline lua_Integer
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment