diff --git a/include/r3.h b/include/r3.h index ae83acc..2dc99e7 100644 --- a/include/r3.h +++ b/include/r3.h @@ -28,10 +28,14 @@ typedef struct _node node; typedef struct _route route; struct _node { - edge ** edges; + edge ** edges; int edge_len; int edge_cap; + route ** conditions; + int condition_len; + int condition_cap; + /** compile-time variables here.... **/ @@ -56,7 +60,6 @@ struct _edge { int pattern_len; bool has_slug; node * child; - route * route; }; typedef struct { @@ -85,7 +88,6 @@ struct _route { char * remote_addr_pattern; int remote_addr_pattern_len; - }; @@ -97,11 +99,11 @@ void r3_tree_free(node * tree); void r3_edge_free(edge * edge); -edge * r3_tree_add_child(node * n, char * pat , node *child); +edge * r3_node_add_child(node * n, char * pat , node *child); edge * r3_node_find_edge(node * n, char * pat); -void r3_tree_append_edge(node *n, edge *child); +void r3_node_append_edge(node *n, edge *child); node * r3_tree_insert_path(node *tree, char *path, route * route, void * data); @@ -124,8 +126,6 @@ node * r3_tree_match(node * n, char * path, int path_len, match_entry * entry); bool r3_node_has_slug_edges(node *n); -node * r3_tree_lookup(node * tree, char * path, int path_len); - edge * r3_edge_create(char * pattern, int pattern_len, node * child); void r3_edge_branch(edge *e, int dl); @@ -133,6 +133,7 @@ void r3_edge_branch(edge *e, int dl); void r3_edge_free(edge * edge); +node * r3_tree_insert_route(node *tree, route * route, void * data); match_entry * match_entry_createl(char * path, int path_len); @@ -147,7 +148,15 @@ route * route_createl(char * path, int path_len); int route_cmp(route *r1, route *r2); +edge * r3_edge_route_create(route * route, node * child); + +node * r3_node_append_condition(node * n, route * route, void * data); + +void route_free(route * route); + #define METHOD_GET 2 #define METHOD_POST 2<<1 +#define METHOD_PUT 2<<1 +#define METHOD_DELETE 2<<1 #endif /* !NODE_H */ diff --git a/src/edge.c b/src/edge.c index 686aa1f..2d338d8 100644 --- a/src/edge.c +++ b/src/edge.c @@ -24,6 +24,14 @@ #include "r3.h" #include "str_array.h" +edge * r3_edge_create(char * pattern, int pattern_len, node * child) { + edge * e = (edge*) malloc( sizeof(edge) ); + e->pattern = pattern; + e->pattern_len = pattern_len; + e->child = child; + return e; +} + /** @@ -47,7 +55,7 @@ void r3_edge_branch(edge *e, int dl) { // Migrate the child edges to the new edge we just created. for ( int i = 0 ; i < tmp_r3_edge_len ; i++ ) { - r3_tree_append_edge(c1, tmp_edges[i]); + r3_node_append_edge(c1, tmp_edges[i]); e->child->edges[i] = NULL; } e->child->edge_len = 0; @@ -55,20 +63,10 @@ void r3_edge_branch(edge *e, int dl) { info("branched pattern: %s\n", e1->pattern); - r3_tree_append_edge(e->child, e1); + r3_node_append_edge(e->child, e1); c1->endpoint++; } - -edge * r3_edge_create(char * pattern, int pattern_len, node * child) { - edge * e = (edge*) malloc( sizeof(edge) ); - e->pattern = pattern; - e->pattern_len = pattern_len; - e->child = child; - e->route = NULL; - return e; -} - void r3_edge_free(edge * e) { if (e->pattern) { free(e->pattern); diff --git a/src/node.c b/src/node.c index a13a821..38f20af 100644 --- a/src/node.c +++ b/src/node.c @@ -63,7 +63,7 @@ void r3_tree_free(node * tree) { /* parent node, edge pattern, child */ -edge * r3_tree_add_child(node * n, char * pat , node *child) { +edge * r3_node_add_child(node * n, char * pat , node *child) { // find the same sub-pattern, if it does not exist, create one edge * e; @@ -74,7 +74,7 @@ edge * r3_tree_add_child(node * n, char * pat , node *child) { } e = r3_edge_create( pat, strlen(pat), child); - r3_tree_append_edge(n, e); + r3_node_append_edge(n, e); // str_array_append(n->edge_patterns, pat); // assert( str_array_len(n->edge_patterns) == n->edge_len ); return e; @@ -82,8 +82,7 @@ edge * r3_tree_add_child(node * n, char * pat , node *child) { -void r3_tree_append_edge(node *n, edge *e) { - +void r3_node_append_edge(node *n, edge *e) { if (!n->edges) { n->edge_cap = 3; n->edges = malloc(sizeof(edge) * n->edge_cap); @@ -194,27 +193,6 @@ void r3_tree_compile_patterns(node * n) { } } -route * route_create(char * path) { - return route_createl(path, strlen(path)); -} - -void route_free(route * route) { - free(route); -} - -route * route_createl(char * path, int path_len) { - route * info = malloc(sizeof(route)); - info->path = path; - info->path_len = path_len; - info->request_method = 0; // can be (GET || POST) - - info->host = NULL; // required host name - info->host_len = 0; - - info->remote_addr_pattern = NULL; - info->remote_addr_pattern_len = 0; - return info; -} match_entry * match_entry_createl(char * path, int path_len) { match_entry * entry = malloc(sizeof(match_entry)); @@ -337,30 +315,17 @@ inline edge * r3_node_find_edge_str(node * n, char * str, int str_len) { } -node * r3_tree_lookup(node * tree, char * path, int path_len) { - str_array * tokens = split_route_pattern(path, path_len); - - node * n = tree; - edge * e = NULL; - int i = 0; - for (; i < tokens->len ; i++ ) { - e = r3_node_find_edge(n, str_array_fetch(tokens, i) ); - if (!e) { - return NULL; - } - n = e->child; - } - if (n->endpoint) { - return n; - } - return NULL; -} node * r3_node_create() { node * n = (node*) malloc( sizeof(node) ); n->edges = NULL; n->edge_len = 0; n->edge_cap = 0; + + n->conditions = NULL; + n->condition_len = 0; + n->condition_cap = 0; + n->endpoint = 0; n->combined_pattern = NULL; n->pcre_pattern = NULL; @@ -368,11 +333,41 @@ node * r3_node_create() { } +route * route_create(char * path) { + return route_createl(path, strlen(path)); +} + +void route_free(route * route) { + free(route); +} + +route * route_createl(char * path, int path_len) { + route * info = malloc(sizeof(route)); + info->path = path; + info->path_len = path_len; + info->request_method = 0; // can be (GET || POST) + + info->host = NULL; // required host name + info->host_len = 0; + + info->remote_addr_pattern = NULL; + info->remote_addr_pattern_len = 0; + return info; +} + +node * r3_tree_insert_route(node *tree, route * route, void * data) { + return r3_tree_insert_pathl(tree, route->path, route->path_len, route, data); +} + node * r3_tree_insert_path(node *tree, char *path, route * route, void * data) { return r3_tree_insert_pathl(tree, path, strlen(path) , route , data); } + +/** + * Return the last inserted node. + */ node * r3_tree_insert_pathl(node *tree, char *path, int path_len, route * route, void * data) { node * n = tree; @@ -405,19 +400,19 @@ node * r3_tree_insert_pathl(node *tree, char *path, int path_len, route * route, if ( offset == 0 ) { // not found, we should just insert a whole new edge node * child = r3_tree_create(3); - r3_tree_add_child(n, strndup(path, path_len) , child); + r3_node_add_child(n, strndup(path, path_len) , child); info("edge not found, insert one: %s\n", path); child->data = data; child->endpoint++; return child; } else if ( offset == e->pattern_len ) { // fully-equal to the pattern of the edge - char * subroute = path + offset; - int subroute_len = path_len - offset; + char * subpath = path + offset; + int subpath_len = path_len - offset; // there are something more we can insert - if ( subroute_len > 0 ) { - return r3_tree_insert_pathl(e->child, subroute, subroute_len, route, data); + if ( subpath_len > 0 ) { + return r3_tree_insert_pathl(e->child, subpath, subpath_len, route, data); } else { // no more path to insert e->child->endpoint++; // make it as an endpoint @@ -444,7 +439,7 @@ node * r3_tree_insert_pathl(node *tree, char *path, int path_len, route * route, s2_len = path_len - offset; e2 = r3_edge_create(strndup(s2, s2_len), s2_len, c2); // printf("edge right: %s\n", e2->pattern); - r3_tree_append_edge(e->child, e2); + r3_node_append_edge(e->child, e2); char *op = e->pattern; @@ -551,6 +546,39 @@ int route_cmp(route *r1, route *r2) { return 0; } + +/** + * Create a data only node. + */ +node * r3_node_append_condition(node * n, route * route, void * data) { + /* + if (!n->conditions) { + n->condition_cap = 3; + n->conditions = malloc(sizeof(condition) * n->condition_cap); + } + if (n->condition_len >= n->condition_cap) { + n->condition_cap *= 2; + n->conditions = realloc(n->conditions, sizeof(condition) * n->condition_cap); + } + n->conditions[ n->condition_len++ ] = condition; + */ + return n; +} + +/** + * Create a route-only edge. (without pattern) + */ +edge * r3_edge_route_create(route * route, node * child) { + edge * e = (edge*) malloc( sizeof(edge) ); + /* + e->pattern = NULL; + e->pattern_len = 0; + e->child = child; + // e->route = NULL; + */ + return e; +} + /* char * r3_node_trace(node * n) { diff --git a/src/token.c b/src/token.c index b7c7a2b..6f2bc27 100644 --- a/src/token.c +++ b/src/token.c @@ -63,55 +63,3 @@ void str_array_dump(str_array *l) { -/** - * This function is used to split route path into a string array, not for performance. - * hence this function should be safe. - * - * Split "/path/foo/{id}" into [ "/path" , "/foo" , "/{id}" ] - * Split "/path/bar/{id}" into [ "/path" , "/foo" , "/{id}" ] - * Split "/blog/post/{id}" into [ "/blog" , "/post" , "/{id}" ] - * Split "/blog/{id}" into [ "/blog" , "/{id}" ] - * Split "/blog" into [ "/blog" ] - * Split "/b" into [ "/b" ] - * Split "/{id}" into [ "/{id}" ] - * - * @param char* pattern - * @param int pattern_len - * - * @return char** - */ -str_array * split_route_pattern(char *pattern, int pattern_len) { - char *s1, *p = pattern; - - str_array * str_array = str_array_create( 20 ); - - s1 = p; - p++; - while (*p && (p - pattern) < pattern_len ) { - - // a slug - if ( *p == '{' ) { - // find closing '}' - while (*p != '}') { - p++; - assert(p - pattern < pattern_len ); // throw exception - } - p++; // contains the '}' - // printf("==> %s\n", 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) ); - str_array_append(str_array, strndup(s1, p-s1) ); - s1 = p; - } - p++; - } - - if ( p-s1 > 0 ) { - str_array_append(str_array, strndup(s1, p-s1) ); - } - return str_array; -} diff --git a/tests/bench_str.csv b/tests/bench_str.csv index 0d80dc7..ec0d2f5 100644 --- a/tests/bench_str.csv +++ b/tests/bench_str.csv @@ -102,3 +102,16 @@ 1400385528,13333901.32 1400385535,11961732.08 1400385563,12910309.71 +1400385616,12105227.61 +1400385713,13601851.15 +1400385728,13344674.03 +1400385734,13685060.22 +1400385774,13223631.32 +1400385951,11001406.94 +1400386286,10682057.04 +1400386296,11152665.22 +1400386480,10908179.24 +1400386496,11514008.98 +1400386505,11172976.25 +1400386731,11184613.82 +1400387044,10760384.75 diff --git a/tests/check_tree.c b/tests/check_tree.c index f8b1b10..7d0b2da 100644 --- a/tests/check_tree.c +++ b/tests/check_tree.c @@ -22,8 +22,8 @@ START_TEST (test_r3_node_construct_uniq) node * child = r3_tree_create(3); - // fail_if( r3_tree_add_child(n, strdup("/add") , child) != NULL ); - // fail_if( r3_tree_add_child(n, strdup("/add") , child) != NULL ); + // fail_if( r3_node_add_child(n, strdup("/add") , child) != NULL ); + // fail_if( r3_node_add_child(n, strdup("/add") , child) != NULL ); r3_tree_free(n); } @@ -35,7 +35,7 @@ START_TEST (test_r3_node_find_edge) node * child = r3_tree_create(3); - fail_if( r3_tree_add_child(n, strdup("/add") , child) == FALSE ); + fail_if( r3_node_add_child(n, strdup("/add") , child) == FALSE ); fail_if( r3_node_find_edge(n, "/add") == NULL ); fail_if( r3_node_find_edge(n, "/bar") != NULL ); @@ -198,41 +198,6 @@ END_TEST -START_TEST (test_route_split) -{ - str_array *t; - - t = split_route_pattern("/blog", strlen("/blog") ); - fail_if( t == NULL ); - // str_array_dump(t); - str_array_free(t); - - t = split_route_pattern("/foo/{id}", strlen("/foo/{id}") ); - fail_if( t == NULL ); - // str_array_dump(t); - fail_if( t->len != 2 ); - str_array_free(t); - - t = split_route_pattern("/foo/bar/{id}", strlen("/foo/bar/{id}") ); - fail_if( t == NULL ); - // str_array_dump(t); - fail_if( t->len != 3 ); - str_array_free(t); - - t = split_route_pattern("/{title}", strlen("/{title}") ); - fail_if( t == NULL ); - // str_array_dump(t); - fail_if( t->len != 1 ); - str_array_free(t); - - t = split_route_pattern("/", strlen("/") ); - fail_if( t == NULL ); - // str_array_dump(t); - fail_if( t->len != 1 ); - str_array_free(t); - -} -END_TEST START_TEST (test_str_array) { @@ -272,25 +237,38 @@ START_TEST(test_route_cmp) r2->request_method = METHOD_POST; fail_if( route_cmp(r1, r2) == 0, "should be different"); + + route_free(r1); + route_free(r2); } END_TEST + + START_TEST(test_insert_route) { - match_entry * entry = match_entry_createl("/blog/post", strlen("/blog/post") ); + int var1 = 22; + int var2 = 33; + route *r1 = route_create("/blog/post"); + route *r2 = route_create("/blog/post"); + r1->request_method = METHOD_GET; + r2->request_method = METHOD_POST; + fail_if( route_cmp(r1, r2) == 0, "should be different"); - match_entry * entry2 = match_entry_create("/blog/post"); + match_entry * entry = match_entry_create("/blog/post"); + node * n = r3_tree_create(2); + r3_tree_insert_route(n, r1, &var1); + r3_tree_insert_route(n, r2, &var2); - node * tree = r3_tree_create(2); - - // route *info = route_create("/blog/post", strlen("/blog/post") ); - - // r3_tree_insert_route(n, "/foo/bar/baz", NULL); - + match_entry_free(entry); + route_free(r1); + route_free(r2); } END_TEST + + START_TEST(benchmark_str) { match_entry * entry = match_entry_createl("/blog/post", strlen("/blog/post") ); @@ -667,7 +645,6 @@ Suite* r3_suite (void) { Suite *suite = suite_create("blah"); TCase *tcase = tcase_create("testcase"); - tcase_add_test(tcase, test_route_split); tcase_add_test(tcase, test_str_array); tcase_add_test(tcase, test_ltrim_slash); tcase_add_test(tcase, test_r3_node_construct_uniq);