| //+------------------------------------------------------------------+
|
| //| ArrayList.mqh |
|
| //| Copyright 2000-2025, MetaQuotes Ltd. |
|
| //| https://www.mql5.com |
|
| //+------------------------------------------------------------------+
|
| #include <Generic\Interfaces\IList.mqh>
|
| #include <Generic\Interfaces\IComparer.mqh>
|
| #include <Generic\Internal\EqualFunction.mqh>
|
| #include <Generic\Internal\ArrayFunction.mqh>
|
| #include <Generic\Internal\Introsort.mqh>
|
| #include <Generic\Internal\DefaultComparer.mqh>
|
| //+------------------------------------------------------------------+
|
| //| Class CArrayList<T>. |
|
| //| Usage: Represents a strongly typed list of values that can be |
|
| //| accessed by index. Provides methods to search, sort, and |
|
| //| manipulate lists. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| class CArrayList: public IList<T>
|
| {
|
| protected:
|
| T m_items[];
|
| int m_size;
|
| const int m_default_capacity;
|
|
|
| public:
|
| CArrayList(void);
|
| CArrayList(const int capacity);
|
| CArrayList(ICollection<T>*collection);
|
| CArrayList(T &array[]);
|
| ~CArrayList(void);
|
| //--- methods of access to protected data
|
| int Capacity(void);
|
| void Capacity(const int capacity);
|
| int Count(void);
|
| bool Contains(T item);
|
| void TrimExcess(void);
|
| //--- method of access to the data
|
| bool TryGetValue(const int index,T &value);
|
| bool TrySetValue(const int index,T value);
|
| //--- methods of filling the array
|
| bool Add(T item);
|
| bool AddRange(T &array[]);
|
| bool AddRange(ICollection<T>*collection);
|
| bool Insert(const int index,T item);
|
| bool InsertRange(const int index,T &array[]);
|
| bool InsertRange(const int index,ICollection<T>*collection);
|
| //--- methods of copy data from collection
|
| int CopyTo(T &dst_array[],const int dst_start=0);
|
| //--- methods for binary searching index
|
| int BinarySearch(T item);
|
| int BinarySearch(T item,IComparer<T>*comparer);
|
| int BinarySearch(const int index,const int count,T item,IComparer<T>*comparer);
|
| //--- methods for searching index
|
| int IndexOf(T item);
|
| int IndexOf(T item,const int start_index);
|
| int IndexOf(T item,const int start_index,const int count);
|
| int LastIndexOf(T item);
|
| int LastIndexOf(T item,const int start_index);
|
| int LastIndexOf(T item,const int start_index,const int count);
|
| //--- methods of cleaning and deleting
|
| void Clear(void);
|
| bool Remove(T item);
|
| bool RemoveAt(const int index);
|
| bool RemoveRange(const int start_index,const int count);
|
| //--- reversing method
|
| bool Reverse(void);
|
| bool Reverse(const int start_index,const int count);
|
| //--- sorting method
|
| bool Sort(void);
|
| bool Sort(IComparer<T>*comparer);
|
| bool Sort(const int start_index,const int count,IComparer<T>*comparer);
|
|
|
| private:
|
| void EnsureCapacity(const int min);
|
| };
|
| //+------------------------------------------------------------------+
|
| //| Initializes a new instance of the CArrayList<T> class that is |
|
| //| empty and has the default initial capacity. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| CArrayList::CArrayList(void): m_default_capacity(4),
|
| m_size(0)
|
| {
|
| ArrayResize(m_items,m_default_capacity);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Initializes a new instance of the CArrayList<T> class that is |
|
| //| empty and has the specified initial capacity. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| CArrayList::CArrayList(const int capacity): m_default_capacity(4),
|
| m_size(0)
|
| {
|
| ArrayResize(m_items,capacity);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Initializes a new instance of the CArrayList<T> class that |
|
| //| contains elements copied from the specified array and has |
|
| //| sufficient capacity to accommodate the number of elements copied.|
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| CArrayList::CArrayList(T &array[]): m_default_capacity(4),
|
| m_size(0)
|
| {
|
| m_size=ArrayCopy(m_items,array);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Initializes a new instance of the CArrayList<T> class that |
|
| //| contains elements copied from the specified collection and has |
|
| //| sufficient capacity to accommodate the number of elements copied.|
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| CArrayList::CArrayList(ICollection<T>*collection): m_default_capacity(4),
|
| m_size(0)
|
| {
|
| //--- check collection
|
| if(CheckPointer(collection)!=POINTER_INVALID)
|
| m_size=collection.CopyTo(m_items,0);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Destructor. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| CArrayList::~CArrayList(void)
|
| {
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Gets the total number of elements the internal data structure can|
|
| //| hold without resizing. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| int CArrayList::Capacity(void)
|
| {
|
| return ArraySize(m_items);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Sets the total number of elements the internal data structure can|
|
| //| hold without resizing. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| void CArrayList::Capacity(const int capacity)
|
| {
|
| //--- check new capacity should be greater than current size
|
| if(capacity>=m_size && capacity!=ArraySize(m_items))
|
| {
|
| if(capacity>0)
|
| ArrayResize(m_items,capacity);
|
| else
|
| ArrayFree(m_items);
|
| }
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Gets the number of elements. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| int CArrayList::Count(void)
|
| {
|
| return(m_size);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Determines whether an element is in the list. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::Contains(T item)
|
| {
|
| //--- try to find item in array
|
| for(int i=0; i<m_size; i++)
|
| {
|
| //--- use default equality function
|
| if(::Equals(m_items[i],item))
|
| return(true);
|
| }
|
| return(false);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Gets the element at the specified index. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::TryGetValue(const int index,T &value)
|
| {
|
| //--- check index
|
| if((uint)index<(uint)m_size)
|
| {
|
| //--- get value by index
|
| value=m_items[index];
|
| return(true);
|
| }
|
| return(false);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Sets the element at the specified index. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::TrySetValue(const int index,T value)
|
| {
|
| //--- check index
|
| if((uint)index<(uint)m_size)
|
| {
|
| //--- set value by index
|
| m_items[index]=value;
|
| return(true);
|
| }
|
| return(false);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Sets the capacity to the actual number of elements in the list, |
|
| //| if that number is less than a threshold value. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| void CArrayList::TrimExcess(void)
|
| {
|
| //--- calculate threshold value
|
| int threshold=(int)(((double)ArraySize(m_items))*0.9);
|
| //--- set a сapacity equal to the size
|
| if(m_size<threshold)
|
| Capacity(m_size);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Adds an value to the end of the list. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::Add(T item)
|
| {
|
| //--- increse capacity if its necessary
|
| if(m_size==ArraySize(m_items))
|
| EnsureCapacity(m_size+1);
|
| //--- add value to the end
|
| m_items[m_size++]=item;
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Adds the elements of the specified array to the end of the list. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::AddRange(T &array[])
|
| {
|
| //--- increse capacity if its necessary
|
| if(m_size==ArraySize(m_items))
|
| EnsureCapacity(m_size+ArraySize(array));
|
| //--- add values to the end
|
| m_size+=ArrayCopy(m_items,array,m_size);
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Adds the elements of the specified collection to the end of the |
|
| //| list. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::AddRange(ICollection<T>*collection)
|
| {
|
| //--- check collection
|
| if(CheckPointer(collection)==POINTER_INVALID)
|
| return(false);
|
| //--- increse capacity if its necessary
|
| if(m_size==ArraySize(m_items))
|
| EnsureCapacity(m_size+collection.Count());
|
| //--- add value to the end
|
| m_size+=collection.CopyTo(m_items,m_size);
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Inserts an element into the list at the specified index. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::Insert(const int index,T item)
|
| {
|
| //--- check index
|
| if((uint)index>(uint)m_size)
|
| return(false);
|
| //--- increse capacity if its necessary
|
| if(m_size==ArraySize(m_items))
|
| EnsureCapacity(m_size+1);
|
| //--- shift the values to the right
|
| if(index<m_size)
|
| ArrayCopy(m_items,m_items,index+1,index,m_size-index);
|
| //--- insert value by index
|
| m_items[index]=item;
|
| m_size++;
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Inserts the elements of a array into the list at the specified |
|
| //| index. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::InsertRange(const int index,T &array[])
|
| {
|
| //--- check index
|
| if((uint)index>(uint)m_size)
|
| return(false);
|
| int size=ArraySize(array);
|
| //--- check size of inserted array
|
| if(size>0)
|
| {
|
| //--- increse capacity if its necessary
|
| EnsureCapacity(m_size+size);
|
| //--- shift the values to the right
|
| if(index<m_size)
|
| ArrayCopy(m_items,m_items,index+size,index,m_size-index);
|
| //--- insert values by index
|
| m_size+=ArrayCopy(m_items,array,index);
|
| }
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Inserts the elements of a collection into the list at the |
|
| //| specified index. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::InsertRange(const int index,ICollection<T>*collection)
|
| {
|
| //--- check collection
|
| if(CheckPointer(collection)==POINTER_INVALID)
|
| return(false);
|
| //--- check index
|
| if((uint)index>(uint)m_size)
|
| return(false);
|
| int count=collection.Count();
|
| //--- check count of inserted collection
|
| if(count>0)
|
| {
|
| //--- increse capacity if its necessary
|
| EnsureCapacity(m_size+count);
|
| //--- shift the values to the right
|
| if(index<m_size)
|
| ArrayCopy(m_items,m_items,index+count,index,m_size-index);
|
| //--- insert values by index
|
| m_size+=collection.CopyTo(m_items,index);
|
| }
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Copies a range of elements from the list to a compatible |
|
| //| one-dimensional array. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| int CArrayList::CopyTo(T &dst_array[],const int dst_start=0)
|
| {
|
| return ArrayCopy(dst_array,m_items,dst_start,0,m_size);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Searches a range of elements in the sorted list for an element |
|
| //| using the specified comparer and returns the zero-based index of |
|
| //| the element. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| int CArrayList::BinarySearch(const int start_index,const int count,T item,IComparer<T>*comparer)
|
| {
|
| //--- check index
|
| if(start_index<0 || count<0 || m_size-start_index<count)
|
| return(-1);
|
| //--- check comparer
|
| if(CheckPointer(comparer)!=POINTER_INVALID)
|
| {
|
| //--- use specified comparer
|
| return ArrayBinarySearch(m_items, start_index, count, item, comparer);
|
| }
|
| else
|
| {
|
| CDefaultComparer<T>def_comparer;
|
| //--- use default comparer
|
| return ArrayBinarySearch(m_items, start_index, count, item, GetPointer(def_comparer));
|
| }
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Searches the entire sorted list for an element using the |
|
| //| specified comparer and returns the zero-based index of the |
|
| //| element. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| int CArrayList::BinarySearch(T item,IComparer<T>*comparer)
|
| {
|
| return BinarySearch(0, m_size, item, comparer);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Searches the entire sorted list for an element using the default |
|
| //| comparer and returns the zero-based index of the element. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| int CArrayList::BinarySearch(T item)
|
| {
|
| return BinarySearch(item, NULL);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Searches for the specified value and returns the zero-based index|
|
| //| of the first occurrence within the entire list. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| int CArrayList::IndexOf(T item)
|
| {
|
| return ArrayIndexOf(m_items, item, 0, m_size);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Searches for the specified value and returns the zero-based index|
|
| //| of the first occurrence within the range of elements in the list |
|
| //| that extends from the specified index to the last element. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| int CArrayList::IndexOf(T item,const int start_index)
|
| {
|
| //--- check start index
|
| if(start_index>=m_size)
|
| return(-1);
|
|
|
| return ArrayIndexOf(m_items, item, start_index, m_size-start_index);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Searches for the specified value and returns the zero-based index|
|
| //| of the first occurrence within the range of elements in the list |
|
| //| that starts at the specified index and contains the specified |
|
| //| number of elements. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| int CArrayList::IndexOf(T item,const int start_index,const int count)
|
| {
|
| //--- check start index and count
|
| if(start_index<0 || count<0 || start_index>=m_size)
|
| return(-1);
|
|
|
| return ArrayIndexOf(m_items, item, start_index, MathMin(m_size-start_index,count));
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Searches for the specified value and returns the zero-based index|
|
| //| of the last occurrence within the entire list. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| int CArrayList::LastIndexOf(T item)
|
| {
|
| return LastIndexOf(item, m_size - 1, m_size);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Searches for the specified value and returns the zero-based index|
|
| //| of the last occurrence within the range of elements in the list |
|
| //| that extends from the first element to the specified index. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| int CArrayList::LastIndexOf(T item,const int start_index)
|
| {
|
| //--- check start index
|
| if(start_index>=m_size)
|
| return(-1);
|
|
|
| return ArrayLastIndexOf(m_items, item, start_index, start_index+1);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Searches for the specified value and returns the zero-based |
|
| //| index of the last occurrence within the range of elements in the |
|
| //| list that contains the specified number of elements and ends at |
|
| //| the specified index. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| int CArrayList::LastIndexOf(T item,const int start_index,const int count)
|
| {
|
| //--- check start index and count
|
| if(start_index<0 || count<0 || start_index>=m_size)
|
| return(-1);
|
|
|
| return ArrayLastIndexOf(m_items, item, start_index, MathMin(start_index+1,count));
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Removes all elements from the list. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| void CArrayList::Clear(void)
|
| {
|
| //--- check current size
|
| if(m_size>0)
|
| {
|
| ZeroMemory(m_items);
|
| m_size=0;
|
| }
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Removes the element at the specified index of the list. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::RemoveAt(const int index)
|
| {
|
| //--- check index
|
| if((uint)index>=(uint)m_size)
|
| return(false);
|
| //--- decrement size
|
| m_size--;
|
| //--- shift the values to the left
|
| if(index<m_size)
|
| ArrayCopy(m_items,m_items,index,index+1,m_size-index);
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Removes the first occurrence of a specific object from the list. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::Remove(T item)
|
| {
|
| //--- find index of value
|
| int index=IndexOf(item);
|
| //--- delete element by index
|
| if(index>=0)
|
| return RemoveAt(index);
|
| else
|
| return(false);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Removes a range of elements from the list. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::RemoveRange(const int start_index,const int count)
|
| {
|
| //--- check start index and count
|
| if(start_index<0 || count<0 || m_size-start_index<count)
|
| return(false);
|
| if(count>0)
|
| {
|
| //--- decrement size
|
| m_size-=count;
|
| //--- shift the values to the left
|
| if(start_index<m_size)
|
| ArrayCopy(m_items,m_items,start_index,start_index+count,m_size-start_index);
|
| }
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Reverses the order of the elements in the entire list. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::Reverse(void)
|
| {
|
| return Reverse(0, m_size);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Reverses the order of the elements in the specified range. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::Reverse(const int start_index,const int count)
|
| {
|
| //--- check start index and count
|
| if(start_index<0 || count<0 || m_size-start_index<count)
|
| return(false);
|
| return ArrayReverse(m_items, start_index, count);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Sorts the elements in the entire list using the default comparer.|
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::Sort(void)
|
| {
|
| return Sort(0,m_size,NULL);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Sorts the elements in the entire list using the specified |
|
| //| comparer. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::Sort(IComparer<T>*comparer)
|
| {
|
| return Sort(0,m_size,comparer);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Sorts the elements in a range of elements in list using the |
|
| //| specified comparer. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| bool CArrayList::Sort(const int start_index,const int count,IComparer<T>*comparer)
|
| {
|
| //--- check start index and count
|
| if(start_index<0 || count<0 || m_size-start_index<count)
|
| return(false);
|
| //--- create instances of sorter
|
| Introsort<T,T>sorter();
|
| //--- set array to sorter
|
| ArrayCopy(sorter.keys,m_items);
|
| //--- check comparer
|
| if(CheckPointer(comparer)!=POINTER_INVALID)
|
| {
|
| //--- use specified comparer
|
| sorter.comparer=comparer;
|
| //--- sort array
|
| sorter.Sort(start_index,count);
|
| }
|
| else
|
| {
|
| //--- use default comparer
|
| CDefaultComparer<T>def_comparer;
|
| sorter.comparer=GetPointer(def_comparer);
|
| //--- sort array
|
| sorter.Sort(start_index,count);
|
| }
|
| //--- store the sorted array
|
| ArrayCopy(m_items,sorter.keys);
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Ensures that the capacity of this list is at least the given |
|
| //| minimum value. If the currect capacity of the list is less than |
|
| //| min, the capacity is increased to twice the current capacity or |
|
| //| to min, whichever is larger. |
|
| //+------------------------------------------------------------------+
|
| template<typename T>
|
| void CArrayList::EnsureCapacity(const int min)
|
| {
|
| int size=ArraySize(m_items);
|
| //--- check current size
|
| if(size<min)
|
| {
|
| int new_capacity=(size==0) ? m_default_capacity : size*2;
|
| //--- allow the list to grow to maximum possible capacity before encountering overflow
|
| if((uint)new_capacity>INT_MAX)
|
| new_capacity=INT_MAX;
|
| if(new_capacity<min)
|
| new_capacity=min;
|
| //--- set new capacity
|
| Capacity(new_capacity);
|
| }
|
| }
|
| //+------------------------------------------------------------------+
|