--- parser3/src/lib/cord/cordbscs.c 2003/09/23 12:14:00 1.2.4.2 +++ parser3/src/lib/cord/cordbscs.c 2017/12/05 22:59:58 1.14 @@ -13,11 +13,9 @@ * Author: Hans-J. Boehm (boehm@parc.xerox.com) */ /* Boehm, October 3, 1994 5:19 pm PDT */ -# include "gc.h" -# include "cord.h" -# include -# include -# include + +#include "pa_config_includes.h" +#include "include/cord.h" /* An implementation of the cord primitives. These are the only */ /* Functions that understand the representation. We perform only */ @@ -70,7 +68,6 @@ typedef union { } CordRep; # define CONCAT_HDR 1 - # define FN_HDR 4 # define SUBSTR_HDR 6 /* Substring nodes are a special case of function nodes. */ @@ -78,9 +75,20 @@ typedef union { /* structure, and the function is either CORD_apply_access_fn */ /* or CORD_index_access_fn. */ +#ifdef CORD_CAT_OPTIMIZATION + +#define CONCAT_HDR_RO 3 + +#define IS_CONCATENATION(s) ((((CordRep *)s)->generic.header & CONCAT_HDR) != 0) +#define IS_RW_CONCATENATION(s) (((CordRep *)s)->generic.header == CONCAT_HDR) + +#else + /* The following may be applied only to function and concatenation nodes: */ #define IS_CONCATENATION(s) (((CordRep *)s)->generic.header == CONCAT_HDR) +#endif + #define IS_FUNCTION(s) ((((CordRep *)s)->generic.header & FN_HDR) != 0) #define IS_SUBSTR(s) (((CordRep *)s)->generic.header == SUBSTR_HDR) @@ -98,6 +106,8 @@ typedef union { #define SHORT_LIMIT (sizeof(CordRep) - 1) /* Cords shorter than this are C strings */ +/* paf: using knowledge of interal structure to speedup */ +char CORD_nul_func(size_t i, void * client_data); /* Dump the internal representation of x to stdout, with initial */ /* indentation level n. */ @@ -111,9 +121,14 @@ void CORD_dump_inner(CORD x, unsigned n) 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]); + for (i = 0; i <= SHORT_LIMIT*1000; i++) { + if (x[i] == '\0') { putchar('!'); break; } + switch(x[i]){ + case '\n': putchar('|'); break; + case '\r': putchar('#'); break; + case '\t': putchar('@'); break; + default: putchar(x[i]); break; + } } if (x[i] != '\0') fputs("...", stdout); putchar('\n'); @@ -129,7 +144,7 @@ void CORD_dump_inner(CORD x, unsigned n) &(((CordRep *)x) -> function); if (IS_SUBSTR(x)) printf("(Substring) "); printf("Function: %p (len: %d): ", x, (int)(func -> len)); - for (i = 0; i < 20 && i < func -> len; i++) { + for (i = 0; i < 20*1000 && i < func -> len; i++) { putchar((*(func -> fn))(i, func -> client_data)); } if (i < func -> len) fputs("...", stdout); @@ -192,6 +207,7 @@ CORD CORD_cat_char_star(CORD x, const ch result_len = right_len + leny; /* length of new_right */ if (result_len <= SHORT_LIMIT) { new_right = 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'; @@ -231,14 +247,13 @@ CORD CORD_cat_char_star(CORD x, const ch } } - CORD CORD_cat(CORD x, CORD y) { register size_t result_len; register int depth; register size_t lenx; - if (x == CORD_EMPTY) return(y); + if (x == CORD_EMPTY) return(y); if (y == CORD_EMPTY) return(x); if (CORD_IS_STRING(y)) { return(CORD_cat_char_star(x, y, strlen(y))); @@ -274,7 +289,157 @@ CORD CORD_cat(CORD x, CORD y) } } +#ifdef CORD_CAT_OPTIMIZATION +void CORD_concatenation_protect(CORD x){ + if(IS_RW_CONCATENATION(x)) + ((struct Concatenation*)x)->header = CONCAT_HDR_RO; +} + +/* Optimized version to be called from parser code */ +CORD CORD_cat_char_star_optimized(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) leny=strlen(y); // PAF + if (y == 0) ABORT("CORD_cat_char_star(,y,) y==0"); // PAF + if (*y == 0) ABORT("CORD_cat_char_star(,y,) y==\"\""); // PAF + if (leny == 0) ABORT("CORD_cat_char_star(,y,) leny==0"); // PAF + + if (CORD_IS_STRING(x)) { + lenx = strlen(x); + result_len = lenx + leny; + if (result_len <= SHORT_LIMIT) { + register char * result = 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 = 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'; + + if (IS_RW_CONCATENATION(x)) { + // Optimization: instead of new Concatenation current is modified + ((CordRep *)x) -> concatenation.right=new_right; + ((CordRep *)x) -> concatenation.len += leny; + return x; + } + + 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 = 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); + } + } +} +/* Optimized version to be called from parser code */ +CORD CORD_cat_optimized(CORD x, CORD y) +{ + register size_t result_len; + register int depth; + register size_t lenx; + + if (x == CORD_EMPTY){ + CORD_concatenation_protect(y); // to guarantee y won't be modified + return(y); + } + if (y == CORD_EMPTY) return(x); + if (CORD_IS_STRING(y)) { + return(CORD_cat_char_star_optimized(x, y, strlen(y))); // optimized version is called + } else if (CORD_IS_STRING(x)) { + lenx = strlen(x); + depth = DEPTH(y) + 1; + } else { + register int depthy = DEPTH(y); + + lenx = LEN(x); + depth = DEPTH(x) + 1; + if (depthy >= depth) depth = depthy + 1; + } + result_len = lenx + LEN(y); + { + register struct Concatenation * result; + + result = GC_NEW(struct Concatenation); + if (result == 0) OUT_OF_MEMORY; + result->header = CONCAT_HDR; + result->depth = depth; +// printf("depth=%d\n", depth); + if (lenx <= MAX_LEFT_LEN) result->left_len = lenx; + result->len = result_len; + result->left = x; + result->right = y; + // PAF@design.ru bug fix: + if (depth >= MAX_DEPTH) { + return(CORD_balance((CORD)result)); + } else { + return((CORD) result); + } + } +} +#endif CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len) { @@ -312,21 +477,6 @@ CORD CORD_from_fn(CORD_fn fn, void * cli } } -CORD CORD_from_fn_gen(CORD_fn fn, void * client_data, size_t len) -{ - register struct Function * result; - if (len <= 0) return(0); - - result = GC_NEW(struct Function); - if (result == 0) OUT_OF_MEMORY; - result->header = FN_HDR; - /* depth is already 0 */ - result->len = len; - result->fn = fn; - result->client_data = client_data; - return((CORD) result); -} - size_t CORD_len(CORD x) { if (x == 0) { @@ -464,10 +614,9 @@ CORD CORD_substr_checked(CORD x, size_t } } -CORD CORD_substr(CORD x, size_t i, size_t n) +CORD CORD_substr(CORD x, size_t i, size_t n, size_t len) { - register size_t len = CORD_len(x); - + if(0 == len) len = CORD_len(x); if (i >= len || n <= 0) return(0); /* n < 0 is impossible in a correct C implementation, but */ /* quite possible under SunOS 4.X. */ @@ -484,6 +633,7 @@ CORD CORD_substr(CORD x, size_t i, size_ int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1, CORD_batched_iter_fn f2, void * client_data) { + int result; if (x == 0) return(0); if (CORD_IS_STRING(x)) { register const char* p = x+i; @@ -493,16 +643,14 @@ int CORD_iter5(CORD x, size_t i, CORD_it return((*f2)(p, client_data)); } else { while (*p) { - if ((*f1)(*p, client_data)) return(1); + if (result=(*f1)(*p, client_data)) + return result; p++; } return(0); } } else if (IS_CONCATENATION(x)) { - register struct Concatenation * conc - = &(((CordRep *)x) -> concatenation); - - + register struct Concatenation * conc = &(((CordRep *)x) -> concatenation); if (i > 0) { register size_t left_len = LEFT_LEN(conc); @@ -511,9 +659,8 @@ int CORD_iter5(CORD x, size_t i, CORD_it client_data)); } } - if (CORD_iter5(conc -> left, i, f1, f2, client_data)) { - return(1); - } + result=CORD_iter5(conc -> left, i, f1, f2, client_data); + if (result) return result; return(CORD_iter5(conc -> right, 0, f1, f2, client_data)); } else /* function */ { register struct Function * f = &(((CordRep *)x) -> function); @@ -521,46 +668,71 @@ int CORD_iter5(CORD x, size_t i, CORD_it register size_t lim = f -> len; for (j = i; j < lim; j++) { - if ((*f1)((*(f -> fn))(j, f -> client_data), client_data)) { - return(1); - } + if (result=(*f1)((*(f -> fn))(j, f -> client_data), client_data)) + return result; } return(0); } } -#define LEFT_BLOCK_LEN(c) ((c) -> left_len != 0? \ - (c) -> left_len \ - : LEN((c) -> left)) /* See cord.h for definition. We assume i is in range. */ -int CORD_block_iter(CORD x, size_t i, CORD_block_iter_fn f1, void * client_data) +int CORD_block_iter(CORD x, size_t i, CORD_block_iter_fn fb, void * client_data) { + int result; if (x == 0) return(0); - //assert(!CORD_IS_STRING(x)); - - if (IS_CONCATENATION(x)) { - register struct Concatenation * conc - = &(((CordRep *)x) -> concatenation); - register int result; + if (CORD_IS_STRING(x)) { + register const char* p = x+i; + const char *b=p; + char bc=*b; + int pc; + if (bc == '\0') ABORT("2nd arg to CORD_iter5 too big"); + do { + pc=*++p; + if(pc!=bc) { + if (result=fb(bc, p-b, client_data)) + return result; + b=p; bc=pc; + } + } while (pc); + return(0); + } else if (IS_CONCATENATION(x)) { + register struct Concatenation * conc= &(((CordRep *)x) -> concatenation); if (i > 0) { - register size_t left_len = LEFT_BLOCK_LEN(conc); + register size_t left_len = LEFT_LEN(conc); - if (i >= left_len) - return CORD_block_iter(conc -> right, i - left_len, f1, - client_data); + if (i >= left_len) { + return(CORD_block_iter(conc -> right, i - left_len, fb, client_data)); + } } - if (result=CORD_block_iter(conc -> left, i, f1, client_data)) - return result; - - return(CORD_block_iter(conc -> right, 0, f1, client_data)); - } else /* function =block */ { + result=CORD_block_iter(conc -> left, i, fb, client_data); + if (result) return result; + return(CORD_block_iter(conc -> right, 0, fb, client_data)); + } else /* function */ { register struct Function * f = &(((CordRep *)x) -> function); + register size_t lim = f -> len; - return f1((char)(unsigned long)f -> client_data, f -> len-i, client_data); + if(f->fn == CORD_nul_func ) { + if (result=fb((char)(unsigned long)f -> client_data, f -> len-i, client_data)) return result; + } else if(f->fn == CORD_apply_access_fn) { + register struct substr_args *descr = (struct substr_args *)f->client_data; + register struct Function * fn_cord = &(descr->sa_cord->function); + + if(fn_cord->fn == CORD_nul_func ) { + if (result=fb((char)(unsigned long)fn_cord->client_data, f -> len-i, client_data)) + return result; + } else + ABORT("CORD_block_iter:CORD_apply_access_fn:unknown_fn should not happen"); + } else { + if(f->fn == CORD_index_access_fn) + ABORT("CORD_block_iter:CORD_index_access_fn should not happen"); + ABORT("CORD_block_iter:unknown_fn should not happen"); + } } + return(0); } + #undef CORD_iter int CORD_iter(CORD x, CORD_iter_fn f1, void * client_data) { @@ -578,7 +750,7 @@ int CORD_riter4(CORD x, size_t i, CORD_i c = *p; if (c == '\0') ABORT("2nd arg to CORD_riter4 too big"); if ((*f1)(c, client_data)) return(1); - if (p == x) break; + if (p == (const char *)x) break; p--; } return(0);