thesis version

This commit is contained in:
2021-05-10 18:14:24 +02:00
commit caf2a692f9
281 changed files with 73182 additions and 0 deletions

75
inc/alsk/impl/bone/farm.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef ALSK_ALSK_IMPL_BONE_FARM_H
#define ALSK_ALSK_IMPL_BONE_FARM_H
#include <cmath>
#include <thread>
#include <tuple>
#include <utility>
#include <vector>
#include "../boneimplbase.h"
#include "../../skeleton/bone/farm.h"
namespace alsk {
/**
* @brief Farm implementation for sequential execution
*/
template<typename R, typename... Args, typename TTask, typename Executor, typename State>
struct Impl<Farm<R(Args...), TTask>, tag::Sequential, Executor, State>:
BoneImplBase<Farm<R(Args...), TTask>, tag::Sequential, Executor, State>
{
using This = Impl;
using Task = Execute<typename This::Skeleton::TaskLinks>;
typename This::Skeleton skeleton;
typename This::Executor executor;
typename This::StateRef state;
constexpr Impl() = default;
template<typename S>
constexpr Impl(S&& skeleton, Executor executor, State& state):
skeleton{std::forward<S>(skeleton)},
executor{executor},
state{state}
{}
constexpr void operator()(Args... args) {
executor.template executeSequential<Task>(
*this, skeleton.task, std::forward_as_tuple(args...), skeleton.n
);
}
};
/**
* @brief Farm implementation for parallel execution
*/
template<typename R, typename... Args, typename TTask, typename Executor, typename State>
struct Impl<Farm<R(Args...), TTask>, tag::Parallel, Executor, State>:
BoneImplBase<Farm<R(Args...), TTask>, tag::Parallel, Executor, State>
{
using This = Impl;
using Task = Execute<typename This::Skeleton::TaskLinks>;
typename This::Skeleton skeleton;
typename This::Executor executor;
typename This::StateRef state;
constexpr Impl() = default;
template<typename S>
constexpr Impl(S&& skeleton, Executor executor, State& state):
skeleton{std::forward<S>(skeleton)},
executor{executor},
state{state}
{}
constexpr void operator()(Args... args) {
executor.template executeParallel<Task>(
*this, skeleton.task, std::forward_as_tuple(args...), skeleton.n
);
}
};
}
#endif

View File

@ -0,0 +1,91 @@
#ifndef ALSK_ALSK_IMPL_BONE_FARMSEL_H
#define ALSK_ALSK_IMPL_BONE_FARMSEL_H
#include <cmath>
#include <thread>
#include <vector>
#include "../boneimplbase.h"
#include "../../skeleton/bone/farmsel.h"
namespace alsk {
/**
* @brief FarmSel implementation for sequential execution
*/
/*
template<typename R, typename... Args, typename... Tasks, typename Executor, typename State>
struct Impl<FarmSel<R(Args...), Tasks...>, tag::Sequential, Executor, State>:
BoneImplBase<FarmSel<R(Args...), Tasks...>, tag::Sequential, Executor, State>
{
using This = Impl;
using Task = Execute<typename This::Skeleton::TaskLinks>;
using Select = Execute<typename This::Skeleton::SelectLinks>;
typename This::Skeleton skeleton;
typename This::Executor executor;
typename This::StateRef state;
constexpr Impl() = default;
template<typename S>
constexpr Impl(S&& skeleton, Executor executor, State& state):
skeleton{std::forward<S>(skeleton)},
executor{executor},
state{state}
{}
constexpr typename This::Return operator()(Args... args) {
using Value = typename This::Return;
auto tupleP = std::forward_as_tuple(args...);
Value best{};
if(skeleton.n)
best = executor.template execute<Task>(*this, skeleton.task, tupleP, std::tuple<>{});
for(std::size_t i = 1; i < skeleton.n; ++i) {
Value current = executor.template execute<Task>(*this, skeleton.task, tupleP, std::tuple<>{});
best = executor.template execute<Select>(
*this, skeleton.select, tupleP, std::tuple<>{}, std::move(current), std::move(best)
);
}
return best;
}
};
*/
/**
* @brief FarmSel implementation for parallel execution
*/
template<typename R, typename... Args, typename... Tasks, typename Tag, typename Executor, typename State>
struct Impl<FarmSel<R(Args...), Tasks...>, Tag, Executor, State>:
BoneImplBase<FarmSel<R(Args...), Tasks...>, Tag, Executor, State>
{
using This = Impl;
using Task = Execute<typename This::Skeleton::TaskLinks>;
using Select = Execute<typename This::Skeleton::SelectLinks>;
typename This::Skeleton skeleton;
typename This::Executor executor;
typename This::StateRef state;
constexpr Impl() = default;
template<typename S>
constexpr Impl(S&& skeleton, Executor executor, State& state):
skeleton{std::forward<S>(skeleton)},
executor{executor},
state{state}
{}
constexpr typename This::Return operator()(Args... args) {
auto tupleP = std::forward_as_tuple(args...);
return executor.template executeParallelAccumulate<typename This::Return, Task, Select>(
*this, skeleton.task, skeleton.select, tupleP, skeleton.n
);
}
};
}
#endif

View File

@ -0,0 +1,57 @@
#ifndef ALSK_ALSK_IMPL_BONE_ITERSEL_H
#define ALSK_ALSK_IMPL_BONE_ITERSEL_H
#include <cmath>
#include <thread>
#include <vector>
#include "../boneimplbase.h"
#include "../../skeleton/bone/itersel.h"
namespace alsk {
/**
* @brief IterSel implementation for any execution
*/
template<typename R, typename... Args, typename... Tasks, typename Tag, typename Executor, typename State>
struct Impl<IterSel<R(Args...), Tasks...>, Tag, Executor, State>:
BoneImplBase<IterSel<R(Args...), Tasks...>, Tag, Executor, State>
{
using This = Impl;
using Task = Execute<typename This::Skeleton::TaskLinks>;
using Select = Execute<typename This::Skeleton::SelectLinks>;
typename This::Skeleton skeleton;
typename This::Executor executor;
typename This::StateRef state;
constexpr Impl() = default;
template<typename S, typename O>
constexpr Impl(S&& skeleton, O&& executor, State& state):
skeleton{std::forward<S>(skeleton)},
executor{std::forward<O>(executor)},
state{state}
{}
// TODO check repeatability with tag::Parallel
constexpr typename This::Return operator()(Args... args) {
using Value = typename This::Return;
auto tupleP = std::forward_as_tuple(args...);
Value best = ArgGet<arg::P<0>>::get(tupleP, std::tuple<>{}, std::tuple<>{});
for(std::size_t i = 0; i < skeleton.n; ++i) {
Value current = executor.template execute<Task>(*this, skeleton.task, tupleP, std::tuple<>{}, best);
best = executor.template execute<Select>(
*this, skeleton.select, tupleP, std::tuple<>{}, std::move(current), std::move(best)
);
}
return best;
}
};
}
#endif

41
inc/alsk/impl/bone/loop.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef ALSK_ALSK_IMPL_BONE_LOOP_H
#define ALSK_ALSK_IMPL_BONE_LOOP_H
#include <tuple>
#include "../boneimplbase.h"
#include "../../skeleton/bone/loop.h"
namespace alsk {
/**
* @brief Loop implementation for any execution
*/
template<typename R, typename... Args, typename Task, typename Tag, typename Executor, typename State>
struct Impl<Loop<R(Args...), Task>, Tag, Executor, State>:
BoneImplBase<Loop<R(Args...), Task>, Tag, Executor, State>
{
using This = Impl;
using ETask = Execute<typename This::Skeleton::TaskLinks>;
typename This::Skeleton skeleton;
typename This::Executor executor;
typename This::StateRef state;
constexpr Impl() = default;
template<typename S, typename O>
constexpr Impl(S&& skeleton, O&& executor, State& state):
skeleton{std::forward<S>(skeleton)},
executor{std::forward<O>(executor)},
state{state}
{}
constexpr typename This::Return operator()(Args... args) {
for(unsigned int i = 0; i < skeleton.n; ++i)
executor.template execute<ETask>(*this, skeleton.task, std::forward_as_tuple(args...), std::tuple<>{});
}
};
}
#endif

View File

@ -0,0 +1,82 @@
#ifndef ALSK_ALSK_IMPL_BONE_SERIAL_H
#define ALSK_ALSK_IMPL_BONE_SERIAL_H
#include "../boneimplbase.h"
#include "../../skeleton/bone/serial.h"
namespace alsk {
/**
* @brief Serial implementation for any execution
*/
template<typename R, typename... Args, typename... Tasks, typename Tag, typename Executor, typename State>
struct Impl<Serial<R(Args...), Tasks...>, Tag, Executor, State>:
BoneImplBase<Serial<R(Args...), Tasks...>, Tag, Executor, State>
{
using This = Impl;
using Results = tmp::Repack<std::tuple, tmp::PackReplace<typename This::Skeleton::PackR, void, tmp::Void>>;
typename This::Skeleton skeleton;
typename This::Executor executor;
typename This::StateRef state;
Results results;
constexpr Impl() = default;
template<typename S, typename O>
constexpr Impl(S&& skeleton, O&& executor, State& state):
skeleton{std::forward<S>(skeleton)},
executor{std::forward<O>(executor)},
state{state}
{}
// out-of-class definition to silence -Winline
~Impl() noexcept;
// TODO: what happens with rvalue references?
constexpr typename This::Return operator()(Args... args) {
return serial(std::forward_as_tuple(args...));
}
private:
template<typename TupleP>
constexpr decltype(auto) serial(TupleP&& p) {
serial<0, typename This::Skeleton::Links>(skeleton.tasks, p);
return ArgGet<R>::get(std::tuple<>{}, std::move(results), std::tuple<>{});
}
/**
* execute
*/
template<
std::size_t I, typename LinksPack, typename TupleTasks,
typename TupleP,
std::enable_if_t<(I < std::tuple_size<std::decay_t<TupleTasks>>::value)>* = nullptr
>
constexpr void serial(TupleTasks& tasks, TupleP& p) {
using Task = Execute<tmp::PackHead<LinksPack>>;
std::get<I>(results) = executor.template execute<Task>(
*this, std::get<I>(tasks), p, results
);
serial<I+1, tmp::PackTrail<LinksPack>>(tasks, p);
}
/**
* recursion terminaison
*/
template<
std::size_t I, typename LinksPack, typename TupleTasks,
typename TupleP,
std::enable_if_t<(I == std::tuple_size<std::decay_t<TupleTasks>>::value)>* = nullptr
>
constexpr void serial(TupleTasks&&, TupleP&&) noexcept {}
};
// out-of-class definition to silence -Winline
template<typename R, typename... Args, typename... Tasks, typename Tag, typename Executor, typename State>
Impl<Serial<R(Args...), Tasks...>, Tag, Executor, State>::~Impl() noexcept {}
}
#endif

View File

@ -0,0 +1,46 @@
#ifndef ALSK_ALSK_IMPL_BONE_WHILE_H
#define ALSK_ALSK_IMPL_BONE_WHILE_H
#include <cmath>
#include <vector>
#include "../boneimplbase.h"
#include "../../skeleton/bone/while.h"
namespace alsk {
/**
* @brief While implementation for any execution
*/
template<typename R, typename... Args, typename... Tasks, typename Tag, typename Executor, typename State>
struct Impl<While<R(Args...), Tasks...>, Tag, Executor, State>:
BoneImplBase<While<R(Args...), Tasks...>, Tag, Executor, State>
{
using This = Impl;
using Test = Execute<typename This::Skeleton::TestLinks>;
using Task = Execute<typename This::Skeleton::TaskLinks>;
typename This::Skeleton skeleton;
typename This::Executor executor;
typename This::StateRef state;
constexpr Impl() = default;
template<typename S, typename O>
constexpr Impl(S&& skeleton, O&& executor, State& state):
skeleton{std::forward<S>(skeleton)},
executor{std::forward<O>(executor)},
state{state}
{}
template<typename T>
constexpr typename This::Return operator()(T& a, T const& b) {
auto tupleP = std::forward_as_tuple(a, b);
while(executor.template execute<Test>(*this, skeleton.test, tupleP, std::tuple<>{}))
executor.template execute<Task>(*this, skeleton.task, tupleP, std::tuple<>{});
}
};
}
#endif

View File

@ -0,0 +1,40 @@
#ifndef ALSK_ALSK_IMPL_BONEIMPLBASE_H
#define ALSK_ALSK_IMPL_BONEIMPLBASE_H
#include <functional>
#include "execute.h"
#include "tags.h"
#include "../utility.h"
namespace alsk {
template<typename, typename, typename, typename> struct BoneImplBase;
template<
template<typename...> class Bone,
typename R, typename... Args, typename... Tasks,
typename Tag_, typename Executor_, typename State_
>
struct BoneImplBase<Bone<R(Args...), Tasks...>, Tag_, Executor_, State_> {
using Signature = R(Args...);
using Skeleton = Bone<Signature, Tasks...>;
using Tag = Tag_;
using Executor = Executor_;
using ExecutorInfo = typename std::decay_t<Executor_>::Info;
using State = State_;
using StateRef = std::reference_wrapper<State>;
using Return = RealType<R, typename Skeleton::Packs>;
ExecutorInfo executorInfo;
constexpr BoneImplBase() noexcept {}
std::size_t id = 0;
};
}
#endif

89
inc/alsk/impl/callable.h Normal file
View File

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

118
inc/alsk/impl/execute.h Normal file
View File

@ -0,0 +1,118 @@
#ifndef ALSK_ALSK_IMPL_EXECUTE_H
#define ALSK_ALSK_IMPL_EXECUTE_H
#include "../skeleton/utility.h"
#include "../executor/traits.h"
namespace alsk {
namespace impl {
/**
* @brief internal implement function
* @param executor an instance of the selected executor
* @param skeleton an instance of the skeleton to implement
* @param state the shared state
* @param id the task identifier
* @param eInfo information provided by the executor
*/
template<
typename Executor, typename S, typename State, typename CtxId, typename ExecutorInfo,
std::enable_if_t<isSkeleton<S>>* = nullptr,
std::enable_if_t<isExecutor<Executor>>* = nullptr
>
auto implement(Executor& executor, S&& skeleton, State&& state, CtxId&& id, ExecutorInfo&& eInfo) {
using ImplType = Impl<std::decay_t<S>, typename Executor::Tag, Executor&, std::remove_reference_t<State>>;
auto impl = ImplType{std::forward<S>(skeleton), executor, std::forward<State>(state)};
impl.id = std::forward<CtxId>(id);
impl.executorInfo = std::forward<ExecutorInfo>(eInfo);
return impl;
}
/**
* @brief internal implement function for end muscles
* @param executor ignored
* @param value a muscle
* @param state ignored
* @param id ignored
* @param eInfo ignored
*/
template<typename Executor, typename T, typename State, typename CtxId, typename ExecutorInfo,
std::enable_if_t<not isSkeleton<T>>* = nullptr,
std::enable_if_t<isExecutor<Executor>>* = nullptr
>
decltype(auto) implement(Executor&, T&& value, State&&, CtxId&&, ExecutorInfo&&) {
return std::forward<T>(value);
}
}
/**
* Execute
*/
namespace impl {
template<typename> struct Execute {};
template<typename Ret, typename... Ps>
struct Execute<Ret(Ps...)> {
template<
typename Impl, typename Task, typename CtxId, typename ExecutorInfo,
typename P, typename R, typename... Args
>
static decltype(auto) execute(Impl& impl, Task&& task, CtxId&& cid, ExecutorInfo&& eInfo, P&& p, R&& r, Args&&... args) {
auto id = impl.id + std::forward<CtxId>(cid) * impl.skeleton.step;
typename Impl::State& state = impl.state;
return executeF(
impl::implement(impl.executor, std::forward<Task>(task), state, id, std::forward<ExecutorInfo>(eInfo)),
std::forward<P>(p), std::forward<R>(r),
state.context.args(impl.executor.contextId(impl, id)),
std::forward<Args>(args)...
);
}
private:
template<
typename F, typename P, typename R, typename C, typename... Args,
typename Result = tmp::invoke_result_t<
std::decay_t<F>,
Args...,
ArgType<Ps, arg::Placeholders<P, R, C>>...
>,
std::enable_if_t<not std::is_same<Result, void>::value>* = nullptr
>
static Result executeF(F&& f, P&& p, R&& r, C&& c, Args&&... args) {
return std::forward<F>(f)(
std::forward<Args>(args)...,
ArgGet<Ps>::get(std::forward<P>(p), std::forward<R>(r), std::forward<C>(c))...
);
}
template<
typename F, typename P, typename R, typename C, typename... Args,
typename Result = tmp::invoke_result_t<
std::decay_t<F>,
Args...,
ArgType<Ps, arg::Placeholders<P, R, C>>...
>,
std::enable_if_t<std::is_same<Result, void>::value>* = nullptr
>
static auto executeF(F&& f, P&& p, R&& r, C&& c, Args&&... args) {
std::forward<F>(f)(
std::forward<Args>(args)...,
ArgGet<Ps>::get(std::forward<P>(p), std::forward<R>(r), std::forward<C>(c))...
);
return tmp::Void{};
}
};
}
template<typename Signature>
using Execute = impl::Execute<ArgFilter<Signature>>;
}
#endif

13
inc/alsk/impl/impl.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef ALSK_ALSK_IMPL_IMPL_H
#define ALSK_ALSK_IMPL_IMPL_H
#include "bone/farm.h"
#include "bone/farmsel.h"
#include "bone/itersel.h"
#include "bone/loop.h"
#include "bone/serial.h"
#include "bone/while.h"
#include "implement.h"
#endif

57
inc/alsk/impl/implement.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef ALSK_ALSK_IMPL_IMPLEMENT_H
#define ALSK_ALSK_IMPL_IMPLEMENT_H
#include <utility>
#include "callable.h"
#include "../context/context.h"
#include "../executor/traits.h"
namespace alsk {
/**
* @brief implement a skeleton
* @param TExecutor the executor template
* @param Skeleton the skeleton type
* @param Context [optional] the type of the context
*
* @return a callable
*/
template<template<typename> class TExecutor, typename Skeleton,
typename Context = DefaultContext,
std::enable_if_t<isSkeleton<Skeleton>>* = nullptr,
std::enable_if_t<isExecutor<TExecutor<Skeleton>>>* = nullptr
>
auto implement() {
using Executor = TExecutor<Skeleton>;
using State = CallableState<Context, Executor>;
using ImplType = Impl<Skeleton, typename Executor::Tag, Executor, State>;
return Callable<ImplType>(Skeleton{}, Executor{});
}
/**
* @brief implement a skeleton
* @param executor an instance of the executor
* @param skeleton an instance of the skeleton to implement
* @param Context [optional] the type of the context
*
* @return a callable
*/
template<typename Context = DefaultContext,
typename Executor, typename S,
std::enable_if_t<isSkeleton<S>>* = nullptr,
std::enable_if_t<isExecutor<Executor>>* = nullptr
>
auto implement(Executor&& executor, S&& skeleton) {
using ExecutorT = std::decay_t<Executor>;
using State = CallableState<Context, ExecutorT>;
using ImplType = Impl<std::decay_t<S>, typename ExecutorT::Tag, ExecutorT, State>;
return Callable<ImplType>(std::forward<S>(skeleton), std::forward<Executor>(executor));
}
}
#endif

13
inc/alsk/impl/tags.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef ALSK_ALSK_IMPL_TAGS_H
#define ALSK_ALSK_IMPL_TAGS_H
namespace alsk {
namespace tag {
struct Sequential {};
struct Parallel {};
}
}
#endif