|
Packit |
979a56 |
/*
|
|
Packit |
979a56 |
* Copyright (C) 2011 Red Hat, Inc.
|
|
Packit |
979a56 |
*
|
|
Packit |
979a56 |
* Author: Angus Salkeld <asalkeld@redhat.com>
|
|
Packit |
979a56 |
*
|
|
Packit |
979a56 |
* This file is part of libqb.
|
|
Packit |
979a56 |
*
|
|
Packit |
979a56 |
* libqb is free software: you can redistribute it and/or modify
|
|
Packit |
979a56 |
* it under the terms of the GNU Lesser General Public License as published by
|
|
Packit |
979a56 |
* the Free Software Foundation, either version 2.1 of the License, or
|
|
Packit |
979a56 |
* (at your option) any later version.
|
|
Packit |
979a56 |
*
|
|
Packit |
979a56 |
* libqb is distributed in the hope that it will be useful,
|
|
Packit |
979a56 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
979a56 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
979a56 |
* GNU Lesser General Public License for more details.
|
|
Packit |
979a56 |
*
|
|
Packit |
979a56 |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit |
979a56 |
* along with libqb. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
979a56 |
*/
|
|
Packit |
979a56 |
#include <os_base.h>
|
|
Packit |
979a56 |
#include <assert.h>
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
#include <qb/qbdefs.h>
|
|
Packit |
979a56 |
#include <qb/qblist.h>
|
|
Packit |
979a56 |
#include <qb/qbmap.h>
|
|
Packit |
979a56 |
#include "map_int.h"
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
struct trie_iter {
|
|
Packit |
979a56 |
struct qb_map_iter i;
|
|
Packit |
979a56 |
const char *prefix;
|
|
Packit |
979a56 |
struct trie_node *n;
|
|
Packit |
979a56 |
struct trie_node *root;
|
|
Packit |
979a56 |
};
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
struct trie_node {
|
|
Packit |
979a56 |
uint32_t idx;
|
|
Packit |
979a56 |
char *segment;
|
|
Packit |
979a56 |
uint32_t num_segments;
|
|
Packit |
979a56 |
char *key;
|
|
Packit |
979a56 |
void *value;
|
|
Packit |
979a56 |
struct trie_node **children;
|
|
Packit |
979a56 |
uint32_t num_children;
|
|
Packit |
979a56 |
uint32_t refcount;
|
|
Packit |
979a56 |
struct trie_node *parent;
|
|
Packit |
979a56 |
struct qb_list_head *notifier_head;
|
|
Packit |
979a56 |
};
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
struct trie {
|
|
Packit |
979a56 |
struct qb_map map;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
size_t length;
|
|
Packit |
979a56 |
uint32_t num_nodes;
|
|
Packit |
979a56 |
uint32_t mem_used;
|
|
Packit |
979a56 |
struct trie_node *header;
|
|
Packit |
979a56 |
};
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static void trie_notify(struct trie_node *n, uint32_t event, const char *key,
|
|
Packit |
979a56 |
void *old_value, void *value);
|
|
Packit |
979a56 |
static struct trie_node *trie_new_node(struct trie *t, struct trie_node *parent);
|
|
Packit |
979a56 |
static void trie_destroy_node(struct trie_node *node);
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
/*
|
|
Packit |
979a56 |
* characters are stored in reverse to make accessing the
|
|
Packit |
979a56 |
* more common case (non-control chars) more space efficient.
|
|
Packit |
979a56 |
*/
|
|
Packit |
979a56 |
#define TRIE_CHAR2INDEX(ch) (126 - ch)
|
|
Packit |
979a56 |
#define TRIE_INDEX2CHAR(idx) (126 - idx)
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static int32_t
|
|
Packit |
979a56 |
trie_node_alive(struct trie_node *node)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
if (node->value == NULL ||
|
|
Packit |
979a56 |
node->refcount <= 0) {
|
|
Packit |
979a56 |
return QB_FALSE;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
return QB_TRUE;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static struct trie_node *
|
|
Packit |
979a56 |
trie_node_next(struct trie_node *node, struct trie_node *root, int all)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie_node *c = node;
|
|
Packit |
979a56 |
struct trie_node *n;
|
|
Packit |
979a56 |
struct trie_node *p;
|
|
Packit |
979a56 |
int i;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
keep_going:
|
|
Packit |
979a56 |
n = NULL;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
/* child/outward
|
|
Packit |
979a56 |
*/
|
|
Packit |
979a56 |
for (i = c->num_children - 1; i >= 0; i--) {
|
|
Packit |
979a56 |
if (c->children[i]) {
|
|
Packit |
979a56 |
n = c->children[i];
|
|
Packit |
979a56 |
break;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
if (n) {
|
|
Packit |
979a56 |
if (all || trie_node_alive(n)) {
|
|
Packit |
979a56 |
return n;
|
|
Packit |
979a56 |
} else {
|
|
Packit |
979a56 |
c = n;
|
|
Packit |
979a56 |
goto keep_going;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
/* sibling/parent
|
|
Packit |
979a56 |
*/
|
|
Packit |
979a56 |
if (c == root) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
p = c;
|
|
Packit |
979a56 |
do {
|
|
Packit |
979a56 |
for (i = p->idx - 1; i >= 0; i--) {
|
|
Packit |
979a56 |
if (p->parent->children[i]) {
|
|
Packit |
979a56 |
n = p->parent->children[i];
|
|
Packit |
979a56 |
break;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
if (n == NULL) {
|
|
Packit |
979a56 |
p = p->parent;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
} while (n == NULL && p != root);
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (n) {
|
|
Packit |
979a56 |
if (all || trie_node_alive(n)) {
|
|
Packit |
979a56 |
return n;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
if (n == root) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
c = n;
|
|
Packit |
979a56 |
goto keep_going;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
return n;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static struct trie_node *
|
|
Packit |
979a56 |
new_child_node(struct trie *t, struct trie_node * parent, char ch)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie_node *new_node;
|
|
Packit |
979a56 |
int old_max_idx;
|
|
Packit |
979a56 |
int i;
|
|
Packit |
979a56 |
int idx = TRIE_CHAR2INDEX(ch);
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (idx >= parent->num_children) {
|
|
Packit |
979a56 |
old_max_idx = parent->num_children;
|
|
Packit |
979a56 |
parent->num_children = QB_MAX(idx + 1, 30);
|
|
Packit |
979a56 |
t->mem_used += (sizeof(struct trie_node*) * (parent->num_children - old_max_idx));
|
|
Packit |
979a56 |
parent->children = realloc(parent->children,
|
|
Packit |
979a56 |
(parent->num_children * sizeof(struct trie_node*)));
|
|
Packit |
979a56 |
if (parent->children == NULL) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
for (i = old_max_idx; i < parent->num_children; i++) {
|
|
Packit |
979a56 |
parent->children[i] = NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
new_node = trie_new_node(t, parent);
|
|
Packit |
979a56 |
if (new_node == NULL) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
new_node->idx = idx;
|
|
Packit |
979a56 |
parent->children[idx] = new_node;
|
|
Packit |
979a56 |
return new_node;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static struct trie_node *
|
|
Packit |
979a56 |
trie_node_split(struct trie *t, struct trie_node *cur_node, int seg_cnt)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie_node *split_node;
|
|
Packit |
979a56 |
struct trie_node ** children = cur_node->children;
|
|
Packit |
979a56 |
uint32_t num_children = cur_node->num_children;
|
|
Packit |
979a56 |
struct qb_list_head *tmp;
|
|
Packit |
979a56 |
int i;
|
|
Packit |
979a56 |
int s;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
cur_node->children = NULL;
|
|
Packit |
979a56 |
cur_node->num_children = 0;
|
|
Packit |
979a56 |
split_node = new_child_node(t, cur_node, cur_node->segment[seg_cnt]);
|
|
Packit |
979a56 |
if (split_node == NULL) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
split_node->children = children;
|
|
Packit |
979a56 |
split_node->num_children = num_children;
|
|
Packit |
979a56 |
for (i = 0; i < split_node->num_children; i++) {
|
|
Packit |
979a56 |
if (split_node->children[i]) {
|
|
Packit |
979a56 |
split_node->children[i]->parent = split_node;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
split_node->value = cur_node->value;
|
|
Packit |
979a56 |
split_node->key = cur_node->key;
|
|
Packit |
979a56 |
split_node->refcount = cur_node->refcount;
|
|
Packit |
979a56 |
cur_node->value = NULL;
|
|
Packit |
979a56 |
cur_node->key = NULL;
|
|
Packit |
979a56 |
cur_node->refcount = 0;
|
|
Packit |
979a56 |
/* move notifier list to split */
|
|
Packit |
979a56 |
tmp = split_node->notifier_head;
|
|
Packit |
979a56 |
split_node->notifier_head = cur_node->notifier_head;
|
|
Packit |
979a56 |
cur_node->notifier_head = tmp;
|
|
Packit |
979a56 |
qb_list_init(cur_node->notifier_head);
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (seg_cnt < cur_node->num_segments) {
|
|
Packit |
979a56 |
split_node->num_segments = cur_node->num_segments - seg_cnt - 1;
|
|
Packit |
979a56 |
split_node->segment = malloc(split_node->num_segments * sizeof(char));
|
|
Packit |
979a56 |
if (split_node->segment == NULL) {
|
|
Packit |
979a56 |
trie_destroy_node(split_node);
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
for (i = (seg_cnt + 1); i < cur_node->num_segments; i++) {
|
|
Packit |
979a56 |
s = i - seg_cnt - 1;
|
|
Packit |
979a56 |
split_node->segment[s] = cur_node->segment[i];
|
|
Packit |
979a56 |
cur_node->segment[i] = '\0';
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
cur_node->num_segments = seg_cnt;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
return cur_node;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static struct trie_node *
|
|
Packit |
979a56 |
trie_insert(struct trie *t, const char *key)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie_node *cur_node = t->header;
|
|
Packit |
979a56 |
struct trie_node *new_node;
|
|
Packit |
979a56 |
char *cur = (char *)key;
|
|
Packit |
979a56 |
int idx = TRIE_CHAR2INDEX(key[0]);
|
|
Packit |
979a56 |
int seg_cnt = 0;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
do {
|
|
Packit |
979a56 |
new_node = NULL;
|
|
Packit |
979a56 |
if (cur_node->num_segments > 0 &&
|
|
Packit |
979a56 |
seg_cnt < cur_node->num_segments) {
|
|
Packit |
979a56 |
if (cur_node->segment[seg_cnt] == *cur) {
|
|
Packit |
979a56 |
/* we found the char in the segment */
|
|
Packit |
979a56 |
seg_cnt++;
|
|
Packit |
979a56 |
} else {
|
|
Packit |
979a56 |
cur_node = trie_node_split(t, cur_node, seg_cnt);
|
|
Packit |
979a56 |
if (cur_node == NULL) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
new_node = new_child_node(t, cur_node, *cur);
|
|
Packit |
979a56 |
if (new_node == NULL) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
} else if (idx < cur_node->num_children &&
|
|
Packit |
979a56 |
cur_node->children[idx]) {
|
|
Packit |
979a56 |
/* the char can be found on the next node */
|
|
Packit |
979a56 |
new_node = cur_node->children[idx];
|
|
Packit |
979a56 |
} else if (cur_node == t->header) {
|
|
Packit |
979a56 |
/* the root node is empty so make it on the next node */
|
|
Packit |
979a56 |
new_node = new_child_node(t, cur_node, *cur);
|
|
Packit |
979a56 |
if (new_node == NULL) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
} else if (cur_node->value == NULL &&
|
|
Packit |
979a56 |
qb_list_empty(cur_node->notifier_head) &&
|
|
Packit |
979a56 |
cur_node->num_children == 0 &&
|
|
Packit |
979a56 |
seg_cnt == cur_node->num_segments) {
|
|
Packit |
979a56 |
/* we are on a leaf (with no value) so just add it as a segment */
|
|
Packit |
979a56 |
cur_node->segment = realloc(cur_node->segment, cur_node->num_segments + 1);
|
|
Packit |
979a56 |
cur_node->segment[cur_node->num_segments] = *cur;
|
|
Packit |
979a56 |
t->mem_used += sizeof(char);
|
|
Packit |
979a56 |
cur_node->num_segments++;
|
|
Packit |
979a56 |
seg_cnt++;
|
|
Packit |
979a56 |
} else if (seg_cnt == cur_node->num_segments) {
|
|
Packit |
979a56 |
/* on the last segment need to make a new node */
|
|
Packit |
979a56 |
new_node = new_child_node(t, cur_node, *cur);
|
|
Packit |
979a56 |
if (new_node == NULL) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
} else /* need_to_split */ {
|
|
Packit |
979a56 |
cur_node = trie_node_split(t, cur_node, seg_cnt);
|
|
Packit |
979a56 |
if (cur_node == NULL) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
new_node = new_child_node(t, cur_node, *cur);
|
|
Packit |
979a56 |
if (new_node == NULL) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
if (new_node) {
|
|
Packit |
979a56 |
seg_cnt = 0;
|
|
Packit |
979a56 |
cur_node = new_node;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
cur++;
|
|
Packit |
979a56 |
idx = TRIE_CHAR2INDEX(*cur);
|
|
Packit |
979a56 |
} while (*cur != '\0');
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (cur_node->num_segments > 0 &&
|
|
Packit |
979a56 |
seg_cnt < cur_node->num_segments) {
|
|
Packit |
979a56 |
/* we need to split */
|
|
Packit |
979a56 |
cur_node = trie_node_split(t, cur_node, seg_cnt);
|
|
Packit |
979a56 |
if (cur_node == NULL) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
new_node = new_child_node(t, cur_node, *cur);
|
|
Packit |
979a56 |
if (new_node == NULL) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
return cur_node;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static struct trie_node *
|
|
Packit |
979a56 |
trie_lookup(struct trie *t, const char *key, int exact_match)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie_node *cur_node = t->header;
|
|
Packit |
979a56 |
char *cur = (char *)key;
|
|
Packit |
979a56 |
int idx = TRIE_CHAR2INDEX(key[0]);
|
|
Packit |
979a56 |
int seg_cnt = 0;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
do {
|
|
Packit |
979a56 |
if (cur_node->num_segments > 0 &&
|
|
Packit |
979a56 |
seg_cnt < cur_node->num_segments) {
|
|
Packit |
979a56 |
if (cur_node->segment[seg_cnt] == *cur) {
|
|
Packit |
979a56 |
/* we found the char in the segment */
|
|
Packit |
979a56 |
seg_cnt++;
|
|
Packit |
979a56 |
} else {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
} else if (idx < cur_node->num_children &&
|
|
Packit |
979a56 |
cur_node->children[idx]) {
|
|
Packit |
979a56 |
/* the char can be found on the next node */
|
|
Packit |
979a56 |
cur_node = cur_node->children[idx];
|
|
Packit |
979a56 |
seg_cnt = 0;
|
|
Packit |
979a56 |
} else {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
cur++;
|
|
Packit |
979a56 |
idx = TRIE_CHAR2INDEX(*cur);
|
|
Packit |
979a56 |
} while (*cur != '\0');
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (exact_match &&
|
|
Packit |
979a56 |
cur_node->num_segments > 0 &&
|
|
Packit |
979a56 |
seg_cnt < cur_node->num_segments) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
return cur_node;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static void
|
|
Packit |
979a56 |
trie_node_release(struct trie *t, struct trie_node *node)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
int i;
|
|
Packit |
979a56 |
int empty = QB_FALSE;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (node->key == NULL &&
|
|
Packit |
979a56 |
node->parent != NULL &&
|
|
Packit |
979a56 |
qb_list_empty(node->notifier_head)) {
|
|
Packit |
979a56 |
struct trie_node *p = node->parent;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (node->num_children == 0) {
|
|
Packit |
979a56 |
empty = QB_TRUE;
|
|
Packit |
979a56 |
} else {
|
|
Packit |
979a56 |
empty = QB_TRUE;
|
|
Packit |
979a56 |
for (i = node->num_children - 1; i >= 0; i--) {
|
|
Packit |
979a56 |
if (node->children[i]) {
|
|
Packit |
979a56 |
empty = QB_FALSE;
|
|
Packit |
979a56 |
break;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
if (!empty) {
|
|
Packit |
979a56 |
return;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
/*
|
|
Packit |
979a56 |
* unlink the node from the parent
|
|
Packit |
979a56 |
*/
|
|
Packit |
979a56 |
p->children[node->idx] = NULL;
|
|
Packit |
979a56 |
trie_destroy_node(node);
|
|
Packit |
979a56 |
t->num_nodes--;
|
|
Packit |
979a56 |
t->mem_used -= sizeof(struct trie_node);
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
trie_node_release(t, p);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static void
|
|
Packit |
979a56 |
trie_node_destroy(struct trie *t, struct trie_node *n)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
if (n->value == NULL) {
|
|
Packit |
979a56 |
return;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
trie_notify(n, QB_MAP_NOTIFY_DELETED, n->key, n->value, NULL);
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
n->key = NULL;
|
|
Packit |
979a56 |
n->value = NULL;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
trie_node_release(t, n);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static void
|
|
Packit |
979a56 |
trie_print_node(struct trie_node *n, struct trie_node *r, const char *suffix)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
int i;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (n->parent) {
|
|
Packit |
979a56 |
trie_print_node(n->parent, n, suffix);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
if (n->idx == 0) {
|
|
Packit |
979a56 |
return;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
printf("[%c", (char) TRIE_INDEX2CHAR(n->idx));
|
|
Packit |
979a56 |
for (i = 0; i < n->num_segments; i++) {
|
|
Packit |
979a56 |
printf("%c", n->segment[i]);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
if (n == r) {
|
|
Packit |
979a56 |
#ifndef S_SPLINT_S
|
|
Packit |
979a56 |
printf("] (%" PRIu32 ") %s\n", n->refcount, suffix);
|
|
Packit |
979a56 |
#endif /* S_SPLINT_S */
|
|
Packit |
979a56 |
} else {
|
|
Packit |
979a56 |
printf("] ");
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static void
|
|
Packit |
979a56 |
trie_node_ref(struct trie *t, struct trie_node *node)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
if (t->header == node) {
|
|
Packit |
979a56 |
return;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
node->refcount++;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static void
|
|
Packit |
979a56 |
trie_node_deref(struct trie *t, struct trie_node *node)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
if (!trie_node_alive(node)) {
|
|
Packit |
979a56 |
return;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
node->refcount--;
|
|
Packit |
979a56 |
if (node->refcount > 0) {
|
|
Packit |
979a56 |
return;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
trie_node_destroy(t, node);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static void
|
|
Packit |
979a56 |
trie_destroy(struct qb_map *map)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie *t = (struct trie *)map;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
struct trie_node *cur_node = t->header;
|
|
Packit |
979a56 |
struct trie_node *fwd_node;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
do {
|
|
Packit |
979a56 |
fwd_node = trie_node_next(cur_node, t->header, QB_FALSE);
|
|
Packit |
979a56 |
trie_node_destroy(t, cur_node);
|
|
Packit |
979a56 |
} while ((cur_node = fwd_node));
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
free(t);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static void
|
|
Packit |
979a56 |
trie_destroy_node(struct trie_node *node)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
free(node->segment);
|
|
Packit |
979a56 |
free(node->children);
|
|
Packit |
979a56 |
free(node->notifier_head);
|
|
Packit |
979a56 |
free(node);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static struct trie_node *
|
|
Packit |
979a56 |
trie_new_node(struct trie *t, struct trie_node *parent)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie_node *new_node = calloc(1, sizeof(struct trie_node));
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (new_node == NULL) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
new_node->notifier_head = calloc(1, sizeof(struct qb_list_head));
|
|
Packit |
979a56 |
if (new_node->notifier_head == NULL) {
|
|
Packit |
979a56 |
free(new_node);
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
new_node->parent = parent;
|
|
Packit |
979a56 |
new_node->num_children = 0;
|
|
Packit |
979a56 |
new_node->children = NULL;
|
|
Packit |
979a56 |
new_node->num_segments = 0;
|
|
Packit |
979a56 |
new_node->segment = NULL;
|
|
Packit |
979a56 |
t->num_nodes++;
|
|
Packit |
979a56 |
t->mem_used += sizeof(struct trie_node);
|
|
Packit |
979a56 |
qb_list_init(new_node->notifier_head);
|
|
Packit |
979a56 |
return new_node;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
void
|
|
Packit |
979a56 |
qb_trie_dump(qb_map_t* m)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie * t = (struct trie*)m;
|
|
Packit |
979a56 |
struct trie_node *n;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (t == NULL) {
|
|
Packit |
979a56 |
return;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
#ifndef S_SPLINT_S
|
|
Packit |
979a56 |
printf("nodes: %" PRIu32 ", bytes: %" PRIu32 "\n", t->num_nodes, t->mem_used);
|
|
Packit |
979a56 |
#endif /* S_SPLINT_S */
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
n = t->header;
|
|
Packit |
979a56 |
do {
|
|
Packit |
979a56 |
if (n->num_children == 0) {
|
|
Packit |
979a56 |
trie_print_node(n, n, " ");
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
n = trie_node_next(n, t->header, QB_FALSE);
|
|
Packit |
979a56 |
} while (n);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static void
|
|
Packit |
979a56 |
trie_put(struct qb_map *map, const char *key, const void *value)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie *t = (struct trie *)map;
|
|
Packit |
979a56 |
struct trie_node *n = trie_insert(t, key);
|
|
Packit |
979a56 |
if (n) {
|
|
Packit |
979a56 |
const char *old_value = n->value;
|
|
Packit |
979a56 |
const char *old_key = n->key;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
n->key = (char *)key;
|
|
Packit |
979a56 |
n->value = (void *)value;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (old_value == NULL) {
|
|
Packit |
979a56 |
trie_node_ref(t, n);
|
|
Packit |
979a56 |
t->length++;
|
|
Packit |
979a56 |
trie_notify(n, QB_MAP_NOTIFY_INSERTED,
|
|
Packit |
979a56 |
n->key, NULL, n->value);
|
|
Packit |
979a56 |
} else {
|
|
Packit |
979a56 |
trie_notify(n, QB_MAP_NOTIFY_REPLACED,
|
|
Packit |
979a56 |
(char *)old_key, (void *)old_value,
|
|
Packit |
979a56 |
(void *)value);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static int32_t
|
|
Packit |
979a56 |
trie_rm(struct qb_map *map, const char *key)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie *t = (struct trie *)map;
|
|
Packit |
979a56 |
struct trie_node *n = trie_lookup(t, key, QB_TRUE);
|
|
Packit |
979a56 |
if (n) {
|
|
Packit |
979a56 |
trie_node_deref(t, n);
|
|
Packit |
979a56 |
t->length--;
|
|
Packit |
979a56 |
return QB_TRUE;
|
|
Packit |
979a56 |
} else {
|
|
Packit |
979a56 |
return QB_FALSE;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static void *
|
|
Packit |
979a56 |
trie_get(struct qb_map *map, const char *key)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie *t = (struct trie *)map;
|
|
Packit |
979a56 |
struct trie_node *n = trie_lookup(t, key, QB_TRUE);
|
|
Packit |
979a56 |
if (n) {
|
|
Packit |
979a56 |
return n->value;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static void
|
|
Packit |
979a56 |
trie_notify_deref(struct qb_map_notifier *f)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
f->refcount--;
|
|
Packit |
979a56 |
if (f->refcount == 0) {
|
|
Packit |
979a56 |
qb_list_del(&f->list);
|
|
Packit |
979a56 |
free(f);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static void
|
|
Packit |
979a56 |
trie_notify_ref(struct qb_map_notifier *f)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
f->refcount++;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static void
|
|
Packit |
979a56 |
trie_notify(struct trie_node *n,
|
|
Packit |
979a56 |
uint32_t event, const char *key, void *old_value, void *value)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie_node *c = n;
|
|
Packit |
979a56 |
struct qb_list_head *list;
|
|
Packit |
979a56 |
struct qb_list_head *next;
|
|
Packit |
979a56 |
struct qb_list_head *head;
|
|
Packit |
979a56 |
struct qb_map_notifier *tn;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
do {
|
|
Packit |
979a56 |
head = c->notifier_head;
|
|
Packit |
979a56 |
qb_list_for_each_safe(list, next, head) {
|
|
Packit |
979a56 |
tn = qb_list_entry(list, struct qb_map_notifier, list);
|
|
Packit |
979a56 |
trie_notify_ref(tn);
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if ((tn->events & event) &&
|
|
Packit |
979a56 |
((tn->events & QB_MAP_NOTIFY_RECURSIVE) ||
|
|
Packit |
979a56 |
(n == c))) {
|
|
Packit |
979a56 |
tn->callback(event, (char *)key, old_value,
|
|
Packit |
979a56 |
value, tn->user_data);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
if (((event & QB_MAP_NOTIFY_DELETED) ||
|
|
Packit |
979a56 |
(event & QB_MAP_NOTIFY_REPLACED)) &&
|
|
Packit |
979a56 |
(tn->events & QB_MAP_NOTIFY_FREE)) {
|
|
Packit |
979a56 |
tn->callback(QB_MAP_NOTIFY_FREE, (char *)key,
|
|
Packit |
979a56 |
old_value, value, tn->user_data);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
trie_notify_deref(tn);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
c = c->parent;
|
|
Packit |
979a56 |
} while (c);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static int32_t
|
|
Packit |
979a56 |
trie_notify_add(qb_map_t * m, const char *key,
|
|
Packit |
979a56 |
qb_map_notify_fn fn, int32_t events, void *user_data)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie *t = (struct trie *)m;
|
|
Packit |
979a56 |
struct qb_map_notifier *f;
|
|
Packit |
979a56 |
struct trie_node *n;
|
|
Packit |
979a56 |
struct qb_list_head *list;
|
|
Packit |
979a56 |
int add_to_tail = QB_FALSE;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (key) {
|
|
Packit |
979a56 |
n = trie_lookup(t, key, QB_TRUE);
|
|
Packit |
979a56 |
if (n == NULL) {
|
|
Packit |
979a56 |
n = trie_insert(t, key);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
} else {
|
|
Packit |
979a56 |
n = t->header;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
if (n) {
|
|
Packit |
979a56 |
qb_list_for_each(list, n->notifier_head) {
|
|
Packit |
979a56 |
f = qb_list_entry(list, struct qb_map_notifier, list);
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (events & QB_MAP_NOTIFY_FREE &&
|
|
Packit |
979a56 |
f->events == events) {
|
|
Packit |
979a56 |
/* only one free notifier */
|
|
Packit |
979a56 |
return -EEXIST;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
if (f->events == events &&
|
|
Packit |
979a56 |
f->callback == fn &&
|
|
Packit |
979a56 |
f->user_data == user_data) {
|
|
Packit |
979a56 |
return -EEXIST;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
f = malloc(sizeof(struct qb_map_notifier));
|
|
Packit |
979a56 |
if (f == NULL) {
|
|
Packit |
979a56 |
return -errno;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
f->events = events;
|
|
Packit |
979a56 |
f->user_data = user_data;
|
|
Packit |
979a56 |
f->callback = fn;
|
|
Packit |
979a56 |
f->refcount = 1;
|
|
Packit |
979a56 |
qb_list_init(&f->list);
|
|
Packit |
979a56 |
if (key) {
|
|
Packit |
979a56 |
if (events & QB_MAP_NOTIFY_RECURSIVE) {
|
|
Packit |
979a56 |
add_to_tail = QB_TRUE;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
} else {
|
|
Packit |
979a56 |
if (events & QB_MAP_NOTIFY_FREE) {
|
|
Packit |
979a56 |
add_to_tail = QB_TRUE;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
if (add_to_tail) {
|
|
Packit |
979a56 |
qb_list_add_tail(&f->list, n->notifier_head);
|
|
Packit |
979a56 |
} else {
|
|
Packit |
979a56 |
qb_list_add(&f->list, n->notifier_head);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
return 0;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
return -EINVAL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static int32_t
|
|
Packit |
979a56 |
trie_notify_del(qb_map_t * m, const char *key,
|
|
Packit |
979a56 |
qb_map_notify_fn fn, int32_t events,
|
|
Packit |
979a56 |
int32_t cmp_userdata, void *user_data)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie *t = (struct trie *)m;
|
|
Packit |
979a56 |
struct trie_node *n;
|
|
Packit |
979a56 |
struct qb_list_head *list;
|
|
Packit |
979a56 |
struct qb_list_head *next;
|
|
Packit |
979a56 |
int32_t found = QB_FALSE;
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (key) {
|
|
Packit |
979a56 |
n = trie_lookup(t, key, QB_FALSE);
|
|
Packit |
979a56 |
} else {
|
|
Packit |
979a56 |
n = t->header;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
if (n == NULL) {
|
|
Packit |
979a56 |
return -ENOENT;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
qb_list_for_each_safe(list, next, n->notifier_head) {
|
|
Packit |
979a56 |
struct qb_map_notifier *f = qb_list_entry(list, struct qb_map_notifier, list);
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (f->events == events && f->callback == fn) {
|
|
Packit |
979a56 |
if (cmp_userdata && (f->user_data == user_data)) {
|
|
Packit |
979a56 |
trie_notify_deref(f);
|
|
Packit |
979a56 |
found = QB_TRUE;
|
|
Packit |
979a56 |
} else if (!cmp_userdata) {
|
|
Packit |
979a56 |
trie_notify_deref(f);
|
|
Packit |
979a56 |
found = QB_TRUE;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
if (found) {
|
|
Packit |
979a56 |
trie_node_release(t, n);
|
|
Packit |
979a56 |
return 0;
|
|
Packit |
979a56 |
} else {
|
|
Packit |
979a56 |
return -ENOENT;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static qb_map_iter_t *
|
|
Packit |
979a56 |
trie_iter_create(struct qb_map *map, const char *prefix)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie_iter *i = malloc(sizeof(struct trie_iter));
|
|
Packit |
979a56 |
struct trie *t = (struct trie *)map;
|
|
Packit |
979a56 |
if (i == NULL) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
i->i.m = map;
|
|
Packit |
979a56 |
i->prefix = prefix;
|
|
Packit |
979a56 |
i->n = t->header;
|
|
Packit |
979a56 |
i->root = t->header;
|
|
Packit |
979a56 |
return (qb_map_iter_t *) i;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static const char *
|
|
Packit |
979a56 |
trie_iter_next(qb_map_iter_t * i, void **value)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie_iter *si = (struct trie_iter *)i;
|
|
Packit |
979a56 |
struct trie_node *p = si->n;
|
|
Packit |
979a56 |
struct trie *t = (struct trie *)(i->m);
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (p == NULL) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (p->parent == NULL && si->prefix) {
|
|
Packit |
979a56 |
si->root = trie_lookup(t, si->prefix, QB_FALSE);
|
|
Packit |
979a56 |
if (si->root == NULL) {
|
|
Packit |
979a56 |
si->n = NULL;
|
|
Packit |
979a56 |
} else if (si->root->value == NULL) {
|
|
Packit |
979a56 |
si->n = trie_node_next(si->root, si->root, QB_FALSE);
|
|
Packit |
979a56 |
} else {
|
|
Packit |
979a56 |
si->n = si->root;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
} else {
|
|
Packit |
979a56 |
si->n = trie_node_next(p, si->root, QB_FALSE);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
if (si->n == NULL) {
|
|
Packit |
979a56 |
trie_node_deref(t, p);
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
trie_node_ref(t, si->n);
|
|
Packit |
979a56 |
trie_node_deref(t, p);
|
|
Packit |
979a56 |
*value = si->n->value;
|
|
Packit |
979a56 |
return si->n->key;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static void
|
|
Packit |
979a56 |
trie_iter_free(qb_map_iter_t * i)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie_iter *si = (struct trie_iter *)i;
|
|
Packit |
979a56 |
struct trie *t = (struct trie *)(i->m);
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
if (si->n != NULL) {
|
|
Packit |
979a56 |
/* if free'ing the iterator before getting to the last
|
|
Packit |
979a56 |
* node make sure we de-ref the current node.
|
|
Packit |
979a56 |
*/
|
|
Packit |
979a56 |
trie_node_deref(t, si->n);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
free(i);
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
static size_t
|
|
Packit |
979a56 |
trie_count_get(struct qb_map *map)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie *list = (struct trie *)map;
|
|
Packit |
979a56 |
return list->length;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
qb_map_t *
|
|
Packit |
979a56 |
qb_trie_create(void)
|
|
Packit |
979a56 |
{
|
|
Packit |
979a56 |
struct trie *t = malloc(sizeof(struct trie));
|
|
Packit |
979a56 |
if (t == NULL) {
|
|
Packit |
979a56 |
return NULL;
|
|
Packit |
979a56 |
}
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
t->map.put = trie_put;
|
|
Packit |
979a56 |
t->map.get = trie_get;
|
|
Packit |
979a56 |
t->map.rm = trie_rm;
|
|
Packit |
979a56 |
t->map.count_get = trie_count_get;
|
|
Packit |
979a56 |
t->map.iter_create = trie_iter_create;
|
|
Packit |
979a56 |
t->map.iter_next = trie_iter_next;
|
|
Packit |
979a56 |
t->map.iter_free = trie_iter_free;
|
|
Packit |
979a56 |
t->map.destroy = trie_destroy;
|
|
Packit |
979a56 |
t->map.notify_add = trie_notify_add;
|
|
Packit |
979a56 |
t->map.notify_del = trie_notify_del;
|
|
Packit |
979a56 |
t->length = 0;
|
|
Packit |
979a56 |
t->num_nodes = 0;
|
|
Packit |
979a56 |
t->mem_used = sizeof(struct trie);
|
|
Packit |
979a56 |
t->header = trie_new_node(t, NULL);
|
|
Packit |
979a56 |
|
|
Packit |
979a56 |
return (qb_map_t *) t;
|
|
Packit |
979a56 |
}
|