一.前言
在前一篇文章里我们给出了evbuffer和evbuffer_chain相关的基础增删之类的接口函数,在本文中我们重点研究evbuffer的读写查找等接口函数的实现原理。
二.查找函数分析
(1)evbuffer_ptr结构体
该结构体用于查找使用。
/**
指向buffer中指定位置,可以快速的浏览而不需要反复查找
修改evbuffer会导致其失效
Pointer to a position within an evbuffer.
Used when repeatedly searching through a buffer. Calling any function
that modifies or re-packs the buffer contents may invalidate all
evbuffer_ptrs for that buffer. Do not modify or contruct these values
except with evbuffer_ptr_set.
An evbuffer_ptr can represent any position from the start of a buffer up
to a position immediately after the end of a buffer.
@see evbuffer_ptr_set()
*/
struct evbuffer_ptr {
ev_ssize_t pos;
/* Do not alter or rely on the values of fields: they are for internal
* use */
struct {
void *chain;
size_t pos_in_chain;
} internal_;
};
(2)evbuffer_ptr_set()函数
给evbuffer_ptr进行赋值。
/* 给evbuffer_ptr赋值
* 两种使用方式:
*(1) evbuffer_ptr_set(buf, &pos, N, EVBUFFER_PTR_SET)
* 从buffer开始设置第N位为pos指向的位置
*(2) evbuffer_ptr_set(buf, &pos, N, EVBUFFER_PTR_ADD)
* 向前N位,指向pos
*
* 对于未初始化的evbuffer_ptr只能用第一种
*/
int
evbuffer_ptr_set(struct evbuffer *buf, struct evbuffer_ptr *pos,
size_t position, enum evbuffer_ptr_how how)
{
size_t left = position;
struct evbuffer_chain *chain = NULL;
int result = 0;
EVBUFFER_LOCK(buf);
/* 这里注意两种how的不同在于一个是pos = position
* 另一个是pos = postion + pos,即从pos开始数position位置
*/
switch (how) {
case EVBUFFER_PTR_SET:
chain = buf->first;
pos->pos = position;
position = 0;
break;
case EVBUFFER_PTR_ADD:
/* this avoids iterating over all previous chains if
we just want to advance the position */
if (pos->pos < 0 || EV_SIZE_MAX - position < (size_t)pos->pos) {
EVBUFFER_UNLOCK(buf);
return -1;
}
chain = pos->internal_.chain;
pos->pos += position;
position = pos->internal_.pos_in_chain;
break;
}
EVUTIL_ASSERT(EV_SIZE_MAX - left >= position);
while (chain && position + left >= chain->off) {
left -= chain->off - position;
chain = chain->next;
position = 0;
}
if (chain) {
pos->internal_.chain = chain;
pos->internal_.pos_in_chain = position + left;
} else if (left == 0) {
/* The first byte in the (nonexistent) chain after the last chain */
pos->internal_.chain = NULL;
pos->internal_.pos_in_chain = 0;
} else {
PTR_NOT_FOUND(pos);
result = -1;
}
EVBUFFER_UNLOCK(buf);
return result;
}
(3)搜索函数evbuffer_search()
主要调用evbuffer_search_range()
struct evbuffer_ptr
evbuffer_search(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start)
{
return evbuffer_search_range(buffer, what, len, start, NULL);
}
(4)evbuffer_search_range()
/*查找函数,指明范围*/
struct evbuffer_ptr
evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start, const struct evbuffer_ptr *end)
{
struct evbuffer_ptr pos;
struct evbuffer_chain *chain, *last_chain = NULL;
const unsigned char *p;
char first;
EVBUFFER_LOCK(buffer);
/*start和end指明了查找的范围*/
if (start) {
memcpy(&pos, start, sizeof(pos));
chain = pos.internal_.chain;
} else {
pos.pos = 0;
chain = pos.internal_.chain = buffer->first;
pos.internal_.pos_in_chain = 0;
}
if (end)
last_chain = end->internal_.chain;
if (!len || len > EV_SSIZE_MAX)
goto done;
first = what[0];
/*根据start和end赋值得到的evbuffer_chain进行查找*/
while (chain) {
const unsigned char *start_at =
chain->buffer + chain->misalign +
pos.internal_.pos_in_chain;
/* const void * memchr ( const void * ptr, int value, size_t num );
* 函数的作用是:在ptr指向的内存块中(长度为num个字节),需找字符value。
* 如果找到就返回对应的位置,找不到返回NULL
*/
p = memchr(start_at, first,
chain->off - pos.internal_.pos_in_chain);
if (p) {
//pos指向了这个chain中出现等于what[0]字符的位置
pos.pos += p - start_at;
pos.internal_.pos_in_chain += p - start_at;
//evbuffer_ptr_memcmp比较整个字符串。如果有需要的话,该函数会跨
//evbuffer_chain进行比较,但不会修改pos。如果成功匹配,那么返回0
if (!evbuffer_ptr_memcmp(buffer, &pos, what, len)) {
//end之后的就算找到了也算是失败
if (end && pos.pos + (ev_ssize_t)len > end->pos)
goto not_found;
else
goto done;
}
++pos.pos;
++pos.internal_.pos_in_chain;
//找完了也没找到
if (pos.internal_.pos_in_chain == chain->off) {
chain = pos.internal_.chain = chain->next;
pos.internal_.pos_in_chain = 0;
}
} else {
if (chain == last_chain)
goto not_found;
/*在下一个evbuffer_chain寻找*/
pos.pos += chain->off - pos.internal_.pos_in_chain;
chain = pos.internal_.chain = chain->next;
pos.internal_.pos_in_chain = 0;
}
}
not_found:
PTR_NOT_FOUND(&pos);
done:
EVBUFFER_UNLOCK(buffer);
return pos;
}