1 #ifndef UTOPIA_CORE_APPLY_HH
2 #define UTOPIA_CORE_APPLY_HH
16 template<
class Container>
17 using entity_t =
typename Container::value_type::element_type;
46 template<
typename State,
typename Rule,
typename... Args>
52 std::is_invocable_v<Rule,
53 typename std::remove_reference_t<Args>::reference...>,
54 "Cannot invoke the Rule with the given container elements as arguments!"
55 " Please check the rule signature!");
59 using type = std::invoke_result_t<
61 typename std::remove_reference_t<Args>::reference...>;
66 std::is_same_v<type, void> or std::is_convertible_v<type, State>,
67 "Invoking the rule must return a type that can be converted to the "
68 "Entity state type!");
74 template<
typename State,
typename Rule,
typename... Args>
81 template<
typename State,
typename Rule,
typename... Args>
93 template<
class Tuple, std::size_t... I>
94 constexpr decltype(
auto)
97 return std::make_tuple(std::get<I>(std::forward<Tuple>(t))...);
112 template<
class Tuple>
113 constexpr decltype(
auto)
117 std::forward<Tuple>(t),
118 std::make_index_sequence<
119 std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
129 typename std::enable_if_t<mode == Update::sync, int> = 0,
130 typename std::enable_if_t<
131 impl::entity_t<ContTarget>::mode
134 const ContTarget& cont_target,
135 ContArgs&&... cont_args)
160 typename std::enable_if_t<mode == Update::sync, int> = 0,
161 typename std::enable_if_t<
162 impl::entity_t<ContTarget>::mode
166 const ContTarget& cont_target,
167 ContArgs&&... cont_args)
172 static_assert(not is_void_rule<State, Rule, ContTarget, ContArgs...>(),
173 "Cannot apply void rules in a synchronous update!");
177 std::vector<State> state_cache(cont_target.size(),
178 cont_target.front()->state);
190 [&rule](
auto&& args) {
191 return std::apply(rule,
192 std::forward<decltype(args)>(args));
201 std::get<0>(tpl)->state = std::move(std::get<1>(tpl));
211 typename std::enable_if_t<mode == Update::async, int> = 0,
212 typename std::enable_if_t<
213 impl::entity_t<ContTarget>::mode
215 typename std::enable_if_t<shuffle == Shuffle::off, int> = 0>
218 const ContTarget& cont_target,
219 ContArgs&&... cont_args)
221 apply_rule<mode, shuffle>(
248 typename std::enable_if_t<mode == Update::async, int> = 0,
249 typename std::enable_if_t<
250 impl::entity_t<ContTarget>::mode
252 typename std::enable_if_t<shuffle == Shuffle::off, int> = 0>
256 const ContTarget& cont_target,
257 ContArgs&&... cont_args)
265 if constexpr (is_void_rule<State, Rule, ContTarget, ContArgs...>()) {
269 std::forward<decltype(args)>(args));
274 auto& cell = std::get<0>(args);
275 cell->state = std::apply(rule,
276 std::forward<decltype(args)>(args));
288 typename std::enable_if_t<mode == Update::async, int> = 0,
289 typename std::enable_if_t<
290 impl::entity_t<ContTarget>::mode
292 typename std::enable_if_t<shuffle == Shuffle::on, int> = 0>
295 const ContTarget& cont_target,
297 ContArgs&&... cont_args)
299 apply_rule<mode, shuffle>(
339 typename std::enable_if_t<mode == Update::async, int> = 0,
340 typename std::enable_if_t<
341 impl::entity_t<ContTarget>::mode
343 typename std::enable_if_t<shuffle == Shuffle::on, int> = 0>
347 const ContTarget& cont_target,
349 ContArgs&&... cont_args)
361 using Tuple = std::tuple<
363 std::reference_wrapper<
364 const typename std::remove_reference_t<ContTarget>::value_type>,
368 std::is_const_v<std::remove_reference_t<ContArgs>>,
370 std::reference_wrapper<
371 const typename std::remove_reference_t<ContArgs>::value_type>,
373 std::reference_wrapper<
374 typename std::remove_reference_t<ContArgs>::value_type>>...>;
379 begin(args_container),
end(args_container), std::forward<RNG>(
rng));
383 if constexpr(is_void_rule<State, Rule, ContTarget, ContArgs...>())
387 begin(args_container),
389 [&rule](
auto&& args) {
394 std::forward<decltype(args)>(args)));
400 begin(args_container),
402 [&rule](
auto&& args) {
406 std::forward<decltype(args)>(args));
407 auto& entity = std::get<0>(tpl);
410 entity->state = std::apply(rule, tpl);
428 bool sync=impl::entity_t<Container>::is_sync()>
429 std::enable_if_t<sync, void>
434 std::invoke_result_t<Rule, typename Container::value_type>;
436 if constexpr(std::is_same_v<ReturnType, void>) {
439 [&rule](
const auto& entity){ rule(entity); }
445 [&rule](
const auto& entity){ entity->state_new() = rule(entity); }
453 [](
const auto& entity){ entity->update(); }
467 bool sync=impl::entity_t<Container>::is_sync()>
468 std::enable_if_t<not sync && not shuffle, void>
473 std::invoke_result_t<Rule, typename Container::value_type>;
475 if constexpr(std::is_same_v<ReturnType, void>) {
478 [&rule](
const auto& entity){ rule(entity); }
484 [&rule](
const auto& entity){ entity->state() = rule(entity); }
499 bool sync=impl::entity_t<Container>::is_sync()>
500 std::enable_if_t<not sync && shuffle, void>
503 std::remove_const_t<Container> container_shuffled(container);
506 std::forward<RNG>(
rng));
510 std::invoke_result_t<Rule, typename Container::value_type>;
512 if constexpr(std::is_same_v<ReturnType, void>)
516 [&rule](
const auto& entity){ rule(entity); }
523 [&rule](
const auto& entity){ entity->state() = rule(entity); }
Helper class for checking rule signatures and return types.
Definition: apply.hh:48
std::invoke_result_t< Rule, typename std::remove_reference_t< Args >::reference... > type
Report rule invoke result.
Definition: apply.hh:61
OutputIt transform(const Utopia::ExecPolicy policy, InputIt first1, InputIt last1, OutputIt d_first, UnaryOperation unary_op)
Apply a unary operator to a range and store the result in a new range.
Definition: parallel.hh:368
void for_each(const Utopia::ExecPolicy policy, InputIt first, InputIt last, UnaryFunction f)
Apply a function to a range.
Definition: parallel.hh:346
decltype(auto) range(const Graph &g)
Get the iterator range over selected graph entities.
Definition: iterator.hh:149
ExecPolicy
Runtime execution policies.
Definition: parallel.hh:60
@ seq
Sequential (i.e., regular) execution.
Definition: parallel.hh:66
@ par_unseq
SIMD execution on multiple threads.
Definition: parallel.hh:69
constexpr decltype(auto) make_tuple_from_tuple(Tuple &&t)
Helper function to create a tuple from a tuple.
Definition: apply.hh:114
constexpr decltype(auto) make_tuple_from_tuple_impl(Tuple &&t, std::index_sequence< I... >)
Helper function to create a tuple from a tuple using an index sequence.
Definition: apply.hh:95
Shuffle
Switch for enabling/disabling shuffling the cells for asynchronous updates.
Definition: apply.hh:27
constexpr bool is_void_rule()
Helper function to check if the rule returns void
Definition: apply.hh:82
Update
Update modes when applying rules.
Definition: state.hh:20
typename rule_invoke_result< State, Rule, Args... >::type rule_invoke_result_t
Helper definition to query the rule result type.
Definition: apply.hh:76
void apply_rule(Rule &&rule, const ContTarget &cont_target, ContArgs &&... cont_args)
Sequential overload.
Definition: apply.hh:133
@ off
Immediately apply the rule sequentially.
@ on
Shuffle the container before applying the rule sequentially.
@ manual
User chooses update type when calling apply_rule()
std::mt19937 rng
– Type definitions ----------------------------------------------------—
Definition: test_revision.cc:17
typename Container::value_type::element_type entity_t
Return the element type of any container holding pointers to entities.
Definition: apply.hh:17
Definition: parallel.hh:235