Add benchmark and bug fixes

This commit is contained in:
c9s 2014-05-16 18:03:52 +08:00
parent 6b39b72ebe
commit 046ec9e977
6 changed files with 550 additions and 131 deletions

View file

@ -12,8 +12,7 @@ typedef unsigned char bool;
#define FALSE 0 #define FALSE 0
#define TRUE 1 #define TRUE 1
// #define DEBUG 1
#define DEBUG 1
#ifdef DEBUG #ifdef DEBUG
#define info(fmt, ...) \ #define info(fmt, ...) \

View file

@ -21,7 +21,6 @@ struct _node;
typedef struct _edge edge; typedef struct _edge edge;
typedef struct _node node; typedef struct _node node;
struct _node { struct _node {
edge ** edges; edge ** edges;
int edge_len; int edge_len;
@ -33,7 +32,6 @@ struct _node {
pcre * pcre_pattern; pcre * pcre_pattern;
pcre_extra * pcre_extra; pcre_extra * pcre_extra;
/** /**
* the pointer of route structure * the pointer of route structure
*/ */
@ -49,6 +47,12 @@ struct _edge {
node * child; node * child;
}; };
typedef struct {
char ** vars;
int vars_len;
char * path; // dispatched path
void * route_ptr; // route ptr
} match_entry;
node * rtree_create(int cap); node * rtree_create(int cap);
@ -65,8 +69,6 @@ edge * node_find_edge(node * n, char * pat);
void rtree_append_edge(node *n, edge *child); void rtree_append_edge(node *n, edge *child);
node * rtree_insert_tokens(node * tree, token_array * tokens);
node * rtree_insert_path(node *tree, char *route, void * route_ptr); node * rtree_insert_path(node *tree, char *route, void * route_ptr);
node * rtree_insert_pathn(node *tree, char *route, int route_len, void * route_ptr); node * rtree_insert_pathn(node *tree, char *route, int route_len, void * route_ptr);
@ -80,7 +82,7 @@ void rtree_compile(node *n);
void rtree_compile_patterns(node * n); void rtree_compile_patterns(node * n);
node * rtree_match(node * n, char * path, int path_len); node * rtree_match(node * n, char * path, int path_len, match_entry * entry);
bool node_has_slug_edges(node *n); bool node_has_slug_edges(node *n);
@ -92,4 +94,7 @@ void edge_branch(edge *e, int dl);
void edge_free(edge * edge); void edge_free(edge * edge);
#endif /* !NODE_H */ #endif /* !NODE_H */

View file

@ -10,29 +10,29 @@
#include "define.h" #include "define.h"
typedef struct _token_array { typedef struct _str_array {
char **tokens; char **tokens;
int len; int len;
int cap; int cap;
} token_array; } str_array;
token_array * token_array_create(int cap); str_array * str_array_create(int cap);
bool token_array_is_full(token_array * l); bool str_array_is_full(str_array * l);
bool token_array_resize(token_array *l, int new_cap); bool str_array_resize(str_array *l, int new_cap);
bool token_array_append(token_array * list, char * token); bool str_array_append(str_array * list, char * token);
void token_array_free(token_array *l); void str_array_free(str_array *l);
void token_array_dump(token_array *l); void str_array_dump(str_array *l);
token_array * split_route_pattern(char *pattern, int pattern_len); str_array * split_route_pattern(char *pattern, int pattern_len);
#define token_array_fetch(t,i) t->tokens[i] #define str_array_fetch(t,i) t->tokens[i]
#define token_array_len(t) t->len #define str_array_len(t) t->len
#define token_array_cap(t) t->cap #define str_array_cap(t) t->cap
#endif /* !TOKEN_H */ #endif /* !TOKEN_H */

View file

@ -45,7 +45,7 @@ void rtree_free(node * tree) {
free(tree->combined_pattern); free(tree->combined_pattern);
free(tree->edges); free(tree->edges);
// token_array_free(tree->edge_patterns); // str_array_free(tree->edge_patterns);
free(tree); free(tree);
tree = NULL; tree = NULL;
} }
@ -65,8 +65,8 @@ edge * rtree_add_child(node * n, char * pat , node *child) {
e = edge_create( pat, strlen(pat), child); e = edge_create( pat, strlen(pat), child);
rtree_append_edge(n, e); rtree_append_edge(n, e);
// token_array_append(n->edge_patterns, pat); // str_array_append(n->edge_patterns, pat);
// assert( token_array_len(n->edge_patterns) == n->edge_len ); // assert( str_array_len(n->edge_patterns) == n->edge_len );
return e; return e;
} }
@ -127,6 +127,7 @@ void rtree_compile_patterns(node * n) {
p = cpat; p = cpat;
edge *e = NULL; edge *e = NULL;
for ( int i = 0 ; i < n->edge_len ; i++ ) { for ( int i = 0 ; i < n->edge_len ; i++ ) {
e = n->edges[i]; e = n->edges[i];
@ -152,6 +153,12 @@ void rtree_compile_patterns(node * n) {
const char *error; const char *error;
int erroffset; int erroffset;
unsigned int option_bits;
if (n->pcre_pattern)
free(n->pcre_pattern);
if (n->pcre_extra)
free(n->pcre_extra);
// n->pcre_pattern; // n->pcre_pattern;
n->pcre_pattern = pcre_compile( n->pcre_pattern = pcre_compile(
@ -174,7 +181,9 @@ void rtree_compile_patterns(node * n) {
node * rtree_match(node * n, char * path, int path_len) { node * rtree_match(node * n, char * path, int path_len, match_entry * entry) {
// info("try matching: %s\n", path);
if (n->combined_pattern && n->pcre_pattern) { if (n->combined_pattern && n->pcre_pattern) {
info("pcre matching %s on %s\n", n->combined_pattern, path); info("pcre matching %s on %s\n", n->combined_pattern, path);
// int ovector_count = (n->edge_len + 1) * 2; // int ovector_count = (n->edge_len + 1) * 2;
@ -206,18 +215,27 @@ node * rtree_match(node * n, char * path, int path_len) {
} }
int i; int i;
edge *e;
for (i = 1; i < rc; i++) for (i = 1; i < rc; i++)
{ {
char *substring_start = path + ovector[2*i]; char *substring_start = path + ovector[2*i];
int substring_length = ovector[2*i+1] - ovector[2*i]; int substring_length = ovector[2*i+1] - ovector[2*i];
info("%2d: %.*s\n", i, substring_length, substring_start); info("%2d: %.*s\n", i, substring_length, substring_start);
if ( substring_length > 0) { if ( substring_length > 0) {
int restlen = path_len - ovector[2*i+1]; // fully match to the end int restlen = path_len - ovector[2*i+1]; // fully match to the end
info("matched item => restlen:%d edges:%d i:%d\n", restlen, n->edge_len, i); info("matched item => restlen:%d edges:%d i:%d\n", restlen, n->edge_len, i);
if (restlen) {
return rtree_match( n->edges[i - 1]->child, substring_start + substring_length, restlen); e = n->edges[i - 1];
if (entry && e->has_slug) {
// entry->
} }
return n->edges[i - 1]->child;
if (restlen == 0) {
return e->child;
}
return rtree_match( e->child, substring_start + substring_length, restlen, entry);
} }
} }
// does not match // does not match
@ -230,7 +248,7 @@ node * rtree_match(node * n, char * path, int path_len) {
if(len == 0) { if(len == 0) {
return e->child; return e->child;
} else { } else {
return rtree_match(e->child, path + e->pattern_len, len); return rtree_match(e->child, path + e->pattern_len, len, entry);
} }
} }
return NULL; return NULL;
@ -238,27 +256,43 @@ node * rtree_match(node * n, char * path, int path_len) {
edge * node_find_edge_str(node * n, char * str, int str_len) { edge * node_find_edge_str(node * n, char * str, int str_len) {
edge *e; edge *e;
char *p;
char *s;
for ( int i = 0 ; i < n->edge_len ; i++ ) { for ( int i = 0 ; i < n->edge_len ; i++ ) {
e = n->edges[i]; e = n->edges[i];
char *p = e->pattern; p = e->pattern;
while ( *p == *str ) { s = str;
p++;
info("matching '%s' with '%s'\n", str, e->pattern);
if ( str_len < e->pattern_len ) {
continue;
} }
if ( strncmp(e->pattern, str, e->pattern_len) == 0 ) {
return e;
}
/*
while ( *p == *s ) {
p++;
s++;
}
info("matched len: %d == pattern len %d\n", (int)(p - e->pattern) , e->pattern_len);
if ( p - e->pattern == e->pattern_len ) { if ( p - e->pattern == e->pattern_len ) {
return e; return e;
} }
*/
} }
return NULL; return NULL;
} }
node * rtree_lookup(node * tree, char * path, int path_len) { node * rtree_lookup(node * tree, char * path, int path_len) {
token_array * tokens = split_route_pattern(path, path_len); str_array * tokens = split_route_pattern(path, path_len);
node * n = tree; node * n = tree;
edge * e = NULL; edge * e = NULL;
for ( int i = 0 ; i < tokens->len ; i++ ) { for ( int i = 0 ; i < tokens->len ; i++ ) {
e = node_find_edge(n, token_array_fetch(tokens, i) ); e = node_find_edge(n, str_array_fetch(tokens, i) );
if (!e) { if (!e) {
return NULL; return NULL;
} }
@ -282,25 +316,6 @@ node * node_create() {
} }
node * rtree_insert_tokens(node * tree, token_array * tokens) {
node * n = tree;
edge * e = NULL;
for ( int i = 0 ; i < tokens->len ; i++ ) {
e = node_find_edge(n, token_array_fetch(tokens, i) );
if (e) {
n = e->child;
continue;
}
// insert node
node * child = node_create();
rtree_add_child(n, strdup(token_array_fetch(tokens,i)) , child);
n = child;
}
n->endpoint++;
return n;
}
node * rtree_insert_path(node *tree, char *route, void * route_ptr) node * rtree_insert_path(node *tree, char *route, void * route_ptr)
{ {
return rtree_insert_pathn(tree, route, strlen(route) , route_ptr); return rtree_insert_pathn(tree, route, strlen(route) , route_ptr);
@ -343,6 +358,7 @@ node * rtree_insert_pathn(node *tree, char *route, int route_len, void * route_p
rtree_add_child(n, strndup(route, route_len) , child); rtree_add_child(n, strndup(route, route_len) , child);
info("edge not found, insert one: %s\n", route); info("edge not found, insert one: %s\n", route);
child->route_ptr = route_ptr; child->route_ptr = route_ptr;
child->endpoint++;
return child; return child;
} else if ( dl == e->pattern_len ) { // fully-equal to the pattern of the edge } else if ( dl == e->pattern_len ) { // fully-equal to the pattern of the edge
@ -389,15 +405,10 @@ node * rtree_insert_pathn(node *tree, char *route, int route_len, void * route_p
c2->endpoint++; c2->endpoint++;
c2->route_ptr = route_ptr; c2->route_ptr = route_ptr;
return c2; return c2;
} else if ( dl > 0 ) {
} else { } else {
printf("unexpected condition."); printf("unexpected condition.");
return NULL; return NULL;
} }
// token_array * t = split_route_pattern(route, strlen(route));
// return rtree_insert_tokens(tree, t);
// n->endpoint++;
return n; return n;
} }
@ -441,7 +452,7 @@ void edge_branch(edge *e, int dl) {
e->child->edge_len = 0; e->child->edge_len = 0;
e->child->endpoint--; e->child->endpoint--;
info("branched pattern: %s", e1->pattern); info("branched pattern: %s\n", e1->pattern);
rtree_append_edge(e->child, e1); rtree_append_edge(e->child, e1);
c1->endpoint++; c1->endpoint++;
@ -473,7 +484,9 @@ void rtree_dump(node * n, int level) {
if ( n->combined_pattern ) { if ( n->combined_pattern ) {
printf(" regexp:%s", n->combined_pattern); printf(" regexp:%s", n->combined_pattern);
} }
printf("\n");
printf(" endpoint:%d\n", n->endpoint);
for ( int i = 0 ; i < n->edge_len ; i++ ) { for ( int i = 0 ; i < n->edge_len ; i++ ) {
edge * e = n->edges[i]; edge * e = n->edges[i];
print_indent(level); print_indent(level);
@ -491,3 +504,9 @@ void rtree_dump(node * n, int level) {
} }
} }
} }
/*
char * node_trace(node * n) {
}
*/

View file

@ -11,15 +11,15 @@
#include "token.h" #include "token.h"
token_array * token_array_create(int cap) { str_array * str_array_create(int cap) {
token_array * list = (token_array*) malloc( sizeof(token_array) ); str_array * list = (str_array*) malloc( sizeof(str_array) );
list->len = 0; list->len = 0;
list->cap = cap; list->cap = cap;
list->tokens = (char**) malloc( sizeof(char*) * cap); list->tokens = (char**) malloc( sizeof(char*) * cap);
return list; return list;
} }
void token_array_free(token_array *l) { void str_array_free(str_array *l) {
for ( int i = 0; i < l->len ; i++ ) { for ( int i = 0; i < l->len ; i++ ) {
char * t = l->tokens[ i ]; char * t = l->tokens[ i ];
free(t); free(t);
@ -27,19 +27,19 @@ void token_array_free(token_array *l) {
free(l); free(l);
} }
bool token_array_is_full(token_array * l) { bool str_array_is_full(str_array * l) {
return l->len >= l->cap; return l->len >= l->cap;
} }
bool token_array_resize(token_array *l, int new_cap) { bool str_array_resize(str_array *l, int new_cap) {
l->tokens = realloc(l->tokens, sizeof(char**) * new_cap); l->tokens = realloc(l->tokens, sizeof(char**) * new_cap);
l->cap = new_cap; l->cap = new_cap;
return l->tokens != NULL; return l->tokens != NULL;
} }
bool token_array_append(token_array * l, char * token) { bool str_array_append(str_array * l, char * token) {
if ( token_array_is_full(l) ) { if ( str_array_is_full(l) ) {
bool ret = token_array_resize(l, l->cap + 20); bool ret = str_array_resize(l, l->cap + 20);
if (ret == FALSE ) { if (ret == FALSE ) {
return FALSE; return FALSE;
} }
@ -48,7 +48,7 @@ bool token_array_append(token_array * l, char * token) {
return TRUE; return TRUE;
} }
void token_array_dump(token_array *l) { void str_array_dump(str_array *l) {
printf("["); printf("[");
for ( int i = 0; i < l->len ; i++ ) { for ( int i = 0; i < l->len ; i++ ) {
printf("\"%s\"", l->tokens[i] ); printf("\"%s\"", l->tokens[i] );
@ -79,10 +79,10 @@ void token_array_dump(token_array *l) {
* *
* @return char** * @return char**
*/ */
token_array * split_route_pattern(char *pattern, int pattern_len) { str_array * split_route_pattern(char *pattern, int pattern_len) {
char *s1, *p = pattern; char *s1, *p = pattern;
token_array * token_array = token_array_create( 20 ); str_array * str_array = str_array_create( 20 );
s1 = p; s1 = p;
p++; p++;
@ -97,20 +97,20 @@ token_array * split_route_pattern(char *pattern, int pattern_len) {
} }
p++; // contains the '}' p++; // contains the '}'
// printf("==> %s\n", strndup(s1, p-s1) ); // printf("==> %s\n", strndup(s1, p-s1) );
token_array_append(token_array, strndup(s1, p-s1) ); str_array_append(str_array, strndup(s1, p-s1) );
s1 = p; s1 = p;
continue; continue;
} }
else if ( *p == '/' ) { else if ( *p == '/' ) {
// printf("==> %s\n", strndup(s1, p-s1) ); // printf("==> %s\n", strndup(s1, p-s1) );
token_array_append(token_array, strndup(s1, p-s1) ); str_array_append(str_array, strndup(s1, p-s1) );
s1 = p; s1 = p;
} }
p++; p++;
} }
if ( p-s1 > 0 ) { if ( p-s1 > 0 ) {
token_array_append(token_array, strndup(s1, p-s1) ); str_array_append(str_array, strndup(s1, p-s1) );
} }
return token_array; return str_array;
} }

View file

@ -1,9 +1,32 @@
#include <stdio.h> #include <stdio.h>
#include <check.h> #include <check.h>
#include <stdlib.h>
#include "str.h" #include "str.h"
#include "node.h" #include "node.h"
#include "token.h" #include "token.h"
#include <sys/time.h>
#define MICRO_IN_SEC 1000000.00
#define SEC_IN_MIN 60
#define NUL '\0'
double microtime() {
struct timeval tp;
long sec = 0L;
double msec = 0.0;
char ret[100];
if (gettimeofday((struct timeval *) &tp, (NUL)) == 0) {
msec = (double) (tp.tv_usec / MICRO_IN_SEC);
sec = tp.tv_sec;
if (msec >= 1.0)
msec -= (long) msec;
return sec + msec;
}
return 0;
}
START_TEST (test_ltrim_slash) START_TEST (test_ltrim_slash)
{ {
fail_if( strcmp( ltrim_slash("/blog") , "blog" ) != 0 ); fail_if( strcmp( ltrim_slash("/blog") , "blog" ) != 0 );
@ -42,11 +65,14 @@ END_TEST
START_TEST (test_compile) START_TEST (test_compile)
{ {
token_array *t; str_array *t;
node * n; node * n;
n = rtree_create(10); n = rtree_create(10);
match_entry * entry;
node *m;
edge *e ;
rtree_insert_pathn(n, "/zoo", strlen("/zoo"), NULL); rtree_insert_pathn(n, "/zoo", strlen("/zoo"), NULL);
rtree_insert_pathn(n, "/foo", strlen("/foo"), NULL); rtree_insert_pathn(n, "/foo", strlen("/foo"), NULL);
@ -55,43 +81,51 @@ START_TEST (test_compile)
fail_if( n->combined_pattern ); fail_if( n->combined_pattern );
fail_if( NULL == node_find_edge_str(n, "/", strlen("/") ) ); fail_if( NULL == node_find_edge_str(n, "/", strlen("/") ) );
#ifdef DEBUG
rtree_dump(n, 0);
#endif
rtree_insert_pathn(n, "/foo/{id}", strlen("/foo/{id}"), NULL); rtree_insert_pathn(n, "/foo/{id}", strlen("/foo/{id}"), NULL);
rtree_insert_pathn(n, "/{id}", strlen("/{id}"), NULL); rtree_insert_pathn(n, "/{id}", strlen("/{id}"), NULL);
rtree_compile(n); rtree_compile(n);
rtree_compile(n); // test double compile
#ifdef DEBUG
rtree_dump(n, 0); rtree_dump(n, 0);
#endif
/*
fail_if(n->edges[0]->child->combined_pattern == NULL); fail_if(n->edges[0]->child->combined_pattern == NULL);
edge *e = node_find_edge_str(n, "/", strlen("/") ); e = node_find_edge_str(n, "/", strlen("/") );
fail_if( NULL == e ); fail_if( NULL == e );
*/
/* /*
printf( "%s\n", e->pattern ); printf( "%s\n", e->pattern );
printf( "%s\n", e->child->combined_pattern ); printf( "%s\n", e->child->combined_pattern );
printf( "%s\n", n->edges[0]->child->combined_pattern); printf( "%s\n", n->edges[0]->child->combined_pattern);
printf( "%s\n", n->combined_pattern ); printf( "%s\n", n->combined_pattern );
*/ */
node *m = rtree_match( e->child , "foo", strlen("foo") );
entry = calloc( sizeof(entry) , 1 );
m = rtree_match( n , "/foo", strlen("/foo"), entry);
fail_if( NULL == m ); fail_if( NULL == m );
m = rtree_match( n , "/foo", strlen("/foo") ); m = rtree_match( n , "/zoo", strlen("/zoo"), entry);
fail_if( NULL == m ); fail_if( NULL == m );
m = rtree_match( n , "/zoo", strlen("/zoo") ); m = rtree_match( n , "/bar", strlen("/bar"), entry);
fail_if( NULL == m ); fail_if( NULL == m );
m = rtree_match( n , "/bar", strlen("/bar") ); m = rtree_match( n , "/xxx", strlen("/xxx"), entry);
fail_if( NULL == m ); fail_if( NULL == m );
m = rtree_match( n , "/xxx", strlen("/xxx") ); m = rtree_match( n , "/foo/xxx", strlen("/foo/xxx"), entry);
fail_if( NULL == m ); fail_if( NULL == m );
m = rtree_match( n , "/foo/xxx", strlen("/foo/xxx") ); m = rtree_match( n , "/some_id", strlen("/some_id"), entry);
fail_if( NULL == m ); fail_if( NULL == m );
ck_assert_int_gt( m->endpoint , 0 ); // should not be an endpoint
m = rtree_match( n , "/not_found", strlen("/not_found") );
fail_if( NULL == m ); // should be the node of "/"
ck_assert_int_eq( m->endpoint , 0 ); // should not be an endpoint
} }
END_TEST END_TEST
@ -144,44 +178,33 @@ START_TEST (test_rtree_insert_pathn)
{ {
node * n = rtree_create(10); node * n = rtree_create(10);
// printf("Inserting /foo/bar\n"); info("Inserting /foo/bar\n");
rtree_insert_pathn(n, "/foo/bar", strlen("/foo/bar"), NULL); rtree_insert_path(n, "/foo/bar", NULL);
// rtree_dump(n, 0); // rtree_dump(n, 0);
// printf("Inserting /foo/zoo\n"); info("Inserting /foo/zoo\n");
rtree_insert_pathn(n, "/foo/zoo", strlen("/foo/zoo"), NULL); rtree_insert_path(n, "/foo/zoo", NULL);
// rtree_dump(n, 0); // rtree_dump(n, 0);
// printf("Inserting /f/id\n"); info("Inserting /f/id\n");
rtree_insert_pathn(n, "/f/id", strlen("/f/id") , NULL); rtree_insert_path(n, "/f/id" , NULL);
// rtree_dump(n, 0); // rtree_dump(n, 0);
// printf("Inserting /post/{id}\n"); info("Inserting /post/{id}\n");
rtree_insert_pathn(n, "/post/{id}", strlen("/post/{id}"), NULL); rtree_insert_pathn(n, "/post/{id}", strlen("/post/{id}"), NULL);
// rtree_dump(n, 0); // rtree_dump(n, 0);
// printf("Inserting /post/{handle}\n"); info("Inserting /post/{handle}\n");
rtree_insert_pathn(n, "/post/{handle}", strlen("/post/{handle}"), NULL); rtree_insert_pathn(n, "/post/{handle}", strlen("/post/{handle}"), NULL);
// rtree_dump(n, 0); // rtree_dump(n, 0);
// printf("Inserting /post/{handle}-{id}\n"); info("Inserting /post/{handle}-{id}\n");
rtree_insert_pathn(n, "/post/{handle}-{id}", strlen("/post/{handle}-{id}"), NULL); rtree_insert_pathn(n, "/post/{handle}-{id}", strlen("/post/{handle}-{id}"), NULL);
rtree_compile(n); rtree_compile(n);
// rtree_dump(n, 0);
/*
fail_if( rtree_lookup(n , "/a/jj/kk" , strlen("/a/jj/kk") ) == NULL );
fail_if( rtree_lookup(n , "/a/jj" , strlen("/a/jj") ) != NULL );
fail_if( rtree_lookup(n , "/a/jj/kk/ll" , strlen("/a/jj/kk/ll") ) != NULL );
fail_if( rtree_lookup(n, "/xxxx", strlen("xxxx") ) != NULL );
*/
// fail_if( node_find_edge(n, "/add") == NULL );
// fail_if( node_find_edge(n, "/bar") != NULL );
#ifdef DEBUG
rtree_dump(n, 0);
#endif
rtree_free(n); rtree_free(n);
} }
END_TEST END_TEST
@ -191,60 +214,431 @@ END_TEST
START_TEST (test_route_split) START_TEST (test_route_split)
{ {
token_array *t; str_array *t;
t = split_route_pattern("/blog", strlen("/blog") ); t = split_route_pattern("/blog", strlen("/blog") );
fail_if( t == NULL ); fail_if( t == NULL );
token_array_dump(t); str_array_dump(t);
token_array_free(t); str_array_free(t);
t = split_route_pattern("/foo/{id}", strlen("/foo/{id}") ); t = split_route_pattern("/foo/{id}", strlen("/foo/{id}") );
fail_if( t == NULL ); fail_if( t == NULL );
token_array_dump(t); str_array_dump(t);
fail_if( t->len != 2 ); fail_if( t->len != 2 );
token_array_free(t); str_array_free(t);
t = split_route_pattern("/foo/bar/{id}", strlen("/foo/bar/{id}") ); t = split_route_pattern("/foo/bar/{id}", strlen("/foo/bar/{id}") );
fail_if( t == NULL ); fail_if( t == NULL );
token_array_dump(t); str_array_dump(t);
fail_if( t->len != 3 ); fail_if( t->len != 3 );
token_array_free(t); str_array_free(t);
t = split_route_pattern("/{title}", strlen("/{title}") ); t = split_route_pattern("/{title}", strlen("/{title}") );
fail_if( t == NULL ); fail_if( t == NULL );
token_array_dump(t); str_array_dump(t);
fail_if( t->len != 1 ); fail_if( t->len != 1 );
token_array_free(t); str_array_free(t);
t = split_route_pattern("/", strlen("/") ); t = split_route_pattern("/", strlen("/") );
fail_if( t == NULL ); fail_if( t == NULL );
token_array_dump(t); str_array_dump(t);
fail_if( t->len != 1 ); fail_if( t->len != 1 );
token_array_free(t); str_array_free(t);
} }
END_TEST END_TEST
START_TEST (test_token_array) START_TEST (test_str_array)
{ {
token_array * l = token_array_create(3); str_array * l = str_array_create(3);
fail_if( l == NULL ); fail_if( l == NULL );
fail_if( FALSE == token_array_append(l, strdup("abc") ) ); fail_if( FALSE == str_array_append(l, strdup("abc") ) );
fail_if( l->len != 1 ); fail_if( l->len != 1 );
fail_if( FALSE == token_array_append(l, strdup("foo") ) ); fail_if( FALSE == str_array_append(l, strdup("foo") ) );
fail_if( l->len != 2 ); fail_if( l->len != 2 );
fail_if( FALSE == token_array_append(l, strdup("bar") ) ); fail_if( FALSE == str_array_append(l, strdup("bar") ) );
fail_if( l->len != 3 ); fail_if( l->len != 3 );
fail_if( FALSE == token_array_append(l, strdup("zoo") ) ); fail_if( FALSE == str_array_append(l, strdup("zoo") ) );
fail_if( l->len != 4 ); fail_if( l->len != 4 );
fail_if( FALSE == token_array_resize(l, l->cap * 2) ); fail_if( FALSE == str_array_resize(l, l->cap * 2) );
str_array_free(l);
}
END_TEST
START_TEST(benchmark_str)
{
match_entry * entry = calloc( sizeof(entry) , 1 );
node * n = rtree_create(1);
rtree_insert_path(n, "/foo/bar/baz", NULL);
rtree_insert_path(n, "/foo/bar/qux", NULL);
rtree_insert_path(n, "/foo/bar/quux", NULL);
rtree_insert_path(n, "/foo/bar/corge", NULL);
rtree_insert_path(n, "/foo/bar/grault", NULL);
rtree_insert_path(n, "/foo/bar/garply", NULL);
rtree_insert_path(n, "/foo/baz/bar", NULL);
rtree_insert_path(n, "/foo/baz/qux", NULL);
rtree_insert_path(n, "/foo/baz/quux", NULL);
rtree_insert_path(n, "/foo/baz/corge", NULL);
rtree_insert_path(n, "/foo/baz/grault", NULL);
rtree_insert_path(n, "/foo/baz/garply", NULL);
rtree_insert_path(n, "/foo/qux/bar", NULL);
rtree_insert_path(n, "/foo/qux/baz", NULL);
rtree_insert_path(n, "/foo/qux/quux", NULL);
rtree_insert_path(n, "/foo/qux/corge", NULL);
rtree_insert_path(n, "/foo/qux/grault", NULL);
rtree_insert_path(n, "/foo/qux/garply", NULL);
rtree_insert_path(n, "/foo/quux/bar", NULL);
rtree_insert_path(n, "/foo/quux/baz", NULL);
rtree_insert_path(n, "/foo/quux/qux", NULL);
rtree_insert_path(n, "/foo/quux/corge", NULL);
rtree_insert_path(n, "/foo/quux/grault", NULL);
rtree_insert_path(n, "/foo/quux/garply", NULL);
rtree_insert_path(n, "/foo/corge/bar", NULL);
rtree_insert_path(n, "/foo/corge/baz", NULL);
rtree_insert_path(n, "/foo/corge/qux", NULL);
rtree_insert_path(n, "/foo/corge/quux", NULL);
rtree_insert_path(n, "/foo/corge/grault", NULL);
rtree_insert_path(n, "/foo/corge/garply", NULL);
rtree_insert_path(n, "/foo/grault/bar", NULL);
rtree_insert_path(n, "/foo/grault/baz", NULL);
rtree_insert_path(n, "/foo/grault/qux", NULL);
rtree_insert_path(n, "/foo/grault/quux", NULL);
rtree_insert_path(n, "/foo/grault/corge", NULL);
rtree_insert_path(n, "/foo/grault/garply", NULL);
rtree_insert_path(n, "/foo/garply/bar", NULL);
rtree_insert_path(n, "/foo/garply/baz", NULL);
rtree_insert_path(n, "/foo/garply/qux", NULL);
rtree_insert_path(n, "/foo/garply/quux", NULL);
rtree_insert_path(n, "/foo/garply/corge", NULL);
rtree_insert_path(n, "/foo/garply/grault", NULL);
rtree_insert_path(n, "/bar/foo/baz", NULL);
rtree_insert_path(n, "/bar/foo/qux", NULL);
rtree_insert_path(n, "/bar/foo/quux", NULL);
rtree_insert_path(n, "/bar/foo/corge", NULL);
rtree_insert_path(n, "/bar/foo/grault", NULL);
rtree_insert_path(n, "/bar/foo/garply", NULL);
rtree_insert_path(n, "/bar/baz/foo", NULL);
rtree_insert_path(n, "/bar/baz/qux", NULL);
rtree_insert_path(n, "/bar/baz/quux", NULL);
rtree_insert_path(n, "/bar/baz/corge", NULL);
rtree_insert_path(n, "/bar/baz/grault", NULL);
rtree_insert_path(n, "/bar/baz/garply", NULL);
rtree_insert_path(n, "/bar/qux/foo", NULL);
rtree_insert_path(n, "/bar/qux/baz", NULL);
rtree_insert_path(n, "/bar/qux/quux", NULL);
rtree_insert_path(n, "/bar/qux/corge", NULL);
rtree_insert_path(n, "/bar/qux/grault", NULL);
rtree_insert_path(n, "/bar/qux/garply", NULL);
rtree_insert_path(n, "/bar/quux/foo", NULL);
rtree_insert_path(n, "/bar/quux/baz", NULL);
rtree_insert_path(n, "/bar/quux/qux", NULL);
rtree_insert_path(n, "/bar/quux/corge", NULL);
rtree_insert_path(n, "/bar/quux/grault", NULL);
rtree_insert_path(n, "/bar/quux/garply", NULL);
rtree_insert_path(n, "/bar/corge/foo", NULL);
rtree_insert_path(n, "/bar/corge/baz", NULL);
rtree_insert_path(n, "/bar/corge/qux", NULL);
rtree_insert_path(n, "/bar/corge/quux", NULL);
rtree_insert_path(n, "/bar/corge/grault", NULL);
rtree_insert_path(n, "/bar/corge/garply", NULL);
rtree_insert_path(n, "/bar/grault/foo", NULL);
rtree_insert_path(n, "/bar/grault/baz", NULL);
rtree_insert_path(n, "/bar/grault/qux", NULL);
rtree_insert_path(n, "/bar/grault/quux", NULL);
rtree_insert_path(n, "/bar/grault/corge", NULL);
rtree_insert_path(n, "/bar/grault/garply", NULL);
rtree_insert_path(n, "/bar/garply/foo", NULL);
rtree_insert_path(n, "/bar/garply/baz", NULL);
rtree_insert_path(n, "/bar/garply/qux", NULL);
rtree_insert_path(n, "/bar/garply/quux", NULL);
rtree_insert_path(n, "/bar/garply/corge", NULL);
rtree_insert_path(n, "/bar/garply/grault", NULL);
rtree_insert_path(n, "/baz/foo/bar", NULL);
rtree_insert_path(n, "/baz/foo/qux", NULL);
rtree_insert_path(n, "/baz/foo/quux", NULL);
rtree_insert_path(n, "/baz/foo/corge", NULL);
rtree_insert_path(n, "/baz/foo/grault", NULL);
rtree_insert_path(n, "/baz/foo/garply", NULL);
rtree_insert_path(n, "/baz/bar/foo", NULL);
rtree_insert_path(n, "/baz/bar/qux", NULL);
rtree_insert_path(n, "/baz/bar/quux", NULL);
rtree_insert_path(n, "/baz/bar/corge", NULL);
rtree_insert_path(n, "/baz/bar/grault", NULL);
rtree_insert_path(n, "/baz/bar/garply", NULL);
rtree_insert_path(n, "/baz/qux/foo", NULL);
rtree_insert_path(n, "/baz/qux/bar", NULL);
rtree_insert_path(n, "/baz/qux/quux", NULL);
rtree_insert_path(n, "/baz/qux/corge", NULL);
rtree_insert_path(n, "/baz/qux/grault", NULL);
rtree_insert_path(n, "/baz/qux/garply", NULL);
rtree_insert_path(n, "/baz/quux/foo", NULL);
rtree_insert_path(n, "/baz/quux/bar", NULL);
rtree_insert_path(n, "/baz/quux/qux", NULL);
rtree_insert_path(n, "/baz/quux/corge", NULL);
rtree_insert_path(n, "/baz/quux/grault", NULL);
rtree_insert_path(n, "/baz/quux/garply", NULL);
rtree_insert_path(n, "/baz/corge/foo", NULL);
rtree_insert_path(n, "/baz/corge/bar", NULL);
rtree_insert_path(n, "/baz/corge/qux", NULL);
rtree_insert_path(n, "/baz/corge/quux", NULL);
rtree_insert_path(n, "/baz/corge/grault", NULL);
rtree_insert_path(n, "/baz/corge/garply", NULL);
rtree_insert_path(n, "/baz/grault/foo", NULL);
rtree_insert_path(n, "/baz/grault/bar", NULL);
rtree_insert_path(n, "/baz/grault/qux", NULL);
rtree_insert_path(n, "/baz/grault/quux", NULL);
rtree_insert_path(n, "/baz/grault/corge", NULL);
rtree_insert_path(n, "/baz/grault/garply", NULL);
rtree_insert_path(n, "/baz/garply/foo", NULL);
rtree_insert_path(n, "/baz/garply/bar", NULL);
rtree_insert_path(n, "/baz/garply/qux", NULL);
rtree_insert_path(n, "/baz/garply/quux", NULL);
rtree_insert_path(n, "/baz/garply/corge", NULL);
rtree_insert_path(n, "/baz/garply/grault", NULL);
rtree_insert_path(n, "/qux/foo/bar", NULL);
rtree_insert_path(n, "/qux/foo/baz", NULL);
rtree_insert_path(n, "/qux/foo/quux", NULL);
rtree_insert_path(n, "/qux/foo/corge", NULL);
rtree_insert_path(n, "/qux/foo/grault", NULL);
rtree_insert_path(n, "/qux/foo/garply", NULL);
rtree_insert_path(n, "/qux/bar/foo", NULL);
rtree_insert_path(n, "/qux/bar/baz", NULL);
rtree_insert_path(n, "/qux/bar/quux", NULL);
rtree_insert_path(n, "/qux/bar/corge", (void*) 999);
rtree_insert_path(n, "/qux/bar/grault", NULL);
rtree_insert_path(n, "/qux/bar/garply", NULL);
rtree_insert_path(n, "/qux/baz/foo", NULL);
rtree_insert_path(n, "/qux/baz/bar", NULL);
rtree_insert_path(n, "/qux/baz/quux", NULL);
rtree_insert_path(n, "/qux/baz/corge", NULL);
rtree_insert_path(n, "/qux/baz/grault", NULL);
rtree_insert_path(n, "/qux/baz/garply", NULL);
rtree_insert_path(n, "/qux/quux/foo", NULL);
rtree_insert_path(n, "/qux/quux/bar", NULL);
rtree_insert_path(n, "/qux/quux/baz", NULL);
rtree_insert_path(n, "/qux/quux/corge", NULL);
rtree_insert_path(n, "/qux/quux/grault", NULL);
rtree_insert_path(n, "/qux/quux/garply", NULL);
rtree_insert_path(n, "/qux/corge/foo", NULL);
rtree_insert_path(n, "/qux/corge/bar", NULL);
rtree_insert_path(n, "/qux/corge/baz", NULL);
rtree_insert_path(n, "/qux/corge/quux", NULL);
rtree_insert_path(n, "/qux/corge/grault", NULL);
rtree_insert_path(n, "/qux/corge/garply", NULL);
rtree_insert_path(n, "/qux/grault/foo", NULL);
rtree_insert_path(n, "/qux/grault/bar", NULL);
rtree_insert_path(n, "/qux/grault/baz", NULL);
rtree_insert_path(n, "/qux/grault/quux", NULL);
rtree_insert_path(n, "/qux/grault/corge", NULL);
rtree_insert_path(n, "/qux/grault/garply", NULL);
rtree_insert_path(n, "/qux/garply/foo", NULL);
rtree_insert_path(n, "/qux/garply/bar", NULL);
rtree_insert_path(n, "/qux/garply/baz", NULL);
rtree_insert_path(n, "/qux/garply/quux", NULL);
rtree_insert_path(n, "/qux/garply/corge", NULL);
rtree_insert_path(n, "/qux/garply/grault", NULL);
rtree_insert_path(n, "/quux/foo/bar", NULL);
rtree_insert_path(n, "/quux/foo/baz", NULL);
rtree_insert_path(n, "/quux/foo/qux", NULL);
rtree_insert_path(n, "/quux/foo/corge", NULL);
rtree_insert_path(n, "/quux/foo/grault", NULL);
rtree_insert_path(n, "/quux/foo/garply", NULL);
rtree_insert_path(n, "/quux/bar/foo", NULL);
rtree_insert_path(n, "/quux/bar/baz", NULL);
rtree_insert_path(n, "/quux/bar/qux", NULL);
rtree_insert_path(n, "/quux/bar/corge", NULL);
rtree_insert_path(n, "/quux/bar/grault", NULL);
rtree_insert_path(n, "/quux/bar/garply", NULL);
rtree_insert_path(n, "/quux/baz/foo", NULL);
rtree_insert_path(n, "/quux/baz/bar", NULL);
rtree_insert_path(n, "/quux/baz/qux", NULL);
rtree_insert_path(n, "/quux/baz/corge", NULL);
rtree_insert_path(n, "/quux/baz/grault", NULL);
rtree_insert_path(n, "/quux/baz/garply", NULL);
rtree_insert_path(n, "/quux/qux/foo", NULL);
rtree_insert_path(n, "/quux/qux/bar", NULL);
rtree_insert_path(n, "/quux/qux/baz", NULL);
rtree_insert_path(n, "/quux/qux/corge", NULL);
rtree_insert_path(n, "/quux/qux/grault", NULL);
rtree_insert_path(n, "/quux/qux/garply", NULL);
rtree_insert_path(n, "/quux/corge/foo", NULL);
rtree_insert_path(n, "/quux/corge/bar", NULL);
rtree_insert_path(n, "/quux/corge/baz", NULL);
rtree_insert_path(n, "/quux/corge/qux", NULL);
rtree_insert_path(n, "/quux/corge/grault", NULL);
rtree_insert_path(n, "/quux/corge/garply", NULL);
rtree_insert_path(n, "/quux/grault/foo", NULL);
rtree_insert_path(n, "/quux/grault/bar", NULL);
rtree_insert_path(n, "/quux/grault/baz", NULL);
rtree_insert_path(n, "/quux/grault/qux", NULL);
rtree_insert_path(n, "/quux/grault/corge", NULL);
rtree_insert_path(n, "/quux/grault/garply", NULL);
rtree_insert_path(n, "/quux/garply/foo", NULL);
rtree_insert_path(n, "/quux/garply/bar", NULL);
rtree_insert_path(n, "/quux/garply/baz", NULL);
rtree_insert_path(n, "/quux/garply/qux", NULL);
rtree_insert_path(n, "/quux/garply/corge", NULL);
rtree_insert_path(n, "/quux/garply/grault", NULL);
rtree_insert_path(n, "/corge/foo/bar", NULL);
rtree_insert_path(n, "/corge/foo/baz", NULL);
rtree_insert_path(n, "/corge/foo/qux", NULL);
rtree_insert_path(n, "/corge/foo/quux", NULL);
rtree_insert_path(n, "/corge/foo/grault", NULL);
rtree_insert_path(n, "/corge/foo/garply", NULL);
rtree_insert_path(n, "/corge/bar/foo", NULL);
rtree_insert_path(n, "/corge/bar/baz", NULL);
rtree_insert_path(n, "/corge/bar/qux", NULL);
rtree_insert_path(n, "/corge/bar/quux", NULL);
rtree_insert_path(n, "/corge/bar/grault", NULL);
rtree_insert_path(n, "/corge/bar/garply", NULL);
rtree_insert_path(n, "/corge/baz/foo", NULL);
rtree_insert_path(n, "/corge/baz/bar", NULL);
rtree_insert_path(n, "/corge/baz/qux", NULL);
rtree_insert_path(n, "/corge/baz/quux", NULL);
rtree_insert_path(n, "/corge/baz/grault", NULL);
rtree_insert_path(n, "/corge/baz/garply", NULL);
rtree_insert_path(n, "/corge/qux/foo", NULL);
rtree_insert_path(n, "/corge/qux/bar", NULL);
rtree_insert_path(n, "/corge/qux/baz", NULL);
rtree_insert_path(n, "/corge/qux/quux", NULL);
rtree_insert_path(n, "/corge/qux/grault", NULL);
rtree_insert_path(n, "/corge/qux/garply", NULL);
rtree_insert_path(n, "/corge/quux/foo", NULL);
rtree_insert_path(n, "/corge/quux/bar", NULL);
rtree_insert_path(n, "/corge/quux/baz", NULL);
rtree_insert_path(n, "/corge/quux/qux", NULL);
rtree_insert_path(n, "/corge/quux/grault", NULL);
rtree_insert_path(n, "/corge/quux/garply", NULL);
rtree_insert_path(n, "/corge/grault/foo", NULL);
rtree_insert_path(n, "/corge/grault/bar", NULL);
rtree_insert_path(n, "/corge/grault/baz", NULL);
rtree_insert_path(n, "/corge/grault/qux", NULL);
rtree_insert_path(n, "/corge/grault/quux", NULL);
rtree_insert_path(n, "/corge/grault/garply", NULL);
rtree_insert_path(n, "/corge/garply/foo", NULL);
rtree_insert_path(n, "/corge/garply/bar", NULL);
rtree_insert_path(n, "/corge/garply/baz", NULL);
rtree_insert_path(n, "/corge/garply/qux", NULL);
rtree_insert_path(n, "/corge/garply/quux", NULL);
rtree_insert_path(n, "/corge/garply/grault", NULL);
rtree_insert_path(n, "/grault/foo/bar", NULL);
rtree_insert_path(n, "/grault/foo/baz", NULL);
rtree_insert_path(n, "/grault/foo/qux", NULL);
rtree_insert_path(n, "/grault/foo/quux", NULL);
rtree_insert_path(n, "/grault/foo/corge", NULL);
rtree_insert_path(n, "/grault/foo/garply", NULL);
rtree_insert_path(n, "/grault/bar/foo", NULL);
rtree_insert_path(n, "/grault/bar/baz", NULL);
rtree_insert_path(n, "/grault/bar/qux", NULL);
rtree_insert_path(n, "/grault/bar/quux", NULL);
rtree_insert_path(n, "/grault/bar/corge", NULL);
rtree_insert_path(n, "/grault/bar/garply", NULL);
rtree_insert_path(n, "/grault/baz/foo", NULL);
rtree_insert_path(n, "/grault/baz/bar", NULL);
rtree_insert_path(n, "/grault/baz/qux", NULL);
rtree_insert_path(n, "/grault/baz/quux", NULL);
rtree_insert_path(n, "/grault/baz/corge", NULL);
rtree_insert_path(n, "/grault/baz/garply", NULL);
rtree_insert_path(n, "/grault/qux/foo", NULL);
rtree_insert_path(n, "/grault/qux/bar", NULL);
rtree_insert_path(n, "/grault/qux/baz", NULL);
rtree_insert_path(n, "/grault/qux/quux", NULL);
rtree_insert_path(n, "/grault/qux/corge", NULL);
rtree_insert_path(n, "/grault/qux/garply", NULL);
rtree_insert_path(n, "/grault/quux/foo", NULL);
rtree_insert_path(n, "/grault/quux/bar", NULL);
rtree_insert_path(n, "/grault/quux/baz", NULL);
rtree_insert_path(n, "/grault/quux/qux", NULL);
rtree_insert_path(n, "/grault/quux/corge", NULL);
rtree_insert_path(n, "/grault/quux/garply", NULL);
rtree_insert_path(n, "/grault/corge/foo", NULL);
rtree_insert_path(n, "/grault/corge/bar", NULL);
rtree_insert_path(n, "/grault/corge/baz", NULL);
rtree_insert_path(n, "/grault/corge/qux", NULL);
rtree_insert_path(n, "/grault/corge/quux", NULL);
rtree_insert_path(n, "/grault/corge/garply", NULL);
rtree_insert_path(n, "/grault/garply/foo", NULL);
rtree_insert_path(n, "/grault/garply/bar", NULL);
rtree_insert_path(n, "/grault/garply/baz", NULL);
rtree_insert_path(n, "/grault/garply/qux", NULL);
rtree_insert_path(n, "/grault/garply/quux", NULL);
rtree_insert_path(n, "/grault/garply/corge", NULL);
rtree_insert_path(n, "/garply/foo/bar", NULL);
rtree_insert_path(n, "/garply/foo/baz", NULL);
rtree_insert_path(n, "/garply/foo/qux", NULL);
rtree_insert_path(n, "/garply/foo/quux", NULL);
rtree_insert_path(n, "/garply/foo/corge", NULL);
rtree_insert_path(n, "/garply/foo/grault", NULL);
rtree_insert_path(n, "/garply/bar/foo", NULL);
rtree_insert_path(n, "/garply/bar/baz", NULL);
rtree_insert_path(n, "/garply/bar/qux", NULL);
rtree_insert_path(n, "/garply/bar/quux", NULL);
rtree_insert_path(n, "/garply/bar/corge", NULL);
rtree_insert_path(n, "/garply/bar/grault", NULL);
rtree_insert_path(n, "/garply/baz/foo", NULL);
rtree_insert_path(n, "/garply/baz/bar", NULL);
rtree_insert_path(n, "/garply/baz/qux", NULL);
rtree_insert_path(n, "/garply/baz/quux", NULL);
rtree_insert_path(n, "/garply/baz/corge", NULL);
rtree_insert_path(n, "/garply/baz/grault", NULL);
rtree_insert_path(n, "/garply/qux/foo", NULL);
rtree_insert_path(n, "/garply/qux/bar", NULL);
rtree_insert_path(n, "/garply/qux/baz", NULL);
rtree_insert_path(n, "/garply/qux/quux", NULL);
rtree_insert_path(n, "/garply/qux/corge", NULL);
rtree_insert_path(n, "/garply/qux/grault", NULL);
rtree_insert_path(n, "/garply/quux/foo", NULL);
rtree_insert_path(n, "/garply/quux/bar", NULL);
rtree_insert_path(n, "/garply/quux/baz", NULL);
rtree_insert_path(n, "/garply/quux/qux", NULL);
rtree_insert_path(n, "/garply/quux/corge", NULL);
rtree_insert_path(n, "/garply/quux/grault", NULL);
rtree_insert_path(n, "/garply/corge/foo", NULL);
rtree_insert_path(n, "/garply/corge/bar", NULL);
rtree_insert_path(n, "/garply/corge/baz", NULL);
rtree_insert_path(n, "/garply/corge/qux", NULL);
rtree_insert_path(n, "/garply/corge/quux", NULL);
rtree_insert_path(n, "/garply/corge/grault", NULL);
rtree_insert_path(n, "/garply/grault/foo", NULL);
rtree_insert_path(n, "/garply/grault/bar", NULL);
rtree_insert_path(n, "/garply/grault/baz", NULL);
rtree_insert_path(n, "/garply/grault/qux", NULL);
rtree_insert_path(n, "/garply/grault/quux", NULL);
rtree_insert_path(n, "/garply/grault/corge", NULL);
rtree_compile(n);
// rtree_dump(n, 0);
// match_entry *entry = calloc( sizeof(entry) , 1 );
node *m;
m = rtree_match(n , "/qux/bar/corge", strlen("/qux/bar/corge"), NULL);
fail_if( m == NULL );
// rtree_dump( m, 0 );
ck_assert_int_eq( (int) m->route_ptr, 999 );
printf("Benchmarking...\n");
double s = microtime();
unsigned int N = 5000000;
for (int i = 0; i < 5000000 ; i++ ) {
rtree_match(n , "/qux/bar/corge", strlen("/qux/bar/corge"), NULL);
}
double e = microtime();
printf("%.2f i/sec\n", e - s / N );
printf("%lf seconds\n", e - s );
FILE *fp = fopen("bench_str.csv", "a+");
fprintf(fp, "%.2f,\"%s\"\n", e - s / N, "using strcmp" );
fclose(fp);
token_array_free(l);
} }
END_TEST END_TEST
@ -253,7 +647,7 @@ Suite* r3_suite (void) {
TCase *tcase = tcase_create("testcase"); TCase *tcase = tcase_create("testcase");
tcase_add_test(tcase, test_route_split); tcase_add_test(tcase, test_route_split);
tcase_add_test(tcase, test_token_array); tcase_add_test(tcase, test_str_array);
tcase_add_test(tcase, test_ltrim_slash); tcase_add_test(tcase, test_ltrim_slash);
tcase_add_test(tcase, test_node_construct_uniq); tcase_add_test(tcase, test_node_construct_uniq);
tcase_add_test(tcase, test_node_find_edge); tcase_add_test(tcase, test_node_find_edge);
@ -261,6 +655,8 @@ Suite* r3_suite (void) {
tcase_add_test(tcase, test_compile_slug); tcase_add_test(tcase, test_compile_slug);
tcase_add_test(tcase, test_compile); tcase_add_test(tcase, test_compile);
tcase_add_test(tcase, benchmark_str);
suite_add_tcase(suite, tcase); suite_add_tcase(suite, tcase);
return suite; return suite;