diff --git a/include/node.h b/include/node.h index 4986ad7..d92d71c 100644 --- a/include/node.h +++ b/include/node.h @@ -29,7 +29,7 @@ void rnode_free(rnode * tree); void redge_free(redge * edge); -bool rnode_add_child(rnode * n, char * pat , rnode *child); +redge * rnode_add_child(rnode * n, char * pat , rnode *child); redge * rnode_find_edge(rnode * n, char * pat); diff --git a/include/str.h b/include/str.h index 831d5c7..d58218a 100644 --- a/include/str.h +++ b/include/str.h @@ -7,6 +7,11 @@ #ifndef STR_H #define STR_H + +int strndiff(char * d1, char * d2, unsigned int n); + +int strdiff(char * d1, char * d2); + char * slug_to_pcre(char * slug, char sep); char * ltrim_slash(char* str); diff --git a/src/node.c b/src/node.c index 1d8e11a..b55d46e 100644 --- a/src/node.c +++ b/src/node.c @@ -17,9 +17,9 @@ #include "token.h" struct _rnode { - redge ** children; - int children_len; - int children_cap; + redge ** edges; + int edge_len; + int edge_cap; /* the combined regexp pattern string from pattern_tokens */ char * combined_pattern; @@ -45,9 +45,9 @@ struct _redge { rnode * rnode_create(int cap) { rnode * n = (rnode*) malloc( sizeof(rnode) ); - n->children = (redge**) malloc( sizeof(redge*) * 10 ); - n->children_len = 0; - n->children_cap = 10; + n->edges = (redge**) malloc( sizeof(redge*) * 10 ); + n->edge_len = 0; + n->edge_cap = 10; n->endpoint = 0; n->combined_pattern = NULL; // n->edge_patterns = token_array_create(10); @@ -55,10 +55,12 @@ rnode * rnode_create(int cap) { } void rnode_free(rnode * tree) { - for (int i = 0 ; i < tree->children_len ; i++ ) { - redge_free(tree->children[ i ]); + for (int i = 0 ; i < tree->edge_len ; i++ ) { + if (tree->edges[i]) { + redge_free(tree->edges[ i ]); + } } - free(tree->children); + free(tree->edges); // token_array_free(tree->edge_patterns); free(tree); tree = NULL; @@ -67,38 +69,38 @@ void rnode_free(rnode * tree) { /* parent node, edge pattern, child */ -bool rnode_add_child(rnode * n, char * pat , rnode *child) { +redge * rnode_add_child(rnode * n, char * pat , rnode *child) { // find the same sub-pattern, if it does not exist, create one redge * e; e = rnode_find_edge(n, pat); if (e) { - return FALSE; + return e; } 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 ); - return TRUE; + // assert( token_array_len(n->edge_patterns) == n->edge_len ); + return e; } void rnode_append_edge(rnode *n, redge *e) { - if (n->children_len >= n->children_cap) { - n->children_cap *= 2; - n->children = realloc(n->children, sizeof(redge) * n->children_cap); + if (n->edge_len >= n->edge_cap) { + n->edge_cap *= 2; + n->edges = realloc(n->edges, sizeof(redge) * n->edge_cap); } - n->children[ n->children_len++ ] = e; + n->edges[ n->edge_len++ ] = e; } redge * rnode_find_edge(rnode * n, char * pat) { redge * e; - for (int i = 0 ; i < n->children_len ; i++ ) { - e = n->children[i]; + for (int i = 0 ; i < n->edge_len ; i++ ) { + e = n->edges[i]; if ( strcmp(e->pattern, pat) == 0 ) { return e; } @@ -123,8 +125,8 @@ void rnode_combine_patterns(rnode * n) { p = cpat; redge *e = NULL; - for ( int i = 0 ; i < n->children_len ; i++ ) { - e = n->children[i]; + for ( int i = 0 ; i < n->edge_len ; i++ ) { + e = n->edges[i]; strncat(p++,"(", 1); strncat(p, e->pattern, e->pattern_len); @@ -132,7 +134,7 @@ void rnode_combine_patterns(rnode * n) { strncat(p++,")", 1); - if ( i + 1 < n->children_len ) { + if ( i + 1 < n->edge_len ) { strncat(p++,"|",1); } } @@ -161,7 +163,6 @@ rnode * rnode_lookup(rnode * tree, char * path, int path_len) { - rnode * rnode_insert_tokens(rnode * tree, token_array * tokens) { rnode * n = tree; redge * e = NULL; @@ -187,16 +188,121 @@ rnode * rnode_insert_route(rnode *tree, char *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); + rnode * n = tree; + redge * e = NULL; + + char * p = route; + + /* length of common prefix */ + int dl = 0; + for( int i = 0 ; i < n->edge_len ; i++ ) { + dl = strndiff(route, n->edges[i]->pattern, n->edges[i]->pattern_len); + + // printf("dl: %d %s vs %s\n", dl, route, n->edges[i]->pattern ); + + // no common, consider insert a new edge + if ( dl > 0 ) { + e = n->edges[i]; + break; + } + } + + + if ( dl == 0 ) { + // not found, we should just insert a whole new edge + rnode * child = rnode_create(3); + rnode_add_child(n, strndup(route, route_len) , child); + printf("edge not found, insert one: %s\n", route); + + n = child; + return n; + } else if ( dl == e->pattern_len ) { // fully-equal to the pattern of the edge + char * subroute = route + dl; + int subroute_len = route_len - dl; + + // there are something more we can insert + if ( subroute_len > 0 ) { + return rnode_insert_routel(e->child, subroute, subroute_len); + } else { + // no more, + e->child->endpoint++; // make it as an endpoint, TODO: put the route value + return e->child; + } + + } else if ( dl < e->pattern_len ) { + printf("branch the edge dl: %d\n", dl); + /* it's partically matched with the pattern, + * we should split the end point and make a branch here... + */ + rnode *c1, *c2; // child 1, child 2 + redge *e1, *e2; // edge 1, edge 2 + char * s1 = e->pattern + dl; + char * s2 = route + dl; + int s1_len = 0, s2_len = 0; + + redge **tmp_edges = e->child->edges; + int **tmp_edge_len = e->child->edge_len; + + // the suffix edge of the leaf + c1 = rnode_create(3); + s1_len = e->pattern_len - dl; + e1 = redge_create(strndup(s1, s1_len), s1_len, c1); + // printf("edge left: %s\n", e1->pattern); + + // Migrate the child edges to the new edge we just created. + for ( int i = 0 ; i < tmp_edge_len ; i++ ) { + rnode_append_edge(c1, tmp_edges[i]); + e->child->edges[i] = NULL; + } + e->child->edge_len = 0; + + rnode_append_edge(e->child, e1); + + + + + // here is the new edge from. + c2 = rnode_create(3); + s2_len = route_len - dl; + e2 = redge_create(strndup(s2, s2_len), s2_len, c2); + // printf("edge right: %s\n", e2->pattern); + rnode_append_edge(e->child, e2); + + // truncate the original edge pattern + free(e->pattern); + e->pattern = strndup(e->pattern, dl); + e->pattern_len = dl; + + + + // Move the child edges to the new suffix edge child + /* + e->child->edge_len = 0; + */ + + + // move n->edges to c1 + c1->endpoint++; + c2->endpoint++; + return c2; + } else if ( dl > 0 ) { + + } else { + printf("unexpected condition."); + return NULL; + } + // token_array * t = split_route_pattern(route, strlen(route)); + // return rnode_insert_tokens(tree, t); + // n->endpoint++; + return n; } void rnode_dump(rnode * n, int level) { - if ( n->children_len ) { + if ( n->edge_len ) { print_indent(level); printf("*\n"); - for ( int i = 0 ; i < n->children_len ; i++ ) { - redge * e = n->children[i]; + for ( int i = 0 ; i < n->edge_len ; i++ ) { + redge * e = n->edges[i]; print_indent(level + 1); printf("+ \"%s\"\n", e->pattern); rnode_dump( e->child, level + 1); @@ -214,7 +320,9 @@ redge * redge_create(char * pattern, int pattern_len, rnode * child) { } void redge_free(redge * e) { - free(e->pattern); + if (e->pattern) { + free(e->pattern); + } if ( e->child ) { rnode_free(e->child); } diff --git a/src/str.c b/src/str.c index b707440..a204f4d 100644 --- a/src/str.c +++ b/src/str.c @@ -11,6 +11,27 @@ #include "str.h" #include "token.h" +int strndiff(char * d1, char * d2, unsigned int n) { + char * o = d1; + while ( *d1 == *d2 && n-- > 0 ) { + d1++; + d2++; + } + return d1 - o; +} + + +int strdiff(char * d1, char * d2) { + char * o = d1; + while( *d1 == *d2 ) { + d1++; + d2++; + } + return d1 - o; +} + + + /** * @param char * sep separator */ diff --git a/tests/test_tree.c b/tests/test_tree.c index ad4bd70..1588191 100644 --- a/tests/test_tree.c +++ b/tests/test_tree.c @@ -17,8 +17,8 @@ START_TEST (test_rnode_construct_uniq) rnode * child = rnode_create(3); - fail_if( rnode_add_child(n, strdup("/add") , child) == FALSE ); - fail_if( rnode_add_child(n, strdup("/add") , child) != FALSE ); + // fail_if( rnode_add_child(n, strdup("/add") , child) != NULL ); + // fail_if( rnode_add_child(n, strdup("/add") , child) != NULL ); rnode_free(n); } @@ -90,12 +90,23 @@ START_TEST (test_slug_to_pcre) END_TEST -START_TEST (test_rnode_insert_tokens) +START_TEST (test_rnode_insert_routel) { - token_array *t; - rnode * n = rnode_create(10); + printf("Inserting /foo/bar\n"); + rnode_insert_routel(n, "/foo/bar", strlen("/foo/bar") ); + rnode_dump(n, 0); + + printf("Inserting /foo/zoo\n"); + rnode_insert_routel(n, "/foo/zoo", strlen("/foo/zoo") ); + rnode_dump(n, 0); + + printf("Inserting /f/id\n"); + rnode_insert_routel(n, "/f/id", strlen("/f/id") ); + rnode_dump(n, 0); + + /* fail_if(n == NULL, "rnode tree"); t = split_route_pattern("/foo/bar", strlen("/foo/bar") ); @@ -112,15 +123,15 @@ START_TEST (test_rnode_insert_tokens) t = split_route_pattern("/a/jj/kk", strlen("/a/jj/kk") ); fail_if( rnode_insert_tokens(n , t) == NULL ); - - rnode_dump(n, 0); + */ + /* fail_if( rnode_lookup(n , "/a/jj/kk" , strlen("/a/jj/kk") ) == NULL ); fail_if( rnode_lookup(n , "/a/jj" , strlen("/a/jj") ) != NULL ); fail_if( rnode_lookup(n , "/a/jj/kk/ll" , strlen("/a/jj/kk/ll") ) != NULL ); - fail_if( rnode_lookup(n, "/xxxx", strlen("xxxx") ) != NULL ); + */ // fail_if( rnode_find_edge(n, "/add") == NULL ); @@ -201,7 +212,7 @@ Suite* r3_suite (void) { tcase_add_test(tcase, test_ltrim_slash); tcase_add_test(tcase, test_rnode_construct_uniq); tcase_add_test(tcase, test_rnode_find_edge); - tcase_add_test(tcase, test_rnode_insert_tokens); + tcase_add_test(tcase, test_rnode_insert_routel); tcase_add_test(tcase, test_slug_to_pcre); tcase_add_test(tcase, test_combine_patterns);