328 lines
6.4 KiB
C
328 lines
6.4 KiB
C
/*
|
|
* Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com
|
|
*/
|
|
|
|
|
|
#include "ngx_map.h"
|
|
|
|
|
|
static void
|
|
ngx_map_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
|
|
ngx_rbtree_node_t *sentinel)
|
|
{
|
|
ngx_rbtree_node_t **p;
|
|
intptr_t *raw_key, *raw_key_temp;
|
|
ngx_map_t **map;
|
|
|
|
for (;;) {
|
|
|
|
if (node->key < temp->key) {
|
|
p = &temp->left;
|
|
} else if (node->key > temp->key) {
|
|
p = &temp->right;
|
|
} else {
|
|
raw_key = (intptr_t *)((char *) node
|
|
+ offsetof(ngx_map_node_t, raw_key));
|
|
raw_key_temp = (intptr_t *)((char *) temp
|
|
+ offsetof(ngx_map_node_t, raw_key));
|
|
map = (ngx_map_t **)((char *) node + offsetof(ngx_map_node_t, map));
|
|
|
|
switch ((*map)->cmp(*raw_key, *raw_key_temp)) {
|
|
case -1:
|
|
p = &temp->left;
|
|
break;
|
|
case 1:
|
|
p = &temp->right;
|
|
break;
|
|
default: /* key is duplicate */
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (*p == sentinel) {
|
|
break;
|
|
}
|
|
|
|
temp = *p;
|
|
}
|
|
|
|
*p = node;
|
|
node->parent = temp;
|
|
node->left = sentinel;
|
|
node->right = sentinel;
|
|
ngx_rbt_red(node);
|
|
}
|
|
|
|
void
|
|
ngx_map_init(ngx_map_t *map, ngx_map_hash_pt hash, ngx_cmp_pt cmp)
|
|
{
|
|
ngx_rbtree_init(&map->rbtree, &map->sentinel, ngx_map_rbtree_insert_value);
|
|
map->hash = hash;
|
|
map->cmp = cmp;
|
|
}
|
|
|
|
ngx_map_node_t *
|
|
ngx_map_begin(ngx_map_t *map)
|
|
{
|
|
ngx_rbtree_node_t *p;
|
|
|
|
if (ngx_map_empty(map)) {
|
|
return NULL;
|
|
}
|
|
|
|
p = map->rbtree.root;
|
|
|
|
for (;;) {
|
|
if (p->left == map->rbtree.sentinel) {
|
|
break;
|
|
}
|
|
|
|
p = p->left;
|
|
}
|
|
|
|
return (ngx_map_node_t *) p;
|
|
}
|
|
|
|
ngx_map_node_t *
|
|
ngx_map_rbegin(ngx_map_t *map)
|
|
{
|
|
ngx_rbtree_node_t *p;
|
|
|
|
if (ngx_map_empty(map)) {
|
|
return NULL;
|
|
}
|
|
|
|
p = map->rbtree.root;
|
|
|
|
for (;;) {
|
|
if (p->right == map->rbtree.sentinel) {
|
|
break;
|
|
}
|
|
|
|
p = p->right;
|
|
}
|
|
|
|
return (ngx_map_node_t *) p;
|
|
}
|
|
|
|
ngx_map_node_t *
|
|
ngx_map_next(ngx_map_node_t *n)
|
|
{
|
|
ngx_map_t *map;
|
|
ngx_rbtree_node_t *p, *top;
|
|
|
|
map = n->map;
|
|
p = &n->rn;
|
|
top = NULL;
|
|
|
|
if (p->right != map->rbtree.sentinel) {
|
|
// current node has right subtree
|
|
top = p->right;
|
|
} else {
|
|
for (;;) {
|
|
if (p == map->rbtree.root) {
|
|
return NULL;
|
|
}
|
|
|
|
if (p->parent->left == p) {
|
|
return (ngx_map_node_t *) p->parent;
|
|
}
|
|
|
|
// p->parent->right == p
|
|
p = p->parent;
|
|
}
|
|
}
|
|
|
|
// get the mininum node
|
|
p = top;
|
|
for (;;) {
|
|
if (p->left == map->rbtree.sentinel) {
|
|
break;
|
|
}
|
|
|
|
p = p->left;
|
|
}
|
|
|
|
return (ngx_map_node_t *) p;
|
|
}
|
|
|
|
ngx_map_node_t *
|
|
ngx_map_prev(ngx_map_node_t *n)
|
|
{
|
|
ngx_map_t *map;
|
|
ngx_rbtree_node_t *p, *top;
|
|
|
|
map = n->map;
|
|
p = &n->rn;
|
|
top = NULL;
|
|
|
|
if (p->left != map->rbtree.sentinel) {
|
|
// current node has left subtree
|
|
top = p->left;
|
|
} else {
|
|
for (;;) {
|
|
if (p == map->rbtree.root) {
|
|
return NULL;
|
|
}
|
|
|
|
if (p->parent->right == p) {
|
|
return (ngx_map_node_t *) p->parent;
|
|
}
|
|
|
|
// p->parent->left == p
|
|
p = p->parent;
|
|
}
|
|
}
|
|
|
|
// get the maximum node
|
|
p = top;
|
|
for (;;) {
|
|
if (p->right == map->rbtree.sentinel) {
|
|
break;
|
|
}
|
|
|
|
p = p->right;
|
|
}
|
|
|
|
return (ngx_map_node_t *) p;
|
|
}
|
|
|
|
void
|
|
ngx_map_insert(ngx_map_t *map, ngx_map_node_t *node, ngx_flag_t covered)
|
|
{
|
|
ngx_map_node_t *n;
|
|
|
|
node->rn.key = map->hash(node->raw_key);
|
|
node->map = map;
|
|
|
|
n = ngx_map_find(map, node->raw_key);
|
|
if (n == NULL) {
|
|
ngx_rbtree_insert(&map->rbtree, &node->rn);
|
|
} else if (covered) {
|
|
ngx_map_delete(map, node->raw_key);
|
|
ngx_rbtree_insert(&map->rbtree, &node->rn);
|
|
}
|
|
}
|
|
|
|
void
|
|
ngx_map_delete(ngx_map_t *map, intptr_t key)
|
|
{
|
|
ngx_map_node_t *node;
|
|
|
|
node = ngx_map_find(map, key);
|
|
if (node) {
|
|
ngx_rbtree_delete(&map->rbtree, &node->rn);
|
|
}
|
|
}
|
|
|
|
ngx_map_node_t *
|
|
ngx_map_find(ngx_map_t *map, intptr_t key)
|
|
{
|
|
ngx_rbtree_node_t *p;
|
|
ngx_rbtree_key_t k;
|
|
intptr_t *key_temp;
|
|
|
|
if (ngx_map_empty(map)) {
|
|
return NULL;
|
|
}
|
|
|
|
k = map->hash(key);
|
|
p = map->rbtree.root;
|
|
|
|
for (;;) {
|
|
if (k < p->key) {
|
|
p = p->left;
|
|
} else if (k > p->key) {
|
|
p = p->right;
|
|
} else {
|
|
key_temp = (intptr_t *)((char *) p
|
|
+ offsetof(ngx_map_node_t, raw_key));
|
|
|
|
switch (map->cmp(key, *key_temp)) {
|
|
case -1:
|
|
p = p->left;
|
|
break;
|
|
case 1:
|
|
p = p->right;
|
|
break;
|
|
case 0:
|
|
return (ngx_map_node_t *) p;
|
|
}
|
|
}
|
|
|
|
if (p == map->rbtree.sentinel) {
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* ngx_str_t */
|
|
ngx_rbtree_key_t
|
|
ngx_map_hash_str(intptr_t key)
|
|
{
|
|
ngx_str_t *k;
|
|
|
|
k = (ngx_str_t *) key;
|
|
|
|
return ngx_hash_key(k->data, k->len);
|
|
}
|
|
|
|
int
|
|
ngx_cmp_str(intptr_t key1, intptr_t key2)
|
|
{
|
|
ngx_str_t *k1, *k2;
|
|
ngx_int_t rc;
|
|
|
|
k1 = (ngx_str_t *) key1;
|
|
k2 = (ngx_str_t *) key2;
|
|
|
|
rc = ngx_memn2cmp(k1->data, k2->data, k1->len, k2->len);
|
|
|
|
if (rc < 0) {
|
|
return -1;
|
|
} else if (rc > 0) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* ngx_uint_t */
|
|
ngx_rbtree_key_t
|
|
ngx_map_hash_uint(intptr_t key)
|
|
{
|
|
return (ngx_rbtree_key_t) key;
|
|
}
|
|
|
|
int
|
|
ngx_cmp_uint(intptr_t key1, intptr_t key2)
|
|
{
|
|
if ((ngx_uint_t) key1 < (ngx_uint_t) key2) {
|
|
return -1;
|
|
} else if ((ngx_uint_t) key1 > (ngx_uint_t) key2) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* ngx_int_t */
|
|
ngx_rbtree_key_t
|
|
ngx_map_hash_int(intptr_t key)
|
|
{
|
|
return (ngx_rbtree_key_t) key;
|
|
}
|
|
|
|
int
|
|
ngx_cmp_int(intptr_t key1, intptr_t key2)
|
|
{
|
|
if ((ngx_int_t) key1 < (ngx_int_t) key2) {
|
|
return -1;
|
|
} else if ((ngx_int_t) key1 > (ngx_int_t) key2) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|