Skip to content

Instantly share code, notes, and snippets.

@jaredhoberock
Created August 2, 2018 16:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jaredhoberock/9eb90aa5f9e4755a1ea4b206a8e837c1 to your computer and use it in GitHub Desktop.
Save jaredhoberock/9eb90aa5f9e4755a1ea4b206a8e837c1 to your computer and use it in GitHub Desktop.
Experimental polymorphic executor which exposes a single .execute() function
// $ clang-5.0 -std=c++17 -Iexecutors-impl/include -lstdc++ neo_executor.cpp
#include <experimental/execution>
#include <type_traits>
#include <iostream>
template<class T>
struct __is_bulk_task
{
template<class U = T,
class = decltype(std::declval<U>().function()),
class = decltype(std::declval<U>().shape()),
class = decltype(std::declval<U>().shared_factory())
>
static constexpr bool test(int) { return true; }
static constexpr bool test(...) { return false; }
static constexpr bool value = test(0);
};
template<class T>
static constexpr bool __is_bulk_task_v = __is_bulk_task<T>::value;
template<class Function, class SharedFactory>
struct __bulk_task_t
{
Function& function()
{
return f_;
}
const Function& function() const
{
return f_;
}
size_t shape() const
{
return shape_;
}
SharedFactory& shared_factory()
{
return shared_factory_;
}
const SharedFactory& shared_factory() const
{
return shared_factory_;
}
Function f_;
size_t shape_;
SharedFactory shared_factory_;
};
template<class Function, class SharedFactory>
__bulk_task_t<std::decay_t<Function>, std::decay_t<SharedFactory>> __bulk_task(Function&& f, size_t n, SharedFactory&& shared_factory)
{
return {std::forward<Function>(f), n, std::forward<SharedFactory>(shared_factory)};
}
template<class NeoExecutor>
struct __old_executor_adaptor
{
friend bool operator==(const __old_executor_adaptor& a, const __old_executor_adaptor& b) noexcept
{
return a.adapted_ex_ == b.adapted_ex_;
}
friend bool operator!=(const __old_executor_adaptor& a, const __old_executor_adaptor& b) noexcept
{
return !(a == b);
}
template<class Function, class SharedFactory>
void bulk_execute(Function&& f, size_t n, SharedFactory&& shared_factory) const noexcept
{
adapted_ex_.execute(__bulk_task(std::forward<Function>(f), n, std::forward<SharedFactory>(shared_factory)));
}
template<class Function,
class = std::enable_if_t<
std::is_invocable_v<std::decay_t<Function>>
>
>
void execute(Function&& f) const noexcept
{
adapted_ex_.execute(std::forward<Function>(f));
}
NeoExecutor adapted_ex_;
};
template<class... SupportableProperties>
class neo_executor : private std::experimental::execution::executor<SupportableProperties...>
{
private:
using super_t = std::experimental::execution::executor<SupportableProperties...>;
public:
neo_executor() = default;
neo_executor(const neo_executor&) = default;
template<class Executor>
neo_executor(const Executor& ex) : super_t(__old_executor_adaptor<Executor>{ex}) {}
template<class Function>
void execute(Function&& f) const
{
// XXX this if should also check that single is in the SupportableProperties
if constexpr (std::is_invocable_v<Function>)
{
super_t::execute(std::forward<Function>(f));
}
// XXX this if should also check that bulk is in the SupportableProperties
else if constexpr (__is_bulk_task_v<Function>)
{
super_t::bulk_execute(f.function(), f.shape(), f.shared_factory());
}
else
{
static_assert("Unrecognized callable.");
}
}
};
class inline_executor
{
public:
friend bool operator==(const inline_executor&, const inline_executor&) noexcept
{
return true;
}
friend bool operator!=(const inline_executor&, const inline_executor&) noexcept
{
return false;
}
template <class Function>
void execute(Function f) const noexcept
{
f();
}
};
static_assert(std::experimental::execution::is_oneway_executor_v<inline_executor>, "one way executor requirements not met");
class neo_bulk_executor
{
public:
friend bool operator==(const neo_bulk_executor&, const neo_bulk_executor&) noexcept
{
return true;
}
friend bool operator!=(const neo_bulk_executor&, const neo_bulk_executor&) noexcept
{
return false;
}
template<class BulkTask>
void execute(BulkTask task) const noexcept
{
auto f = std::move(task.function());
auto shape = task.shape();
auto shared = std::move(task.shared_factory())();
for(auto i = 0; i < shape; ++i)
{
f(i, shared);
}
}
};
int main()
{
using namespace std::experimental::execution;
inline_executor inline_ex;
neo_bulk_executor bulk_ex;
neo_executor<oneway_t, single_t> wrapped_inline_ex(inline_ex);
wrapped_inline_ex.execute([]
{
std::cout << "Hello world from inline agent" << std::endl;
});
neo_executor<oneway_t, bulk_t> wrapped_bulk_ex(bulk_ex);
wrapped_bulk_ex.execute(__bulk_task(
[](size_t i, auto& shared)
{
std::cout << "Hello world from bulk agent " << i << std::endl;
},
10,
[]{ return 13; }
));
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment