这一篇介绍一些列表函数的实现。

取值

取值用法和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)相关推荐

  1. python和lua哪个有前途_lua、python对比学习

    一.基本数据类型: lua:nil(空).boolean(false和nil为假).number(数值).string(字符串).table(表).function(方法).thread (线程).u ...

  2. python是不是特别垃圾-Python是垃圾?(转)

    第一个常见看法是: python和basic差不多应该是容易学,但是功能弱的语言 basic是好多人的年幼时的回忆了,gvbasic,gwbasic,qbaisc,各种版本把很多人带入了快乐的世界里面 ...

  3. python 搜寻蓝牙_3 Python Web搜寻器和搜寻器

    python 搜寻蓝牙 在理想环境中,您需要的所有数据都将以开放且有据可查的格式清晰呈现,您可以轻松下载并使用它们以实现所需的目的. 在现实世界中,数据是混乱的,很少按照您的需要打包,并且经常是过时的 ...

  4. python lua 性能比较 内存_Lua 的速度为什么比 Python 快?

    最近研究了下Python的代码,有了一些新的发现.大量的内置字符串常量没有做Intern优化,在python源码中搜索形如"__dict__"之类的常量是这么用的: PyObjec ...

  5. python js 性能_lua与python性能测试比较

    CLR/C#/Java/Python/IronPython/JavaScript/Lua/Ruby/Squirre l性能测试 今天蛋疼地看到一篇,考虑到已经是2年前的文章了,现在的编译器可能会进一步 ...

  6. python用途与前景-Python的发展前景及干货!!

    如今,Python已经成为一种再主流不过的编程语言了.它天生丽质,易于读写,非常实用,从而赢得广泛的群众基础,被誉为"宇宙最好的编程语言",被无数程序员热烈追捧.随着时代的发展越来 ...

  7. python语言能干什么-python语言能做什么

    python语言可以用来做许多事,常见的一般有web开发.爬虫开发.人工智能以及游戏开发和构建桌面软件等等 Python是一个非常好用的编程语言而且开发速度快,语法简单通俗易懂,容易上手.非常适合初学 ...

  8. Python学习笔记: Python 标准库概览二

    本文来自:入门指南 开胃菜参考:开胃菜 使用Python解释器:使用Python解释器 本文对Python的简介:Python 简介 Python流程介绍:深入Python 流程 Python数据结构 ...

  9. c++调用python原理_C++调用Python浅析

    环境 VS2005Python2.5.4 Windows XP SP3 简述 一般开发过游戏的都知道Lua和C++可以很好的结合在一起,取长补短,把Lua脚本当成类似动态链接库来使用,很好的利用了脚本 ...

最新文章

  1. C# 创建控制台应用程序
  2. oracle存储过程备份,利用ORACLE存储过程与JOB结合实现对数据表自动备份
  3. LeetCode OJ -Happy Number
  4. UA MATH563 概率论的数学基础I 概率空间1 基本概念
  5. 怎样快速画出一个正方体_人教版小学数学五年级下册 长方体和正方体的体积 教案、课件,公开课视频...
  6. [精选代码笔记]Anagram, group-anagrams, two sum
  7. 排除瓶颈和加速django项目
  8. Waveform Audio 驱动(Wavedev2)之:WAV API模拟
  9. TypeScript 常用的新玩法
  10. 高性能服务器机柜,TS系列网络服务器机柜
  11. 小清新自适应宇航员404页面丢失svg错误网页源码
  12. node.js 之 socket.io
  13. MYSQL 中varchar类型转text格式
  14. Java 避免创建不必要的对象
  15. jenkins教程菜鸟_Jenkins教程:在Windows平台安装Jenkins
  16. python调用r语言函数_让R与Python共舞
  17. Spark大数据面试题1
  18. 安装semantic segmentation editor
  19. C++笔记——第一个MFC程序
  20. Java生鲜电商平台-异常模块的设计与架构

热门文章

  1. VC6.0显示代码行号
  2. 机器人运动学(a simple car)
  3. 高级线性表——静态链表(最全静态链表解读)
  4. c 语言epc编码如何解开,EPC编码结构
  5. pycharm安装scrapy失败_Scrapy ——环境搭配与一个简单的例子
  6. U-Boot 之二 详解使用 eclipse + J-Link 进行编译及在线调试
  7. android qq分组展开,Android仿qq分组管理的第三方库
  8. mysql正确打开方式_MySQL中MVCC的正确打开方式
  9. Splash 渲染引擎简介
  10. mysql基础拓扑图