nginx自定的list跟我們常見的list是不太一樣的,不同點就在於它的節點,它的節點不像我們常見的list的節點,只能存放一個元素,ngx_list_t的節點實際上是一個固定大小的數組。
在初始化的時候,我們需要設定元素需要佔用的空間大小,每個節點數組的容量大小。在添加元素到這個list裏面的時候,會在最尾部的節點裏的數組上添加元素,如果這個節點的數組存滿了,再增加新的節點。
我們看一下數據結構定義:
typedef struct ngx_list_part_s ngx_list_part_t;
struct ngx_list_part_s {
void *elts; // 當前節點內存的起始位置(每個節點內存大小是size*nalloc)
ngx_uint_t nelts; // 當前節點中已存放元素的數量
ngx_list_part_t *next; // next節點
};
typedef struct {
ngx_list_part_t *last; // 指向鏈表中最後一個節點,這個存在的好處是添加元素很方便啊
ngx_list_part_t part; // 鏈表頭節點,注意這裏不是指針,而是list的一部分
size_t size; // 單個元素的大小
ngx_uint_t nalloc; // 每一個節點的容量(能存儲nalloc個元素)
ngx_pool_t *pool; // list所在的內存池
} ngx_list_t;
創建鏈表函數:
ngx_list_t *ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size);
/* 創建很簡單,跟array一樣,先分配好結構體的內存,再調用init進行初始化並分配節點elts的內存
create時設定nalloc=n, size=size */
static ngx_inline ngx_int_t
ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size);
/* 如果ngx_list_t類型的變量不是通過調用函數ngx_list_create創建的(比如某結構體中有個ngx_list),
就必須調用此函數去初始化,否則往這個list裏追加元素會引發不可預知的行爲,亦或程序會崩潰 */
添加元素函數:
void *
ngx_list_push(ngx_list_t *l)
{
void *elt;
ngx_list_part_t *last;
last = l->last;
// 如果當前節點滿員了,申請下一個節點出來,還是先結構體後內存空間
//(有個問題,如果結構出來了內存區拿不到豈不是浪費空間了又,好吧無所謂了,已經出錯了這時)
if (last->nelts == l->nalloc) {
last = ngx_palloc(l->pool, sizeof(ngx_list_part_t));
if (last == NULL) {
return NULL;
}
last->elts = ngx_palloc(l->pool, l->nalloc * l->size);
if (last->elts == NULL) {
return NULL;
}
last->nelts = 0;
last->next = NULL;
l->last->next = last; // 重定向last
l->last = last;
}
elt = (char *) last->elts + l->size * last->nelts;
return elt;
}
對了,再加一段代碼,這是nginx的源文件中被註釋掉的,我感覺是作者留給我們遍歷list的示範:
/*
*
* the iteration through the list:
*
* part = &list.part;
* data = part->elts;
*
* for (i = 0 ;; i++) {
*
* if (i >= part->nelts) {
* if (part->next == NULL) {
* break;
* }
*
* part = part->next;
* data = part->elts;
* i = 0;
* }
*
* ... data[i] ...
*
* }
*/