Nginx/core/ngx_list
ngx_list.h
/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #ifndef _NGX_LIST_H_INCLUDED_ #define _NGX_LIST_H_INCLUDED_ #include <ngx_config.h> #include <ngx_core.h> typedef struct ngx_list_part_s ngx_list_part_t; // 参考:nginx源码分析—链表结构ngx_list_t http://blog.csdn.net/livelylittlefish/article/details/6599065 /* ngx_list_t是nginx中使用的链表结构,但与我们常说的链表结构(例如`std::list`)不太一样, 它符合list类型数据结构的一些特点,比如可以添加元素,实现动态自增长,不会像数组类型的数据结构,受到初始设定的数组容量的限制, 不同点就在于它的节点,`std::list`每个节点只能存放一个元素,ngx_list_t的节点却是一个固定大小的数组,可以存放多个元素。 在初始化的时候,我们需要设定单个元素所需要占用的内存空间大小,以及每个节点数组的容量大小。 在添加元素到这个list里面的时候,会在最尾部的节点里的数组上添加元素,如果这个节点的数组存满了,就再增加一个新的节点到这个list里面去。 */ // ngx_list_part_s是代表ngx_list_t链表的一个节点。 // 它自身包含了一个数组,用来存放最终的元素 struct ngx_list_part_s { void *elts; //链表元素elts数组,数组申请的空间大小为size*nalloc ngx_uint_t nelts; //当前已使用的elts个数,一定要小于等于nalloc ngx_list_part_t *next; //指向ngx_list_t中的下个链表part }; // ngx_list_t结构是一个链表,链表中每个节点是ngx_list_part_t结构。 // 而ngx_list_part_t中有个elts是一个数组,储存了任意大小固定的元素,它是由ngx_pool_t分配的连续空间 typedef struct { ngx_list_part_t *last; //指向链表中最后一个元素,其作用相当于尾指针。插入新的节点时,从此开始。 ngx_list_part_t part; //链表中第一个元素,其作用相当于头指针。遍历时,从此开始。 size_t size; //链表中每个元素的大小 ngx_uint_t nalloc; //链表的每个ngx_list_part_t中elts数组的所能容纳的最大元素个数 ngx_pool_t *pool; //当前list数据存放的内存池 } ngx_list_t; //ngx_list_create和ngx_list_init功能是一样的都是创建一个list,只是返回值不一样... ngx_list_t *ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size); // ngx_list_init是初始化了一个已有的链表 static ngx_inline ngx_int_t ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size) { list->part.elts = ngx_palloc(pool, n * size); //从内存池申请空间后,让elts指向可用空间 if (list->part.elts == NULL) { return NGX_ERROR; } list->part.nelts = 0; //刚分配下来,还没使用,所以为0 list->part.next = NULL; list->last = &list->part; //last开始的时候指向首节点 list->size = size; list->nalloc = n; list->pool = pool; return NGX_OK; } /* * * 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] ... * * } */ void *ngx_list_push(ngx_list_t *list); #endif /* _NGX_LIST_H_INCLUDED_ */
ngx_list.c
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
//该函数创建一个ngx_list_t类型的对象,并对该list的第一个节点分配存放元素的内存空间。
//
//pool: 分配内存使用的pool。
//n: 每个节点(ngx_list_part_t)最多可以存放的元素个数
//size: 每个元素所占用的内存大小
ngx_list_t *
ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
ngx_list_t *list;
// 先创建一个ngx_list_t指针
list = ngx_palloc(pool, sizeof(ngx_list_t));
if (list == NULL) {
return NULL;
}
list->part.elts = ngx_palloc(pool, n * size);
if (list->part.elts == NULL) {
return NULL;
}
list->part.nelts = 0;
list->part.next = NULL;
list->last = &list->part;
list->size = size;
list->nalloc = n;
list->pool = pool;
return list;
}
/*
ngx_list_create的使用示例:
ngx_list_t *testlist = ngx_list_create(r->pool, 4, sizeof(ngx_str_t));
if (testlist == NULL) {
return NGX_ERROR;
}
*/
// 往链表l中添加新的元素,返回的是新分配的元素的首地址
void *
ngx_list_push(ngx_list_t *l)
{
void *elt;
ngx_list_part_t *last;
last = l->last;
if (last->nelts == l->nalloc) {
// 这里是last节点已经使用了nlloc的elts,所以必须新建一个last节点
/* the last part is full, allocate a new list part */
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;
l->last = last;
}
elt = (char *) last->elts + l->size * last->nelts;
last->nelts++;
return elt;
}
/*
ngx_list_push的使用实例:
ngx_str_t *str = ngx_list_push(testlist);
if (str == NULL) {
return NGX_ERROR;
}
str->len = sizeof("Hello World");
str->value = "Hello World";
*/
/*遍历链表的实例
//part用于指向链表中的每一个ngx_list_part_t数组
ngx_list_part_t* part = &testlist.part;
//根据链表中的数据类型,把数组里的elts转化为该类型使用
ngx_str_t* str = part->elts;
//i表示元素在链表的每个ngx_list_part_t数组里的序号
for (i = 0;;i++)
{
if (i>=part->next)
{
if (part->next == NULL)
{
//说明某个ngx_list_part_t数组的next指针为空,则说明已经遍历完链表
break;
}
//访问下一个ngx_list_part_t
part = part->next;
header = part->elts;
//将i的序号重置为0,准备重新访问下一个数组
i = 0;
}
//这里可以很方便地取到当前遍历到的链表元素、
printf("List Element:%*s\n", str[i].len, str[i].data);
}
*/
浙公网安备 33010602011771号