注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

anqiang专栏

不要问细节是怎么搞的,源码说明一切

 
 
 

日志

 
 

Instm类的源码解析  

2010-08-16 02:25:08|  分类: PType |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

Instm类定义了一个抽象的输入流操作集合。这个输入流定义了,数据的读入操作,行操作,以及其它的操作。

 

Rawread()  数据读取操作

Bufvalidate  缓存填充操作

Seekx  文件指针移动操作

Line  行读操作

 

这些读写的过程都是通过一个BufferData从协调。这个Buffer的大小为8192byte。对于这个缓存的申请和释放工作由基类iobase负责。这个BufferData一次性读入8192byte的数据,在下一步的读请求到来时,先从缓存中得到数据来满足当前的需求,如果不能满足则先将数据读入到缓存,然后搬迁给需求数据的buf

具体过程请参见int instm::read(void* buf, int count) 代码注释

/*

 *

 *  C++ Portable Types Library (PTypes)

 *  Version 2.1.1  Released 27-Jun-2007

 *

 *  Copyright (C) 2001-2007 Hovik Melikyan

 *

 *  http://www.melikyan.com/ptypes/

 *

 */

 

#include <errno.h>

#include <string.h>

#include <limits.h>

 

#ifdef WIN32

#  include <windows.h>

#else

#  include <unistd.h>

#endif

 

#include "pstreams.h"

 

 

PTYPES_BEGIN

 

//instm的构造函数,调用了基类的构造函数

instm::instm(int ibufsize): iobase(ibufsize)

{

}

 

//析构函数

instm::~instm()

{

}

 

//classid值在ptypes.h文件中定义

int instm::classid()

{

    return CLASS_INSTM;

}

 

//做原始(底层)读操作

int instm::dorawread(char* buf, int count)

{

    if (handle == invhandle)

       return -1;

#ifdef WIN32

    unsigned long ret;

    if (!ReadFile(HANDLE(handle), buf, count, &ret, nil))

#else

    int ret;

    if ((ret = ::read(handle, buf, count)) < 0)

#endif

    {

        //这是在windows或者unix下读失败后的操作

        int e = uerrno();

        if (e == EPIPE)

            ret = 0;

        else

            error(e, "Couldn't read");

    }

    return ret;

}

 

 

int instm::rawread(char* buf, int count)

{

       //保证streamactive状态

    requireactive();

    try

    {

           //执行读操作

        int ret = dorawread(buf, count);

       

        //判断读操作是否成功

        if (ret <= 0) {

               //读操作失败

            ret = 0;

            eof = true;

            chstat(IO_EOF);

        }

        else

        {

               //读操作成功

               //改变指针位置

            abspos += ret;

            //改变设备的状态为 "正在读取"

            chstat(IO_READING);

        }

        return ret;

    }

    catch (estream*)

    {

        eof = true;

        chstat(IO_EOF);

        throw;

    }

}

 

 

large instm::tellx()

{

    return abspos - bufend + bufpos;

}

 

//buf中填充内容

void instm::bufvalidate()

{

    requirebuf();

    bufclear();

    //这一步实际上是向缓存中填充数据,因为数据都读入到bufdata中的

    bufend = rawread(bufdata, bufsize);

}

 

//通过一定的模式来移动文件指针到一个新的位置。

large instm::seekx(large newpos, ioseekmode mode)

{

    if (bufdata != 0 && mode != IO_END)

    {

        if (mode == IO_CURRENT)

        {

            newpos += tellx();

            mode = IO_BEGIN;

        }

 

        // see if it is possible to seek within the buffer

        large newbufpos = newpos - (abspos - bufend);

        if (newbufpos >= 0 && newbufpos <= bufend)

        {

            bufpos = (int)newbufpos;

            eof = false;

            return tellx();

        }

    }

 

    // if IO_END or if not possible to seek within the buffer

    return iobase::seekx(newpos, mode);

}

 

//判断是否到了文件结尾

bool instm::get_eof()

{

       //如果没有到达文件结尾,而且存在缓存且缓存已读取完毕,则重新读入缓存

    if (!eof && bufdata != 0 && bufpos >= bufend)

           //向缓存中添加内容

        bufvalidate();

    return eof;

}

 

 

int instm::get_dataavail()

{

    get_eof();

    return bufend - bufpos;

}

 

//获得前一个字符值

char instm::preview()

{

       //如果没有到达文件结尾,而且已到达缓存的结尾,则填充缓存

    if (!eof && bufpos >= bufend)

        bufvalidate();

    //此时如果已经到了文件末尾,则返回文件结束符

    if (eof)

        return eofchar;

    //否则的话,返回buffer当前位置的字符值

    return bufdata[bufpos];

}

 

 

void instm::putback()

{

    requireactive();

    if (bufpos == 0)

        fatal(CRIT_FIRST + 14, "putback() failed");

    bufpos--;

    eof = false;

}

 

//判断是否当前到了行末尾

bool instm::get_eol()

{

              //获得当前字符值

    char c = preview();

    return (eof || c == 10 || c == 13);

}

 

//跳过一个行结束符

void instm::skipeol()

{

    switch (preview())

    {

    case 10:

        get();

        break;

    case 13:

        get();

        if (preview() == 10)

            get();

        break;

    }

}

 

//向前移动一位,实质上是缓存中的指针移动了一位

char instm::get()

{

    char ret = preview();

    if (!eof)

        bufpos++;

    return ret;

}

 

 

string instm::token(const cset& chars, int limit)

{

    requirebuf();

    string ret;

    while (!get_eof())

    {

        char* b = bufdata + bufpos;

        char* e = bufdata + bufend;

        char* p = b;

        while (p < e && (*p & chars))

            p++;

        int n = p - b;

        limit -= n;

        if (limit < 0)

        {

            bufpos += n + limit;

            error(ERANGE, "Token too long");

        }

        concat(ret, b, n);

        bufpos += n;

        if (p < e)

            break;

    }

    return ret;

}

 

 

string instm::token(const cset& chars)

{

    return token(chars, INT_MAX);

}

 

 

static cset linechars = cset("*") - cset("~0a~0d");

 

 

string instm::line(int limit)

{

    string ret = token(linechars, limit);

    skipeol();

    return ret;

}

 

 

string instm::line()

{

    string ret = token(linechars, INT_MAX);

    skipeol();

    return ret;

}

 

 

int instm::token(const cset& chars, char* buf, int count)

{

    requirebuf();

    int ret = 0;

    while (count > 0 && !get_eof())

    {

        char* b = bufdata + bufpos;

        char* e = b + imin(count, bufend - bufpos);

        char* p = b;

        while (p < e && (*p & chars))

            p++;

        int n = p - b;

        memcpy(buf, b, n);

        buf += n;

        ret += n;

        count -= n;

        bufpos += n;

        if (p < e)

            break;

    }

    return ret;

}

 

 

int instm::line(char* buf, int size, bool eateol)

{

    int ret = token(linechars, buf, size);

    if (eateol)

        skipeol();

    return ret;

}

 

//读取一定的数据量到buf中,数量值为count

//这让我联想到Lucene中底层文件系统的设计了。比较相似

int instm::read(void* buf, int count)

{

    int ret = 0;

    //首选判断bufdata中是否存在,如果不存在,则直接从底层读取数据到buf

    //否则,从现有的bufdata中读取数据到buf中,直到满足buf的需求为止。返回值为读取到的数据量

    if (bufdata == 0)

        ret = rawread(pchar(buf), count);

    else

    {

           //从现有的bufdata中读取数据,get_eof()中涉及到了内存内容的重新读入

           //这个主要对于读入数量count远小于bufSize的情况,

           //在这种情况下,我们可以尽量的减小向输入设备读取数据的次数

        while (count > 0 && !get_eof())

        {

            int n = imin(count, bufend - bufpos);

            //拷贝缓存中的数据到内存中

            memcpy(buf, bufdata + bufpos, n);

            //读取一部分后,开始移位

            buf = pchar(buf) + n;

            ret += n;

            count -= n;

            bufpos += n;

        }

    }

    return ret;

}

 

 

int instm::skip(int count)

{

    int ret = 0;

    //确保有bufdata存在

    requirebuf();

    while (count > 0 && !get_eof())

    {

        int n = imin(count, bufend - bufpos);

        ret += n;

        count -= n;

        bufpos += n;

    }

    return ret;

}

 

 

int instm::skiptoken(const cset& chars)

{

    int ret = 0;

    requirebuf();

    while (!get_eof())

    {

        char* b = bufdata + bufpos;

        char* e = bufdata + bufend;

        char* p = b;

        while (p < e && (*p & chars))

            p++;

        int n = p - b;

        bufpos += n;

        ret += n;

        if (p < e)

            break;

    }

    return ret;

}

 

 

void instm::skipline(bool eateol)

{

    if (!get_eol())

        skiptoken(linechars);

    if (eateol)

        skipeol();

}

 

 

PTYPES_END

  评论这张
 
阅读(367)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017