Sequoia
Loading...
Searching...
No Matches
Suite.hpp
Go to the documentation of this file.
1
2// Copyright Oliver J. Rosten 2023. //
3// Distributed under the GNU GENERAL PUBLIC LICENSE, Version 3.0. //
4// (See accompanying file LICENSE.md or copy at //
5// https://www.gnu.org/licenses/gpl-3.0.en.html) //
7
12#pragma once
13
17
18#include <algorithm>
19#include <ranges>
20#include <string>
21#include <tuple>
22#include <variant>
23#include <vector>
24
25namespace sequoia::object
26{
27 template<class T>
28 struct is_suite : std::false_type {};
29
30 template<class T>
31 using is_suite_t = typename is_suite<T>::type;
32
33 template<class T>
34 inline constexpr bool is_suite_v{is_suite<T>::value};
35
36 template<class... Ts>
37 requires ((is_suite_v<Ts> && ...) || ((!is_suite_v<Ts>) && ...))
38 class suite;
39
40 template<class... Ts>
41 struct is_suite<suite<Ts...>> : std::true_type {};
42
43 template<class... Ts>
44 requires ((is_suite_v<Ts> && ...) || ((!is_suite_v<Ts>) && ...))
45 class suite
46 {
47 public:
48 std::string name;
49 std::tuple<Ts...> values;
50
51 suite(std::string name, Ts&&... ts)
52 : name{std::move(name)}
53 , values{std::forward<Ts>(ts)...} {}
54 };
55
56
57 template<class... Ts>
59
60 template<class... Ts>
61 using leaf_extractor_t = typename leaf_extractor<Ts...>::type;
62
63 template<class... Ts>
64 struct leaf_extractor<std::tuple<Ts...>>
65 {
66 using type = std::tuple<Ts...>;
67 };
68
69 template<class... Ts>
70 requires ((!is_suite_v<Ts>) && ...)
71 struct leaf_extractor<suite<Ts...>>
72 {
73 using type = std::tuple<Ts...>;
74 };
75
76 template<class... Ts>
77 struct leaf_extractor<suite<Ts...>>
78 {
79 using type = leaf_extractor_t<leaf_extractor_t<Ts>...>;
80 };
81
82 template<class... Ts, class... Us>
83 struct leaf_extractor<std::tuple<Ts...>, std::tuple<Us...>>
84 {
85 using type = std::tuple<Ts..., Us...>;
86 };
87
88 template<class... Ts, class... Us>
89 struct leaf_extractor<suite<Ts...>, std::tuple<Us...>>
90 {
91 using type = std::tuple<leaf_extractor_t<suite<Ts...>>, Us...>;
92 };
93
94 template<class... Ts, class... Us>
95 struct leaf_extractor<std::tuple<Ts...>, suite<Us...>>
96 {
97 using type = std::tuple<Ts..., leaf_extractor_t<suite<Us...>>>;
98 };
99
100 template<class T, class U, class... Vs>
101 struct leaf_extractor<T, U, Vs...>
102 {
103 using type = leaf_extractor_t<leaf_extractor_t<T, U>, Vs...>;
104 };
105
106 template<class T, class Transform>
108
109 template<class T, class Transform>
110 using leaves_to_variant_or_unique_type_t = typename leaves_to_variant_or_unique_type<T, Transform>::type;
111
112 template<class... Ts, class Transform>
113 requires (std::invocable<Transform, Ts> && ...)
114 struct leaves_to_variant_or_unique_type<std::tuple<Ts...>, Transform>
115 {
116 using type = std::variant<std::remove_cvref_t<std::invoke_result_t<Transform, Ts>>...>;
117 };
118
119 template<class T, class... Ts, class Transform>
120 requires (std::is_same_v<std::remove_cvref_t<std::invoke_result_t<Transform, T>>, std::remove_cvref_t<std::invoke_result_t<Transform, Ts>>> && ...)
121 struct leaves_to_variant_or_unique_type<std::tuple<T, Ts...>, Transform>
122 {
123 using type = std::remove_cvref_t<std::invoke_result_t<Transform, T>>;
124 };
125
126 template<class... Ts, class Transform>
127 struct leaves_to_variant_or_unique_type<suite<Ts...>, Transform>
128 {
129 using type = typename leaves_to_variant_or_unique_type<leaf_extractor_t<suite<Ts...>>, Transform>::type;
130 };
131
132
133 template<class...>
135
136 template<class... Ts>
137 using faithful_variant_t = typename faithful_variant<Ts...>::type;
138
139 template<>
141 {};
142
143 template<class T>
145 {
146 using type = std::variant<T>;
147 };
148
149 template<class... Ts, class T>
150 requires (std::is_same_v<Ts, T> || ...)
151 struct faithful_variant<std::variant<Ts...>, T>
152 {
153 using type = std::variant<Ts...>;
154 };
155
156 template<class... Ts, class T>
157 struct faithful_variant<std::variant<Ts...>, T>
158 {
159 using type = std::variant<Ts..., T>;
160 };
161
162 template<class... Ts, class T, class... Us>
163 struct faithful_variant<std::variant<Ts...>, T, Us...>
164 {
165 using type = faithful_variant_t<faithful_variant_t<std::variant<Ts...>, T>, Us...>;
166 };
167
168 template<class T, class... Ts>
169 struct faithful_variant<T, Ts...>
170 {
171 using type = faithful_variant_t<std::variant<T>, Ts...>;
172 };
173
174
175 template<class T, std::invocable<T> Transform>
177 {
178 using type = std::invoke_result_t<Transform, T>;
179 };
180
181 template<class T, class Transform>
182 using to_variant_or_unique_type_t = typename to_variant_or_unique_type<T, Transform>::type;
183
184 template<class... Ts, std::invocable<suite<Ts...>> Transform>
185 struct to_variant_or_unique_type<suite<Ts...>, Transform>
186 {
187 using variant_type = faithful_variant_t<std::invoke_result_t<Transform, suite<Ts...>>, to_variant_or_unique_type_t<Ts, Transform>...>;
188 using type = std::conditional_t<std::variant_size_v<variant_type> == 1, std::variant_alternative_t<0, variant_type>, variant_type>;
189 };
190
191 namespace impl
192 {
193 template<class... Ts, class Fn>
194 void extract_leaves(suite<Ts...>& s, Fn fn)
195 {
196 [&] <std::size_t... Is> (std::index_sequence<Is...>) {
197 (fn(std::get<Is>(s.values)), ...);
198 }(std::make_index_sequence<sizeof...(Ts)>{});
199 }
200
201 template<class... Ts, class Filter, class Transform, class Container, class... PreviousSuites>
202 requires (is_suite_v<PreviousSuites> && ...) && ((!is_suite_v<Ts>) && ...)
203 Container&& extract_leaves(suite<Ts...>& s, Filter&& filter, Transform t, Container&& c, const PreviousSuites&... previous)
204 {
205 auto emplacer{
206 [&] <class V> (V&& val) {
207 if(filter(val, previous..., s)) c.emplace_back(t(std::move(val)));
208 }
209 };
210
211 extract_leaves(s, emplacer);
212 return std::forward<Container>(c);
213 }
214
215 template<class... Ts, class Filter, class Transform, class Container, class... PreviousSuites>
216 requires (is_suite_v<PreviousSuites> && ...) && ((is_suite_v<Ts>) && ...)
217 Container&& extract_leaves(suite<Ts...>& s, Filter&& filter, Transform t, Container&& c, const PreviousSuites&... previous)
218 {
219 auto extractor{
220 [&]<class V>(V&& val) { extract_leaves(std::forward<V>(val), std::forward<Filter>(filter), t, std::forward<Container>(c), previous..., s); }
221 };
222
223 extract_leaves(s, extractor);
224 return std::forward<Container>(c);
225 }
226
227 template<class... Ts,
228 class Transform,
229 class Tree,
230 std::integral SizeType = typename Tree::size_type,
231 class Fn>
232 requires maths::dynamic_tree<std::remove_cvref_t<Tree>>
233 Tree&& extract_tree(suite<Ts...>& s, Transform transform, Tree&& tree, const SizeType parentNode, Fn fn)
234 {
235 const auto node{tree.add_node(parentNode, transform(s))};
236
237 [node, fn, &s] <std::size_t... Is> (std::index_sequence<Is...>) {
238 (fn(node, std::get<Is>(s.values)), ...);
239 }(std::make_index_sequence<sizeof...(Ts)>{});
240
241 if(!std::ranges::distance(tree.cedges(node)))
242 tree.prune(node);
243
244 return std::forward<Tree>(tree);
245 }
246
247
248 template<class... Ts, class Filter, class Transform, class Tree, std::integral SizeType = typename Tree::size_type, class... PreviousSuites>
249 requires maths::dynamic_tree<std::remove_cvref_t<Tree>> && (is_suite_v<PreviousSuites> && ...) && ((!is_suite_v<Ts>) && ...)
250 Tree&& extract_tree(suite<Ts...>& s, Filter&& filter, Transform transform, Tree&& tree, const SizeType parentNode, const PreviousSuites&... previous)
251 {
252 auto emplacer{
253 [&](SizeType node, auto&& val) {
254 if(filter(val, previous..., s))
255 tree.add_node(node, transform(std::move(val)));
256 }
257 };
258
259 return impl::extract_tree(s, transform, std::forward<Tree>(tree), parentNode, emplacer);
260 }
261
262 template<class... Ts, class Filter, class Transform, class Tree, std::integral SizeType = typename Tree::size_type, class... PreviousSuites>
263 requires maths::dynamic_tree<std::remove_cvref_t<Tree>> && (is_suite_v<PreviousSuites> && ...) && ((is_suite_v<Ts>) && ...)
264 Tree&& extract_tree(suite<Ts...>& s, Filter&& filter, Transform transform, Tree&& tree, const SizeType parentNode, const PreviousSuites&... previous)
265 {
266 auto recurser{
267 [&] <class V> (SizeType node, V&& val) {
268 impl::extract_tree(std::forward<V>(val), std::forward<Filter>(filter), transform, std::forward<Tree>(tree), node, previous..., s);
269 }
270 };
271
272 return impl::extract_tree(s, transform, std::forward<Tree>(tree), parentNode, recurser);
273 }
274 }
275
276 template<class Suite,
277 class Filter,
278 class Transform = std::identity,
279 class Container = std::vector<leaves_to_variant_or_unique_type_t<Suite, Transform>>>
280 requires is_suite_v<Suite>
281 [[nodiscard]]
282 Container extract_leaves(Suite s, Filter&& filter, Transform t = {})
283 {
284 return impl::extract_leaves(s, std::forward<Filter>(filter), std::move(t), Container{});
285 }
286
287 template<class Suite,
288 class Filter,
289 class Transform,
290 maths::dynamic_tree Tree = maths::directed_tree<maths::tree_link_direction::forward, maths::null_weight, to_variant_or_unique_type_t<Suite, Transform>>>
291 requires is_suite_v<Suite>
292 [[nodiscard]]
293 Tree extract_tree(Suite s, Filter&& filter, Transform transform)
294 {
295 return impl::extract_tree(s, std::forward<Filter>(filter), std::move(transform), Tree{}, Tree::npos);
296 }
297
298 template<class Suite,
299 class Filter,
300 class Transform,
301 maths::dynamic_tree Tree>
302 requires is_suite_v<Suite>
303 Tree& extract_tree(Suite s, Filter&& filter, Transform transform, Tree& tree, typename Tree::size_type pos)
304 {
305 return impl::extract_tree(s, std::forward<Filter>(filter), std::move(transform), tree, pos);
306 }
307
309 {
310 template<class T>
311 requires has_intrinsic_nomenclator<T> || has_extrinsic_nomenclator<T>
312 [[nodiscard]]
313 std::string operator()(const T& t) const
314 {
315 return object::nomenclature(t);
316 }
317 };
318
319 template
320 <
321 class ItemKeyType,
322 class ItemCompare,
323 class ItemProjector,
324 class T
325 >
326 inline constexpr bool granular_filter_for{
327 requires (const ItemKeyType& val, ItemCompare comp, ItemProjector proj, const T& t) {
328 { comp(val, proj(t)) } -> std::same_as<bool>;
329 }
330 };
331
332 template
333 <
334 class ItemKeyType,
335 class ItemCompare,
336 class ItemProjector
337 >
339 {
340 public:
341 using items_key_type = ItemKeyType;
342 using suites_map_type = std::vector<std::pair<std::string, bool>>;
343 using items_map_type = std::vector<std::pair<ItemKeyType, bool>>;
344 using selected_suites_iterator = typename suites_map_type::const_iterator;
345 using selected_items_iterator = typename items_map_type::const_iterator;
346 using optional_suite_selection = std::optional<std::vector<std::string>>;
347 using optional_item_selection = std::optional<std::vector<items_key_type>>;
348
349 granular_filter(ItemCompare compare = {}, ItemProjector proj = {})
350 : m_Compare{std::move(compare)}
351 , m_Proj{std::move(proj)}
352 {}
353
354 granular_filter(optional_suite_selection selectedSuites, optional_item_selection selectedItems, ItemCompare compare = {}, ItemProjector proj = {})
355 : m_Compare{std::move(compare)}
356 , m_Proj{std::move(proj)}
357 , m_SelectedSuites{make(std::move(selectedSuites))}
358 , m_SelectedItems{make(std::move(selectedItems))}
359 {}
360
361 void add_selected_suite(std::string name)
362 {
363 add(m_SelectedSuites, std::move(name));
364 }
365
366 void add_selected_item(items_key_type key)
367 {
368 add(m_SelectedItems, std::move(key));
369 }
370
371 template<class T, class... Suites>
372 requires (is_suite_v<Suites> && ...) && granular_filter_for<ItemKeyType, ItemCompare, ItemProjector, T>
373 [[nodiscard]]
374 bool operator()(const T& val, const Suites&... suites)
375 {
376 if(!m_SelectedSuites && !m_SelectedItems) return true;
377
378 // Don't use logical short-circuit, otherwise the maps may not accurately update
379 std::array<bool, sizeof...(Suites) + 1> isFound{ find(m_SelectedItems, val, m_Proj, m_Compare), find(m_SelectedSuites, suites, item_to_name{}, std::ranges::equal_to{}) ... };
380
381 return std::ranges::any_of(isFound, [](bool b) { return b; });
382 }
383
384 [[nodiscard]]
385 std::optional<std::ranges::subrange<selected_suites_iterator>> selected_suites() const noexcept
386 {
387 return m_SelectedSuites ? std::optional<std::ranges::subrange<selected_suites_iterator>>{{m_SelectedSuites->begin(), m_SelectedSuites->end()}} : std::nullopt;
388 }
389
390 [[nodiscard]]
391 std::optional<std::ranges::subrange<selected_items_iterator>> selected_items() const noexcept
392 {
393 return m_SelectedItems ? std::optional<std::ranges::subrange<selected_items_iterator>>{{m_SelectedItems->begin(), m_SelectedItems->end()}} : std::nullopt;
394 }
395
396 [[nodiscard]]
397 friend bool operator==(const granular_filter&, const granular_filter&) noexcept = default;
398
399 [[nodiscard]]
400 operator bool() const noexcept
401 {
402 return m_SelectedSuites || m_SelectedItems;
403 }
404 private:
405 [[no_unique_address]] ItemCompare m_Compare{};
406 [[no_unique_address]] ItemProjector m_Proj{};
407 std::optional<suites_map_type> m_SelectedSuites{};
408 std::optional<items_map_type> m_SelectedItems{};
409
410 template<class Key>
411 using opt_map_type = std::optional<std::vector<std::pair<Key, bool>>>;
412
413 template<class Key>
414 static void add(opt_map_type<Key>& map, Key k)
415 {
416 using map_type = typename opt_map_type<Key>::value_type;
417 if(!map) map = map_type{};
418
419 map->emplace_back(std::move(k), false);
420 }
421
422 template<class Key>
423 [[nodiscard]]
424 static opt_map_type<Key> make(std::optional<std::vector<Key>> selected)
425 {
426 if(!selected) return std::nullopt;
427
428 std::vector<std::pair<Key, bool>> selection{};
429 for (auto& e : *selected)
430 selection.emplace_back(std::move(e), false);
431
432 return selection;
433 }
434
435 template<class Key, class U, class Projector, class Comp>
436 static bool find(opt_map_type<Key>& selected, const U& u, Projector proj, Comp compare)
437 {
438 if(selected)
439 {
440 auto found{std::ranges::find_if(*selected, [&proj, &compare, &u](const std::pair<Key, bool>& e) { return compare(e.first, proj(u)); })};
441
442 if(found != selected->end())
443 {
444 found->second = true;
445 return true;
446 }
447 }
448
449 return false;
450 }
451 };
452}
Restriction of Dynamic Graphs to Trees.
Traits and Concepts for graphs.
Utilities for associating types with names.
Definition: Suite.hpp:339
Definition: Suite.hpp:46
Definition: Suite.hpp:134
Definition: Suite.hpp:28
Definition: Suite.hpp:309
Definition: Suite.hpp:58