313 lines
23 KiB
Plaintext
313 lines
23 KiB
Plaintext
//+------------------------------------------------------------------+
|
||
//| Queue.mqh |
|
||
//| Copyright 2016-2017, MetaQuotes Software Corp. |
|
||
//| https://www.mql5.com |
|
||
//+------------------------------------------------------------------+
|
||
#include <Generic\Interfaces\ICollection.mqh>
|
||
#include <Generic\Internal\ArrayFunction.mqh>
|
||
#include <Generic\Internal\EqualFunction.mqh>
|
||
//+------------------------------------------------------------------+
|
||
//| Class CQueue<T>. |
|
||
//| Usage: Represents a first-in, first-out collection of objects. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
class CQueue: public ICollection<T>
|
||
{
|
||
protected:
|
||
T m_array[];
|
||
int m_size;
|
||
int m_head; // first valid element in the queue
|
||
int m_tail; // last valid element in the queue
|
||
const int m_default_capacity;
|
||
|
||
public:
|
||
CQueue(void);
|
||
CQueue(const int capacity);
|
||
CQueue(ICollection<T>&collection[]);
|
||
CQueue(T &array[]);
|
||
~CQueue(void);
|
||
//--- methods of filling data
|
||
bool Add(T value);
|
||
bool Enqueue(T value);
|
||
//--- methods of access to protected data
|
||
int Count(void);
|
||
bool Contains(T item);
|
||
void TrimExcess(void);
|
||
//--- methods of copy data from collection
|
||
int CopyTo(T &dst_array[],const int dst_start=0);
|
||
//--- methods of cleaning and removing
|
||
void Clear(void);
|
||
bool Remove(T item);
|
||
T Dequeue(void);
|
||
T Peek(void);
|
||
|
||
private:
|
||
void SetCapacity(const int capacity);
|
||
};
|
||
//+------------------------------------------------------------------+
|
||
//| Initializes a new instance of the CQueue<T> class that is empty |
|
||
//| and has the default initial capacity. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
CQueue::CQueue(void): m_default_capacity(4),
|
||
m_size(0),
|
||
m_head(0),
|
||
m_tail(0)
|
||
{
|
||
ArrayResize(m_array,m_default_capacity);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Initializes a new instance of the CQueue<T> class that is empty |
|
||
//| and has the specified initial capacity or the default initial |
|
||
//| capacity, whichever is greater. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
CQueue::CQueue(const int capacity): m_default_capacity(4),
|
||
m_size(0),
|
||
m_head(0),
|
||
m_tail(0)
|
||
{
|
||
ArrayResize(m_array,capacity);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Initializes a new instance of the CQueue<T> class that contains |
|
||
//| elements copied from the specified array and has sufficient |
|
||
//| capacity to accommodate the number of elements copied. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
CQueue::CQueue(T &array[]): m_default_capacity(4),
|
||
m_head(0)
|
||
{
|
||
m_size=ArrayCopy(m_array,array);
|
||
//--- set tail
|
||
m_tail=m_size;
|
||
if(m_size%2==1)
|
||
ArrayResize(m_array,m_size+1);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Initializes a new instance of the CQueue<T> class that contains |
|
||
//| elements copied from the specified collection and has sufficient |
|
||
//| capacity to accommodate the number of elements copied. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
CQueue::CQueue(ICollection<T>*collection): m_default_capacity(4),
|
||
m_head(0)
|
||
{
|
||
//--- check collection
|
||
if(CheckPointer(collection)!=POINTER_INVALID)
|
||
m_size=collection.CopyTo(m_array);
|
||
else
|
||
m_size=0;
|
||
//--- set tail
|
||
m_tail=m_size;
|
||
if(m_size%2==1)
|
||
ArrayResize(m_array,m_size+1);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Destructor. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
CQueue::~CQueue(void)
|
||
{
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Inserts an value at the top of the CQueue<T>. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
bool CQueue::Add(T value)
|
||
{
|
||
return Enqueue(value);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Gets the number of elements. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
int CQueue::Count(void)
|
||
{
|
||
return(m_size);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Removes all values from the CQueue<T>. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
bool CQueue::Contains(T item)
|
||
{
|
||
int count=m_size;
|
||
//--- try to find item in array
|
||
while(count-->0)
|
||
{
|
||
//--- use default equality function
|
||
if(::Equals(m_array[count],item))
|
||
return(true);
|
||
}
|
||
return(false);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Sets the capacity to the actual number of elements in the queue, |
|
||
//| if that number is less than a threshold value. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
void CQueue::TrimExcess(void)
|
||
{
|
||
//--- calculate threshold value
|
||
int threshold=(int)(((double)ArraySize(m_array))*0.9);
|
||
//--- set a сapacity equal to the size
|
||
if(m_size<threshold)
|
||
SetCapacity(m_size);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Copies a range of elements from the queue to a compatible |
|
||
//| one-dimensional array. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
int CQueue::CopyTo(T &dst_array[],const int dst_start=0)
|
||
{
|
||
|
||
//--- resize array
|
||
if(dst_start+m_size>ArraySize(dst_array))
|
||
ArrayResize(dst_array,dst_start+m_size);
|
||
//--- check tail and head
|
||
if(m_tail>m_head)
|
||
{
|
||
//--- copying an array from head to tail
|
||
int num_copied=ArrayCopy(dst_array,m_array,dst_start,m_head,m_tail);
|
||
//--- return number of copied elements
|
||
return(num_copied);
|
||
}
|
||
else
|
||
{
|
||
//--- copying an array from head to end
|
||
int num_copied=ArrayCopy(dst_array,m_array,dst_start,m_head,m_size-m_tail);
|
||
//--- copying an array from beginning to tail
|
||
num_copied+=ArrayCopy(dst_array,m_array,dst_start+num_copied,0,m_tail);
|
||
//--- return number of copied elements
|
||
return(num_copied);
|
||
}
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Removes all values from the CQueue<T>. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
void CQueue::Clear(void)
|
||
{
|
||
//--- check current size
|
||
if(m_size>0)
|
||
{
|
||
ArrayFree(m_array);
|
||
m_size=0;
|
||
m_head=0;
|
||
m_tail=0;
|
||
}
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Removes the first occurrence of a specific value from the stack. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
bool CQueue::Remove(T item)
|
||
{
|
||
//--- first try to find index of item
|
||
//--- find from head to end
|
||
int index=ArrayIndexOf(m_array,item,m_head,m_size-m_head);
|
||
if(index!=-1)
|
||
{
|
||
//--- shift the values to the left
|
||
ArrayCopy(m_array,m_array,index,index+1);
|
||
//--- decrement size
|
||
m_size--;
|
||
return(true);
|
||
}
|
||
//--- second try to find index of item
|
||
//--- find from start to tail
|
||
index=ArrayIndexOf(m_array,item,0,m_tail+1);
|
||
if(index!=-1)
|
||
{
|
||
//--- shift the values to the right
|
||
ArrayCopy(m_array,m_array,index,index+1);
|
||
//--- decrement size
|
||
m_size--;
|
||
//--- decrement head and tail
|
||
m_tail--;
|
||
m_head--;
|
||
return(true);
|
||
}
|
||
return(false);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Adds an value to the end of the CQueue<T>. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
bool CQueue::Enqueue(T value)
|
||
{
|
||
//--- check current size
|
||
if(m_size==ArraySize(m_array))
|
||
{
|
||
//--- calculate new capacity
|
||
int new_capacity=(int)((long)ArraySize(m_array) *(long)2);
|
||
if(new_capacity<ArraySize(m_array)+4)
|
||
new_capacity=ArraySize(m_array)+4;
|
||
//--- set new capacity
|
||
SetCapacity(new_capacity);
|
||
}
|
||
//--- add value to the end
|
||
m_array[m_tail]=value;
|
||
//--- increase size and recalculate tail
|
||
m_size++;
|
||
m_tail=(m_tail+1)%ArraySize(m_array);
|
||
return(true);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Removes and returns the value at the beginning of the CQueue<T>. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
T CQueue::Dequeue(void)
|
||
{
|
||
//--- get value from the end
|
||
T removed=m_array[m_head];
|
||
//--- decrement size and recalculate head
|
||
m_head=(m_head+1)%ArraySize(m_array);
|
||
m_size--;
|
||
return(removed);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Returns the value at the beginning of the CQueue<T> without |
|
||
//| removing. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
T CQueue::Peek(void)
|
||
{
|
||
//--- get value from the end
|
||
return(m_array[m_head]);
|
||
}
|
||
//+------------------------------------------------------------------+
|
||
//| Grows or shrinks the buffer to hold capacity values. |
|
||
//+------------------------------------------------------------------+
|
||
template<typename T>
|
||
void CQueue::SetCapacity(const int capacity)
|
||
{
|
||
int size=ArraySize(m_array);
|
||
//--- create a new array array for temporary storage
|
||
T new_array[];
|
||
ArrayResize(new_array,capacity);
|
||
//--- check size
|
||
if(m_size>0)
|
||
{
|
||
if(m_head<m_tail)
|
||
{
|
||
//--- shift the values to the left
|
||
ArrayCopy(new_array,m_array,0,m_head,m_size);
|
||
}
|
||
else
|
||
{
|
||
//--- shift the values to the left
|
||
ArrayCopy(new_array,m_array,0,m_head,size-m_head);
|
||
//--- shift the values to the right
|
||
ArrayCopy(new_array,m_array,size-m_head,0,m_tail);
|
||
}
|
||
}
|
||
//---
|
||
ArrayCopy(m_array,new_array);
|
||
//--- set new tail and head
|
||
m_head=0;
|
||
m_tail=(m_size == capacity) ? 0 : m_size;
|
||
}
|
||
//+------------------------------------------------------------------+ |