OGS
CheckEvalOrderRT.h
Go to the documentation of this file.
1
11#pragma once
12
13#include <boost/mp11.hpp>
14#include <typeindex>
15#include <unordered_set>
16
17#include "Apply.h"
18#include "BaseLib/Logging.h"
19
20namespace ProcessLib::Graph
21{
22namespace detail
23{
24template <typename T>
26 : boost::mp11::mp_bool<std::is_lvalue_reference_v<T> &&
27 std::is_const_v<std::remove_reference_t<T>>>
28{
29 static_assert(std::is_lvalue_reference_v<T>,
30 "The current implementation only deals with l-value "
31 "references as function arguments. If you want to extend it, "
32 "test thoroughly in order to not introduce bugs.");
33};
34
35template <typename T>
36struct IsOutputArgument : boost::mp11::mp_bool<!IsInputArgument<T>::value>
37{
38 static_assert(std::is_lvalue_reference_v<T>,
39 "The current implementation only deals with l-value "
40 "references as function arguments. If you want to extend it, "
41 "test thoroughly in order to not introduce bugs.");
42};
43
44template <typename Model>
45bool isEvalOrderCorrectRT(std::unordered_set<std::type_index>& computed_data)
46{
47 using namespace boost::mp11;
48
49 using ModelArgs =
50 typename GetFunctionArgumentTypes<decltype(&Model::eval)>::type;
51 using ModelInputs = mp_filter<IsInputArgument, ModelArgs>;
52 using ModelOutputs = mp_filter<IsOutputArgument, ModelArgs>;
53
54 using ModelInputsWrapped = mp_transform<mp_identity, ModelInputs>;
55
56 // Check that all inputs have already been computed before.
57 bool all_inputs_computed = true;
58 mp_for_each<ModelInputsWrapped>(
59 [&computed_data,
60 &all_inputs_computed]<typename Input>(mp_identity<Input>)
61 {
62 if (!computed_data.contains(std::type_index{typeid(Input)}))
63 {
64 ERR("Input {} of model {} has not been computed/set before the "
65 "model evaluation.",
66 typeid(Input).name(), typeid(Model).name());
67 all_inputs_computed = false;
68 }
69 });
70 if (!all_inputs_computed)
71 {
72 return false;
73 }
74
75 using ModelOutputsWrapped = mp_transform<mp_identity, ModelOutputs>;
76
77 // All outputs are "computed data", now.
78 bool no_output_precomputed = true;
79 mp_for_each<ModelOutputsWrapped>(
80 [&computed_data,
81 &no_output_precomputed]<typename Output>(mp_identity<Output>)
82 {
83 auto const [it, emplaced] = computed_data.emplace(typeid(Output));
84
85 if (!emplaced)
86 {
87 ERR("Output {} of model {} is computed more than once.",
88 typeid(Output).name(),
89 typeid(Model).name());
90 no_output_precomputed = false;
91 }
92 });
93
94 return no_output_precomputed;
95}
96
97template <typename... Models>
98bool isEvalOrderCorrectRT(boost::mp11::mp_list<Models...>,
99 std::unordered_set<std::type_index>&& computed_data)
100{
101 return (isEvalOrderCorrectRT<Models>(computed_data) && ...);
102}
103} // namespace detail
104
113template <typename Models, typename Inputs>
114bool isEvalOrderCorrectRT() // RT for runtime
115{
116 using namespace boost::mp11;
117
118 static_assert(mp_is_list<Models>::value);
119 static_assert(mp_is_list<Inputs>::value);
120
121 // Wrap inputs. The elements of InputsWrapped are default constructible.
122 using InputsWrapped = mp_transform<mp_identity, Inputs>;
123
124 // "Holds" all data that has been computed successively by the invoked
125 // models.
126 std::unordered_set<std::type_index> computed_data;
127
128 // All inputs are considered "computed data".
129 mp_for_each<InputsWrapped>(
130 [&computed_data]<typename Input>(mp_identity<Input>)
131 { computed_data.emplace(typeid(Input)); });
132
133 return detail::isEvalOrderCorrectRT(mp_rename<Models, mp_list>{},
134 std::move(computed_data));
135}
136} // namespace ProcessLib::Graph
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:45
bool isEvalOrderCorrectRT(std::unordered_set< std::type_index > &computed_data)