/* 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 #include #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 = pymol::calloc(1); G->Util->StartSec = UtilGetSecondsEpoch(); 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)Util->StartSec; } /** * Get a timestamp in seconds since 1970-01-01 */ double UtilGetSecondsEpoch() { #ifndef _WIN32 struct timeval tv; gettimeofday(&tv,NULL); return tv.tv_sec + (tv.tv_usec / 1e6); #else struct __timeb64 timebuffer; _ftime64( &timebuffer ); return timebuffer.time + (timebuffer.millitm / 1e3); #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(n0) *(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--; } } } /** * Removes unprintables and flanking whitespace * @param s string to be cleaned * @return whitespace-trimmed string with readable characters */ std::string UtilCleanStdStr(const std::string& s) { std::string ret; auto is_not_whitespace = [](char c) { return c > ' '; }; auto is_printable = [](char c) { return c >= ' '; }; auto leading = std::find_if(s.begin(), s.end(), is_not_whitespace); auto trailing = std::find_if(s.rbegin(), s.rend(), is_not_whitespace); std::copy_if(leading, trailing.base(), std::back_inserter(ret), is_printable); return ret; } /** * 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(size); 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>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>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 + 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 CGORenderAlpha() 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;av) min=v; } range = (max-min)/.9999F; /* for boundary conditions */ if(range0) { tmp = pymol::malloc((itemSize*nItem)); index = pymol::malloc(nItem+1); ErrChkPtr(G,tmp); ErrChkPtr(G,index); UtilSortIndex(nItem,array,index,fOrdered); for(a=0;a0) /* 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); } }