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_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 ); r3_tree_free(n); }
/** * Return the last inserted node. */ node * _r3_tree_insert_pathl(node *tree, char *path, int path_len, route * route, void * data) { node * n = tree; edge * e = NULL; /* length of common prefix */ int prefix_len = 0; for( int i = 0 ; i < n->edge_len ; i++ ) { prefix_len = strndiff(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 ); // no common, consider insert a new edge if ( prefix_len > 0 ) { e = n->edges[i]; break; } } // branch the edge at correct position (avoid broken slugs) char *slug_s; if ( (slug_s = inside_slug(path, path_len, path + prefix_len)) != NULL ) { prefix_len = slug_s - path; } // common prefix not found, insert a new edge for this pattern if ( prefix_len == 0 ) { // there are two more slugs, we should break them into several parts if ( count_slug(path, path_len) > 1 ) { char *p = find_slug_placeholder(path, NULL); #ifdef DEBUG assert(p); #endif // find the next one p = find_slug_placeholder(p + 1, NULL); #ifdef DEBUG assert(p); #endif // insert the first one edge, and break at "p" node * child = r3_tree_create(3); r3_node_add_child(n, strndup(path, (int)(p - path)), child); // and insert the rest part to the child return _r3_tree_insert_pathl(child, p, path_len - (int)(p - path), route, data); } else { node * child = r3_tree_create(3); r3_node_add_child(n, strndup(path, path_len) , child); // info("edge not found, insert one: %s\n", path); child->data = data; child->endpoint++; if (route) { route->data = data; r3_node_append_route(child, route); } return child; } } else if ( prefix_len == e->pattern_len ) { // fully-equal to the pattern of the edge char * subpath = path + prefix_len; int subpath_len = path_len - prefix_len; // there are something more we can insert if ( subpath_len > 0 ) { return _r3_tree_insert_pathl(e->child, subpath, subpath_len, route, data); } else { // there are no more path to insert // see if there is an endpoint already if (e->child->endpoint) { // XXX: return an error code instead of NULL return NULL; } e->child->endpoint++; // make it as an endpoint e->child->data = data; if (route) { route->data = data; r3_node_append_route(e->child, route); } return e->child; } } else if ( prefix_len < e->pattern_len ) { // printf("branch the edge prefix_len: %d\n", prefix_len); /* it's partially matched with the pattern, * we should split the end point and make a branch here... */ char * s2 = path + prefix_len; int s2_len = path_len - prefix_len; r3_edge_branch(e, prefix_len); return _r3_tree_insert_pathl(e->child, s2 , s2_len, route , data); } else { printf("unexpected route."); return NULL; } return n; }
/** * Return the last inserted node. */ node * r3_tree_insert_pathl(node *tree, char *path, int path_len, route * route, void * data) { node * n = tree; edge * e = NULL; /* length of common prefix */ int offset = 0; for( int i = 0 ; i < n->edge_len ; i++ ) { offset = strndiff(path, n->edges[i]->pattern, n->edges[i]->pattern_len); // printf("offset: %d %s vs %s\n", offset, path, n->edges[i]->pattern ); // no common, consider insert a new edge if ( offset > 0 ) { e = n->edges[i]; break; } } // branch the edge at correct position (avoid broken slugs) char *slug_s = strchr(path, '{'); char *slug_e = strchr(path, '}'); if ( slug_s && slug_e ) { if ( offset > (slug_s - path) && offset < (slug_e - path) ) { // break before '{' offset = slug_s - path; } } if ( offset == 0 ) { // not found, we should just insert a whole new edge node * child = r3_tree_create(3); r3_node_add_child(n, strndup(path, path_len) , child); info("edge not found, insert one: %s\n", path); child->data = data; child->endpoint++; if (route) { route->data = data; r3_node_append_route(child, route); } return child; } else if ( offset == e->pattern_len ) { // fully-equal to the pattern of the edge char * subpath = path + offset; int subpath_len = path_len - offset; // there are something more we can insert 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 e->child->data = data; if (route) { route->data = data; r3_node_append_route(e->child, route); } return e->child; } } else if ( offset < e->pattern_len ) { // printf("branch the edge offset: %d\n", offset); /* it's partially matched with the pattern, * we should split the end point and make a branch here... */ node *c2; // child 1, child 2 edge *e2; // edge 1, edge 2 char * s2 = path + offset; int s2_len = 0; r3_edge_branch(e, offset); // here is the new edge from. c2 = r3_tree_create(3); s2_len = path_len - offset; e2 = r3_edge_create(strndup(s2, s2_len), s2_len, c2); // printf("edge right: %s\n", e2->pattern); r3_node_append_edge(e->child, e2); char *op = e->pattern; // truncate the original edge pattern e->pattern = strndup(e->pattern, offset); e->pattern_len = offset; free(op); // move n->edges to c1 c2->endpoint++; c2->data = data; if (route) { route->data = data; r3_node_append_route(c2, route); } return c2; } else { printf("unexpected route."); return NULL; } return n; }