Lua C++ bindings (1)

好几个项目都用了 Lua 作为配置文件语言,但是一直都用官方提供的 C API,写起来十分繁琐。本来大部分的配置文件都是 key-value 式的配置,简单地封装一下就足够了,但是本着完美主义的倾向一直都觉得要么就别封装,要么就写一个功能完善的,而函数调用和自定义类导出这部分一直没想明白怎么弄,因此迟迟没动手。至于为什么不直接使用 LuaBind 这样强大的东东,一方面是不喜欢 LuaBind 依赖 Boost 太臃肿,另一方面也是趁着这个机会学习一下。

从去年 10 月左右就开始磕磕碰碰地写,三两下就把变量部分搞定了,不过之后就停滞了。直到去年年底的时候看了下 C++11 提供的变长参数模板有了些头绪,于是写成了现在这样,总的来说已经基本可用,心里的成就感满满的,于是写点东西记录一下,也算是打个广告。关于这个库准备写两篇博客,第一篇从使用者的角度介绍一下使用方法,第二篇从开发者的角度写写演变过程及设计原则。这里介绍的是第一个提交的版本,后续有变化的话不再同步更新博客了,只会更新相关的文档。

哦,忘了打广告,代码放在 github 上,猛点 这里。需要 C++11 的支持,使用 g++ 编译时加上选项 -std=c++11。

变量设置

先来看一个“Hello, world!”式的程序:

#include <iostream>
using namespace std;

#include "luacpp.hpp"
using namespace 

阅读全文…

B- 树

1972 年 R. Bayer 和 E. McCreight 的论文(参考资料 [1])提出了 B- 树。B- 树是一棵平衡树,与一般的平衡二叉树(AVL,红黑树等)不同的是,B- 树的每个节点最多可以拥有 m(m=2)个元素,(m+1)个子节点,并且所有的叶子节点位于同一层。B- 树的查找和插入的时间复杂度和二叉树一样,都是 O(logn),但因为每个节点保存的元素比较多(一般是几十个到几百个之间),树的高度比一般的二叉树要小很多,访问硬盘次数更少,在数据不能全部加载到内存的时候比一般的二叉树效率要好。

定义

一棵最多有 2n+1 个元素(其中 n= 1)的 B- 树的定义如下(参考资料 [2, 3]):

  • 每个节点最多有 2n+1 个元素;
  • 每个非叶子节点(根节点除外)至少有 n+1 棵子树;
  • 如果根节点不是叶子节点,则至少有 2 棵子树;
  • 一个有 k 棵子树的非叶子节点有

阅读全文…

Linux 异步 IO 之 epoll

epoll 是 Linux 内核在 2.5 引入的一个 I/O 事件通知机制,用来取代旧的 select(2) 和 poll(2)。

select() 的工作模式

从通知机制上说,select() 的方式和 epoll 的方式类似,都是阻塞在某个函数上,如果有指定的 I/O 事件发生的话函数就会返回。这样的通知机制的好处在于,在没有事件发生的时候系统可以去干别的事情。不过 select() 只告诉你有事件发生了,但是没有说清楚是哪些 fd 触发了事件通知,你需要去遍历所有的 fd 来找出哪些真正需要处理。select() 的函数原型如下:

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);

fd_set 是一个 …

阅读全文…

chroot 使用笔记

看了下最近很火很高大上的 Docker,比较好奇底层的实现机制,发现主要依赖 Linux Container(LXC) 和 cgroup,于是又了解了下 LXC,在看的过程中看到和 chroot 的比较,突然一些零散的片段在我脑海里迅速串起来……

一直在用 Debian 6,由于不爽 GNOME 3 所以没有升级,不过内核和 GCC 倒是在追新。传说 Debian 8 要使用 XFCE 作为默认桌面,小小期待一下。虽然不是什么狂热的追新族,但是在夜深人静的时候也会悄悄把源切到 unstable 然后 upgrade 看看有哪些自己喜欢的工具升级了。不过 unstable 的依赖关系经常处于不完整状态,有时安装一个包 apt-get 解析出来的关系能把整个系统都删掉,所以也有过几次搞坏系统的经历;而且重装了之后一些特定版本的软件又找不回来了,所以在有升级冲动的时候都会先对根分区备份一下(我的系统只有根目录和家目录)放到家目录里,万一搞坏了可以迅速恢复,而且备份之后的系统还可以作为镜像复制到其它机器上(中间就有过一次换电脑的经历,把旧的系统完整复制过来了)。

好吧,顺便记录一下系统备份和恢复的过程。首先用 U 盘或光盘装个 Live 系统(我用的是 SystemRescueCd ),备份的时候用启动盘启动,把硬盘上的根分区挂载到一个目录上然后在该目录下执行 tar(tar 在解压的时候会还原打包时的相对路径);恢复是同样的步骤,只是把打包变成解压。恢复的时候很多情况下 GRUB …

阅读全文…

使用 C 编写 Lua 模块

Lua 作为一种小巧的语言,一般都是嵌入到 C/C++ 中作为扩展语言,但是也可以作为独立的脚本语言使用,并且可以使用 C/C++ 编写扩展模块。在参考资料 [1] 中有怎样用 C/C++ 编写模块的介绍,但是比较零散,也不是很详细,所以在这里整理一下。

这里使用的 Lua 版本是 5.2.3,系统是 Debian 7。

Hello, world!

不废话,还是先看一下经典的 “Hello, world!” 例子。

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

static int l_hello(lua_State* l)
{
    printf("Hello, world!\n");
    return 0;
}

static const 

阅读全文…

使用 Lua 扩展你的程序 (1)

Lua(参考资料[1])是巴西里约热内卢天主教大学的一个研究小组于 1993 年开发的。小组主要由 Roberto Ierusalimschy, Waldemar Celes 和 Luiz Henrique de Figueiredo 组成,最开始的原型为了处理数据而开发的一种脚本语言,后来逐渐演变成现在的样子。Lua 虽然小巧,但是也包含分支循环结构,动态类型,闭包等特性,有兴趣的可以看看参考资料[2]。只用 Lua 提供的原生 C API 写出来的程序和汇编差不多,需要精确控制栈的内容。为了解放程序员,网上有一些封装好了的 Lua 库,用起来也很方便。

这里主要记录自己使用 Lua 对程序进行扩展的一些尝试,用到相关的 Lua 特性时会展开介绍一下。特别说一下,虽然主要使用 Lua 作为配置文件的语言,但是用其它的语言(Python, Perl, Ruby, …)也可以达到同样的效果,只要程序能够解析所使用的语言,甚至 XML 也可以用来实现后文提到的一些功能,不过前提是你的解析器要支持 XML 来定义分支和循环等功能 :)

简单的 key/value 配置文件

需要配置参数取值的一个常见例子是数据源问题。例如程序需要从一个文件获取运行时需要的数据,测试和正式发布所使用的数据不一样,为了验证程序的正确性也准备了多套不同的数据。为了方便测试,程序使用了一个配置文件 …

阅读全文…

关于 so 的一些笔记

现在的程序越来越复杂,由多个模块构成,如果把所有的模块和依赖都编译到一个单一的可执行文件中,不仅文件体积很大,而且也不利于模块更新;而且有些基础模块可以被多个程序共用,没必要各个程序都打包一份,因此就有了动态链接库。顾名思义,动态链接库就是可以动态地进行链接,在程序需要的时候才会进行加载,并且这份代码在内存里是共享的,在 Windows 中叫“Dynamic Link Library”,后缀是 dll,Linux 上叫“Shared Object”,后缀一般是“so”。

Hello, world!

下面是经典的打印“Hello, world!”的例子:

#ifndef __HELLO_H__
#define __HELLO_H__

void print(void);

#endif
/* hello.c */

#include <stdio.h>

void print(void)
{
    printf("Hello, world!\n");
}
/* main.c */

#include "hello.h"

int main(void)
{
    print();

    return 

阅读全文…