CYD-UI
A C++ library for building native graphic user interfaces
Loading...
Searching...
No Matches
compute.cppm
Go to the documentation of this file.
1
5
6export module cydui.dimensions:compute;
7
8import std;
9
10import fabric.logging;
11
12export import :types;
13export import :expression;
14export import :impl;
15
16
17namespace cydui::dimensions {
18 export template <typename T>
19 struct cycle_t {
20 std::deque<typename dimension_impl<T>::sptr> dimensions{};
21 };
22
23 export template <typename T>
25 std::vector<cycle_t<T>> cycles{};
26
27 operator bool() const {
28 return cycles.empty();
29 }
30 };
31
32 template <typename T>
34 cycle_t<T>& cycle,
35 typename dimension_impl<T>::sptr start,
36 typename dimension_impl<T>::sptr head,
37 const std::unordered_map<std::string, dimension<T>>& global_parameters
38 ) {
39 std::unordered_set<std::shared_ptr<dimension_impl<T>>> deps{};
40 for (const auto& dep: head->expr().dependencies()) {
41 deps.insert(dep);
42 }
43 for (const auto& param: head->expr().parameters()) {
44 if (head->context_->contains(param.name)) {
45 auto& param_dim = head->context_->operator[](param.name);
46 deps.insert(param_dim.impl());
47 } else if (global_parameters.contains(param.name)) {
48 auto& param_dim = global_parameters.at(param.name);
49 deps.insert(param_dim.impl());
50 } else {
51 LOG::print{FATAL}("Missing expression parameter: {}", param.name);
52 }
53 }
54
55 for (const auto& dependency: deps) {
56 if (dependency == start) {
57 cycle.dimensions.emplace_front(dependency);
58 return true;
59 } else {
60 if (find_cycle(cycle, start, dependency, global_parameters)) {
61 cycle.dimensions.emplace_front(dependency);
62 return true;
63 }
64 }
65 }
66 return false;
67 }
68
69 template <typename T>
71 typename dimension_impl<T>::sptr dim,
72 const std::unordered_map<std::string, dimension<T>>& parameters
73 ) {
75 expression& expr = dim->expr();
76
77 std::deque<typename expression::node_t::sptr> stack{};
78 std::stack<std::pair<typename expression::node_t::sptr, std::deque<T>>> result_stack{};
79 stack.emplace_back(expr.tree());
80 result_stack.emplace(typename expression::node_t::sptr{nullptr}, std::deque<T>{});
81
82 // LOG::print{FATAL
83 // }("Something went wrong while evaluating an expression, result_stack invalid: {}",
84 // expr.to_string());
85 while (!stack.empty()) {
86 auto top = stack.back();
87 if (top == nullptr) {
88 result_stack.top().second.push_back(T{});
89 stack.pop_back();
90 continue;
91 }
92
93 switch (top->op) {
95 result_stack.top().second.push_back(top->const_value);
96 stack.pop_back();
97 break;
99 result_stack.top().second.push_back(top->dimension->value_);
100 stack.pop_back();
101 break;
103 if (dim->context_->contains(top->parameter.name)) {
104 auto& d = (*dim->context_)[top->parameter.name];
105 result_stack.top().second.push_back((*dim->context_)[top->parameter.name].value());
106 stack.pop_back();
107 } else if (parameters.contains(top->parameter.name)) {
108 result_stack.top().second.push_back(parameters.at(top->parameter.name).value());
109 stack.pop_back();
110 } else {
111 LOG::print{FATAL
112 }("Missing parameter while evaluating expression: {}", top->parameter.name);
113 return false;
114 }
115 break;
120 if (result_stack.top().first != top) {
121 result_stack.emplace(top, std::deque<T>{});
122 for (auto it = top->children.rbegin(); it != top->children.rend(); ++it) {
123 stack.emplace_back(*it);
124 }
125 } else {
126 auto res = result_stack.top().second;
127 T accumulator{res.front()};
128 switch (top->op) {
130 for (auto it = std::next(res.begin()); it != res.end(); ++it) {
131 accumulator.value += (*it).template as<screen::pixel>().value;
132 }
133 break;
135 for (auto it = std::next(res.begin()); it != res.end(); ++it) {
136 accumulator.value -= (*it).template as<screen::pixel>().value;
137 }
138 break;
140 for (auto it = std::next(res.begin()); it != res.end(); ++it) {
141 accumulator.value *= (*it).template as<screen::pixel>().value;
142 }
143 break;
145 for (auto it = std::next(res.begin()); it != res.end(); ++it) {
146 accumulator.value /= (*it).template as<screen::pixel>().value;
147 }
148 break;
149 default:
150 break;
151 }
152 result_stack.pop();
153 result_stack.top().second.push_back(accumulator);
154 stack.pop_back();
155 }
156 break;
157 default:
158 LOG::print{FATAL} //
159 ("Expression node has invalid operator {}", static_cast<std::size_t>(top->op));
160 break;
161 }
162 }
163
164 if (result_stack.size() == 1 && result_stack.top().first == nullptr
165 && result_stack.top().second.size() == 1) {
166 dim->value_ = result_stack.top().second.front();
167 dim->unknown_ = false;
168 return true;
169 }
170 LOG::print{FATAL
171 }("Something went wrong while evaluating an expression, result_stack invalid: {}",
172 expr.to_string());
173 return false;
174 }
175
176 export template <typename T>
178 dimension<T>& dim_, const std::unordered_map<std::string, dimension<T>>& parameters = {}
179 ) {
180 typename dimension_impl<T>::sptr dim = dim_.impl();
181 std::unordered_set<typename dimension_impl<T>::sptr> visited{};
182 std::deque<typename dimension_impl<T>::sptr> stack{};
183 std::vector<cycle_t<T>> cycles{};
184 stack.emplace_back(dim);
185
186 while (!stack.empty()) {
187 auto top = stack.back();
188
189 if (not top->is_unknown()) {
190 stack.pop_back();
191 visited.erase(top);
192 continue;
193 }
194
195 std::unordered_set<std::shared_ptr<dimension_impl<T>>> deps{};
196 visited.insert(top);
197 for (const auto& dep: top->expr().dependencies()) {
198 deps.insert(dep);
199 }
200 for (const auto& param: top->expr().parameters()) {
201 if (top->context_->contains(param.name)) {
202 auto& param_dim = top->context_->operator[](param.name);
203 deps.insert(param_dim.impl());
204 } else if (parameters.contains(param.name)) {
205 auto& param_dim = parameters.at(param.name);
206 deps.insert(param_dim.impl());
207 } else {
208 LOG::print{FATAL}("Missing expression parameter: {}", param.name);
209 }
210 }
211
212 if (deps.empty()) {
213 if (top->is_unknown()) {
214 evaluate_expression<T>(top, parameters);
215 }
216 stack.pop_back();
217 visited.erase(top);
218 } else {
219 bool work_to_do = false;
220
221 for (auto it = deps.begin(); it != deps.end(); ++it) {
222 auto dep = *it;
223 if (not dep->is_unknown())
224 continue;
225 if (visited.contains(dep)) {
227 cycle_t<T> cycle{};
228 std::size_t i = 0;
229 // LOG::print{INFO}("Possible cycle detected:");
230 // LOG::print{INFO}("START: [0x{:X}] {}::{} = {}", (unsigned long)(dim_.impl()->get()), dim_.impl()->context_->get_name(), dim_.impl()->name_, dim_.impl()->expr().to_string());
231 // for (const auto& v: visited) {
232 // LOG::print{INFO}(" {}: [0x{:X}] {}::{} = {}", i++, (unsigned long)(v.get()), v->context_->get_name(), v->name_, v->expr().to_string());
233 // }
234
235 if (!find_cycle(cycle, dep, dep, parameters)) {
236 LOG::print{FATAL}("Cycle detection gave a false positive.");
237 } else {
238 LOG::print{ERROR}("Dependency cycle in dimensions:");
239 i = 0;
240 for (const auto& v: cycle.dimensions) {
241 LOG::print{ERROR}(" {}: {}::{} = {}", i++, v->context_->get_name(), v->name_, v->expr().to_string());
242 }
243 }
244 cycles.emplace_back(cycle);
245 } else {
246 stack.emplace_back(dep);
247 work_to_do = true;
248 }
249 }
250
251 if (!work_to_do) {
252 if (top->is_unknown()) {
253 evaluate_expression<T>(top, parameters);
254 }
255 stack.pop_back();
256 visited.erase(top);
257 }
258 }
259 }
260
261 return {cycles};
262 }
263
264 // export template <typename T>
265 // const T& get_value(const dimension<T>& dim) {
266 // // LOG::print{INFO}("Value: {}", dim.value().to_string());
267 // return dim.value();
268 // }
269} // namespace cydui::dimensions
std::shared_ptr< dimension_impl > sptr
Definition impl.cppm:28
std::shared_ptr< node_t > sptr
std::string to_string() const
bool find_cycle(cycle_t< T > &cycle, typename dimension_impl< T >::sptr start, typename dimension_impl< T >::sptr head, const std::unordered_map< std::string, dimension< T > > &global_parameters)
Definition compute.cppm:33
compute_result_t< T > compute_dimension(dimension< T > &dim_, const std::unordered_map< std::string, dimension< T > > &parameters={})
Definition compute.cppm:177
bool evaluate_expression(typename dimension_impl< T >::sptr dim, const std::unordered_map< std::string, dimension< T > > &parameters)
Definition compute.cppm:70
std::vector< cycle_t< T > > cycles
Definition compute.cppm:25
std::deque< typename dimension_impl< T >::sptr > dimensions
Definition compute.cppm:20