
#ifndef PLS_PARALLEL_ITERATOR_TASK_H
#define PLS_PARALLEL_ITERATOR_TASK_H

#include "pls/internal/data_structures/stamped_integer.h"
#include "abstract_task.h"

namespace pls {
namespace internal {
namespace scheduling {

using data_structures::stamped_integer;

template<typename RandomIt, typename Function>
class parallel_iterator_task : public abstract_task {
  alignas(64) const int step = 8;

  alignas(64) RandomIt first_, last_;
  alignas(64) Function function_;

  // External stealing
  alignas(64) std::atomic<size_t> first_index_;
  alignas(64) std::atomic<size_t> to_be_processed_;
  alignas(64) std::atomic<stamped_integer> last_index_;

  alignas(64) parallel_iterator_task *parent_;

  bool steal_front(size_t &stolen_max_index);
  bool steal_back(size_t &stolen_first_index, size_t &stolen_last_index);

 protected:
  bool internal_stealing(abstract_task *other_task) override;
  bool split_task(base::swmr_spin_lock * /*lock*/) override;

 public:
  explicit parallel_iterator_task(RandomIt first, RandomIt last, Function function, const abstract_task::id &id);
  parallel_iterator_task(const parallel_iterator_task &other);
  void execute() override;
};
}
}
}
#include "parallel_iterator_task_impl.h"

#endif //PLS_PARALLEL_ITERATOR_TASK_H
