序列化容器—二进制编码与解码

0 前言

     在rpc或分布式节点间的通讯框架里面,我们经常会有“业务数据与二进制流数据之间进行编码或解码转换”的场景要求,在jdk的nio框架里面有既有的ByteBuffer类满足此需求,那么在c++里面,同样我们简单看看,一个具有类似功能的类DataBuffer。  

1 实现机制

     其实现机制:通过指针偏移指向同一块内存,分别表示内存的起始与结束偏移位置,分别表示读与写的偏移位置。如下图:  

2 操作步骤

   2.1 读取数据时,仅需偏移_pdata即可

       源码如下:

    bool readBytes(void *dst, int len) {

        if (_pdata + len > _pfree) {

            return false;

        }

        memcpy(dst, _pdata, len);

        _pdata += len;

        assert(_pfree>=_pdata);

        return true;

    }
View Code

   2.2 写数据时,仅需偏移_pfree指针即可

       源码如下:             

  void writeString(const char *str) {

        int len = (str ? static_cast<int32_t>(strlen(str)) : 0);

        if (len>0) len ++;

        expand(static_cast<int32_t>(len+sizeof(uint32_t)));

        writeInt32(len);

        if (len>0) {

            memcpy(_pfree, str, len);

            _pfree += (len);

        }

    }
View Code

    2.3 当所需内存不足时(_ppend - _pfree < need ),干两件事情:

        a 申请新的当前于内存空间2倍的内存(<<= 1)

        b 把已有数据拷贝至新的内存块上

       源码如下:

inline void expand(int need) {

        if (_pstart == NULL) {

            int len = 256;

            while (len < need) len <<= 1;

            _pfree = _pdata = _pstart = (unsigned char*)malloc(len);

            _pend = _pstart + len;

        } else if (_pend - _pfree < need) { // 空间不够

            int flen = static_cast<int32_t>((_pend - _pfree) + (_pdata - _pstart));

            int dlen = static_cast<int32_t>(_pfree - _pdata);

 

            if (flen < need || flen * 4 < dlen) {

                int bufsize = static_cast<int32_t>((_pend - _pstart) * 2);

                while (bufsize - dlen < need)

                    bufsize <<= 1;

 

                unsigned char *newbuf = (unsigned char *)malloc(bufsize);

                if (newbuf == NULL)

                {

                  TBSYS_LOG(ERROR, "expand data buffer failed, length: %d", bufsize);

                }

                assert(newbuf != NULL);

                if (dlen > 0) {

                    memcpy(newbuf, _pdata, dlen);

                }

                free(_pstart);

 

                _pdata = _pstart = newbuf;

                _pfree = _pstart + dlen;

                _pend = _pstart + bufsize;

            } else {

                memmove(_pstart, _pdata, dlen);

                _pfree = _pstart + dlen;

                _pdata = _pstart;

            }

        }

    }
View Code

3 实例

3.1 输入

3.2 输出

   out1: 11 out2: 1100 out3: hello world

 

    源码请见 https://files.cnblogs.com/files/gisorange/databuffer.zip

 

  

 

posted @ 2015-10-19 09:59  gisorange  阅读(1079)  评论(0编辑  收藏  举报