/* indentation level n. */ void CORD_dump_inner(CORD x, unsigned n) { size_t i; for (i = 0; i < (size_t)n; i++) { fputs(" ", stdout); } if (x == 0) { fputs("NIL\n", stdout); } else if (CORD_IS_STRING(x)) { for (i = 0; i <= SHORT_LIMIT; i++) { if (x[i] == '\0') break; putchar(x[i]); } if (x[i] != '\0') fputs("...", stdout); putchar('\n'); } else if (IS_CONCATENATION(x)) { struct Concatenation * conc = &(((CordRep *)x) -> concatenation); printf("Concatenation: %p (len: %d, depth: %d)\n", (void *)x, (int)(conc -> len), (int)(conc -> depth)); CORD_dump_inner(conc -> left, n+1); CORD_dump_inner(conc -> right, n+1); } else /* function */ { struct Function * func = &(((CordRep *)x) -> function); if (IS_SUBSTR(x)) printf("(Substring) "); printf("Function: %p (len: %d): ", (void *)x, (int)(func -> len)); for (i = 0; i < 20 && i < func -> len; i++) { putchar((*(func -> fn))(i, func -> client_data)); } if (i < func -> len) fputs("...", stdout); putchar('\n'); } }
/* See cord.h for definition. We assume i is in range. */ int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1, CORD_batched_iter_fn f2, void * client_data) { if (x == 0) return(0); if (CORD_IS_STRING(x)) { register const char *p = x+i; if (*p == '\0') ABORT("2nd arg to CORD_iter5 too big"); if (f2 != CORD_NO_FN) { return((*f2)(p, client_data)); } else { while (*p) { if ((*f1)(*p, client_data)) return(1); p++; } return(0); } } else if (IS_CONCATENATION(x)) { register struct Concatenation * conc = &(((CordRep *)x) -> concatenation); if (i > 0) { register size_t left_len = LEFT_LEN(conc); if (i >= left_len) { return(CORD_iter5(conc -> right, i - left_len, f1, f2, client_data)); } } if (CORD_iter5(conc -> left, i, f1, f2, client_data)) { return(1); } return(CORD_iter5(conc -> right, 0, f1, f2, client_data)); } else /* function */ { register struct Function * f = &(((CordRep *)x) -> function); register size_t j; register size_t lim = f -> len; for (j = i; j < lim; j++) { if ((*f1)((*(f -> fn))(j, f -> client_data), client_data)) { return(1); } } return(0); } }
/* of the final tree. */ void CORD_balance_insert(CORD x, size_t len, ForestElement * forest) { int depth; if (CORD_IS_STRING(x)) { CORD_add_forest(forest, x, len); } else if (IS_CONCATENATION(x) && ((depth = DEPTH(x)) >= MAX_DEPTH || len < min_len[depth])) { struct Concatenation * conc = &(((CordRep *)x) -> concatenation); size_t left_len = LEFT_LEN(conc); CORD_balance_insert(conc -> left, left_len, forest); CORD_balance_insert(conc -> right, len - left_len, forest); } else /* function or balanced */ { CORD_add_forest(forest, x, len); } }
int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data) { if (x == 0) return(0); if (CORD_IS_STRING(x)) { register const char *p = x + i; register char c; for(;;) { c = *p; if (c == '\0') ABORT("2nd arg to CORD_riter4 too big"); if ((*f1)(c, client_data)) return(1); if (p == x) break; p--; } return(0); } else if (IS_CONCATENATION(x)) { register struct Concatenation * conc = &(((CordRep *)x) -> concatenation); register CORD left_part = conc -> left; register size_t left_len; left_len = LEFT_LEN(conc); if (i >= left_len) { if (CORD_riter4(conc -> right, i - left_len, f1, client_data)) { return(1); } return(CORD_riter4(left_part, left_len - 1, f1, client_data)); } else { return(CORD_riter4(left_part, i, f1, client_data)); } } else /* function */ { register struct Function * f = &(((CordRep *)x) -> function); register size_t j; for (j = i; ; j--) { if ((*f1)((*(f -> fn))(j, f -> client_data), client_data)) { return(1); } if (j == 0) return(0); } } }
/* Return 0 if past the end of cord, 1 o.w. */ void CORD__extend_path(register CORD_pos p) { register struct CORD_pe * current_pe = &(p[0].path[p[0].path_len]); register CORD top = current_pe -> pe_cord; register size_t pos = p[0].cur_pos; register size_t top_pos = current_pe -> pe_start_pos; register size_t top_len = GEN_LEN(top); /* Fill in the rest of the path. */ while(!CORD_IS_STRING(top) && IS_CONCATENATION(top)) { register struct Concatenation * conc = &(((CordRep *)top) -> concatenation); register size_t left_len; left_len = LEFT_LEN(conc); current_pe++; if (pos >= top_pos + left_len) { current_pe -> pe_cord = top = conc -> right; current_pe -> pe_start_pos = top_pos = top_pos + left_len; top_len -= left_len; } else { current_pe -> pe_cord = top = conc -> left; current_pe -> pe_start_pos = top_pos; top_len = left_len; } p[0].path_len++; } /* Fill in leaf description for fast access. */ if (CORD_IS_STRING(top)) { p[0].cur_leaf = top; p[0].cur_start = top_pos; p[0].cur_end = top_pos + top_len; } else { p[0].cur_end = 0; } if (pos >= top_pos + top_len) p[0].path_len = CORD_POS_INVALID; }
/* A version of CORD_substr that assumes i >= 0, n > 0, and i + n < length(x).*/ CORD CORD_substr_checked(CORD x, size_t i, size_t n) { if (CORD_IS_STRING(x)) { if (n > SUBSTR_LIMIT) { return(CORD_substr_closure(x, i, n, CORD_index_access_fn)); } else { char * result = (char *)GC_MALLOC_ATOMIC(n + 1); if (result == 0) OUT_OF_MEMORY; strncpy(result, x+i, n); result[n] = '\0'; return(result); } } else if (IS_CONCATENATION(x)) { struct Concatenation * conc = &(((CordRep *)x) -> concatenation); size_t left_len = LEFT_LEN(conc); size_t right_len = conc -> len - left_len; if (i >= left_len) { if (n == right_len) return(conc -> right); return(CORD_substr_checked(conc -> right, i - left_len, n)); } else if (i+n <= left_len) { if (n == left_len) return(conc -> left); return(CORD_substr_checked(conc -> left, i, n)); } else { /* Need at least one character from each side. */ CORD left_part; CORD right_part; size_t left_part_len = left_len - i; if (i == 0) { left_part = conc -> left; } else { left_part = CORD_substr_checked(conc -> left, i, left_part_len); } if (i + n == right_len + left_len) { right_part = conc -> right; } else { right_part = CORD_substr_checked(conc -> right, 0, n - left_part_len); } return(CORD_cat(left_part, right_part)); } } else /* function */ { if (n > SUBSTR_LIMIT) { if (IS_SUBSTR(x)) { /* Avoid nesting substring nodes. */ struct Function * f = &(((CordRep *)x) -> function); struct substr_args *descr = (struct substr_args *)(f -> client_data); return(CORD_substr_closure((CORD)descr->sa_cord, i + descr->sa_index, n, f -> fn)); } else { return(CORD_substr_closure(x, i, n, CORD_apply_access_fn)); } } else { char * result; struct Function * f = &(((CordRep *)x) -> function); char buf[SUBSTR_LIMIT+1]; char * p = buf; size_t j; size_t lim = i + n; for (j = i; j < lim; j++) { char c = (*(f -> fn))(j, f -> client_data); if (c == '\0') { return(CORD_substr_closure(x, i, n, CORD_apply_access_fn)); } *p++ = c; } result = (char *)GC_MALLOC_ATOMIC(n + 1); if (result == 0) OUT_OF_MEMORY; memcpy(result, buf, n); result[n] = '\0'; return(result); } } }
CORD CORD_cat_char_star(CORD x, const char * y, size_t leny) { size_t result_len; size_t lenx; int depth; if (x == CORD_EMPTY) return(y); if (leny == 0) return(x); if (CORD_IS_STRING(x)) { lenx = strlen(x); result_len = lenx + leny; if (result_len <= SHORT_LIMIT) { char * result = (char *)GC_MALLOC_ATOMIC(result_len + 1); if (result == 0) OUT_OF_MEMORY; # ifdef LINT2 memcpy(result, x, lenx + 1); # else memcpy(result, x, lenx); /* No need to copy the terminating zero */ /* as result[lenx] is written below. */ # endif memcpy(result + lenx, y, leny); result[result_len] = '\0'; return((CORD) result); } else { depth = 1; } } else { CORD right; CORD left; char * new_right; lenx = LEN(x); if (leny <= SHORT_LIMIT/2 && IS_CONCATENATION(x) && CORD_IS_STRING(right = ((CordRep *)x) -> concatenation.right)) { size_t right_len; /* Merge y into right part of x. */ if (!CORD_IS_STRING(left = ((CordRep *)x) -> concatenation.left)) { right_len = lenx - LEN(left); } else if (((CordRep *)x) -> concatenation.left_len != 0) { right_len = lenx - ((CordRep *)x) -> concatenation.left_len; } else { right_len = strlen(right); } result_len = right_len + leny; /* length of new_right */ if (result_len <= SHORT_LIMIT) { new_right = (char *)GC_MALLOC_ATOMIC(result_len + 1); if (new_right == 0) OUT_OF_MEMORY; memcpy(new_right, right, right_len); memcpy(new_right + right_len, y, leny); new_right[result_len] = '\0'; y = new_right; leny = result_len; x = left; lenx -= right_len; /* Now fall through to concatenate the two pieces: */ } if (CORD_IS_STRING(x)) { depth = 1; } else { depth = DEPTH(x) + 1; } } else { depth = DEPTH(x) + 1; } result_len = lenx + leny; } { /* The general case; lenx, result_len is known: */ struct Concatenation * result = GC_NEW(struct Concatenation); if (NULL == result) OUT_OF_MEMORY; result->header = CONCAT_HDR; result->depth = (char)depth; if (lenx <= MAX_LEFT_LEN) result->left_len = (unsigned char)lenx; result->len = (word)result_len; result->left = x; GC_PTR_STORE_AND_DIRTY((void *)&result->right, y); GC_reachable_here(x); if (depth >= MAX_DEPTH) { return(CORD_balance((CORD)result)); } else { return((CORD) result); } } }
CORD CORD_cat_char_star(CORD x, const char * y, size_t leny) { register size_t result_len; register size_t lenx; register int depth; if (x == CORD_EMPTY) return(y); if (leny == 0) return(x); if (CORD_IS_STRING(x)) { lenx = strlen(x); result_len = lenx + leny; if (result_len <= SHORT_LIMIT) { register char * result = MK_GC_MALLOC_ATOMIC(result_len+1); if (result == 0) OUT_OF_MEMORY; memcpy(result, x, lenx); memcpy(result + lenx, y, leny); result[result_len] = '\0'; return((CORD) result); } else { depth = 1; } } else { register CORD right; register CORD left; register char * new_right; register size_t right_len; lenx = LEN(x); if (leny <= SHORT_LIMIT/2 && IS_CONCATENATION(x) && CORD_IS_STRING(right = ((CordRep *)x) -> concatenation.right)) { /* Merge y into right part of x. */ if (!CORD_IS_STRING(left = ((CordRep *)x) -> concatenation.left)) { right_len = lenx - LEN(left); } else if (((CordRep *)x) -> concatenation.left_len != 0) { right_len = lenx - ((CordRep *)x) -> concatenation.left_len; } else { right_len = strlen(right); } result_len = right_len + leny; /* length of new_right */ if (result_len <= SHORT_LIMIT) { new_right = MK_GC_MALLOC_ATOMIC(result_len + 1); if (new_right == 0) OUT_OF_MEMORY; memcpy(new_right, right, right_len); memcpy(new_right + right_len, y, leny); new_right[result_len] = '\0'; y = new_right; leny = result_len; x = left; lenx -= right_len; /* Now fall through to concatenate the two pieces: */ } if (CORD_IS_STRING(x)) { depth = 1; } else { depth = DEPTH(x) + 1; } } else { depth = DEPTH(x) + 1; } result_len = lenx + leny; } { /* The general case; lenx, result_len is known: */ register struct Concatenation * result; result = MK_GC_NEW(struct Concatenation); if (result == 0) OUT_OF_MEMORY; result->header = CONCAT_HDR; result->depth = depth; if (lenx <= MAX_LEFT_LEN) result->left_len = lenx; result->len = result_len; result->left = x; result->right = y; if (depth >= MAX_DEPTH) { return(CORD_balance((CORD)result)); } else { return((CORD) result); } } }