| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- //+------------------------------------------------------------------+
- //| 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 <class T>
- 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 <class T>
- static void ShortSort (T *lo,T *hi,SortFunctionPtr compare);
- template <class T>
- 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
- {
- lo =mid+width;
- total=total-half-1;
- }
- else
- if(result<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<class T>
- 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<class T>
- inline void SMTSearch::Swap(T *a,T *b)
- {
- T c(*a);
- *a=*b;
- *b=c;
- }
- //+------------------------------------------------------------------+
- //| Quick sort from CRT |
- //+------------------------------------------------------------------+
- template<class T>
- 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<loguy) break;
- //---
- Swap(loguy, higuy);
- }
- //---
- Swap(lo, higuy); /* put partition element in place */
- //---
- if(higuy-1-lo>=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);
- }
- //+------------------------------------------------------------------+
|