layer0/Util.cpp (461 lines of code) (raw):

/* A* ------------------------------------------------------------------- B* This file contains source code for the PyMOL computer program C* Copyright (c) Schrodinger, LLC. D* ------------------------------------------------------------------- E* It is unlawful to modify or remove this copyright notice. F* ------------------------------------------------------------------- G* Please see the accompanying LICENSE file for further information. H* ------------------------------------------------------------------- I* Additional authors of this source file include: -* -* -* Z* ------------------------------------------------------------------- */ #include"os_predef.h" #include"os_std.h" #include"os_time.h" #include"Util.h" #include"MemoryDebug.h" #include"Err.h" struct _CUtil { double StartSec; }; int UtilInit(PyMOLGlobals *G) { G->Util = Calloc(CUtil,1); G->Util->StartSec = UtilGetSeconds(G); return 1; } void UtilFree(PyMOLGlobals *G) { FreeP(G->Util); } int UtilShouldWePrintQuantity(int quantity) { if(quantity<10) return 1; if((quantity>0)&&(quantity<0x07FFFFFF)) /* avoids overflow, just in case */ { int factor = 10; while((factor*10)<quantity) factor *= 10; return ((quantity/factor)*factor == quantity); } return 0; } int UtilCountStringVLA(char *vla) { int result=0; int cc; if (vla) { cc=VLAGetSize(vla); while(cc--) { if(!*vla) result++; vla++; } } return(result); } double UtilGetSeconds(PyMOLGlobals *G) { #ifndef _WIN32 /* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */ struct timeval tv; gettimeofday(&tv,NULL); return((tv.tv_sec+(tv.tv_usec/((double)1000000.0)))-G->Util->StartSec); /* END PROPRIETARY CODE SEGMENT */ #else struct __timeb64 timebuffer; _ftime64( &timebuffer ); return((timebuffer.time+(timebuffer.millitm/((double)1000.0)))-G->Util->StartSec); #endif } char *UtilConcat(char *where,const char *what) { while(*what) *(where++)=*(what++); *where=0; return(where); } void UtilConcatVLA(char **vla,ov_size *cc,const char *str) { const char *what; char *where; ov_size len; len=strlen(str); VLACheck((*vla),char,len+*cc+1); where = (*cc)+(*vla); what = str; while(*what) *(where++)=*(what++); *where=0; *(cc)+=len; } void UtilNPadVLA(char **vla,ov_size *cc,const char *str,ov_size len) { const char *what; char *where; ov_size n = 0; VLACheck((*vla),char,len + *cc +1); where = (*cc)+(*vla); what = str; while(*what) { if(n>=len) break; *(where++)=*(what++); n++; } while(n<len) { *(where++) = ' '; n++; } *where=0; *(cc)+=len; } void UtilFillVLA(char **vla,ov_size *cc,char what,ov_size len) { char *where; VLACheck((*vla),char,len+(*cc)+1); where = (*cc)+(*vla); *(cc)+=len; while((len--)>0) *(where++)=what; *where=0; } void UtilNConcat(char *dst,const char *src,ov_size n) { /* copies up to N-1 chars */ ov_size l; l=strlen(dst); if(n>l) { UtilNCopy(dst+l,src,n-l); } } void UtilNCopy(char *dst,const char *src,ov_size n) { /* copies up to N-1 chars */ if(n--) { while(n--) { if(!*src) break; else *(dst++)=*(src++); } } *dst=0; } void UtilNCopyToLower(char *dst,const char *src,ov_size n) { if(n--) { while(n--) { if(!*src) break; else *(dst++)=tolower(*(src++)); } } *dst=0; } void UtilCleanStr(char *s) /*remove flanking white and all unprintables*/ { char *p,*q; p=s; q=s; while(*p) if(*p>32) break; else p++; while(*p) if(*p>=32) (*q++)=(*p++); else p++; *q=0; while(q>=s) { if(*q>32) break; else { (*q)=0; q--; } } } /* * Remove ANSI Escape sequences in-place */ void UtilStripANSIEscapes(char *s) { for (const char *p = s;; ++p, ++s) { while (p[0] == '\033' && p[1] == '[') { while (' ' <= p[2] && p[2] < '@') ++p; p += 3; } if (p != s) *s = *p; if (!p[0]) break; } } void UtilStripANSIEscapes(std::string& str) { UtilStripANSIEscapes(&str[0]); str.resize(strlen(str.c_str())); } void UtilZeroMem(void *ptr,ov_size howMuch) { char *p,*q; p=(char*)ptr; q=p+howMuch; MemoryZero(p,q); } void UtilCopyMem(void *dst,const void *src,ov_size howMuch) /* optimize! */ { /* need to determine the memory is non-overlapping. If so, then use memcpy. */ char *c,*d; c=(char*)dst; d=(char*)src; while(howMuch--) *(c++)=*(d++); } void UtilExpandArrayElements(void *src,void *dst,int n_entries,int old_rec_size,int new_rec_size) { /* simple but ineffient byte-based copy */ char *p,*q,*p_stop,*q_stop; int a; for(a=0;a<n_entries;a++) { p=((char*)src)+(old_rec_size*a); p_stop=p+old_rec_size; q=((char*)dst)+(new_rec_size*a); q_stop=q+new_rec_size; while(p!=p_stop) { *(q++)=*(p++); } while(q!=q_stop) { *(q++)=0; } } } void *UtilArrayCalloc(unsigned int *dim,ov_size ndim,ov_size atom_size) { ov_size size; ov_size sum,product; ov_size chunk; ov_size a,b,c; void *result; char **p; char *q; sum = 0; for(a=0;a<(ndim-1);a++) { product = dim[0]; for(b=1;b<=a;b++) product = product * dim[b]; sum = sum + product * sizeof(void*); } size = atom_size; for(a=0;a<ndim;a++) size = size * dim[a]; size = size + sum; result = (void*)mcalloc(size*2,1); /* what is this *2 for ??? */ if(result) { chunk = 1; p = (char**) result; for(c=0;c<(ndim-1);c++) { if(c<(ndim-2)) { chunk = dim[c+1] * sizeof(void*); } else { chunk = dim[c+1] * atom_size; } product = dim[0]; for(b=1;b<=c;b++) product = product * dim[b]; q = ((char*)p) + product * sizeof(void*); for(a=0;a<product;a++) { *p = q; p++; q+=chunk; } } } return(result); } void UtilApplySortedIndices(int n,int *x, int rec_size, void *src, void *dst) { int a; for(a=0;a<n;a++) { memcpy(((char*)dst)+(a*rec_size), ((char*)src)+(x[a]*rec_size), rec_size); } } void UtilSortIndex(int n,void *array,int *x,UtilOrderFn* fOrdered) { int l,a,r,t,i; if(n<1) return; else if(n==1) { x[0]=0; return; } x--; for(a=1;a<=n;a++) x[a]=a; l=(n>>1)+1; r=n; while(1) { if(l>1) t = x[--l]; else { t = x[r]; x[r] = x[1]; if( --r == 1) { x[1] = t; break; } } i=l; a=l << 1; while (a <= r) { if (a < r && (!fOrdered(array,x[a+1]-1,x[a]-1))) a++; if (!fOrdered(array,x[a]-1,t-1)) { x[i] = x[a]; a += (i=a); } else a = r + 1; } x[i] = t; } x++; for(a=0;a<n;a++) x[a]--; } void UtilSortIndexGlobals(PyMOLGlobals *G,int n,void *array,int *x,UtilOrderFnGlobals* fOrdered) { int l,a,r,t,i; if(n<1) return; else if(n==1) { x[0]=0; return; } x--; for(a=1;a<=n;a++) x[a]=a; l=(n>>1)+1; r=n; while(1) { if(l>1) t = x[--l]; else { t = x[r]; x[r] = x[1]; if( --r == 1) { x[1] = t; break; } } i=l; a=l << 1; while (a <= r) { if (a < r && (!fOrdered(G,array,x[a+1]-1,x[a]-1))) a++; if (!fOrdered(G,array,x[a]-1,t-1)) { x[i] = x[a]; a += (i=a); } else a = r + 1; } x[i] = t; } x++; for(a=0;a<n;a++) x[a]--; } #define MAX_BIN = 100 #ifndef R_SMALL8 #define R_SMALL8 0.00000001F #endif int UtilSemiSortFloatIndex(int n,float *array,int *x, int forward) { return UtilSemiSortFloatIndexWithNBins(n, n, array, x, forward); } int UtilSemiSortFloatIndexWithNBins(int n, int nbins, float *array, int *destx, int forward) { int *start1 = Calloc(int,n + nbins); int ret = UtilSemiSortFloatIndexWithNBinsImpl(start1, n, nbins, array, destx, forward); mfree(start1); return ret; } int UtilSemiSortFloatIndexWithNBinsImpl(int *start1, int n, int nbins, float *array, int *destx, int forward) { /* approximate sort, for quick handling of transparency values */ /* this sort uses 2 arrays start1 and next1 to keep track of */ /* the indexes. The values in start1 are set to the index */ /* relative to the array value within the min/max values. If */ /* there is a collision, the value in next1 is set to the value */ /* that is collided, and start1[idx] is set to the index plus 1 (a+1) */ /* This makes it easy to go through the 2 arrays and write into the */ /* x array the approximate order of the floating point values in array */ /* by indexes. */ /* Since there are two arrays, this guarentees that there */ /* will be enough memory to hold all indexes. If there are many collisions, */ /* the next1 array will hold a link to most of the indexes, which are traversed */ /* when the first index is found in start1. If there are few collisions, then */ /* the majority of the start1 array is used. The total number of items used in */ /* both arrays will always be the number of values, i.e., n. */ /* 9/9/14: BB - added start1 and nbins argument start1 - pre-allocated memory nbins - allows the first array to be controled as the number of bins, to match how CGORenderGLAlpha() sorts its triangles. */ int ok = true; if(n>0) { float min,max,*f,v; float range, scale; int a; int *next1; int idx1; CHECKOK(ok, start1); if (!ok){ return false; } next1 = start1 + nbins; max = (min = array[0]); f = array + 1; for(a=1;a<n;a++) { v = *(f++); if(max<v) max=v; if(min>v) min=v; } range = (max-min)/.9999F; /* for boundary conditions */ if(range<R_SMALL8) { for(a=0;a<n;a++) destx[a] = a; } else { scale = nbins/range; f = array; /* hash by value (actually binning) */ if(forward) { for(a=0;a<n;a++) { idx1 = (int)((*(f++)-min)*scale); next1[a] = start1[idx1]; start1[idx1] = a+1; } } else { for(a=0;a<n;a++) { idx1 = (nbins-1) - (int)((*(f++)-min)*scale); next1[a] = start1[idx1]; start1[idx1] = a+1; } } /* now read out */ { int c=0; int cur1; a=0; while(a<nbins) { if( (cur1 = start1[a]) ) { idx1 = cur1 - 1; while(1) { destx[c++] = idx1; if(! (cur1 = next1[idx1])) break; idx1 = cur1 - 1; } } a++; } } } } return true; } void UtilSortInPlace(PyMOLGlobals *G,void *array,int nItem, unsigned int itemSize, UtilOrderFn *fOrdered) { char *tmp; int *index; int ia; int a; if(nItem>0) { tmp = Alloc(char,(itemSize*nItem)); index = Alloc(int,nItem+1); ErrChkPtr(G,tmp); ErrChkPtr(G,index); UtilSortIndex(nItem,array,index,fOrdered); for(a=0;a<nItem;a++) index[a]++; /* ^tricky index adjustment to avoid flag array */ for(a=0;a<nItem;a++) { ia = abs(index[a])-1; /* ^ */ if(ia!=a) { if(index[a]>0) /* this record not yet copied, so save copy */ { memcpy(((char*)tmp )+(a*itemSize), ((char*)array)+(a*itemSize), itemSize); index[a] = -index[a]; /* set nega-flag */ } if(index[ia]<0) /* nega-flag, so record is stored in tmp */ memcpy(((char*)array)+(a*itemSize), ((char*)tmp )+(ia*itemSize), itemSize); else { memcpy(((char*)array)+(a*itemSize), ((char*)array)+(ia*itemSize), itemSize); index[ia] = -index[ia]; /* nega-flag: record doesn't need to be backed up */ } } } mfree(tmp); mfree(index); } }