lua与python结合_Lua和Python:实现一个高效的List对象(3)
這一篇介紹一些列表函數的實現。
取值
取值用法和Table一樣,用ls[idx]獲得列表的值;并且除了可以用正索引,還可以像Python一樣用負索引,如-1表示最后一個元素,-2表示倒數第2個元素等等,C層代碼如下:
// 取list指針#define checklist(L) (list_t*)luaL_checkudata(L, 1, LIST_MT)// ls[idx]static int list_index(lua_State *L) {
list_t *ls = checklist(L);
int idx = (int)luaL_checkinteger(L, 2);
if (idx > 0) idx--; // 正索引 else if (idx < 0) idx += ls->size; // 負索引 if (idx < 0 || idx >= ls->size) { // 超出范圍的一律返回nil lua_pushnil(L);
return 1;
}
int ref = ls->ary[idx].ref; // 取引用值 lua_getuservalue(L, 1); // 將list的關聯Table放到棧上 lua_rawgeti(L, -1, ref); // 通過引用取Table的值,并返回 return 1;
}
設值
對列表設值必須限定在長度之內,超出會拋出錯誤,唯一的例外是在列表最后設值,那樣將認為是往后面追加,比如這樣寫:ls[#ls+1] = "ok"。
不能將nil設置給列表,因為Lua認為設置nil是刪除元素,要達到類似的需求,可給列表設置false。
設值和取值一樣支持負索引。
// ls[idx] = vstatic int list_newindex(lua_State *L) {
list_t *ls = checklist(L);
int idx = (int)luaL_checkinteger(L, 2);
if (idx > 0) idx--; // 正索引 else if (idx < 0) idx += ls->size; // 負索引 luaL_argcheck(L, 0 <= idx && idx <= ls->size, 2, "index out of range"); // 范圍檢查 if (lua_isnoneornil(L, 3)) // 不允許設置為nil luaL_argerror(L, 3, "value can not be nil");
lua_getuservalue(L, 1); // 將list的關聯Table放到棧上 lua_pushvalue(L, 3); // 將設置的值壓棧 if (idx == ls->size) { // 往后追加 check_and_grow_size(ls, 1);
ls->ary[ls->size++].ref = ref_value(L, ls, -2);
} else { // 正常設值 lua_rawseti(L, -2, ls->ary[idx].ref);
}
return 0;
}
check_and_grow_size檢查數組的內存是否夠用,不夠會按2倍來擴展內存:
static void check_and_grow_size(list_t *ls, int n) {
int newcap = ls->cap;
while (ls->size + n > newcap)
newcap <<= 1;
if (newcap != ls->cap) {
ls->ary = (refdata_t*)realloc(ls->ary, newcap*sizeof(refdata_t));
ls->cap = newcap;
}
}
取值/設值由于用了元表的方法,多了一個間接層,必然比直接訪問Table要慢一點。
取列表長度
按Lua的習慣,取長度用#ls,只需將list的size返回即可,效率比Table取長度要快得多:
// #lsstatic int list_len(lua_State *L) {
list_t *ls = checklist(L);
lua_pushinteger(L, ls->size);
return 1;
}
清除列表內容
直接將list的size置0即可,對于關聯的Table,干脆拋棄它,直接新建一個Table關聯:
// list.clear(ls[, shink])static int list_clear(lua_State *L) {
list_t *ls = checklist(L);
int shink = lua_toboolean(L, 2); // 如果指定shink,會收縮內存 ls->size = 0; // 直接置0 ls->ref = 0;
if (shink) {
ls->cap = 4;
ls->ary = (refdata_t*)realloc(ls->ary, ls->cap * sizeof(refdata_t));
}
lua_createtable(L, ls->cap, 0); // 重新創建Table,替換掉老的Table,老Table會被Lua自動GC回收掉。 lua_setuservalue(L, 1);
return 0;
}
交換兩個位置的元素
這同樣是一個很高效的操作,不需要涉及到Table的操作,直接將兩個引用交換:
// list.exchange(ls, idx1, idx2)static int list_exchange(lua_State *L) {
list_t *ls = checklist(L);
int idx1 = (int)luaL_checkinteger(L, 2) - 1;
int idx2 = (int)luaL_checkinteger(L, 3) - 1;
if (idx1 == idx2) return 0;
luaL_argcheck(L, 0 <= idx1 && idx1 < ls->size, 2, "index out of range");
luaL_argcheck(L, 0 <= idx2 && idx2 < ls->size, 3, "index out of range");
refdata_t ref = ls->ary[idx1]; // 交換引用即可 ls->ary[idx1] = ls->ary[idx2];
ls->ary[idx2] = ref;
return 0;
}
插入元素
接口和table.insert一樣,如果不指定pos則往后插入,如果指定則插入到pos位置:
// list.insert(ls, [pos,] value)static int list_insert(lua_State *L) {
list_t *ls = checklist(L);
int pos, n, vidx;
if (lua_gettop(L) == 2) { // 只有兩個參數,則認為沒有指定pos,pos設置為size pos = ls->size;
vidx = 2;
} else { // 有指定pos pos = (int)luaL_checkinteger(L, 2) - 1;
vidx = 3;
}
if (lua_isnoneornil(L, vidx)) // 不允許設置nil luaL_argerror(L, vidx, "value can not be nil");
// 檢查pos的合法性 luaL_argcheck(L, 0 <= pos && pos <= ls->size, 2, "index out of range");
// 檢查和增長內存 check_and_grow_size(ls, 1);
// 如果不是往后插入,則要移動內存 if (pos != ls->size)
memmove(ls->ary + pos + 1, ls->ary + pos, (ls->size - pos) * sizeof(refdata_t));
lua_getuservalue(L, 1); // 取關聯Table lua_pushvalue(L, vidx); // 將要設置的值入棧 ls->ary[pos].ref = ref_value(L, ls, -2); // 將值設為Table,同時返回一個引用,保存到數組。 ls->size++;
return 0;
}
我們后面的操作都是對引用的操作,Table只是設值和去除值。
刪除元素
接口和table.remove一樣,如果不指定pos則從最后刪除,如果指定則刪除pos的值,最后返回刪除的值
// list.remove(ls[, pos]) -> vstatic int list_remove(lua_State *L) {
list_t *ls = checklist(L);
int pos = luaL_optinteger(L, 2, ls->size) - 1;
luaL_argcheck(L, 0 <= pos && pos < ls->size, 2, "index out of range");
int ref = ls->ary[pos].ref;
// 如果不是刪除最后一個,則要移動內存 if (pos != ls->size - 1)
memmove(ls->ary + pos, ls->ary + pos + 1, (ls->size - pos - 1) * sizeof(refdata_t));
ls->size--;
lua_getuservalue(L, 1); // 取關聯Table lua_rawgeti(L, -1, ref); // 將要刪除的值取出,返回 unref_value(L, -2, ref); // 刪除值,解除引用 return 1;
}
其他接口
除了上面的函數,還有其他的接口,這里就不一一介紹了,我最后會把完整代碼共享出來。
下一篇單獨把排序拿出來說,并給出一個高效的實現。
總結
以上是生活随笔為你收集整理的lua与python结合_Lua和Python:实现一个高效的List对象(3)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pe系统中无线网卡驱动加载不了怎么办 无
- 下一篇: csrf漏洞防御方案_变量覆盖漏洞利用及