r3/src/node.c

225 lines
4.7 KiB
C
Raw Normal View History

2014-05-14 22:08:42 -04:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
2014-05-14 22:08:42 -04:00
// Jemalloc memory management
#include <jemalloc/jemalloc.h>
2014-05-15 01:39:50 -04:00
// PCRE
#include <pcre.h>
2014-05-14 22:08:42 -04:00
// Judy array
#include <Judy.h>
2014-05-15 06:26:41 -04:00
#include "str.h"
2014-05-15 01:39:50 -04:00
#include "node.h"
#include "token.h"
2014-05-15 06:02:10 -04:00
struct _rnode {
redge ** children;
int children_len;
int children_cap;
/* the combined regexp pattern string from pattern_tokens */
2014-05-15 09:17:30 -04:00
char * combined_pattern;
int combined_pattern_len;
2014-05-15 06:26:41 -04:00
2014-05-15 09:17:30 -04:00
int endpoint;
2014-05-15 06:02:10 -04:00
};
struct _redge {
char * pattern;
int pattern_len;
2014-05-15 09:17:30 -04:00
bool is_slug;
2014-05-15 06:02:10 -04:00
rnode * child;
};
2014-05-14 22:08:42 -04:00
// String value as the index http://judy.sourceforge.net/doc/JudySL_3x.htm
2014-05-15 01:39:50 -04:00
2014-05-15 06:26:41 -04:00
/**
* Create a rnode object
*/
2014-05-15 01:39:50 -04:00
rnode * rnode_create(int cap) {
2014-05-15 09:17:30 -04:00
rnode * n = (rnode*) malloc( sizeof(rnode) );
2014-05-15 01:39:50 -04:00
2014-05-15 06:02:10 -04:00
n->children = (redge**) malloc( sizeof(redge*) * 10 );
2014-05-15 01:39:50 -04:00
n->children_len = 0;
n->children_cap = 10;
2014-05-15 06:26:41 -04:00
n->endpoint = 0;
2014-05-15 09:17:30 -04:00
n->combined_pattern = NULL;
2014-05-15 06:02:10 -04:00
// n->edge_patterns = token_array_create(10);
2014-05-15 01:39:50 -04:00
return n;
}
void rnode_free(rnode * tree) {
for (int i = 0 ; i < tree->children_len ; i++ ) {
2014-05-15 06:02:10 -04:00
redge_free(tree->children[ i ]);
2014-05-15 01:39:50 -04:00
}
free(tree->children);
2014-05-15 06:02:10 -04:00
// token_array_free(tree->edge_patterns);
2014-05-15 01:39:50 -04:00
free(tree);
tree = NULL;
}
2014-05-15 06:02:10 -04:00
2014-05-15 01:39:50 -04:00
/* parent node, edge pattern, child */
2014-05-15 06:02:10 -04:00
bool rnode_add_child(rnode * n, char * pat , rnode *child) {
2014-05-15 01:39:50 -04:00
// find the same sub-pattern, if it does not exist, create one
2014-05-15 06:02:10 -04:00
redge * e;
e = rnode_find_edge(n, pat);
if (e) {
2014-05-15 01:39:50 -04:00
return FALSE;
}
2014-05-15 06:02:10 -04:00
e = redge_create( pat, strlen(pat), child);
rnode_append_edge(n, e);
// token_array_append(n->edge_patterns, pat);
// assert( token_array_len(n->edge_patterns) == n->children_len );
2014-05-15 01:39:50 -04:00
return TRUE;
}
2014-05-15 06:02:10 -04:00
void rnode_append_edge(rnode *n, redge *e) {
2014-05-15 01:39:50 -04:00
if (n->children_len >= n->children_cap) {
n->children_cap *= 2;
2014-05-15 06:02:10 -04:00
n->children = realloc(n->children, sizeof(redge) * n->children_cap);
2014-05-15 01:39:50 -04:00
}
2014-05-15 06:02:10 -04:00
n->children[ n->children_len++ ] = e;
2014-05-15 01:39:50 -04:00
}
2014-05-15 06:02:10 -04:00
redge * rnode_find_edge(rnode * n, char * pat) {
redge * e;
for (int i = 0 ; i < n->children_len ; i++ ) {
e = n->children[i];
if ( strcmp(e->pattern, pat) == 0 ) {
return e;
2014-05-15 01:39:50 -04:00
}
}
return NULL;
}
2014-05-15 09:17:30 -04:00
/**
* This function combines ['/foo', '/bar', '/{slug}'] into (/foo)|(/bar)|/([^/]+)}
*
*/
2014-05-15 08:38:07 -04:00
void rnode_combine_patterns(rnode * n) {
2014-05-15 09:17:30 -04:00
char * cpat;
char * p;
cpat = malloc(128);
if (cpat==NULL)
return;
p = cpat;
2014-05-15 08:38:07 -04:00
redge *e = NULL;
for ( int i = 0 ; i < n->children_len ; i++ ) {
e = n->children[i];
2014-05-15 09:17:30 -04:00
strncat(p++,"(", 1);
strncat(p, e->pattern, e->pattern_len);
p += e->pattern_len;
strncat(p++,")", 1);
if ( i + 1 < n->children_len ) {
strncat(p++,"|",1);
}
2014-05-15 08:38:07 -04:00
}
2014-05-15 09:17:30 -04:00
n->combined_pattern = cpat;
n->combined_pattern_len = p - cpat;
2014-05-15 08:38:07 -04:00
}
2014-05-15 06:26:41 -04:00
rnode * rnode_lookup(rnode * tree, char * path, int path_len) {
token_array * tokens = split_route_pattern(path, path_len);
rnode * n = tree;
redge * e = NULL;
for ( int i = 0 ; i < tokens->len ; i++ ) {
e = rnode_find_edge(n, token_array_fetch(tokens, i) );
if (!e) {
return NULL;
}
n = e->child;
}
if (n->endpoint) {
return n;
}
return NULL;
}
2014-05-15 06:02:10 -04:00
rnode * rnode_insert_tokens(rnode * tree, token_array * tokens) {
rnode * n = tree;
redge * e = NULL;
for ( int i = 0 ; i < tokens->len ; i++ ) {
e = rnode_find_edge(n, token_array_fetch(tokens, i) );
if (e) {
n = e->child;
continue;
}
// insert node
rnode * child = rnode_create(3);
2014-05-15 06:26:41 -04:00
rnode_add_child(n, strdup(token_array_fetch(tokens,i)) , child);
2014-05-15 06:02:10 -04:00
n = child;
}
2014-05-15 06:26:41 -04:00
n->endpoint++;
2014-05-15 06:02:10 -04:00
return n;
}
2014-05-15 06:26:41 -04:00
rnode * rnode_insert_route(rnode *tree, char *route)
{
return rnode_insert_routel(tree, route, strlen(route) );
}
rnode * rnode_insert_routel(rnode *tree, char *route, int route_len)
{
token_array * t = split_route_pattern(route, strlen(route));
return rnode_insert_tokens(tree, t);
}
2014-05-15 06:02:10 -04:00
void rnode_dump(rnode * n, int level) {
if ( n->children_len ) {
print_indent(level);
printf("*\n");
for ( int i = 0 ; i < n->children_len ; i++ ) {
redge * e = n->children[i];
print_indent(level + 1);
printf("+ \"%s\"\n", e->pattern);
rnode_dump( e->child, level + 1);
}
}
}
2014-05-15 01:39:50 -04:00
2014-05-15 06:02:10 -04:00
redge * redge_create(char * pattern, int pattern_len, rnode * child) {
redge * edge = (redge*) malloc( sizeof(redge) );
edge->pattern = pattern;
edge->pattern_len = pattern_len;
edge->child = child;
2014-05-15 09:17:30 -04:00
edge->is_slug = 0;
2014-05-15 06:02:10 -04:00
return edge;
2014-05-15 01:39:50 -04:00
}
2014-05-15 06:02:10 -04:00
void redge_free(redge * e) {
free(e->pattern);
if ( e->child ) {
rnode_free(e->child);
}
}