//+------------------------------------------------------------------+ //| BufferDouble.mqh | //| Copyright 2021, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| Подключаем библиотеки | //+------------------------------------------------------------------+ #include #include "opencl.mqh" #include "defines.mqh" //+------------------------------------------------------------------+ //| Class CBufferDouble | //| Назначение: Класс динамического буфера данных | //+------------------------------------------------------------------+ class CBufferDouble : public CArrayDouble { protected: CMyOpenCL *m_cOpenCL; // Объект контекста OpenCL int m_myIndex; // Индекс буфера данных в контексте public: CBufferDouble(void); ~CBufferDouble(void); //--- Метод инициализации буфера начальными значениями virtual bool BufferInit(uint count, double value); //--- Сложение векторов virtual bool SumArray(const CArrayDouble *src); //--- Созданиие нового буфера в контексте OpenCL virtual bool BufferCreate(CMyOpenCL *opencl); //--- Удаление буфера в контексте OpenCL virtual bool BufferFree(void); //--- Чтение данных буфера из контекста OpenCL virtual bool BufferRead(void); //--- Запись данных буфера в контекст OpenCL virtual bool BufferWrite(void); //--- Получение индекса буфера virtual int GetIndex(void); //--- Изменение индекса буфера virtual bool SetIndex(int index) { if(!m_cOpenCL.BufferFree(m_myIndex)) return false; m_myIndex = index; return true; } //--- Копирование данных буфера в массив virtual int GetData(double &values[], bool load = true); virtual int GetData(CArrayDouble *values, bool load = true); //--- Рассчёт среднего значения буфера данных virtual double MathMean(void); //--- Масштабирование значений буфера virtual int Scaling(double value); //--- Обновдение данных в буфере из массива virtual bool UpdateArray(const int start_pos, const CArrayDouble *src, const int start_src, int count); virtual bool UpdateArray(const int start_pos, const double &src[], const int start_src, int count); //--- Идентификатор класса virtual int Type(void) const { return defBufferDouble; } }; //+------------------------------------------------------------------+ //| Конструктор класса | //+------------------------------------------------------------------+ CBufferDouble::CBufferDouble(void) : m_myIndex(-1) { m_cOpenCL = NULL; } //+------------------------------------------------------------------+ //| Деструктор класса | //+------------------------------------------------------------------+ CBufferDouble::~CBufferDouble(void) { if(CheckPointer(m_cOpenCL) != POINTER_INVALID && m_myIndex >= 0) { if(m_cOpenCL.BufferFree(m_myIndex)) { m_myIndex = -1; m_cOpenCL = NULL; } } Shutdown(); } //+------------------------------------------------------------------+ //| Созданиие нового буфера в контексте OpenCL | //+------------------------------------------------------------------+ bool CBufferDouble::BufferCreate(CMyOpenCL *opencl) { //--- Блок проверки исходных данных if(CheckPointer(opencl) == POINTER_INVALID) { BufferFree(); return false; } //--- Если полученный указатель совпадает с ранее сохранённым просто копируем содержимое буфера в память контекста if(opencl == m_cOpenCL && m_myIndex >= 0) { if(BufferWrite()) return true; } //--- Проверяем наличие ранее сохранённого указателя на контекст OpenCL //--- При наличии, удаляем буфер из неиспользуемого контекста if(CheckPointer(m_cOpenCL) != POINTER_INVALID && m_myIndex >= 0) { if(m_cOpenCL.BufferFree(m_myIndex)) { m_myIndex = -1; m_cOpenCL = NULL; } else return false; } //--- Создаём новый буфер в указнном контексте OpenCL if((m_myIndex = opencl.AddBufferFromArray(m_data, 0, m_data_total, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR)) < 0) return false; m_cOpenCL = opencl; //--- return true; } //+------------------------------------------------------------------+ //| Метод удаления буфера из памяти контекста OpenCL | //+------------------------------------------------------------------+ bool CBufferDouble::BufferFree(void) { //--- Проверяем наличие ранее сохранённого указателя на контекст OpenCL //--- При наличии, удаляем буфер из неиспользуемого контекста if(CheckPointer(m_cOpenCL) != POINTER_INVALID && m_myIndex >= 0) if(m_cOpenCL.BufferFree(m_myIndex)) { m_myIndex = -1; m_cOpenCL = NULL; return true; } if(m_myIndex >= 0) m_myIndex = -1; //--- return false; } //+------------------------------------------------------------------+ //| Метод чтения данных из буфера контекста OpenCL | //+------------------------------------------------------------------+ bool CBufferDouble::BufferRead(void) { if(CheckPointer(m_cOpenCL) == POINTER_INVALID || m_myIndex < 0) return false; //--- return m_cOpenCL.BufferRead(m_myIndex, m_data, 0, 0, m_data_total); } //+------------------------------------------------------------------+ //| Метод записи данных в буфера контекста OpenCL | //+------------------------------------------------------------------+ bool CBufferDouble::BufferWrite(void) { if(CheckPointer(m_cOpenCL) == POINTER_INVALID || m_myIndex < 0) return false; //--- return m_cOpenCL.BufferWrite(m_myIndex, m_data, 0, 0, m_data_total); } //+------------------------------------------------------------------+ //| Метод инициализации буфера начальными значениями | //+------------------------------------------------------------------+ bool CBufferDouble::BufferInit(uint count, double value) { if(!Reserve(count)) return false; m_data_total = (int)fmin(ArrayInitialize(m_data, value), count); //--- return m_data_total == count; } //+------------------------------------------------------------------+ //| Метод получения значений буфера | //+------------------------------------------------------------------+ int CBufferDouble::GetData(double &values[], bool load = true) { if(load && !BufferRead()) return -1; return ArrayCopy(values, m_data, 0, 0, m_data_total); } //+------------------------------------------------------------------+ //| Метод получения значений буфера | //+------------------------------------------------------------------+ int CBufferDouble::GetData(CArrayDouble *values, bool load = true) { if(CheckPointer(values) == POINTER_INVALID) return -1; if(load && !BufferRead()) return -1; if(!values.AssignArray(GetPointer(this))) return -1; return values.m_data_total; } //+------------------------------------------------------------------+ //| Метод суммирования элементов двух буферов данных | //+------------------------------------------------------------------+ bool CBufferDouble::SumArray(const CArrayDouble *src) { int num; //--- Проверка массива исходных жанных if(!CheckPointer(src)) return(false); //--- Резервирование места в динамическом массиве для записи результатов num = src.m_data_total; if(m_data_max < num) { if(!Reserve(num)) return(false); } //--- Цикл сложения элементов массивов for(int i = 0; i < num; i++) { if(m_data_total <= i) m_data[i] = src.m_data[i]; else m_data[i] += src.m_data[i]; } m_sort_mode = src.SortMode(); m_data_total = (int)fmax(m_data_total, num); //--- return(true); } //+------------------------------------------------------------------+ //| Метод вычисления среднего значениия массива | //+------------------------------------------------------------------+ double CBufferDouble::MathMean(void) { if(m_data_total <= 0) return 0; //--- double mean = 0; for(int i = 0; i < m_data_total; i++) mean += m_data[i]; //--- return mean / m_data_total; } //+------------------------------------------------------------------+ //| Получени индекса буфера в контексте OpenCL | //+------------------------------------------------------------------+ int CBufferDouble::GetIndex(void) { if(CheckPointer(m_cOpenCL) == POINTER_INVALID || m_myIndex < 0) { m_myIndex = -1; return m_myIndex; } //--- if(!m_cOpenCL.CheckBuffer(m_myIndex)) m_myIndex = BufferCreate(m_cOpenCL); //--- return m_myIndex; } //+------------------------------------------------------------------+ //| Метод масштабирования данных (умножение на константу) | //+------------------------------------------------------------------+ int CBufferDouble::Scaling(double value) { for(int i = 0; i < m_data_total; i++) m_data[i] *= value; //--- return m_data_total; } //+------------------------------------------------------------------+ //| Метод заполнения буфера из массива данных | //+------------------------------------------------------------------+ bool CBufferDouble::UpdateArray(const int start_pos, const CArrayDouble *src, const int start_src, int count) { if(start_pos < 0 || start_src < 0) return false; if(CheckPointer(src) == POINTER_INVALID) return false; if(count < 0) count = src.Total() - start_src; if(count < 0 || src.Total() < (start_src + count)) return false; if((start_pos + count) > m_data_max && !Reserve(start_pos + count)) return false; //--- for(int i = 0; i < count; i++) m_data[start_pos + i] = src[start_src + i]; //--- return true; } //+------------------------------------------------------------------+ //| Метод заполнения буфера из массива данных | //+------------------------------------------------------------------+ bool CBufferDouble::UpdateArray(const int start_pos, const double &src[], const int start_src, int count) { if(start_pos < 0 || start_src < 0) return false; int src_total = ArraySize(src); if(src_total <= 0) return false; if(count < 0) count = src_total - start_src; if(count < 0 || src_total < (start_src + count)) return false; if((start_pos + count) > m_data_max && !Reserve(start_pos + count)) return false; //--- for(int i = 0; i < count; i++) m_data[start_pos + i] = src[start_src + i]; //--- return true; } //+------------------------------------------------------------------+