
#ifndef PLS_PARALLEL_FOR_IMPL_H
#define PLS_PARALLEL_FOR_IMPL_H

#include "pls/internal/scheduling/task.h"
#include "pls/internal/scheduling/scheduler.h"

#include "pls/internal/helpers/unique_id.h"

namespace pls {
namespace algorithm {

template<typename RandomIt, typename Function>
void parallel_for(RandomIt first, RandomIt last, const Function &function) {
  using namespace ::pls::internal::scheduling;
  constexpr long min_elements = 4;

  long num_elements = std::distance(first, last);
  if (num_elements <= min_elements) {
    // calculate last elements in loop to avoid overhead
    for (auto current = first; current != last; current++) {
      function(*current);
    }
  } else {
    // Cut in half recursively
    long middle_index = num_elements / 2;

    auto body2 = [=] { parallel_for(first + middle_index, last, function); };
    lambda_task_by_reference<decltype(body2)> second_half_task(body2);
    scheduler::spawn_child(second_half_task);

    auto body1 = [=] { parallel_for(first, first + middle_index, function); };
    lambda_task_by_reference<decltype(body1)> first_half_task(body1);
    scheduler::spawn_child(first_half_task);
    scheduler::wait_for_all();
  }
}

}
}

#endif //PLS_INVOKE_PARALLEL_IMPL_H
