序列化容器—二进制编码与解码
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; }
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); } }
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; } } }
3 实例
3.1 输入
3.2 输出
out1: 11 out2: 1100 out3: hello world
源码请见 https://files.cnblogs.com/files/gisorange/databuffer.zip