280 lines
5.6 KiB
C
280 lines
5.6 KiB
C
/*
|
|
* ngx_dict.c
|
|
* Copyright © 2007 Adrian Perez <adrianperez@udc.es>
|
|
*/
|
|
|
|
#ifndef NGX_DICT_DEFAULT_SIZE
|
|
#define NGX_DICT_DEFAULT_SIZE 128
|
|
#endif /* !NGX_DICT_DEFAULT_SIZE */
|
|
|
|
#ifndef NGX_DICT_RESIZE_FACTOR
|
|
#define NGX_DICT_RESIZE_FACTOR 10
|
|
#endif /* !NGX_DICT_RESIZE_FACTOR */
|
|
|
|
#ifndef NGX_DICT_COUNT_TO_SIZE_RATIO
|
|
#define NGX_DICT_COUNT_TO_SIZE_RATIO 1.2
|
|
#endif /* !NGX_DICT_COUNT_TO_SIZE_RATIO */
|
|
|
|
#ifndef NGX_DICT_HASH
|
|
#define NGX_DICT_HASH(_k, _s) (ngx_dict_hashstr(_k) % ((_s) - 1))
|
|
#endif /* !NGX_DICT_HASH */
|
|
|
|
#ifndef NGX_DICT_HASHN
|
|
#define NGX_DICT_HASHN(_k, _s, _n) (ngx_dict_hashnstr(_k, _n) % ((_s) - 1))
|
|
#endif /* !NGX_DICT_HASHN */
|
|
|
|
#ifndef NGX_DICT_KEY_EQ
|
|
#define NGX_DICT_KEY_EQ(_a, _b) (ngx_dict_streq((_a), (_b)))
|
|
#endif /* !NGX_DICT_KEY_EQ */
|
|
|
|
#ifndef NGX_DICT_KEY_EQN
|
|
#define NGX_DICT_KEY_EQN(_a, _b, _blen) (ngx_dict_strneq((_a), (_b), (_blen)))
|
|
#endif /* !NGX_DICT_KEY_EQN */
|
|
|
|
#include "ngx_dict.h"
|
|
|
|
|
|
static ngx_slab_pool_t s_node_slab;
|
|
static ngx_slab_pool_t s_strs_slab;
|
|
|
|
|
|
static inline ngx_dict_node_t*
|
|
_ngx_dict_node_new(const ngx_str_t *key, void *val)
|
|
{
|
|
ngx_dict_node_t *node;
|
|
|
|
node = ngx_slab_alloc(&s_node_slab, sizeof(ngx_dict_node_t));
|
|
node->val = val;
|
|
node->key.len = key->len;
|
|
/* FIXME: Allocate from proper place! */
|
|
node->key.data = ngx_slab_alloc(&s_strs_slab, key->len);
|
|
/* TODO: Copy string data */
|
|
return node;
|
|
}
|
|
|
|
|
|
static inline ngx_dict_node_t*
|
|
_ngx_dict_node_newn(const ngx_str_t *key, size_t len, void *val)
|
|
{
|
|
ngx_dict_node_t *node;
|
|
|
|
node = ngx_slab_alloc(&s_node_slab, sizeof(ngx_dict_node_t));
|
|
node->val = val;
|
|
node->key.len = len;
|
|
/* FIXME: Allocate from proper place! */
|
|
node->key.data = ngx_slab_alloc(&s_strs_slab, len);
|
|
/* TODO: Copy string data */
|
|
return node;
|
|
}
|
|
|
|
|
|
static inline void
|
|
_ngx_dict_node_free(ngx_dict_node_t *node)
|
|
{
|
|
/* TODO: What to free and how?
|
|
w_free(node->key);
|
|
w_free(node);
|
|
*/
|
|
}
|
|
|
|
|
|
static inline void
|
|
_ngx_dict_free_nodes(ngx_dict_t *d)
|
|
{
|
|
ngx_dict_node_t *node = d->first;
|
|
ngx_dict_node_t *next;
|
|
|
|
while (node) {
|
|
next = node->nextNode;
|
|
_ngx_dict_node_free(node);
|
|
node = next;
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
ngx_dict_init(ngx_pool_t *pool, ngx_dict_t *d)
|
|
{
|
|
d->size = NGX_DICT_DEFAULT_SIZE;
|
|
/* TODO: Allocate this one... from where?
|
|
d->nodes = w_alloc(w_dict_node_t*, d->size);
|
|
*/
|
|
return 1;
|
|
}
|
|
|
|
|
|
void
|
|
ngx_dict_free(ngx_dict_t *d)
|
|
{
|
|
_ngx_dict_free_nodes(d);
|
|
/* FIXME: How to deallocate those?
|
|
w_free(d->nodes);
|
|
w_free(d);
|
|
*/
|
|
}
|
|
|
|
|
|
void
|
|
ngx_dict_clear(ngx_dict_t *d)
|
|
{
|
|
_ngx_dict_free_nodes(d);
|
|
memset(d->nodes, 0x00, d->size * sizeof(ngx_dict_node_t*));
|
|
}
|
|
|
|
|
|
void*
|
|
ngx_dict_getn(const ngx_dict_t *d, const ngx_str_t *key, size_t len)
|
|
{
|
|
ngx_dict_node_t *node;
|
|
unsigned hval;
|
|
|
|
hval = NGX_DICT_HASHN(key, d->size, len);
|
|
node = d->nodes[hval];
|
|
|
|
if (node) {
|
|
if (NGX_DICT_KEY_EQN(&node->key, key, len)) {
|
|
return node->val;
|
|
}
|
|
else {
|
|
ngx_dict_node_t *lastNode = node;
|
|
node = node->next;
|
|
while (node) {
|
|
if (NGX_DICT_KEY_EQN(&node->key, key, len)) {
|
|
lastNode->next = node->next;
|
|
node->next = d->nodes[hval];
|
|
d->nodes[hval] = node;
|
|
return node->val;
|
|
}
|
|
lastNode = node;
|
|
node = node->next;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static inline void
|
|
_ngx_dict_rehash(ngx_dict_t *d)
|
|
{
|
|
ngx_dict_node_t *node = d->first;
|
|
|
|
while (node) {
|
|
node->next = NULL;
|
|
node = node->nextNode;
|
|
}
|
|
|
|
d->size *= NGX_DICT_RESIZE_FACTOR;
|
|
/* TODO FIXME XXX: How the hell do we resize memory with nginx's model?
|
|
d->nodes = w_resize(d->nodes, w_dict_node_t*, ++d->size);
|
|
*/
|
|
memset(d->nodes, 0x00, d->size * sizeof(ngx_dict_node_t*));
|
|
|
|
for (node = d->first; node; node = node->nextNode) {
|
|
unsigned hval = NGX_DICT_HASH(&node->key, d->size);
|
|
ngx_dict_node_t *n = d->nodes[hval];
|
|
if (!n) d->nodes[hval] = node;
|
|
else {
|
|
for (;; n = n->next) {
|
|
if (!n->next) {
|
|
n->next = node;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
ngx_dict_setn(ngx_dict_t *d, const ngx_str_t *key, size_t len, void *val)
|
|
{
|
|
unsigned hval;
|
|
ngx_dict_node_t *node;
|
|
|
|
hval = NGX_DICT_HASHN(key, d->size, len);
|
|
node = d->nodes[hval];
|
|
|
|
while (node) {
|
|
if (NGX_DICT_KEY_EQN(&node->key, key, len)) {
|
|
node->val = val;
|
|
return;
|
|
}
|
|
node = node->next;
|
|
}
|
|
|
|
node = _ngx_dict_node_newn(key, len, val);
|
|
|
|
if (d->nodes[hval]) node->next = d->nodes[hval];
|
|
d->nodes[hval] = node;
|
|
|
|
node->nextNode = d->first;
|
|
if (d->first) d->first->prevNode = node;
|
|
d->first = node;
|
|
|
|
d->count++;
|
|
if (d->count > (d->size * NGX_DICT_COUNT_TO_SIZE_RATIO))
|
|
_ngx_dict_rehash(d);
|
|
}
|
|
|
|
|
|
void
|
|
ngx_dict_del(ngx_dict_t *d, const ngx_str_t *key)
|
|
{
|
|
unsigned hval;
|
|
ngx_dict_node_t *node;
|
|
ngx_dict_node_t *lastNode = NULL;
|
|
|
|
hval = NGX_DICT_HASH(key, d->size);
|
|
|
|
for (node = d->nodes[hval]; node; node = node->next) {
|
|
if (NGX_DICT_KEY_EQ(&node->key, key)) {
|
|
ngx_dict_node_t *prevNode = node->prevNode;
|
|
ngx_dict_node_t *nextNode = node->nextNode;
|
|
|
|
if (prevNode) prevNode->nextNode = nextNode;
|
|
else d->first = nextNode;
|
|
if (nextNode) nextNode->prevNode = prevNode;
|
|
|
|
if (lastNode) lastNode->next = node->next;
|
|
else d->nodes[hval] = node->next;
|
|
|
|
_ngx_dict_node_free(node);
|
|
d->count--;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ngx_dict_traverse_nodes(const ngx_dict_t *d, ngx_dict_traverse_fun_t f, void *ctx)
|
|
{
|
|
ngx_dict_node_t *n;
|
|
|
|
for (n = ngx_dict_first_node(d); n != NULL; n = ngx_dict_next_node(n))
|
|
(*f)(n, ctx);
|
|
}
|
|
|
|
|
|
void
|
|
ngx_dict_traverse_keys(const ngx_dict_t *d, ngx_dict_traverse_fun_t f, void *ctx)
|
|
{
|
|
ngx_dict_node_t *n;
|
|
|
|
for (n = ngx_dict_first_node(d); n != NULL; n = ngx_dict_next_node(n))
|
|
(*f)(&n->key, ctx);
|
|
}
|
|
|
|
|
|
void
|
|
ngx_dict_traverse_values(const ngx_dict_t *d, ngx_dict_traverse_fun_t f, void *ctx)
|
|
{
|
|
ngx_dict_node_t *n;
|
|
|
|
for (n = ngx_dict_first_node(d); n != NULL; n = ngx_dict_next_node(n))
|
|
(*f)(n->val, ctx);
|
|
}
|
|
|