small-package/luci-app-nginx-pingos/modules/nginx-toolkit-module/ngx_map.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;
}
}