libevent源码解析(六)evbuffer读写查找接口函数

一.前言

  在前一篇文章里我们给出了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;
}

猜你喜欢

转载自blog.csdn.net/u013354486/article/details/80859453