//+------------------------------------------------------------------+ //| MetaTrader 5 API | //| Copyright 2000-2019, MetaQuotes Software Corp. | //| http://www.metaquotes.net | //+------------------------------------------------------------------+ #pragma once //+------------------------------------------------------------------+ //| Search functions | //+------------------------------------------------------------------+ class SMTSearch { public: typedef int (__cdecl *SortFunctionPtr)(const void *, const void *); public: //--- insert static char* Insert(void *base,const void *elem,size_t total,const size_t width,SortFunctionPtr compare); //--- quick sort template static void QuickSort(T *base,UINT num,SortFunctionPtr compare); //--- static void* Search(const void *key,void *base,size_t total,const size_t width,SortFunctionPtr compare); static void* SearchGreatOrEq(const void *key,void *base,size_t total,const size_t width,SortFunctionPtr compare); static void* SearchGreater(const void *key,void *base,size_t total,const size_t width,SortFunctionPtr compare); static void* SearchLessOrEq(const void *key,void *base,size_t total,const size_t width,SortFunctionPtr compare); static void* SearchLess(const void *key,void *base,size_t total,const size_t width,SortFunctionPtr compare); static void* SearchLeft(const void *key,void *base,size_t total,const size_t width,SortFunctionPtr compare); static void* SearchRight(const void *key,void *base,size_t total,const size_t width,SortFunctionPtr compare); private: template static void ShortSort (T *lo,T *hi,SortFunctionPtr compare); template static void Swap(T *a,T *b); }; //+------------------------------------------------------------------+ //| Returns 0 if record already exist | //| Returns inserted record otherwise | //| Array should contain enough free space for new element | //+------------------------------------------------------------------+ inline char* SMTSearch::Insert(void *base,const void *elem,size_t total,const size_t width,SortFunctionPtr compare) { //--- check if(base==NULL || elem==NULL || compare==NULL) return(NULL); //--- first element? if(total<1) { memcpy(base,elem,width); return(char*)(base); } //--- initialize char *lo=(char *)base; char *hi=(char *)base+(total-1)*width,*end=hi; char *mid; size_t half; int result; //--- while(total>0) { half=total/2; mid =lo+half*width; //--- compare if((result=compare(elem,mid))>0) // data[mid]elem { total=half; } else { // data[mid]==elem return(NULL); } } //--- insert new memmove(lo+width,lo,end-lo+width); memcpy(lo,elem,width); //--- return(lo); } //+------------------------------------------------------------------+ //| Fast sort | //+------------------------------------------------------------------+ template inline void SMTSearch::ShortSort (T *lo,T *hi,SortFunctionPtr compare) { T *p, *maxval; //--- Note: in assertions below, i and j are alway inside original bound of //--- array to sort. //--- While while(hi > lo) { maxval=lo; for(p=lo+1; p<=hi; p+=1) if (compare(p, maxval) > 0) { maxval=p; } //--- Swap(maxval,hi); hi-=1; } } //+------------------------------------------------------------------+ //| Swap two records | //+------------------------------------------------------------------+ template inline void SMTSearch::Swap(T *a,T *b) { T c(*a); *a=*b; *b=c; } //+------------------------------------------------------------------+ //| Quick sort from CRT | //+------------------------------------------------------------------+ template inline void SMTSearch::QuickSort(T *base,UINT num,SortFunctionPtr compare) { T *lo, *hi; /* ends of sub-array currently sorting */ T *mid; /* points to middle of subarray */ T *loguy, *higuy; /* traveling pointers for partition step */ size_t size; /* size of the sub-array */ T *lostk[30], *histk[30]; int stkptr; /* stack for saving sub-array to be processed */ //--- if (num < 2) return; stkptr=0; /* initialize stack */ lo=base; hi=base + (num-1); /* initialize limits */ //--- recurse: //--- size=(hi - lo) + 1; /* number of el's to sort */ //--- if (size<=8) ShortSort(lo,hi,compare); else { mid=lo + (size/2); /* find middle element */ Swap(mid,lo); /* swap it to beginning of array */ //--- loguy=lo; higuy=hi + 1; //--- for(;;) { //--- do { loguy+=1; } while(loguy<=hi && compare(loguy, lo)<=0); //--- do { higuy-=1; } while(higuy > lo && compare(higuy, lo)>=0); //--- if(higuy=hi-loguy) { if(lo + 1 < higuy) { lostk[stkptr]=lo; histk[stkptr]=higuy - 1; ++stkptr; } if(loguy < hi) { lo=loguy; goto recurse; /* do small recursion */ } } else { if (loguy < hi) { lostk[stkptr]=loguy; histk[stkptr]=hi; ++stkptr; /* save big recursion for later */ } if(lo + 1 < higuy) { hi=higuy - 1; goto recurse; /* do small recursion */ } } } //--- --stkptr; if(stkptr>=0) { lo=lostk[stkptr]; hi=histk[stkptr]; goto recurse; /* pop subarray from stack */ } //--- return; /* all subarrays done */ } //+------------------------------------------------------------------+ //| Binary search (from CRT) | //+------------------------------------------------------------------+ inline void* SMTSearch::Search(const void *key,void *base,size_t num,const size_t width,SortFunctionPtr compare) { char *lo=(char *)base; char *hi=(char *)base + (num - 1) * width; char *mid; size_t half; int result; //--- validation section if(base==NULL || num<1 || width<=0 || compare==NULL) return(NULL); //--- We allow a NULL key here because it breaks some older code and because we do not dereference //--- this ourselves so we can't be sure that it's a problem for the comparison function while(lo<=hi) { if((half=num/2)!=0) { mid=lo + (num & 1 ? half : (half - 1)) * width; if((result=(*compare)(key, mid))==0) return(mid); else if (result < 0) { hi=mid - width; num=num & 1 ? half : half-1; } else { lo=mid + width; num=half; } } else if(num) return((*compare)(key, lo) ? NULL : lo); else break; } //--- return(NULL); } //+------------------------------------------------------------------+ //| Search great or equal key | //+------------------------------------------------------------------+ inline void* SMTSearch::SearchGreatOrEq(const void *key,void *base,size_t total,const size_t width,SortFunctionPtr compare) { //--- check if(key==NULL || base==NULL || total<1 || compare==NULL) return(NULL); //--- char *lo=(char *)base; char *end=(char *)base+total*width; char *mid; size_t half; //--- while(total>0) { half=total/2; mid =lo+half*width; //--- compare if(compare(key,mid)>0) // key>data[mid] { lo =mid+width; total=total-half-1; } else total=half; } //--- is exist? return(lo==end)?(NULL):(lo); } //+------------------------------------------------------------------+ //| Search great than key | //+------------------------------------------------------------------+ inline void* SMTSearch::SearchGreater(const void *key,void *base,size_t total,const size_t width,SortFunctionPtr compare) { //--- check if(key==NULL || base==NULL || total<1 || compare==NULL) return(NULL); //--- char *lo=(char *)base; char *end=(char *)base+total*width; char *mid; size_t half; //--- while(total>0) { half=total/2; mid =lo+half*width; //--- compare if(compare(key,mid)>=0) // key>=data[mid] { lo =mid+width; total=total-half-1; } else total=half; } //--- is exist? return(lo==end)?(NULL):(lo); } //+------------------------------------------------------------------+ //| Search less or equal key | //+------------------------------------------------------------------+ inline void* SMTSearch::SearchLessOrEq(const void *key,void *base,size_t total,const size_t width,SortFunctionPtr compare) { //--- check if(key==NULL || base==NULL || total<1 || compare==NULL) return(NULL); //--- char *lo=(char *)base; char *beg=(char *)base; char *mid; size_t half; //--- while(total>0) { half=total/2; mid =lo+half*width; //--- compare if(compare(key,mid)>=0) // key>=data[mid] { lo =mid+width; total=total-half-1; } else total=half; } //--- is exist? return(lo==beg)?(NULL):(lo-width); } //+------------------------------------------------------------------+ //| Search less than key | //+------------------------------------------------------------------+ inline void* SMTSearch::SearchLess(const void *key,void *base,size_t total,const size_t width,SortFunctionPtr compare) { //--- check if(key==NULL || base==NULL || total<1 || compare==NULL) return(NULL); //--- char *lo=(char *)base; char *beg=(char *)base; char *mid; size_t half; //--- while(total>0) { half=total/2; mid =lo+half*width; //--- compare if(compare(key,mid)>0) // key>data[mid] { lo =mid+width; total=total-half-1; } else total=half; } //--- is exist? return(lo==beg)?(NULL):(lo-width); } //+------------------------------------------------------------------+ //| Search first equal key | //+------------------------------------------------------------------+ inline void* SMTSearch::SearchLeft(const void *key,void *base,size_t total,const size_t width,SortFunctionPtr compare) { //--- check if(key==NULL || base==NULL || total<1 || compare==NULL) return(NULL); //--- search left char* start=(char*)SearchLess(key,base,total,width,compare); //--- if(start!=NULL) { //--- go to next start+=width; //--- check array borders if(start>=((char*)base+total*width)) return(NULL); } else start=(char*)base; //--- is equal? if(!compare(key,start)) return(start); //--- not found return(NULL); } //+------------------------------------------------------------------+ //| Search last equal key | //+------------------------------------------------------------------+ inline void* SMTSearch::SearchRight(const void *key,void *base,size_t total,const size_t width,SortFunctionPtr compare) { //--- check if(key==NULL || base==NULL || total<1 || compare==NULL) return(NULL); //--- search right char* end=(char*)SearchGreater(key,base,total,width,compare); //--- if(end!=NULL) { //--- go to previous end-=width; //--- check array borders if(end<(char*)base) return(NULL); } else end=(char*)base+(total-1)*width; //--- is equal? if(!compare(key,end)) return(end); //--- not found return(NULL); } //+------------------------------------------------------------------+