From 046ec9e9776596fbc762f835b2708147b5665b72 Mon Sep 17 00:00:00 2001 From: c9s Date: Fri, 16 May 2014 18:03:52 +0800 Subject: [PATCH] Add benchmark and bug fixes --- include/define.h | 3 +- include/node.h | 15 +- include/token.h | 24 +-- src/node.c | 99 +++++---- src/token.c | 30 +-- tests/test_tree.c | 510 ++++++++++++++++++++++++++++++++++++++++------ 6 files changed, 550 insertions(+), 131 deletions(-) diff --git a/include/define.h b/include/define.h index 6ba0353..2fdd99b 100644 --- a/include/define.h +++ b/include/define.h @@ -12,8 +12,7 @@ typedef unsigned char bool; #define FALSE 0 #define TRUE 1 - -#define DEBUG 1 +// #define DEBUG 1 #ifdef DEBUG #define info(fmt, ...) \ diff --git a/include/node.h b/include/node.h index 37d55cd..13d1fbd 100644 --- a/include/node.h +++ b/include/node.h @@ -21,7 +21,6 @@ struct _node; typedef struct _edge edge; typedef struct _node node; - struct _node { edge ** edges; int edge_len; @@ -33,7 +32,6 @@ struct _node { pcre * pcre_pattern; pcre_extra * pcre_extra; - /** * the pointer of route structure */ @@ -49,6 +47,12 @@ struct _edge { 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); @@ -65,8 +69,6 @@ edge * node_find_edge(node * n, char * pat); 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_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); -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); @@ -92,4 +94,7 @@ void edge_branch(edge *e, int dl); void edge_free(edge * edge); + + + #endif /* !NODE_H */ diff --git a/include/token.h b/include/token.h index 129e551..ee43cda 100644 --- a/include/token.h +++ b/include/token.h @@ -10,29 +10,29 @@ #include "define.h" -typedef struct _token_array { +typedef struct _str_array { char **tokens; int len; 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 token_array_len(t) t->len -#define token_array_cap(t) t->cap +#define str_array_fetch(t,i) t->tokens[i] +#define str_array_len(t) t->len +#define str_array_cap(t) t->cap #endif /* !TOKEN_H */ diff --git a/src/node.c b/src/node.c index 67cd93c..f174d2a 100644 --- a/src/node.c +++ b/src/node.c @@ -45,7 +45,7 @@ void rtree_free(node * tree) { free(tree->combined_pattern); free(tree->edges); - // token_array_free(tree->edge_patterns); + // str_array_free(tree->edge_patterns); free(tree); tree = NULL; } @@ -65,8 +65,8 @@ edge * rtree_add_child(node * n, char * pat , node *child) { e = edge_create( pat, strlen(pat), child); rtree_append_edge(n, e); - // token_array_append(n->edge_patterns, pat); - // assert( token_array_len(n->edge_patterns) == n->edge_len ); + // str_array_append(n->edge_patterns, pat); + // assert( str_array_len(n->edge_patterns) == n->edge_len ); return e; } @@ -127,6 +127,7 @@ void rtree_compile_patterns(node * n) { p = cpat; + edge *e = NULL; for ( int i = 0 ; i < n->edge_len ; i++ ) { e = n->edges[i]; @@ -152,6 +153,12 @@ void rtree_compile_patterns(node * n) { const char *error; 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 = 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) { info("pcre matching %s on %s\n", n->combined_pattern, path); // int ovector_count = (n->edge_len + 1) * 2; @@ -206,18 +215,27 @@ node * rtree_match(node * n, char * path, int path_len) { } int i; + edge *e; for (i = 1; i < rc; i++) { char *substring_start = path + ovector[2*i]; int substring_length = ovector[2*i+1] - ovector[2*i]; info("%2d: %.*s\n", i, substring_length, substring_start); + if ( substring_length > 0) { 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); - 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 @@ -230,7 +248,7 @@ node * rtree_match(node * n, char * path, int path_len) { if(len == 0) { return e->child; } else { - return rtree_match(e->child, path + e->pattern_len, len); + return rtree_match(e->child, path + e->pattern_len, len, entry); } } 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 *e; + char *p; + char *s; for ( int i = 0 ; i < n->edge_len ; i++ ) { e = n->edges[i]; - char *p = e->pattern; - while ( *p == *str ) { - p++; + p = e->pattern; + s = str; + + 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 ) { return e; } + */ } return NULL; } 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; edge * e = NULL; 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) { 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) { 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); info("edge not found, insert one: %s\n", route); child->route_ptr = route_ptr; + child->endpoint++; return child; } 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->route_ptr = route_ptr; return c2; - } else if ( dl > 0 ) { - } else { printf("unexpected condition."); return NULL; } - // token_array * t = split_route_pattern(route, strlen(route)); - // return rtree_insert_tokens(tree, t); - // n->endpoint++; return n; } @@ -441,7 +452,7 @@ void edge_branch(edge *e, int dl) { e->child->edge_len = 0; e->child->endpoint--; - info("branched pattern: %s", e1->pattern); + info("branched pattern: %s\n", e1->pattern); rtree_append_edge(e->child, e1); c1->endpoint++; @@ -471,9 +482,11 @@ void edge_free(edge * e) { void rtree_dump(node * n, int level) { if ( n->edge_len ) { 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++ ) { edge * e = n->edges[i]; print_indent(level); @@ -491,3 +504,9 @@ void rtree_dump(node * n, int level) { } } } + +/* +char * node_trace(node * n) { + +} +*/ diff --git a/src/token.c b/src/token.c index b50d2ac..05b74a0 100644 --- a/src/token.c +++ b/src/token.c @@ -11,15 +11,15 @@ #include "token.h" -token_array * token_array_create(int cap) { - token_array * list = (token_array*) malloc( sizeof(token_array) ); +str_array * str_array_create(int cap) { + str_array * list = (str_array*) malloc( sizeof(str_array) ); list->len = 0; list->cap = cap; list->tokens = (char**) malloc( sizeof(char*) * cap); return list; } -void token_array_free(token_array *l) { +void str_array_free(str_array *l) { for ( int i = 0; i < l->len ; i++ ) { char * t = l->tokens[ i ]; free(t); @@ -27,19 +27,19 @@ void token_array_free(token_array *l) { free(l); } -bool token_array_is_full(token_array * l) { +bool str_array_is_full(str_array * l) { 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->cap = new_cap; return l->tokens != NULL; } -bool token_array_append(token_array * l, char * token) { - if ( token_array_is_full(l) ) { - bool ret = token_array_resize(l, l->cap + 20); +bool str_array_append(str_array * l, char * token) { + if ( str_array_is_full(l) ) { + bool ret = str_array_resize(l, l->cap + 20); if (ret == FALSE ) { return FALSE; } @@ -48,7 +48,7 @@ bool token_array_append(token_array * l, char * token) { return TRUE; } -void token_array_dump(token_array *l) { +void str_array_dump(str_array *l) { printf("["); for ( int i = 0; i < l->len ; i++ ) { printf("\"%s\"", l->tokens[i] ); @@ -79,10 +79,10 @@ void token_array_dump(token_array *l) { * * @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; - token_array * token_array = token_array_create( 20 ); + str_array * str_array = str_array_create( 20 ); s1 = p; p++; @@ -97,20 +97,20 @@ token_array * split_route_pattern(char *pattern, int pattern_len) { } p++; // contains the '}' // 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; continue; } else if ( *p == '/' ) { // 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; } p++; } 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; } diff --git a/tests/test_tree.c b/tests/test_tree.c index fc24e7f..ee93afc 100644 --- a/tests/test_tree.c +++ b/tests/test_tree.c @@ -1,9 +1,32 @@ #include #include +#include #include "str.h" #include "node.h" #include "token.h" +#include + +#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) { fail_if( strcmp( ltrim_slash("/blog") , "blog" ) != 0 ); @@ -42,11 +65,14 @@ END_TEST START_TEST (test_compile) { - token_array *t; + str_array *t; node * n; n = rtree_create(10); + match_entry * entry; + node *m; + edge *e ; rtree_insert_pathn(n, "/zoo", strlen("/zoo"), NULL); rtree_insert_pathn(n, "/foo", strlen("/foo"), NULL); @@ -55,43 +81,51 @@ START_TEST (test_compile) fail_if( n->combined_pattern ); 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, "/{id}", strlen("/{id}"), NULL); rtree_compile(n); + rtree_compile(n); // test double compile +#ifdef DEBUG rtree_dump(n, 0); +#endif + /* 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 ); - + */ /* printf( "%s\n", e->pattern ); printf( "%s\n", e->child->combined_pattern ); printf( "%s\n", n->edges[0]->child->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 ); - m = rtree_match( n , "/foo", strlen("/foo") ); + m = rtree_match( n , "/zoo", strlen("/zoo"), entry); fail_if( NULL == m ); - m = rtree_match( n , "/zoo", strlen("/zoo") ); + m = rtree_match( n , "/bar", strlen("/bar"), entry); fail_if( NULL == m ); - m = rtree_match( n , "/bar", strlen("/bar") ); + m = rtree_match( n , "/xxx", strlen("/xxx"), entry); 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 ); - m = rtree_match( n , "/foo/xxx", strlen("/foo/xxx") ); + m = rtree_match( n , "/some_id", strlen("/some_id"), entry); fail_if( NULL == m ); - - 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 - + ck_assert_int_gt( m->endpoint , 0 ); // should not be an endpoint } END_TEST @@ -144,44 +178,33 @@ START_TEST (test_rtree_insert_pathn) { node * n = rtree_create(10); - // printf("Inserting /foo/bar\n"); - rtree_insert_pathn(n, "/foo/bar", strlen("/foo/bar"), NULL); + info("Inserting /foo/bar\n"); + rtree_insert_path(n, "/foo/bar", NULL); // rtree_dump(n, 0); - // printf("Inserting /foo/zoo\n"); - rtree_insert_pathn(n, "/foo/zoo", strlen("/foo/zoo"), NULL); + info("Inserting /foo/zoo\n"); + rtree_insert_path(n, "/foo/zoo", NULL); // rtree_dump(n, 0); - // printf("Inserting /f/id\n"); - rtree_insert_pathn(n, "/f/id", strlen("/f/id") , NULL); + info("Inserting /f/id\n"); + rtree_insert_path(n, "/f/id" , NULL); // 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_dump(n, 0); - // printf("Inserting /post/{handle}\n"); + info("Inserting /post/{handle}\n"); rtree_insert_pathn(n, "/post/{handle}", strlen("/post/{handle}"), NULL); // 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_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); } END_TEST @@ -191,60 +214,431 @@ END_TEST START_TEST (test_route_split) { - token_array *t; + str_array *t; t = split_route_pattern("/blog", strlen("/blog") ); fail_if( t == NULL ); - token_array_dump(t); - token_array_free(t); + str_array_dump(t); + str_array_free(t); t = split_route_pattern("/foo/{id}", strlen("/foo/{id}") ); fail_if( t == NULL ); - token_array_dump(t); + str_array_dump(t); fail_if( t->len != 2 ); - token_array_free(t); + str_array_free(t); t = split_route_pattern("/foo/bar/{id}", strlen("/foo/bar/{id}") ); fail_if( t == NULL ); - token_array_dump(t); + str_array_dump(t); fail_if( t->len != 3 ); - token_array_free(t); + str_array_free(t); t = split_route_pattern("/{title}", strlen("/{title}") ); fail_if( t == NULL ); - token_array_dump(t); + str_array_dump(t); fail_if( t->len != 1 ); - token_array_free(t); + str_array_free(t); t = split_route_pattern("/", strlen("/") ); fail_if( t == NULL ); - token_array_dump(t); + str_array_dump(t); fail_if( t->len != 1 ); - token_array_free(t); + str_array_free(t); } 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( FALSE == token_array_append(l, strdup("abc") ) ); + fail_if( FALSE == str_array_append(l, strdup("abc") ) ); 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( FALSE == token_array_append(l, strdup("bar") ) ); + fail_if( FALSE == str_array_append(l, strdup("bar") ) ); 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( 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 @@ -253,7 +647,7 @@ Suite* r3_suite (void) { TCase *tcase = tcase_create("testcase"); 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_node_construct_uniq); 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); + tcase_add_test(tcase, benchmark_str); + suite_add_tcase(suite, tcase); return suite;