1. 思想
数组是相同类型数据的序列,且能通过索引一一对应,相对于链表,优点就是快速随机访问。
动态数组继承了数组的优点,且大小在运行能动态伸缩。
2. 设计
ngx的动态数组基于内存池,具有伸缩能力
3 实现
struct ngx_array_s {
void *elts; // 数组
ngx_uint_t nelts; // 当前实际数组元素
size_t size; // 元素大小
ngx_uint_t nalloc; // 数组容量
ngx_pool_t *pool;
};
static ngx_inline ngx_int_t
3.1 构造
数组构造支持两种情况,数组本身使用内存池分配,和不使用内存池分配
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
/*
* set "array->nelts" before "array->elts", otherwise MSVC thinks
* that "array->nelts" may be used without having been initialized
*/
array->nelts = 0;
array->size = size;
array->nalloc = n;
array->pool = pool;
array->elts = ngx_palloc(pool, n * size);
if (array->elts == NULL) {
return NGX_ERROR;
}
return NGX_OK;
}
ngx_array_t *
ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
{
ngx_array_t *a;
a = ngx_palloc(p, sizeof(ngx_array_t));
if (a == NULL) {
return NULL;
}
a->elts = ngx_palloc(p, n * size);
if (a->elts == NULL) {
return NULL;
}
a->nelts = 0;
a->size = size;
a->nalloc = n;
a->pool = p;
return a;
}
3.2 push
如果数组没有满,则将最后一个空位给用户
否则扩展数组,分两种情况,
- 若数组使用空间为内存池尾部,则可以直接调整内存池尾部指针
- 若不是内存池尾部,则要分配新空间,并拷贝到新空间
void *
ngx_array_push(ngx_array_t *a)
{
void *elt, *new;
size_t size;
ngx_pool_t *p;
if (a->nelts == a->nalloc) {
/* the array is full */
size = a->size * a->nalloc;
p = a->pool;
if ((u_char *) a->elts + size == p->d.last
&& p->d.last + a->size <= p->d.end)
{
/*
* the array allocation is the last in the pool
* and there is space for new allocation
*/
p->d.last += a->size;
a->nalloc++;
} else {
/* allocate a new array */
new = ngx_palloc(p, 2 * size);
if (new == NULL) {
return NULL;
}
ngx_memcpy(new, a->elts, size);
a->elts = new;
a->nalloc *= 2;
}
}
elt = (u_char *) a->elts + a->size * a->nelts;
a->nelts++;
return elt;
}
3.3 destroy
尽可能释放数组占用的内存池空间
void
ngx_array_destroy(ngx_array_t *a)
{
ngx_pool_t *p;
p = a->pool;
if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) {
p->d.last -= a->size * a->nalloc;
}
if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) {
p->d.last = (u_char *) a;
}
}