20 #include <type_traits>
34 using std::runtime_error::runtime_error;
42 virtual ~Dirtyable() =
default;
44 Dirtyable() =
default;
46 void setParent(Dirtyable *newParent)
48 auto **parentVar = parentVariable();
50 *parentVar = newParent;
55 virtual void markDirty()
57 auto *dirtyVar = dirtyVariable();
66 *
const_cast<bool *
>(dirtyVar) =
true;
69 auto **parentVar = parentVariable();
70 if (parentVar && *parentVar) {
71 (*parentVar)->markDirty();
77 auto *dirtyVar = dirtyVariable();
78 return dirtyVar && *dirtyVar;
82 virtual Dirtyable **parentVariable() = 0;
83 virtual const bool *dirtyVariable()
const = 0;
86 template<
typename ResultType>
87 class NodeInterface :
public Dirtyable
93 virtual const ResultType &evaluate()
const = 0;
96 NodeInterface() =
default;
99 template<
typename ResultType>
103 Node(std::unique_ptr<NodeInterface<ResultType>> &&nodeInterface)
104 : m_interface(
std::move(nodeInterface))
108 const ResultType &evaluate()
const
110 return m_interface->evaluate();
113 void setParent(Dirtyable *newParent)
115 m_interface->setParent(newParent);
120 return m_interface->isDirty();
124 std::unique_ptr<NodeInterface<ResultType>> m_interface;
128 class ConstantNode :
public NodeInterface<T>
131 explicit ConstantNode(
const T &value)
136 const T &evaluate()
const override
144 Dirtyable **parentVariable()
override {
return nullptr; }
145 const bool *dirtyVariable()
const override {
return nullptr; }
151 template<
typename PropertyType>
152 class PropertyNode :
public NodeInterface<PropertyType>
155 explicit PropertyNode(
const Property<PropertyType> &property)
156 : m_parent(nullptr), m_dirty(false)
158 setProperty(property);
162 PropertyNode(PropertyNode<PropertyType> &&) =
delete;
164 PropertyNode(
const PropertyNode<PropertyType> &other)
165 : Dirtyable(other.isDirty())
167 setProperty(*other.m_property);
170 virtual ~PropertyNode()
172 m_valueChangedHandle.disconnect();
173 m_movedHandle.disconnect();
174 m_destroyedHandle.disconnect();
177 const PropertyType &evaluate()
const override
180 throw PropertyDestroyedError(
"The Property this node refers to no longer exists!");
184 return m_property->get();
187 void propertyMoved(
const Property<PropertyType> &property)
189 if (&property != m_property) {
190 m_property = &property;
194 m_property =
nullptr;
198 void propertyDestroyed()
200 m_property =
nullptr;
204 Dirtyable **parentVariable()
override {
return &m_parent; }
205 const bool *dirtyVariable()
const override {
return &m_dirty; }
208 void setProperty(
const Property<PropertyType> &property)
210 m_property = &property;
213 m_valueChangedHandle = m_property->valueChanged().connect([
this]() { this->markDirty(); });
214 m_movedHandle = m_property->m_moved.connect([
this](
const Property<PropertyType> &newProp) { this->propertyMoved(newProp); });
215 m_destroyedHandle = m_property->destroyed().connect([
this]() { this->propertyDestroyed(); });
218 const Property<PropertyType> *m_property;
219 ConnectionHandle m_movedHandle;
220 ConnectionHandle m_valueChangedHandle;
221 ConnectionHandle m_destroyedHandle;
224 mutable bool m_dirty;
227 template<
typename ResultType,
typename Operator,
typename... Ts>
228 class OperatorNode :
public NodeInterface<ResultType>
233 template<
typename Op>
234 explicit OperatorNode(Op &&op, Node<Ts> &&...arguments)
235 : m_parent{ nullptr }, m_dirty{ true }, m_op{
std::move(op) }, m_values{
std::move(arguments)... }, m_result(reevaluate())
238 std::is_convertible_v<decltype(m_op(std::declval<Ts>()...)), ResultType>,
239 "The result of the Operator must be convertible to the ReturnType of the Node");
244 template<std::
size_t I>
245 auto setParents() -> std::enable_if_t<I ==
sizeof...(Ts)>
252 template<std::
size_t I>
253 auto setParents() -> std::enable_if_t<I <
sizeof...(Ts)>
256 std::get<I>(m_values).setParent(
this);
260 virtual ~OperatorNode() =
default;
262 const ResultType &evaluate()
const override
264 if (Dirtyable::isDirty()) {
265 m_result = reevaluate();
272 Dirtyable **parentVariable()
override {
return &m_parent; }
273 const bool *dirtyVariable()
const override {
return &m_dirty; }
276 template<std::size_t... Is>
277 ResultType reevaluate_helper(std::index_sequence<Is...>)
const
279 return m_op(std::get<Is>(m_values).evaluate()...);
282 ResultType reevaluate()
const
286 return reevaluate_helper(std::make_index_sequence<
sizeof...(Ts)>());
290 mutable bool m_dirty;
293 std::tuple<Node<Ts>...> m_values;
297 mutable ResultType m_result;
301 struct is_node_helper : std::false_type {
305 struct is_node_helper<Node<T>> : std::true_type {
309 struct is_node : is_node_helper<T> {
A PropertyDestroyedError is thrown whenever a binding is evaluated that references a property that no...
PropertyDestroyedError()=delete
The main namespace of the KDBindings library.