#ifndef ALSK_ALSK_IMPL_CALLABLE_H #define ALSK_ALSK_IMPL_CALLABLE_H #include "../skeleton/utility.h" #include "../executor/executorstate.h" namespace alsk { template struct CallableState { Context context; exec::ExecutorState executor; // out-of-class definition to silence -Winline ~CallableState() noexcept; }; template CallableState::~CallableState() noexcept {} template struct Callable; template< template class Impl, template class Skel, typename R, typename... Operands, typename... Tasks, typename Tag, typename Executor, typename State > struct Callable, Tag, Executor, State>>: Impl, Tag, Executor, State> { using Skeleton = Skel; using Implementation = Impl; using ThisType = Callable; private: std::size_t _parTasksCount; public: State state; template* = nullptr> constexpr Callable(Args&&... args): Implementation(std::forward(args)..., state), _parTasksCount{0} {} // out-of-class definition to silence -Winline ~Callable() noexcept; constexpr decltype(auto) operator()(Operands... operands) { update(); return Implementation::operator()(operands...); } template constexpr decltype(auto) traverse(F&& function, T&& init) { return SkeletonTraversal::execute(Implementation::skeleton, std::forward(function), std::forward(init)); } static constexpr tmp::Depth parallelizableLevels() { return skeletonParallelHeight; } std::size_t parallelTasksCount() const { return _parTasksCount; } constexpr void update() { auto traverser = [](std::size_t, auto&& skl, auto&&... values) { using Skl = decltype(skl); auto subpar = max(values...); skl.step = subpar; return SkeletonTraitsT::parallelizability(std::forward(skl)) * subpar; }; _parTasksCount = traverse(traverser, 1ul); ThisType::executor.config(*this); state.context.setup(ThisType::executor.contextIdCount(static_cast(*this), _parTasksCount)); } }; template< template class Impl, template class Skel, typename R, typename... Operands, typename... Tasks, typename Tag, typename Executor, typename State > Callable, Tag, Executor, State>>::~Callable() noexcept {} } #endif