/** * branch the edge pattern at "dl" offset, * insert a dummy child between the edges. * * * A -> [prefix..suffix] -> B * A -> [prefix] -> B -> [suffix] -> New Child (Copy Data, Edges from B) * */ node * r3_edge_branch(edge *e, int dl) { node *new_child; edge *e1; char * s1 = e->pattern + dl; int s1_len = 0; edge **tmp_edges = e->child->edges; int tmp_edge_len = e->child->edge_len; // the suffix edge of the leaf new_child = r3_tree_create(3); s1_len = e->pattern_len - dl; e1 = r3_edge_create(zstrndup(s1, s1_len), s1_len, new_child); // Migrate the child edges to the new edge we just created. for ( int i = 0 ; i < tmp_edge_len ; i++ ) { r3_node_append_edge(new_child, tmp_edges[i]); e->child->edges[i] = NULL; } e->child->edge_len = 0; new_child->endpoint = e->child->endpoint; e->child->endpoint = 0; // reset endpoint r3_node_append_edge(e->child, e1); new_child->data = e->child->data; // copy data pointer e->child->data = NULL; // truncate the original edge pattern char *op = e->pattern; e->pattern = zstrndup(e->pattern, dl); e->pattern_len = dl; return new_child; }
edge * r3_node_connectl(node * n, const char * pat, int len, int dupl, node *child) { // find the same sub-pattern, if it does not exist, create one edge * e; e = r3_node_find_edge(n, pat); if (e) { return e; } if (dupl) { pat = zstrndup(pat, len); } e = r3_edge_create(pat, len, child); r3_node_append_edge(n, e); return e; }
/* parent node, edge pattern, 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; e = r3_node_find_edge(n, pat); if (e) { return e; } e = r3_edge_create( pat, strlen(pat), child); 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; }
/** * 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; }