0
点赞
收藏
分享

微信扫一扫

spdy_buffer


spdy_binary_buffer: 工具类,作用就是一个可以自动扩容和内存空间回收的buffer(主要用来保存http和spdy传输的内容),单位为字节(类型为unsigned char, 因为字符集的值都是>=0的)
<1> 几个关键的属性:
(1) unsigned char *buffer: 指向保存内容的那部分内存的开头。
(2) size_t len: len表示当前buffer的第一个可写的内存位置(buffer+len, 不代表buffer实际内容的长度,因为可能前面已经有内容被读出), 也是当前buffer实际内容的结尾的下一个位置。
(3) size_t allocated: 代表为此buffer分配的内存的长度。
(4) size_t offset: 代表当前buffer第一个可读的位置,也是当前buffer实际内容的开始内存位置(buffer+offset)。
(5) bool malloced: 代表此buffer使用的内存是否是专门为其malloc的(buffer使用的内存空间有很多来源,不一定就是自己malloc的)。

<2> buffer 内部提供了读取数据填充自己的工具(回调)函数接口,
通过将此函数的指针(read_callback) 以及 要读取的数据的来源(data) 传入read_from()函数来进行填充:

int binary_buffer::read_from(ReadCallback read_callback, void* data) 

 { 

 ................................... 

     added = read_callback(data, buffer+len, allocated-len); 

 ................................... 

 }



<3> 4种构造器:
(1) binary_buffer():
为自己malloc一块内存(buffer随后指向),len 和 offset均初始为0,allocated设为malloc内存的长度,malloced为true。
(2) binary_buffer(usigned char *data, int l):
malloced为false,buffer指向data, offset为0, 而len则为l(因为l代表已经写入buffer所指内存的内容的长度)。
(3) binary_buffer(const std::string &str):
同上,buffer指向的是str的c_str()产生的字符数组(强转为usigned char*)。
(4) binary_buffer(const binary_buffer &str):
同上,buffer直接指向了str这个buffer所使用的内存。

<4> 析构器:
如果内存是malloced的,那么就free。

<5> 一个真正的申请内存并拷贝内容的函数, 同时会将当前buffer的状态初始化,可以理解为一种变相构造器:
void set(const char *x, int l)
首先将len和offset重置为0,
然后如果之前没有自己的专属内存的话,就申请一块长度为l的内存,并将buffer指向其,更新allocated为l。
然后调用add函数将内容从x所指内存位置copy到自己的内存中.

<6> 关键的空间管理函数:
void add_space(int plen)
此函数的作用就是找到可用的长度为plen的内存空间:
(1)判断: offset == len && offset > 0, 这代表当前buffer的内容已经全部被读出,但是offset和len还没有被重置,
那么就进行重置。
(2)判断 plen + len <= allocated, 这代表从当前的第一个可写位置到内存的末尾的空间可以容下plen,直接返回.
(3)如果offset > 0并且 offset > len>>1(代表当前已经读取超过了写入内容的一半), 或者 len + plen - offset <= allocated
(整个内存所剩余的空间可以容下plen,和之前的len后面容下plen不同,这里还包括了offset前面因为读取而腾出的空间)
那么就可以将内存当前的整个内容部分迁移到内存的开头(buffer)来尝试腾出plen的连续内存空间(其实就是内存碎片整理),
offset重置为0(因为第一个可读的内存位置就是 buffer + 0), 而len -= offset(因为整个内容数组都向前平移了offset)
(4)如果plen还是不能被满足,那么就只能申请一块更大的内存了, 内存容量每次的增长固定的幅度,直到找一个能满足当前需求的容量,
然后realloc当前的内存, 更新buffer和allocated。

<7> void add( const unsigned char *p, size_t plen )
基础写入函数
从p所指的位置copy plen长度内容位置。
因为buffer容量有限,因此要先调add_space()来判断是否有足够内存以及不够的话整理扩容.
然后就直接memcpy

<8>int read( char *ptr, int num )
基础读取函数
力所能及的读取 长度为num的内容,但是如果buffer中剩余的内容不够num长,那么返回真正读取的长度,并memcpy相应长度内容到ptr。

<9>add类函数:

bool add( const std::string &x ); 将string的内容读入 

 bool add( const binary_buffer &x ); 将另外一个buffer的内容读入 

 bool add_int( int i, int bytes );将一个长度为bytes个byte长度的数(i)按byte为单位写入 

 bool add_byte( int i ); 读入一个byte 

 bool add_int16( int i ); 读入两个byte 

 bool add_int24( int i ) { return add_int(i,3); } 

 bool add_int32( int i );读入4个byte 

 bool add_hstring( const std::string &x, int bytes=2 ); 

 hstring是比较特殊的类型,在写入之前,要将其长度写入, bytes=2值得是存储长度这个值会占两个字节内存。 

 bool add_hstring( const char *x, int bytes=2 ); 

 binary_buffer *read_buffer( int bytes );


重新构造(new)一个buffer, 其buffer指向当前buffer的第一个读取位置,新buffer的内容长度是bytes

<10>重要的read函数:
int read_number( int bytes )
指明从buffer读取bytes个byte, 并且将其按位从高到低组合为一个unsigned int返回.

<11>控制函数:
void unread( int nbytes ) { assert( offset >= (unsigned)nbytes ); offset -= nbytes; }
将已经读取的nbytes个字符重新标为没有读取,即第一个读取位置回退nbytes(有边界判断)
void consume( int nbytes ){ offset += nbytes; assert(offset<=len); }
直接将nbytes个字符标记为已读,即第一个读取位置前进nbytes(边界判断)
void clear() { len = offset = 0; }
不释放内存,单纯丢弃以前的内容。
void filled( size_t bytes ) { len += bytes; assert(malloced && len <= allocated); }
直接写入bytes个 假 数据,使得可写位置前进bytes

<12>工具函数:
size_t length() const { return len-offset; }
size_t size() const { return len-offset; }
都返回实际内容的长度
const unsigned char *data() const { return buffer+offset; }
返回第一个可读位置的内存地址
unsigned char *write_pointer( size_t nbytes );
返回第一个可写位置的内存地址,同时还要求有nbytes长度的可写内存。

举报

相关推荐

0 条评论