Reimplement queues as circular buffers
This commit is contained in:
@@ -34,6 +34,11 @@ lua_Integer LuaStack::ckinteger(LuaSlot s) const {
|
||||
return lua_tointeger(L_, s);
|
||||
}
|
||||
|
||||
int LuaStack::ckint(LuaSlot s) const {
|
||||
luaL_checktype(L_, s, LUA_TNUMBER);
|
||||
return (int)lua_tointeger(L_, s);
|
||||
}
|
||||
|
||||
lua_Number LuaStack::cknumber(LuaSlot s) const {
|
||||
luaL_checktype(L_, s, LUA_TNUMBER);
|
||||
return lua_tonumber(L_, s);
|
||||
|
||||
@@ -382,6 +382,7 @@ public:
|
||||
|
||||
bool ckboolean(LuaSlot s) const;
|
||||
lua_Integer ckinteger(LuaSlot s) const;
|
||||
int ckint(LuaSlot s) const;
|
||||
lua_Number cknumber(LuaSlot s) const;
|
||||
std::string ckstring(LuaSlot s) const;
|
||||
lua_State *ckthread(LuaSlot s) const;
|
||||
|
||||
@@ -131,76 +131,127 @@ LuaDefine(table_clear, "c") {
|
||||
return LS.result();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Queue operators.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
#define QUEUE_POP 1
|
||||
#define QUEUE_FILL 2
|
||||
#define QUEUE_MAX 3
|
||||
#define QUEUE_BASE 4
|
||||
|
||||
LuaDefine(queue_create, "c") {
|
||||
LuaRet queue;
|
||||
LuaStack LS(L, queue);
|
||||
|
||||
LS.newtable(queue);
|
||||
LS.rawset(queue, "head", 1000000);
|
||||
LS.rawset(queue, "tail", 1000000);
|
||||
const int imax = 8;
|
||||
LS.createtable(queue, QUEUE_BASE + imax - 1, 0);
|
||||
LS.rawseti(queue, QUEUE_POP, 0);
|
||||
LS.rawseti(queue, QUEUE_FILL, 0);
|
||||
LS.rawseti(queue, QUEUE_MAX, imax);
|
||||
for (int i = 0; i < imax; i++) {
|
||||
LS.rawseti(queue, QUEUE_BASE + i, 0);
|
||||
}
|
||||
return LS.result();
|
||||
}
|
||||
|
||||
|
||||
LuaDefine(queue_push, "c") {
|
||||
LuaArg queue, elt;
|
||||
lua_Integer head;
|
||||
LuaStack LS(L, queue, elt);
|
||||
|
||||
LS.rawget(head, queue, "head");
|
||||
LS.rawset(queue, head, elt);
|
||||
LS.rawset(queue, "head", head+1);
|
||||
LuaVar qpop, qfill, qmax, t;
|
||||
LuaStack LS(L, queue, elt, qpop, qfill, qmax, t);
|
||||
LS.checktable(queue);
|
||||
LS.rawgeti(qpop, queue, QUEUE_POP);
|
||||
LS.rawgeti(qfill, queue, QUEUE_FILL);
|
||||
LS.rawgeti(qmax, queue, QUEUE_MAX);
|
||||
int pop = LS.ckint(qpop);
|
||||
int fill = LS.ckint(qfill);
|
||||
int max = LS.ckint(qmax);
|
||||
if (fill == max) {
|
||||
int overflow = (pop + fill) - max;
|
||||
if (overflow < 0) overflow = 0;
|
||||
for (int i = 0; i < overflow; i++) {
|
||||
lua_rawgeti(L, queue.index(), QUEUE_BASE + i);
|
||||
lua_rawseti(L, queue.index(), QUEUE_BASE + i + max);
|
||||
lua_pushinteger(L, 0);
|
||||
lua_rawseti(L, queue.index(), QUEUE_BASE + i);
|
||||
}
|
||||
for (int i = overflow; i < max; i++) {
|
||||
lua_pushinteger(L, 0);
|
||||
lua_rawseti(L, queue.index(), QUEUE_BASE + i + max);
|
||||
}
|
||||
max *= 2;
|
||||
LS.rawseti(queue, QUEUE_MAX, max);
|
||||
}
|
||||
int target = pop + fill;
|
||||
if (target >= max) target -= max;
|
||||
LS.rawseti(queue, QUEUE_BASE + target, elt);
|
||||
LS.rawseti(queue, QUEUE_FILL, fill + 1);
|
||||
return LS.result();
|
||||
}
|
||||
|
||||
LuaDefine(queue_pop, "c") {
|
||||
LuaArg queue;
|
||||
LuaRet elt;
|
||||
lua_Integer head, tail;
|
||||
LuaStack LS(L, queue, elt);
|
||||
|
||||
LS.rawget(tail, queue, "tail");
|
||||
LS.rawget(head, queue, "head");
|
||||
if (head == tail) {
|
||||
LS.set(elt, LuaNil);
|
||||
} else {
|
||||
LS.rawget(elt, queue, tail);
|
||||
LS.rawset(queue, tail, LuaNil);
|
||||
LS.rawset(queue, "tail", tail + 1);
|
||||
LuaVar qpop, qfill, qmax, t;
|
||||
LuaRet result;
|
||||
LuaStack LS(L, queue, qpop, qfill, qmax, result, t);
|
||||
LS.checktable(queue);
|
||||
LS.rawgeti(qpop, queue, QUEUE_POP);
|
||||
LS.rawgeti(qfill, queue, QUEUE_FILL);
|
||||
LS.rawgeti(qmax, queue, QUEUE_MAX);
|
||||
int fill = LS.ckint(qfill);
|
||||
if (fill <= 0) {
|
||||
LS.set(result, LuaNil);
|
||||
return LS.result();
|
||||
}
|
||||
int pop = LS.ckint(qpop);
|
||||
int max = LS.ckint(qmax);
|
||||
LS.rawgeti(result, queue, QUEUE_BASE + pop);
|
||||
LS.rawseti(queue, QUEUE_BASE + pop, 0);
|
||||
int next = pop + 1;
|
||||
if (next == max) next = 0;
|
||||
LS.rawseti(queue, QUEUE_POP, next);
|
||||
LS.rawseti(queue, QUEUE_FILL, fill - 1);
|
||||
return LS.result();
|
||||
}
|
||||
|
||||
LuaDefine(queue_size, "c") {
|
||||
LuaArg queue;
|
||||
LuaRet size;
|
||||
lua_Number head, tail;
|
||||
LuaStack LS(L, queue, size);
|
||||
|
||||
LS.rawget(head, queue, "head");
|
||||
LS.rawget(tail, queue, "tail");
|
||||
LS.set(size, head - tail);
|
||||
LS.checktable(queue);
|
||||
LS.rawget(size, queue, QUEUE_FILL);
|
||||
LS.checknumber(size);
|
||||
return LS.result();
|
||||
}
|
||||
|
||||
LuaDefine(queue_nth, "c") {
|
||||
LuaArg queue, n;
|
||||
LuaArg queue, nn;
|
||||
LuaVar qpop, qfill, qmax;
|
||||
LuaRet elt;
|
||||
lua_Integer nth, head, tail;
|
||||
LuaStack LS(L, queue, n, elt);
|
||||
|
||||
nth = LS.ckinteger(n) - 1;
|
||||
LS.rawget(head, queue, "head");
|
||||
LS.rawget(tail, queue, "tail");
|
||||
if ((nth < 0) || (nth + tail >= head)) {
|
||||
luaL_error(L, "index out of range");
|
||||
LuaStack LS(L, queue, nn, qpop, qfill, qmax, elt);
|
||||
LS.checktable(queue);
|
||||
int n = LS.ckint(nn) - 1;
|
||||
LS.rawgeti(qfill, queue, QUEUE_FILL);
|
||||
int fill = LS.ckint(qfill);
|
||||
if ((n < 0) || (n >= fill)) {
|
||||
LS.set(elt, LuaNil);
|
||||
return LS.result();
|
||||
}
|
||||
LS.rawget(elt, queue, tail + nth);
|
||||
LS.rawgeti(qpop, queue, QUEUE_POP);
|
||||
LS.rawgeti(qmax, queue, QUEUE_MAX);
|
||||
int pop = LS.ckint(qpop);
|
||||
int max = LS.ckint(qmax);
|
||||
int index = pop + n;
|
||||
if (index > max) index -= max;
|
||||
LS.rawgeti(elt, queue, QUEUE_BASE + index);
|
||||
return LS.result();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// table_sortedpairs
|
||||
// table_getpairs
|
||||
//
|
||||
// Given a table, return all the pairs in the table as a sequence.
|
||||
// The resulting sequence contains a 1 in the first position,
|
||||
@@ -209,6 +260,7 @@ LuaDefine(queue_nth, "c") {
|
||||
// sortedpairs({a=1,b=2,c=3}) => {1,"a",1,"b",2,"c",3}
|
||||
//
|
||||
// Note that this function is not directly exposed to lua.
|
||||
// It's exposed only through the 'sortedpairs' iterator.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -307,7 +359,7 @@ static void auxsort (lua_State *L, int tab, int l, int u) {
|
||||
} /* repeat the routine for the larger one */
|
||||
}
|
||||
|
||||
int table_getpairs(lua_State *L, bool sort, bool *unsortable) {
|
||||
static int table_getpairs(lua_State *L, bool sort, bool *unsortable) {
|
||||
lua_checkstack(L, 40);
|
||||
LuaArg tab;
|
||||
LuaVar key, value;
|
||||
|
||||
@@ -72,20 +72,6 @@ int table_empty(lua_State *L);
|
||||
//
|
||||
int table_count(lua_State *L);
|
||||
|
||||
// table_sortedpairs
|
||||
//
|
||||
// Return a vector containing pairs from the table.
|
||||
// This is not exposed directly to lua, but it is used
|
||||
// in the new version of the 'pairs' iterator.
|
||||
//
|
||||
// The boolean 'sort' is used to control whether the pairs
|
||||
// are to be sorted or not.
|
||||
//
|
||||
// The boolean 'unsortable' returns a flag indicating
|
||||
// whether or not unsortable items were omitted.
|
||||
//
|
||||
int table_getpairs(lua_State *L, bool sort, bool *unsortable);
|
||||
|
||||
// table_clear
|
||||
//
|
||||
// Remove all key/value pairs from the table. Does not
|
||||
@@ -95,7 +81,9 @@ int table_clear(lua_State *L);
|
||||
|
||||
// queue_create
|
||||
//
|
||||
// Create and return an empty queue.
|
||||
// Create and return an empty queue. Queues are implemented
|
||||
// as tables which are used as dynamically-expandable circular
|
||||
// buffers.
|
||||
//
|
||||
int queue_create(lua_State *L);
|
||||
|
||||
|
||||
@@ -58,26 +58,23 @@ end
|
||||
|
||||
function unittests.queues()
|
||||
local q = queue.create()
|
||||
assert(q.head == 1000000)
|
||||
assert(q.tail == 1000000)
|
||||
assert(queue.size(q) == 0)
|
||||
assert(table.count(q) == 2)
|
||||
queue.push(q, 27)
|
||||
assert(queue.size(q) == 1)
|
||||
queue.push(q, 45)
|
||||
assert(queue.nth(q, 1) == 27)
|
||||
assert(queue.nth(q, 2) == 45)
|
||||
assert(queue.size(q) == 2)
|
||||
assert(table.count(q) == 4)
|
||||
assert(queue.pop(q) == 27)
|
||||
assert(queue.size(q) == 1)
|
||||
assert(table.count(q) == 3)
|
||||
assert(queue.pop(q) == 45)
|
||||
assert(queue.size(q) == 0)
|
||||
assert(table.count(q) == 2)
|
||||
assert(queue.pop(q) == nil)
|
||||
assert(table.count(q) == 2)
|
||||
assert(q.head == 1000002)
|
||||
assert(q.tail == 1000002)
|
||||
assert(queue.size(q) == 0)
|
||||
for i=1,50 do
|
||||
queue.push(q,i)
|
||||
end
|
||||
for i=1,50 do
|
||||
assert(queue.pop(q)==i)
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user