/* {{{ php_tmpl_load_path */ void php_tmpl_load_path(zval** dest, char* local, int local_len, zval* global) { char *buf; int buf_len; register char *p, *q; if(local_len && local[0] == '/') { buf = (char*)emalloc(local_len + 1); memcpy(buf, local, local_len+1); buf_len = local_len; } else { buf = (char*)emalloc(local_len + ZL(global) + 2); memcpy(buf, ZV(global), ZL(global)); buf[ZL(global)] = '/'; memcpy(buf + 1 + ZL(global), local, local_len+1); buf_len = local_len + 1 + ZL(global); } while((p = strstr(buf, "//"))) { for(q = p+1; *q; q++) *(q-1) = *q; *(q-1) = 0; --buf_len; } /* check for `..` in the path */ /* first, remove path elements to the left of `..` */ for(p = buf; p <= (buf+buf_len-3); p++) { if(memcmp(p, "/..", 3) != 0 || (*(p+3) != '/' && *(p+3) != 0)) continue; for(q = p-1; q >= buf && *q != '/'; q--, buf_len--); --buf_len; if(*q == '/') { p += 3; while(*p) *(q++) = *(p++); *q = 0; buf_len -= 3; p = buf; } } /* second, clear all `..` in the begining of the path because `/../` = `/` */ while(buf_len > 2 && memcmp(buf, "/..", 3) == 0) { for(p = buf+3; *p; p++) *(p-3) = *p; *(p-3) = 0; buf_len -= 3; } /* clear `/` at the end of the path */ while(buf_len > 1 && buf[buf_len-1] == '/') buf[--buf_len] = 0; if(!buf_len) { memcpy(buf, "/", 2); buf_len = 1; } for(p=buf; *p; p++) *p = tolower(*p); zval_dtor(*dest); ZVAL_STRINGL(*dest, buf, buf_len, 0); }
/* {{{ php_tmpl_parse_check_memory */ inline void php_tmpl_parse_check_memory(t_template* tmpl, HashPosition *dup_tag_pos, t_tmpl_tag* tag, uint tag_mod, zval** iteration, zval** dest, uint* offset) { zval **dup_ztag; t_tmpl_tag *dup_tag; if(NULL == *dup_tag_pos || !zend_hash_num_elements(Z_ARRVAL_P(tmpl->dup_tag))) return; /* The next line has been added to avoid skiping of duplicate tags in some circumstances. This is sort of a dirty fix and needs to be optimized for speed. */ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(tmpl->dup_tag), dup_tag_pos); do { if(FAILURE == zend_hash_get_current_data_ex(Z_ARRVAL_P(tmpl->dup_tag), (void*)&dup_ztag, dup_tag_pos)) break; dup_tag = Z_TMPL_TAG(dup_ztag); if(*offset > dup_tag->loff) continue; if(TMPL_TAG == tag_mod) { if(dup_tag->ctx != tag->ctx && dup_tag->loff < tag->loff) continue; if(dup_tag->ctx != tag->ctx || dup_tag->loff >= tag->loff) break; } else { if(dup_tag->ctx != tag && dup_tag->loff < tag->roff) continue; if(dup_tag->ctx != tag || dup_tag->loff > tag->roff) break; } TMPL_PARSE_DEST_ADD(*offset, dup_tag->loff - *offset); *offset = dup_tag->roff; if(FAILURE == zend_hash_find(Z_ARRVAL_PP(iteration), ZV(dup_tag->name), ZL(dup_tag->name)+1, (void*)&dup_ztag)) continue; TMPL_PARSE_DEST_ADD(Z_STRVAL_PP(dup_ztag)-Z_STRVAL_P(tmpl->original), Z_STRLEN_PP(dup_ztag)); } while(SUCCESS == zend_hash_move_forward_ex(Z_ARRVAL_P(tmpl->dup_tag), dup_tag_pos)); }
/* {{{ php_tmpl_line_num Returns line number in template. Used in error messages. */ ulong php_tmpl_line_num(t_template* tmpl, char* ptr) { ulong line_num; char *p; p = ZV(tmpl->original); if(ptr < p || ptr > (p + ZL(tmpl->original))) return 0; for(line_num = 1; p < ptr; p++) if(*p == '\n') line_num++; return line_num; }
/* {{{ php_tmpl_pre_parse_search */ inline void php_tmpl_pre_parse_search(t_template* tmpl, ulong_pair** point, const short typ, uchar* buf, ulong len) { register ulong i, j, k, shift; register ulong cmp; ulong bmBc[256]; if(ZL(tmpl->original) < (int)len) return; /* Using "Tuned Boyer-Moore" searching algorythm */ /* Preprocessing */ for(i=0; i < 256; ++i) bmBc[i] = len; for(i=0; i < len-1; ++i) bmBc[buf[i]] = len - i - 1; shift = bmBc[ buf[len-1] ]; bmBc[ buf[len-1] ] = 0; memset(ZV(tmpl->original) + ZL(tmpl->original), buf[len-1], len); /* Searching */ j = 0; while(j < (ulong)ZL(tmpl->original)) { k = bmBc[ ZV(tmpl->original)[j + len - 1] ]; while(k != 0) { j += k; k = bmBc[ ZV(tmpl->original)[j + len - 1] ]; j += k; k = bmBc[ ZV(tmpl->original)[j + len - 1] ]; j += k; k = bmBc[ ZV(tmpl->original)[j + len - 1] ]; } if(/* memcmp(buf, ZV(tmpl->original) + j, len-1) == 0 && */ j < (ulong)ZL(tmpl->original) && (((tmpl->config_start || tmpl->config_end) && (j < tmpl->config_start || j > tmpl->config_end)) || (!tmpl->config_start && !tmpl->config_end))) { for(cmp = 0; cmp < len; cmp++) if(tolower(buf[cmp]) != tolower(ZV(tmpl->original)[j+cmp])) break; if(cmp == len) { PAIR_CHECK(*point); (*point)[++((*point)[0].r)].l = j; (*point)[(*point)[0].r].r = typ; } } j += shift; } }
/* {{{ php_tmpl_set */ int php_tmpl_set(t_template* tmpl, zval* path, zval** data) { zval **iteration, *cp_data, **ztag; t_tmpl_tag *tag; char *p; if(FAILURE == zend_hash_find(Z_ARRVAL_P(tmpl->tags), ZV(path), ZL(path)+1, (void*)&ztag)) { /* php_error(E_NOTICE, "Can't set value for tag/context \"%s\" which doesn't exist", ZV(path)); */ return FAILURE; } tag = Z_TMPL_TAG(ztag); if(TMPL_TAG == tag->typ) { if((iteration = (zval**)php_tmpl_get_iteration(tmpl, path, TMPL_ITERATION_CURRENT)) == NULL) { return FAILURE; } } else { for(p = ZV(path)+ZL(path); p >= ZV(path) && *p != '/'; p--); *(p > ZV(path) ? p++ : ++p) = 0; ZL(path) = strlen(ZV(path)); if((iteration = (zval**)php_tmpl_get_iteration(tmpl, path, TMPL_ITERATION_CURRENT)) == NULL) { return FAILURE; } } convert_to_string_ex(data); MAKE_STD_ZVAL(cp_data); ZVAL_STRINGL(cp_data, Z_STRVAL_PP(data), Z_STRLEN_PP(data), 1); if(SUCCESS == zend_hash_find(Z_ARRVAL_PP(iteration), ZV(tag->name), ZL(tag->name)+1, (void*)&ztag)) { if(IS_ARRAY == Z_TYPE_PP(ztag)) { /* MEMORY LEAK CAUSED BY THE NEXT LINE !!! */ zend_hash_del(Z_ARRVAL_PP(iteration), ZV(tag->name), ZL(tag->name)+1); } else { tmpl->size -= (Z_STRLEN_PP(ztag) * tag->tag_num); } } zend_hash_update(Z_ARRVAL_PP(iteration), ZV(tag->name), ZL(tag->name)+1, (void*)&cp_data, sizeof(zval**), NULL); tmpl->size += (ZL(cp_data) * tag->tag_num); return SUCCESS; }
short int php_tmpl_pre_parse_config(t_template* tmpl) { zval *zparam; char *nam, *val; uint nam_len, val_len; uchar quote; register char *p; register char *start; nam = (char*)emalloc(TMPL_MAX_TAG_LEN); nam_len = 0; val = (char*)emalloc(TMPL_MAX_TAG_LEN); val_len = 0; MAKE_STD_ZVAL(zparam); array_init(zparam); sprintf(nam, "<%s", TMPL_CONFIG_TAG_NAME); nam_len = strlen(nam); if(!(p = strstrl_ex(ZV(tmpl->original), ZL(tmpl->original), nam, nam_len))) { TMPL_PRE_PARSE_CONFIG_CLEANUP; return SUCCESS; } start = p; p += nam_len; while(1) { /* skip delimiters and check for end of the tag */ while(*p && '>' != *p && IS_DELIM(*p)) p++; if(!(*p) || '>' == *p) { /* end of tag */ if('>' == *p) { /* hide this tag from result output */ for(++p; *p;) *(start++) = *(++p); *start = 0; ZL(tmpl->original) -= (p-start); } break; } /* get parameter name */ for(nam_len=0; *p && nam_len < TMPL_MAX_TAG_LEN && !IS_DELIM(*p) && '=' != *p; p++) nam[nam_len++] = *p; if(!(*p)) break; else nam[nam_len] = 0; if('=' != *p) { php_error(E_ERROR, "Invalid configuration tag parameter in template (line:%d)", php_tmpl_line_num(tmpl, p)); TMPL_PRE_PARSE_CONFIG_CLEANUP; return FAILURE; } /* check if the value is quoted and get the value */ p++; quote = IS_QUOTE(*p) ? *(p++) : 0; for(val_len=0; *p && val_len < TMPL_MAX_TAG_LEN && quote ? quote != *p : !IS_DELIM(*p); p++) val[val_len++] = *p; if(!(*p)) break; else val[val_len] = 0; if(quote && quote != *p) { php_error(E_ERROR, "Invalid parameter value in configuration tag in template (line:%d)", php_tmpl_line_num(tmpl, p)); TMPL_PRE_PARSE_CONFIG_CLEANUP; return FAILURE; } if(quote) p++; add_assoc_stringl(zparam, nam, val, val_len, 1); } php_tmpl_process_param_array(tmpl, zparam); TMPL_PRE_PARSE_CONFIG_CLEANUP; return SUCCESS; }
int php_tmpl_parse(zval** dest, t_template* tmpl, zval* path, HashPosition* pos, zval** data) { uint tag_num; int i; zval **ztag; t_tmpl_tag *tag, *ctx; char *buf; ulong buf_alloc; zval *new_path; zval **tag_data; HashPosition cur_pos, saved_pos, dup_tag_pos; uint offset; unsigned short need_skip; zval **iteration; char *key_tag_key; uint key_tag_len; ulong key_tag_index; /* Initialize variables */ buf_alloc = TMPL_MAX_TAG_LEN; buf = (char*)emalloc(buf_alloc); MAKE_STD_ZVAL(new_path); ZVAL_STRINGL(new_path, buf, 0, 0); dup_tag_pos = NULL; /* Get the context's info from tags array */ if(!pos) { /* This is not a recursion call. Look for the context's last non-empty iteration */ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(tmpl->tags), &cur_pos); i = 0; /* we'll set this flag when found the context */ do { if(HASH_KEY_IS_STRING != zend_hash_get_current_key_ex(Z_ARRVAL_P(tmpl->tags), &key_tag_key, &key_tag_len, &key_tag_index, 0, &cur_pos)) break; if(SUCCESS != zend_hash_get_current_data_ex(Z_ARRVAL_P(tmpl->tags), (void**)&ztag, &cur_pos)) break; tag = ctx = (t_tmpl_tag*)Z_STRVAL_PP(ztag); if(TMPL_CONTEXT != ctx->typ) continue; /* get out of the loop if we're inside of the context we need */ if((uint)ZL(path) == key_tag_len-1 && !memcmp(ZV(path), key_tag_key, ZL(path))) { i = 1; break; } } while(SUCCESS == zend_hash_move_forward_ex(Z_ARRVAL_P(tmpl->tags), &cur_pos)); if(!i) { TMPL_PARSE_CLEANUP; return FAILURE; } tag_data = php_tmpl_get_iteration(tmpl, path, TMPL_ITERATION_PARENT); } else { cur_pos = *pos; tag = ctx = (t_tmpl_tag*)Z_STRVAL_PP((zval**)(cur_pos->pData)); tag_data = data; } saved_pos = cur_pos; /* Check all iterations in the opened context */ zend_hash_internal_pointer_reset(Z_ARRVAL_PP(tag_data)); do { if(FAILURE == zend_hash_get_current_data(Z_ARRVAL_PP(tag_data), (void*)&iteration)) break; /* Uncomment the following line to avoid parsing of empty iterations */ /* if(pos && !zend_hash_num_elements(Z_ARRVAL_PP(iteration))) break; */ /* Initialize the offset from the template's content begining */ offset = (1 == ZL(ctx->name) && '/' == ZV(ctx->name)[0]) ? 0 : ctx->loff + ZL(tmpl->ctx_ol) + ZL(ctx->name) + ZL(tmpl->ctx_or); /* We only need tags which are inside of the context */ cur_pos = saved_pos; for(tag_num = 0; tag_num < ctx->tag_num; tag_num++) { if(FAILURE == zend_hash_move_forward_ex(Z_ARRVAL_P(tmpl->tags), &cur_pos)) break; if(FAILURE == zend_hash_get_current_data_ex(Z_ARRVAL_P(tmpl->tags), (void**)&ztag, &cur_pos)) break; tag = (t_tmpl_tag*)Z_STRVAL_PP(ztag); if(NULL == dup_tag_pos && zend_hash_num_elements(Z_ARRVAL_P(tmpl->dup_tag))) { zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(tmpl->dup_tag), &dup_tag_pos); do { if(FAILURE == zend_hash_get_current_data_ex(Z_ARRVAL_P(tmpl->dup_tag), (void**)&ztag, &dup_tag_pos)) break; } while(Z_TMPL_TAG(ztag)->loff < offset && SUCCESS == zend_hash_move_forward_ex(Z_ARRVAL_P(tmpl->dup_tag), &dup_tag_pos)); } php_tmpl_parse_check_memory(tmpl, &dup_tag_pos, tag, TMPL_TAG, iteration, dest, &offset); TMPL_PARSE_DEST_ADD(offset, tag->loff - offset); offset = tag->roff; need_skip = (FAILURE == zend_hash_find(Z_ARRVAL_PP(iteration), ZV(tag->name), ZL(tag->name)+1, (void*)&ztag)); if(!need_skip) { if(TMPL_CONTEXT == tag->typ && IS_ARRAY == Z_TYPE_PP(ztag)) { /* Processing a context */ /* Make a recursive call */ if(buf_alloc <= (unsigned)(ZL(path)+1+ZL(tag->name)+1)) { while(buf_alloc <= (unsigned)(ZL(path)+1+ZL(tag->name)+1)) buf_alloc <<= 1; (char*)ZV(new_path) = erealloc(ZV(new_path), buf_alloc); } sprintf(ZV(new_path), (1 == ZL(path) && '/' == ZV(path)[0]) ? "%s%s" : "%s/%s", ZV(path), ZV(tag->name)); ZL(new_path) = ZL(path) + ZL(tag->name) + ((1 == ZL(path) && '/' == ZV(path)[0]) ? 0 : 1); php_tmpl_parse(dest, tmpl, new_path, &cur_pos, ztag); } else { /* Processing a tag */ TMPL_PARSE_DEST_ADD(Z_STRVAL_PP(ztag)-Z_STRVAL_P(tmpl->original), Z_STRLEN_PP(ztag)); if(TMPL_CONTEXT == tag->typ) need_skip = 1; } } if(need_skip && TMPL_CONTEXT == tag->typ) { for(i=0; i < (int)tag->tag_num; i++) { if(FAILURE == zend_hash_move_forward_ex(Z_ARRVAL_P(tmpl->tags), &cur_pos)) break; if(FAILURE == zend_hash_get_current_data_ex(Z_ARRVAL_P(tmpl->tags), (void**)&ztag, &cur_pos)) break; i -= (TMPL_CONTEXT == Z_TMPL_TAG(ztag)->typ) ? Z_TMPL_TAG(ztag)->tag_num : 0; } } } php_tmpl_parse_check_memory(tmpl, &dup_tag_pos, ctx, TMPL_CONTEXT, iteration, dest, &offset); if(1 != ZL(path) || '/' != ZV(path)[0]) { TMPL_PARSE_DEST_ADD(offset, ctx->roff - offset - ZL(tmpl->ctx_cl) - ZL(ctx->name)*(ZL(tmpl->ctx_cr)?1:0) - ZL(tmpl->ctx_cr)); } else { TMPL_PARSE_DEST_ADD(offset, ZL(tmpl->original)-offset); } } while(SUCCESS == zend_hash_move_forward(Z_ARRVAL_PP(tag_data))); if(pos) *pos = cur_pos; TMPL_PARSE_CLEANUP; return SUCCESS; }
short int php_tmpl_pre_parse(t_template* tmpl) { ulong_pair *point; register uchar *p; uchar *buf; uint buf_len, buf_alloc, buf_this; uint i, j, len, close_idx; t_tmpl_tag *tag, *context; zval **ztag; if(FAILURE == php_tmpl_pre_parse_config(tmpl)) return FAILURE; /* Initialize variables */ PAIR_INIT(point); buf_alloc = TMPL_MAX_TAG_LEN+4; buf = (uchar*)emalloc(buf_alloc); /* Searching algorythm will require larger buffer */ (char*)ZV(tmpl->original) = erealloc(ZV(tmpl->original), ZL(tmpl->original) + MAX( ZL(tmpl->tag_left), MAX( ZL(tmpl->tag_right), MAX( ZL(tmpl->ctx_ol), MAX( ZL(tmpl->ctx_or), MAX( ZL(tmpl->ctx_cl), ZL(tmpl->ctx_cr) ) ) ) ) ) ); /* Obtain positions of all tags and contexts */ php_tmpl_pre_parse_search(tmpl, &point, TMPL_TAG, ZV(tmpl->tag_left), ZL(tmpl->tag_left)); php_tmpl_pre_parse_search(tmpl, &point, TMPL_TAG_END, ZV(tmpl->tag_right), ZL(tmpl->tag_right)); php_tmpl_pre_parse_search(tmpl, &point, TMPL_CONTEXT_OPEN_LEFT, ZV(tmpl->ctx_ol), ZL(tmpl->ctx_ol)); php_tmpl_pre_parse_search(tmpl, &point, TMPL_CONTEXT_OPEN_RIGHT, ZV(tmpl->ctx_or), ZL(tmpl->ctx_or)); php_tmpl_pre_parse_search(tmpl, &point, TMPL_CONTEXT_CLOSE_LEFT, ZV(tmpl->ctx_cl), ZL(tmpl->ctx_cl)); if(ZL(tmpl->ctx_cr)) php_tmpl_pre_parse_search(tmpl, &point, TMPL_CONTEXT_CLOSE_RIGHT, ZV(tmpl->ctx_cr), ZL(tmpl->ctx_cr)); if(0 == point[0].r) { TMPL_PRE_PARSE_CLEANUP; return SUCCESS; } qsort(&point[1], point[0].r, sizeof(ulong_pair), ULONG_PAIR_COMPARE); strcpy(buf, "/"); buf_len = buf_this = 1; /* Add root context */ TAG_INIT(tag); tag->loff = 0; tag->roff = ZL(tmpl->original); tag->typ = TMPL_CONTEXT; ZVAL_STRINGL(tag->name, "/", 1, 1); add_assoc_stringl(tmpl->tags, buf, (char*)tag, sizeof(t_tmpl_tag), 0); context = tag; context->size = ZL(tmpl->original); /* Pre parse template */ for(i=1; i <= point[0].r; i++) { switch(point[i].r) { case TMPL_TAG: p = ZV(tmpl->original) + point[i].l + ZL(tmpl->tag_left); TMPL_PRE_PARSE_GET_LEN(TMPL_TAG_END, ZL(tmpl->tag_left)); if(buf_alloc < buf_len+len+1) { while(buf_alloc < buf_len+len+1) buf_alloc += TMPL_MAX_TAG_LEN; buf = (char*)erealloc(buf, buf_alloc); } if(buf_len > 1) buf[buf_len++] = '/'; for(j=0; j < len; j++) buf[buf_len++] = tolower(*(p-len+j)); buf[buf_len] = 0; TAG_INIT(tag); tag->loff = point[i].l; tag->roff = point[close_idx].l + ZL(tmpl->tag_right); tag->size = (tag->roff - tag->loff); tag->typ = TMPL_TAG; tag->tag_num = 1; tag->ctx = context; ZVAL_STRINGL(tag->name, buf+buf_len-len, len, 1); if(FAILURE == zend_hash_find(Z_ARRVAL_P(tmpl->tags), buf, buf_len+1, (void*)&ztag)) { /* There's no the tag defined in the current context. Creating one */ add_assoc_stringl(tmpl->tags, buf, (char*)tag, sizeof(t_tmpl_tag), 0); context->tag_num++; } else { /* add another instance of the tag in the same context */ (Z_TMPL_TAG(ztag)->tag_num)++; add_next_index_stringl(tmpl->dup_tag, (char*)tag, sizeof(t_tmpl_tag), 0); } context->size -= tag->size; while(buf_len > 1 && buf[buf_len-1] != '/') buf[--buf_len] = 0; if(buf_len > 1) buf[--buf_len] = 0; i = close_idx; break; case TMPL_CONTEXT_OPEN_LEFT: p = ZV(tmpl->original) + point[i].l + ZL(tmpl->ctx_ol); TMPL_PRE_PARSE_GET_LEN(TMPL_CONTEXT_OPEN_RIGHT, ZL(tmpl->ctx_ol)); if(buf_alloc < buf_len+len+1) { while(buf_alloc < buf_len+len+1) buf_alloc += TMPL_MAX_TAG_LEN; buf = (char*)erealloc(buf, buf_alloc); } if(buf_len > 1) buf[buf_len++] = '/'; buf_this = buf_len; for(j=0; j < len; j++) buf[buf_len++] = tolower(*(p-len+j)); buf[buf_len] = 0; if(SUCCESS == zend_hash_find(Z_ARRVAL_P(tmpl->tags), buf, buf_len+1, (void*)&ztag)) { php_error(E_ERROR, "Duplicate context \"%s\" in template (line: %d)", buf, php_tmpl_line_num(tmpl, p)); TMPL_PRE_PARSE_CLEANUP; return FAILURE; } TAG_INIT(tag); tag->loff = point[i].l; tag->typ = TMPL_CONTEXT; tag->ctx = context; ZVAL_STRINGL(tag->name, buf+buf_len-len, len, 1); add_assoc_stringl(tmpl->tags, buf, (char*)tag, sizeof(t_tmpl_tag), 0); context->tag_num++; context = tag; i = close_idx; break; case TMPL_CONTEXT_CLOSE_LEFT: p = ZV(tmpl->original) + point[i].l + ZL(tmpl->ctx_cl); if(ZL(tmpl->ctx_cr)) { TMPL_PRE_PARSE_GET_LEN(TMPL_CONTEXT_CLOSE_RIGHT, ZL(tmpl->ctx_cl)); for(j=0; j < len; j++) if(buf[buf_this+j] != tolower(*(p-len+j))) break; if(j < len) continue; } tag = context; tag->roff = ZL(tmpl->ctx_cr) ? point[close_idx].l + ZL(tmpl->ctx_cr) : point[i].l + ZL(tmpl->ctx_cl); tag->size += (tag->roff - tag->loff); while(buf_len > 1 && buf[buf_len-1] != '/') buf[--buf_len] = 0; if(buf_len > 1) buf[--buf_len] = 0; buf_this = buf_len; while(buf_this > 1 && buf[buf_this-1] != '/') --buf_this; if(FAILURE == zend_hash_find(Z_ARRVAL_P(tmpl->tags), buf, buf_len+1, (void*)&ztag)) { php_error(E_ERROR, "Can't find parent context in template. You should not see this message"); TMPL_PRE_PARSE_CLEANUP; return FAILURE; } context = (t_tmpl_tag*)Z_STRVAL_PP(ztag); context->size -= tag->size; if(ZL(tmpl->ctx_cr)) i = close_idx; break; } } if(buf_len != 1) { php_error(E_ERROR, "Can't continue with an unterminated context \"%s\" in template (line:%d)", buf, php_tmpl_line_num(tmpl, ZV(tmpl->original) + context->loff)); TMPL_PRE_PARSE_CLEANUP; return FAILURE; } tmpl->size = context->size; TMPL_PRE_PARSE_CLEANUP; return SUCCESS; }
inline void ReformHermitianMatrix ( UpperOrLower uplo, DistMatrix<R,MC,MR>& A, const DistMatrix<R,VR,STAR>& w, const DistMatrix<R,MC,MR>& Z, const RealFunctor& f ) { #ifndef RELEASE PushCallStack("hermitian_function::ReformHermitianMatrix"); #endif const Grid& g = A.Grid(); DistMatrix<R,MC,MR> ZL(g), ZR(g), Z0(g), Z1(g), Z2(g); DistMatrix<R,VR,STAR> wT(g), w0(g), wB(g), w1(g), w2(g); DistMatrix<R,MC, STAR> Z1_MC_STAR(g); DistMatrix<R,VR, STAR> Z1_VR_STAR(g); DistMatrix<R,STAR,MR > Z1Trans_STAR_MR(g); DistMatrix<R,STAR,STAR> w1_STAR_STAR(g); if( uplo == LOWER ) MakeTrapezoidal( LEFT, UPPER, 1, A ); else MakeTrapezoidal( LEFT, LOWER, -1, A ); LockedPartitionRight( Z, ZL, ZR, 0 ); LockedPartitionDown ( w, wT, wB, 0 ); while( ZL.Width() < Z.Width() ) { LockedRepartitionRight ( ZL, /**/ ZR, Z0, /**/ Z1, Z2 ); LockedRepartitionDown ( wT, w0, /**/ /**/ w1, wB, w2 ); Z1_MC_STAR.AlignWith( A ); Z1_VR_STAR.AlignWith( A ); Z1Trans_STAR_MR.AlignWith( A ); //--------------------------------------------------------------------// Z1_MC_STAR = Z1; Z1_VR_STAR = Z1_MC_STAR; w1_STAR_STAR = w1; // Scale Z1[VR,* ] with the modified eigenvalues const int width = Z1_VR_STAR.Width(); const int localHeight = Z1_VR_STAR.LocalHeight(); for( int j=0; j<width; ++j ) { const R omega = f(w1_STAR_STAR.GetLocalEntry(j,0)); R* buffer = Z1_VR_STAR.LocalBuffer(0,j); for( int iLocal=0; iLocal<localHeight; ++iLocal ) buffer[iLocal] *= omega; } Z1Trans_STAR_MR.TransposeFrom( Z1_VR_STAR ); internal::LocalTrrk( uplo, (R)1, Z1_MC_STAR, Z1Trans_STAR_MR, (R)1, A ); //--------------------------------------------------------------------// Z1Trans_STAR_MR.FreeAlignments(); Z1_VR_STAR.FreeAlignments(); Z1_MC_STAR.FreeAlignments(); SlideLockedPartitionDown ( wT, w0, w1, /**/ /**/ wB, w2 ); SlideLockedPartitionRight ( ZL, /**/ ZR, Z0, Z1, /**/ Z2 ); } #ifndef RELEASE PopCallStack(); #endif }
inline void ReformNormalMatrix ( DistMatrix<Complex<R>,MC,MR >& A, const DistMatrix<R, VR,STAR>& w, const DistMatrix<Complex<R>,MC,MR >& Z, const ComplexFunctor& f ) { #ifndef RELEASE PushCallStack("hermitian_function::ReformNormalMatrix"); #endif const Grid& g = A.Grid(); typedef Complex<R> C; DistMatrix<C,MC,MR> ZL(g), ZR(g), Z0(g), Z1(g), Z2(g); DistMatrix<R,VR,STAR> wT(g), w0(g), wB(g), w1(g), w2(g); DistMatrix<C,MC, STAR> Z1_MC_STAR(g); DistMatrix<C,VR, STAR> Z1_VR_STAR(g); DistMatrix<C,STAR,MR > Z1Adj_STAR_MR(g); DistMatrix<R,STAR,STAR> w1_STAR_STAR(g); Zero( A ); LockedPartitionRight( Z, ZL, ZR, 0 ); LockedPartitionDown ( w, wT, wB, 0 ); while( ZL.Width() < Z.Width() ) { LockedRepartitionRight ( ZL, /**/ ZR, Z0, /**/ Z1, Z2 ); LockedRepartitionDown ( wT, w0, /**/ /**/ w1, wB, w2 ); Z1_MC_STAR.AlignWith( A ); Z1_VR_STAR.AlignWith( A ); Z1Adj_STAR_MR.AlignWith( A ); //--------------------------------------------------------------------// Z1_MC_STAR = Z1; Z1_VR_STAR = Z1_MC_STAR; w1_STAR_STAR = w1; // Scale Z1[VR,* ] with the modified eigenvalues const int width = Z1_VR_STAR.Width(); const int localHeight = Z1_VR_STAR.LocalHeight(); for( int j=0; j<width; ++j ) { const C conjOmega = Conj(f(w1_STAR_STAR.GetLocalEntry(j,0))); C* buffer = Z1_VR_STAR.LocalBuffer(0,j); for( int iLocal=0; iLocal<localHeight; ++iLocal ) buffer[iLocal] *= conjOmega; } Z1Adj_STAR_MR.AdjointFrom( Z1_VR_STAR ); internal::LocalGemm ( NORMAL, NORMAL, (C)1, Z1_MC_STAR, Z1Adj_STAR_MR, (C)1, A ); //--------------------------------------------------------------------// Z1Adj_STAR_MR.FreeAlignments(); Z1_VR_STAR.FreeAlignments(); Z1_MC_STAR.FreeAlignments(); SlideLockedPartitionDown ( wT, w0, w1, /**/ /**/ wB, w2 ); SlideLockedPartitionRight ( ZL, /**/ ZR, Z0, Z1, /**/ Z2 ); } #ifndef RELEASE PopCallStack(); #endif }
inline void HermitianFromEVD ( UpperOrLower uplo, DistMatrix<F>& A, const DistMatrix<BASE(F),VR,STAR>& w, const DistMatrix<F>& Z ) { #ifndef RELEASE CallStackEntry entry("HermitianFromEVD"); #endif const Grid& g = A.Grid(); typedef BASE(F) R; DistMatrix<F> ZL(g), ZR(g), Z0(g), Z1(g), Z2(g); DistMatrix<R,VR,STAR> wT(g), w0(g), wB(g), w1(g), w2(g); DistMatrix<F,MC, STAR> Z1_MC_STAR(g); DistMatrix<F,VR, STAR> Z1_VR_STAR(g); DistMatrix<F,STAR,MR > Z1Adj_STAR_MR(g); DistMatrix<R,STAR,STAR> w1_STAR_STAR(g); A.ResizeTo( Z.Height(), Z.Height() ); if( uplo == LOWER ) MakeTrapezoidal( UPPER, A, 1 ); else MakeTrapezoidal( LOWER, A, -1 ); LockedPartitionRight( Z, ZL, ZR, 0 ); LockedPartitionDown ( w, wT, wB, 0 ); while( ZL.Width() < Z.Width() ) { LockedRepartitionRight ( ZL, /**/ ZR, Z0, /**/ Z1, Z2 ); LockedRepartitionDown ( wT, w0, /**/ /**/ w1, wB, w2 ); Z1_MC_STAR.AlignWith( A ); Z1_VR_STAR.AlignWith( A ); Z1Adj_STAR_MR.AlignWith( A ); //--------------------------------------------------------------------// Z1_MC_STAR = Z1; Z1_VR_STAR = Z1_MC_STAR; w1_STAR_STAR = w1; DiagonalScale( RIGHT, NORMAL, w1_STAR_STAR, Z1_VR_STAR ); Z1Adj_STAR_MR.AdjointFrom( Z1_VR_STAR ); LocalTrrk( uplo, F(1), Z1_MC_STAR, Z1Adj_STAR_MR, F(1), A ); //--------------------------------------------------------------------// SlideLockedPartitionDown ( wT, w0, w1, /**/ /**/ wB, w2 ); SlideLockedPartitionRight ( ZL, /**/ ZR, Z0, Z1, /**/ Z2 ); } }