From f3bf32b922f20bb0ff9225e4109df73b5f7273d1 Mon Sep 17 00:00:00 2001 From: c9s Date: Mon, 2 Jun 2014 08:04:57 +0800 Subject: [PATCH] refactor path insert function --- include/r3.h | 2 +- src/edge.c | 2 ++ src/node.c | 90 +++++++++++++++++++++++++++------------------- tests/check_tree.c | 40 +++++++++------------ 4 files changed, 73 insertions(+), 61 deletions(-) diff --git a/include/r3.h b/include/r3.h index 4d8a1bc..0d22c52 100644 --- a/include/r3.h +++ b/include/r3.h @@ -104,7 +104,7 @@ edge * r3_node_connectl(node * n, const char * pat, int len, int strdup, node *c #define r3_node_connect(n, pat, child) r3_node_connectl(n, pat, strlen(pat), 0, child) -edge * r3_node_find_edge(const node * n, const char * pat); +edge * r3_node_find_edge(const node * n, const char * pat, int pat_len); void r3_node_append_edge(node *n, edge *child); diff --git a/src/edge.c b/src/edge.c index b5b8bd0..7305243 100644 --- a/src/edge.c +++ b/src/edge.c @@ -21,6 +21,7 @@ #include "r3.h" #include "r3_str.h" +#include "slug.h" #include "zmalloc.h" edge * r3_edge_create(const char * pattern, int pattern_len, node * child) { @@ -29,6 +30,7 @@ edge * r3_edge_create(const char * pattern, int pattern_len, node * child) { e->pattern_len = pattern_len; e->opcode = 0; e->child = child; + e->has_slug = r3_path_contains_slug_char(e->pattern); return e; } diff --git a/src/node.c b/src/node.c index 9c39470..4a7b126 100644 --- a/src/node.c +++ b/src/node.c @@ -86,7 +86,7 @@ edge * r3_node_connectl(node * n, const char * pat, int len, int dupl, node *chi // find the same sub-pattern, if it does not exist, create one edge * e; - e = r3_node_find_edge(n, pat); + e = r3_node_find_edge(n, pat, len); if (e) { return e; } @@ -115,10 +115,17 @@ void r3_node_append_edge(node *n, edge *e) { n->edges[ n->edge_len++ ] = e; } -edge * r3_node_find_edge(const node * n, const char * pat) { + +/** + * Find the existing edge with specified pattern (include slug) + */ +edge * r3_node_find_edge(const node * n, const char * pat, int pat_len) { edge * e; for (int i = 0 ; i < n->edge_len ; i++ ) { e = n->edges[i]; + + // there is a case: "{foo}" vs "{foo:xxx}", + // we should return the match result: full-match or partial-match if ( strcmp(e->pattern, pat) == 0 ) { return e; } @@ -476,6 +483,10 @@ node * r3_tree_insert_pathl_(node *tree, const char *path, int path_len, route * /* length of common prefix */ int prefix_len = 0; for( int i = 0 ; i < n->edge_len ; i++ ) { + // ignore all edges with slug + if (n->edges[i]->has_slug) + continue; + prefix_len = strndiff( (char*) path, n->edges[i]->pattern, n->edges[i]->pattern_len); // printf("prefix_len: %d %s vs %s\n", prefix_len, path, n->edges[i]->pattern ); @@ -539,56 +550,63 @@ node * r3_tree_insert_pathl_(node *tree, const char *path, int path_len, route * char *slug_p = slug_find_placeholder(path, &slug_len); int slug_pattern_len = 0; char *slug_pattern = slug_find_pattern(slug_p, &slug_pattern_len); + + fprintf(stderr, "slug: %.*s\n", slug_len, slug_p); + fprintf(stderr, "slug pattern: '%.*s'\n", slug_pattern_len, slug_pattern); + int opcode = 0; // if there is a pattern defined. - if (slug_pattern) { + if (slug_pattern_len) { char *cpattern = slug_compile(slug_pattern, slug_pattern_len); opcode = r3_pattern_to_opcode(cpattern, strlen(cpattern)); zfree(cpattern); } else { opcode = OP_EXPECT_NOSLASH; } - // found opcode - if (opcode) { - // if the slug starts after one+ charactor, for example foo{slug} - node *c1; - if (slug_p > path) { - c1 = r3_tree_create(3); - CHECK_PTR(c1); - r3_node_connectl(n, path, slug_p - path, 1, c1); // duplicate - } else { - c1 = n; - } - node * c2 = r3_tree_create(3); - CHECK_PTR(c2); - - edge * op_edge = r3_node_connectl(c1, slug_p, slug_len , 1, c2); - op_edge->opcode = opcode; - - // insert rest - int restlen = (path_len - (slug_p - path)) - slug_len; - if (restlen) { - return r3_tree_insert_pathl_(c2, slug_p + slug_len, restlen, route, data, errstr); - } - - c2->data = data; - c2->endpoint++; - if (route) { - route->data = data; - r3_node_append_route(c2, route); - } - return c2; + // if the slug starts after one+ charactor, for example foo{slug} + node *c1; + if (slug_p > path) { + c1 = r3_tree_create(3); + CHECK_PTR(c1); + r3_node_connectl(n, path, slug_p - path, 1, c1); // duplicate + } else { + c1 = n; } + + node * c2 = r3_tree_create(3); + CHECK_PTR(c2); + + edge * op_edge = r3_node_connectl(c1, slug_p, slug_len , 1, c2); + if(opcode) { + op_edge->opcode = opcode; + } + + int restlen = path_len - ((slug_p - path) + slug_len); + + if (restlen) { + return r3_tree_insert_pathl_(c2, slug_p + slug_len, restlen, route, data, errstr); + } + + c2->data = data; + c2->endpoint++; + if (route) { + route->data = data; + r3_node_append_route(c2, route); + } + return c2; } // only one slug node * child = r3_tree_create(3); CHECK_PTR(child); - - r3_node_connect(n, zstrndup(path, path_len) , child); - child->data = data; child->endpoint++; + if (data) + child->data = data; + + printf("insert %.*s\n", path_len, path); + + r3_node_connectl(n, path, path_len, 1, child); if (route) { route->data = data; r3_node_append_route(child, route); diff --git a/tests/check_tree.c b/tests/check_tree.c index a37afde..5bb381a 100644 --- a/tests/check_tree.c +++ b/tests/check_tree.c @@ -26,21 +26,6 @@ START_TEST (test_r3_node_construct_and_free) } END_TEST -START_TEST (test_r3_node_find_edge) -{ - node * n = r3_tree_create(10); - - node * child = r3_tree_create(3); - - fail_if( r3_node_connect(n, zstrdup("/add") , child) == FALSE ); - fail_if( r3_node_find_edge(n, "/add") == NULL ); - fail_if( r3_node_find_edge(n, "/bar") != NULL ); - - r3_tree_free(n); -} -END_TEST - - static node * create_simple_str_tree() { node * n; n = r3_tree_create(10); @@ -126,6 +111,16 @@ START_TEST (test_incomplete_slug_path) r3_tree_insert_path(n, "/post/{handle:\\d{3}}/{a", NULL); r3_tree_insert_path(n, "/post/{handle:\\d{3}}/{a}", NULL); + ret_node = r3_tree_insert_path(n, "/users/{idx:\\d{3}}/{idy}", NULL); + assert(ret_node); + + // OK to insert, but should return error when compiling patterns + // FIXME: this one returns the inserted node object. + ret_node = r3_tree_insert_path(n, "/users/{idx:\\d{3}}/{idy:aaa}", NULL); + assert(ret_node); + + r3_tree_dump(n, NULL); + r3_tree_free(n); } END_TEST @@ -285,13 +280,13 @@ END_TEST START_TEST (test_str_array) { str_array * l = str_array_create(3); - fail_if( l == NULL ); + ck_assert(l); - fail_if( FALSE == str_array_append(l, zstrdup("abc") ) ); - fail_if( l->len != 1 ); + ck_assert(str_array_append(l, zstrdup("abc"))); + ck_assert( l->len == 1 ); - fail_if( FALSE == str_array_append(l, zstrdup("foo") ) ); - fail_if( l->len != 2 ); + ck_assert(str_array_append(l, zstrdup("foo") )); + ck_assert( l->len == 2 ); fail_if( FALSE == str_array_append(l, zstrdup("bar") ) ); fail_if( l->len != 3 ); @@ -423,14 +418,12 @@ END_TEST Suite* r3_suite (void) { - Suite *suite = suite_create("blah"); + Suite *suite = suite_create("r3 core tests"); TCase *tcase = tcase_create("testcase"); - tcase_set_timeout(tcase, 30); tcase_add_test(tcase, test_r3_node_construct_and_free); tcase_add_test(tcase, test_str_array); tcase_add_test(tcase, test_ltrim_slash); - tcase_add_test(tcase, test_r3_node_find_edge); tcase_add_test(tcase, testr3_tree_insert_pathl); tcase_add_test(tcase, test_compile); tcase_add_test(tcase, test_route_cmp); @@ -441,7 +434,6 @@ Suite* r3_suite (void) { tcase_add_test(tcase, test_pcre_patterns_insert_2); tcase_add_test(tcase, test_pcre_patterns_insert_3); tcase_add_test(tcase, test_incomplete_slug_path); - tcase_set_timeout(tcase, 30); suite_add_tcase(suite, tcase);