-
Notifications
You must be signed in to change notification settings - Fork 1
/
node-conditions.h
151 lines (120 loc) · 4.69 KB
/
node-conditions.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#ifndef AGENCY_NODE_CONDITIONS_H
#define AGENCY_NODE_CONDITIONS_H
#include "node.h"
namespace detail {
/*
* The condition is called only for non nullptr nodes. If the node is nullptr
* the default action is executed. What this default action is can be described
* using `condition_default_value` or others.
*/
struct condition_non_nullptr_only {};
/*
* The condition is called only for a node having a specific type. Otherwise
* the default action is executed. This implies `condition_non_nullptr_only`
*/
struct value_condition_type_restricted : condition_non_nullptr_only {};
template <typename T>
struct value_condition_only_for : value_condition_type_restricted {
using condition_restricted_to = T;
};
/*
* Returns the specified default value as default action.
*/
struct condition_default_value_specified {};
template <bool B>
struct condition_default_value : condition_default_value_specified {
constexpr static bool default_value = B;
};
/*
* Inverts the return value of the non-default action.
*/
struct condition_invert {};
template <typename F>
struct condition_helper : F {
using condition_base = F;
using F::F;
bool operator()(node_ptr const& node) const {
if (node) {
return invert_if_required(visit_node(node));
}
return return_default();
}
private:
template <typename E = F, std::enable_if_t<std::is_base_of_v<condition_default_value_specified, E>, int> = 0>
[[nodiscard]] bool return_default() const noexcept {
return F::default_value;
}
template <typename E = F, std::enable_if_t<std::negation_v<std::is_base_of<condition_default_value_specified, E>>, int> = 0>
[[nodiscard]] bool return_default() const noexcept {
return false;
}
template <typename E = F, std::enable_if_t<std::is_base_of_v<condition_invert, E>, int> = 0>
[[nodiscard]] bool invert_if_required(bool v) const noexcept {
return not v;
}
template <typename E = F, std::enable_if_t<std::negation_v<std::is_base_of<condition_invert, E>>, int> = 0>
[[nodiscard]] bool invert_if_required(bool value) const noexcept {
return value;
}
template <typename E = F, std::enable_if_t<std::is_base_of_v<value_condition_type_restricted, E>, int> = 0>
auto visit_node(node_ptr const& node) const {
using T = typename F::condition_restricted_to;
return node->visit(visitor{[this](T const& v) { return F::operator()(v); },
[this](auto const&) { return return_default(); }});
}
template <typename E = F, std::enable_if_t<std::negation_v<std::is_base_of<value_condition_type_restricted, E>>, int> = 0>
auto visit_node(node_ptr const& node) const {
return F::operator()(node);
}
F& self() { return *static_cast<F*>(this); }
F const& self() const { return *static_cast<F const*>(this); }
};
template <typename T, typename E = typename T::condition_base>
struct insert_condition_invert_trait : E, detail::condition_invert {
using E ::E;
};
template <typename T>
struct not_condition_adapter : condition_helper<insert_condition_invert_trait<T>> {
using E = condition_helper<insert_condition_invert_trait<T>>;
using E::E;
};
} // namespace detail
struct value_equals_condition : detail::condition_default_value<false> {
node_ptr node;
explicit value_equals_condition(node_ptr node) : node(std::move(node)) {}
bool operator()(node_ptr const& other) const noexcept {
return *node == *other;
}
};
struct value_in_condition : detail::condition_default_value<false>,
detail::value_condition_only_for<node_array> {
node_ptr node;
explicit value_in_condition(node_ptr node) : node(std::move(node)) {}
bool operator()(node_array const& array) const noexcept {
return array.contains(node);
}
};
struct value_is_array_condition : detail::condition_default_value<false>,
detail::value_condition_only_for<node_array> {
bool operator()(node_array const& array) const noexcept { return true; }
};
using in_condition = detail::condition_helper<value_in_condition>;
using not_in_condition = detail::not_condition_adapter<in_condition>;
using equal_condition = detail::condition_helper<value_equals_condition>;
using not_equal_condition = detail::not_condition_adapter<equal_condition>;
using is_array_condition = detail::condition_helper<value_is_array_condition>;
struct is_empty_condition {
bool inverted;
explicit is_empty_condition (bool inverted) : inverted(inverted) {}
bool operator()(node_ptr const& node) const noexcept {
return (node == nullptr) != inverted;
}
};
template <typename F>
struct fold_adapter_and : F {
using F::F;
bool operator()(node_ptr const& node, bool value) const {
return F::operator()(node) && value;
}
};
#endif // AGENCY_NODE_CONDITIONS_H