2#ifndef ANCHORS_ANCHOR_H
3#define ANCHORS_ANCHOR_H
8#include <boost/uuid/uuid_generators.hpp>
9#include <boost/uuid/uuid_io.hpp>
12#include <unordered_set>
16struct std::hash<
anchors::AnchorBase> {
17 std::size_t operator()(
const anchors::AnchorBase& a)
const noexcept {
18 return hash_value(a.getId());
25struct std::greater<std::shared_ptr<anchors::AnchorBase>> {
26 bool operator()(
const std::shared_ptr<anchors::AnchorBase>& a1,
27 const std::shared_ptr<anchors::AnchorBase>& a2)
const {
28 return a1->getHeight() > a2->getHeight();
44 virtual T get()
const = 0;
47 virtual void set(
const T& value) = 0;
58template <
typename T,
typename InputType1 = T,
typename InputType2 = T>
79 explicit Anchor(
const T& value);
107 friend std::ostream& operator<<(std::ostream& out,
const Anchor& anchor) {
108 out <<
"[ value=" << anchor.get() <<
", height=" << anchor.getHeight(),
109 ", firstDependency=" << anchor.d_firstDependency
110 <<
", secondDependency="
111 << anchor.d_secondDependency <<
" ]";
118 T get()
const override;
121 void compute(
int stabilizationNumber)
override;
129 void markNecessary()
override;
133 bool isNecessary()
const override;
137 bool isStale()
const override;
141 void decrementNecessaryCount()
override;
145 AnchorBase::AnchorId getId()
const override;
148 int getHeight()
const override;
152 int getRecomputeId()
const override;
155 int getChangeId()
const override;
158 void setChangeId(
int changeId)
override;
161 void set(
const T& value)
override;
164 void addDependant(
const std::shared_ptr<AnchorBase>& dependant)
override;
168 void removeDependant(
const std::shared_ptr<AnchorBase>& dependant)
override;
171 std::unordered_set<std::shared_ptr<AnchorBase>> getDependants()
175 std::vector<std::shared_ptr<AnchorBase>> getDependencies()
const override;
179 boost::uuids::random_generator d_idGenerator;
181 boost::uuids::uuid d_id;
193 int d_numDependencies{};
202 bool d_hasNeverBeenComputed;
204 const std::shared_ptr<AnchorWrap<InputType1>> d_firstDependency;
205 const std::shared_ptr<AnchorWrap<InputType2>> d_secondDependency;
207 std::unordered_set<std::shared_ptr<AnchorBase>> d_dependants;
215template <
typename T,
typename InputType1,
typename InputType2>
217 : d_id(d_idGenerator()),
219 d_hasNeverBeenComputed(true),
222template <
typename T,
typename InputType1,
typename InputType2>
226 : d_id(d_idGenerator()),
227 d_height(input->getHeight() + 1),
228 d_numDependencies(1),
229 d_hasNeverBeenComputed(true),
230 d_firstDependency(input),
232 d_singleInputUpdater(updater) {}
234template <
typename T,
typename InputType1,
typename InputType2>
239 : d_id(d_idGenerator()),
240 d_height(std::max(firstInput->getHeight(), secondInput->getHeight()) + 1),
241 d_numDependencies(2),
242 d_hasNeverBeenComputed(true),
243 d_firstDependency(firstInput),
244 d_secondDependency(secondInput),
246 d_dualInputUpdater(updater) {}
248template <
typename T,
typename InputType1,
typename InputType2>
253template <
typename T,
typename InputType1,
typename InputType2>
254void Anchor<T, InputType1, InputType2>::compute(
int stabilizationNumber) {
255 if (d_recomputeId == stabilizationNumber) {
261 d_recomputeId = stabilizationNumber;
263 d_hasNeverBeenComputed =
false;
265 if (d_numDependencies == 0) {
269 if (d_numDependencies == 1) {
270 InputType1 inputVal = d_firstDependency->get();
271 newValue = d_singleInputUpdater(inputVal);
273 InputType1 inputVal = d_firstDependency->get();
274 InputType2 inputVal2 = d_secondDependency->get();
276 newValue = d_dualInputUpdater(inputVal, inputVal2);
279 if (newValue != d_value) {
280 d_changeId = stabilizationNumber;
285template <
typename T,
typename InputType1,
typename InputType2>
286void Anchor<T, InputType1, InputType2>::markNecessary() {
290template <
typename T,
typename InputType1,
typename InputType2>
291bool Anchor<T, InputType1, InputType2>::isNecessary()
const {
292 return d_necessary > 0;
295template <
typename T,
typename InputType1,
typename InputType2>
296bool Anchor<T, InputType1, InputType2>::isStale()
const {
297 bool recomputeIdLessThanChildChangeId =
false;
299 if (d_numDependencies >= 1) {
300 recomputeIdLessThanChildChangeId =
301 d_recomputeId < d_firstDependency->getChangeId();
303 if (!recomputeIdLessThanChildChangeId && d_numDependencies == 2) {
304 recomputeIdLessThanChildChangeId |=
305 d_recomputeId < d_secondDependency->getChangeId();
309 return isNecessary() &
310 (d_hasNeverBeenComputed || recomputeIdLessThanChildChangeId);
313template <
typename T,
typename InputType1,
typename InputType2>
314void Anchor<T, InputType1, InputType2>::decrementNecessaryCount() {
315 if (d_necessary <= 0) {
322template <
typename T,
typename InputType1,
typename InputType2>
323AnchorBase::AnchorId Anchor<T, InputType1, InputType2>::getId()
const {
327template <
typename T,
typename InputType1,
typename InputType2>
328int Anchor<T, InputType1, InputType2>::getHeight()
const {
332template <
typename T,
typename InputType1,
typename InputType2>
333int Anchor<T, InputType1, InputType2>::getRecomputeId()
const {
334 return d_recomputeId;
337template <
typename T,
typename InputType1,
typename InputType2>
338int Anchor<T, InputType1, InputType2>::getChangeId()
const {
342template <
typename T,
typename InputType1,
typename InputType2>
343void Anchor<T, InputType1, InputType2>::setChangeId(
int changeId) {
344 d_changeId = changeId;
347template <
typename T,
typename InputType1,
typename InputType2>
348void Anchor<T, InputType1, InputType2>::set(
const T& value) {
352template <
typename T,
typename InputType1,
typename InputType2>
353void Anchor<T, InputType1, InputType2>::addDependant(
354 const std::shared_ptr<AnchorBase>& dependant) {
355 d_dependants.insert(dependant);
358template <
typename T,
typename InputType1,
typename InputType2>
359void Anchor<T, InputType1, InputType2>::removeDependant(
360 const std::shared_ptr<AnchorBase>& dependant) {
361 d_dependants.erase(dependant);
364template <
typename T,
typename InputType1,
typename InputType2>
365std::unordered_set<std::shared_ptr<AnchorBase>>
366Anchor<T, InputType1, InputType2>::getDependants()
const {
367 std::unordered_set<std::shared_ptr<AnchorBase>> result;
369 for (
auto& parent : d_dependants) {
370 result.insert(parent);
376template <
typename T,
typename InputType1,
typename InputType2>
377std::vector<std::shared_ptr<AnchorBase>>
378Anchor<T, InputType1, InputType2>::getDependencies()
const {
379 std::vector<std::shared_ptr<AnchorBase>> result;
381 if (d_numDependencies >= 1) {
382 result.push_back(d_firstDependency);
384 if (d_numDependencies == 2) {
385 result.push_back(d_secondDependency);
This class exists to simplify the Anchors API, so that we can pass an Anchor around using only the ty...
Definition: anchor.h:41
A single node in the computation graph containing a value.
Definition: anchor.h:59
std::function< T(InputType1 &, InputType2 &)> DualInputUpdater
Alias for function that accepts inputs of type InputType1 and InputType2 and returns a value of type ...
Definition: anchor.h:71
std::function< T(InputType1 &)> SingleInputUpdater
Alias for function that accepts an input of type InputType1 and returns a value of type T.
Definition: anchor.h:65
Engine is the brain of Anchors, containing the necessary functions and data to retrieve the value of ...
Definition: engine.h:19
Main library namespace.
Definition: anchor.h:32