Lua4.0 ZIO缓冲区

来看一下 ZIO 缓冲。

词法分析读一个一个的字符就是从它读的。

或者 umdump 时也是从它读字符(一个 char 字节)的。

缓冲区隔离了下层数据源的不同,对上层提供一致的读取接口。

相关的代码文件是 lzio.h 和 lzio.c 。

先看一下数据结构:

#ifndef ZBSIZE
#define ZBSIZE  256             /* buffer size */
#endif
struct zio { 
  size_t n;                     /* bytes still unread */
  const unsigned char* p;       /* current position in buffer */
  int (*filbuf)(ZIO* z);
  void* u;                      /* additional data */
  const char *name;
  unsigned char buffer[ZBSIZE]; /* buffer */
};

buffer 是缓冲区,数据就存在它里面。

n 是目前缓冲区还有多少没有读取的数据。

p 是缓冲区当前指针位置。

filbuf 是缓冲区数据为空是用来填充数据的。


看下它的接口,三个 open 接口,分别对应不同的源数据类型。

zread 读取下 n 个字节。

以及用宏定义出来的接口。

zgetc 取缓冲区当前字符,调整未读字符个数,及当前位置指针,如果缓冲区中没有可用的字符,则填充。

zungetc 放回缓冲区字符,也就是回退缓冲区当前位置指针,调整未读字符个数


看下实现。


内存缓冲

static int zmfilbuf (ZIO* z) {
  (void)z;  /* to avoid warnings */
  return EOZ;
}
ZIO* zmopen (ZIO* z, const char* b, size_t size, const char *name) {
  if (b==NULL) return NULL;
  z->n = size;
  z->p = (const unsigned char *)b;
  z->filbuf = zmfilbuf;
  z->u = NULL;
  z->name = name;
  return z;
}

内存缓冲,就是把一个缓冲区当前指针指向内存块 b 。设置相关的参数。

缓冲区填直接返回结束。因为一个内存块读完了就结束了。不存在所谓的再次填充的问题。


字符串缓冲

ZIO* zsopen (ZIO* z, const char* s, const char *name) {
  if (s==NULL) return NULL;
  return zmopen(z, s, strlen(s), name);
}

调用上面的内存缓冲实现。


文件缓冲

static int zffilbuf (ZIO* z) {
  size_t n;
  if (feof((FILE *)z->u)) return EOZ;
  n = fread(z->buffer, 1, ZBSIZE, (FILE *)z->u);
  if (n==0) return EOZ;
  z->n = n-1;
  z->p = z->buffer;
  return *(z->p++);
}
ZIO* zFopen (ZIO* z, FILE* f, const char *name) {
  if (f==NULL) return NULL;
  z->n = 0;
  z->p = z->buffer;
  z->filbuf = zffilbuf;
  z->u = f;
  z->name = name;
  return z;
}

文件缓冲传入文件描述符,及文件名。

重点看下它的填充函数 zffilbuf。

从文件中读取 ZBSIZE 个字符放到 buffer 中。

如果文件结束,则返回 EOZ。

设置未读字符为实际从文件中读取的字符数。

例如,文件过小,或者是最后一次读取时,可能文件中不到 ZBSIZE 个字符。

fread 返回值就是实际读取的字符数。

读取后将返回第一个字符,同时调整未读字符数及当前的指针。这个返回值在 zgetc 中会用到。


从缓冲区读取 n 个字符

size_t zread (ZIO *z, void *b, size_t n) {
  while (n) {
    size_t m;
    if (z->n == 0) {
      if (z->filbuf(z) == EOZ)
        return n;  /* return number of missing bytes */
      zungetc(z);  /* put result from `filbuf' in the buffer */
    }
    m = (n <= z->n) ? n : z->n;  /* min. between n and z->n */
    memcpy(b, z->p, m);
    z->n -= m;
    z->p += m;
    b = (char *)b + m;
    n -= m;
  }
  return 0;
}

从缓冲区中读取 n 个字符。

如果缓冲区中没有字符可读,则调用填充函数。注意 zungetc 的使用,因为在填充函数最后,移动指针了。

读取缓冲区未读的和需要读入的字符个数的较小值。

拷贝到输出。

调整缓冲区未读的字符数,缓冲区当前指针及输出的当前指针,调整待读取字符串个数。

----------------------------------------

到目前为止的问题:

> 函数原型优化 luaU_optchunk

> 打印函数原型 luaU_printchunk

> dump 函数原型 luaU_dumpchunk

> 语法析 luaY_parser

----------------------------------------


转载于:https://my.oschina.net/xhan/blog/491190

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值