//! \~\file pithreadpoolloop.h
//! \~\ingroup Thread
//! \~\brief
//! \~english Parallel loop helper
//! \~russian Вспомогательный класс для параллельного цикла
/*
    PIP - Platform Independent Primitives
    Thread pool loop
    Ivan Pelipenko peri4ko@yandex.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef PITHREADPOOLLOOP_H
#define PITHREADPOOLLOOP_H

#include "pisemaphore.h"
#include "pivector.h"

class PIThread;

//! \~\ingroup Thread
//! \~\brief
//! \~english Helper that runs one integer range across a fixed set of worker threads.
//! \~russian Вспомогательный класс, который выполняет один целочисленный диапазон на фиксированном наборе рабочих потоков.
class PIP_EXPORT PIThreadPoolLoop {
public:
	//! \~english Constructs parallel loop runner with \a thread_cnt worker threads. If \a thread_cnt is less than or equal to zero, the
	//! processor count is used.
	//! \~russian Создает исполнитель параллельного цикла с \a thread_cnt рабочими потоками. Если \a thread_cnt меньше либо равен нулю,
	//! используется количество процессоров.
	PIThreadPoolLoop(int thread_cnt = -1);

	//! \~english Stops worker threads and destroys the loop runner.
	//! \~russian Останавливает рабочие потоки и уничтожает исполнитель цикла.
	virtual ~PIThreadPoolLoop();

	//! \~english Sets the iteration body called once for each index of a started range.
	//! \~russian Устанавливает тело итерации, которое вызывается один раз для каждого индекса запущенного диапазона.
	void setFunction(std::function<void(int)> f);

	//! \~english Waits for the current in-flight batch started by \a start().
	//! \~russian Ожидает завершения текущего запущенного пакета, начатого через \a start().
	void wait();

	//! \~english Starts asynchronous execution for indices in range [\a index_start, \a index_start + \a index_count).
	//! \~russian Запускает асинхронное выполнение для индексов из диапазона [\a index_start, \a index_start + \a index_count).
	void start(int index_start, int index_count);

	//! \~english Runs the configured iteration body for indices in range [\a index_start, \a index_start + \a index_count) and waits for
	//! completion.
	//! \~russian Выполняет настроенное тело итерации для индексов из диапазона [\a index_start, \a index_start + \a index_count) и ожидает
	//! завершения.
	void exec(int index_start, int index_count);

	//! \~english Sets iteration body to \a f, runs it for indices in range [\a index_start, \a index_start + \a index_count), and waits for
	//! completion.
	//! \~russian Устанавливает тело итерации \a f, выполняет его для индексов из диапазона [\a index_start, \a index_start + \a
	//! index_count) и ожидает завершения.
	void exec(int index_start, int index_count, std::function<void(int)> f);

private:
	PIVector<PIThread *> threads;
	std::function<void(int)> func;
	PISemaphore sem_exec, sem_done;
	std::atomic_bool is_destroy = {false};
	std::atomic_int counter = {0}, wait_count = {0};
};


#endif
