Arduino Helpers master
Utility library for Arduino
Updatable.hpp
Go to the documentation of this file.
1/* ✔ */
2
3#pragma once
4
7#include <AH/Error/Error.hpp>
8#include <AH/STL/type_traits>
9#include <AH/STL/utility> // std::forward
11#include <stddef.h>
12
14
27template <class Derived>
28class UpdatableCRTP : public DoublyLinkable<Derived> {
29
30 public:
31#if defined(__GNUC__) && !defined(__clang__)
32#pragma GCC diagnostic push
33#pragma GCC diagnostic ignored "-Wattributes"
34#endif
35
36 // When a Derived instance is constructed, the base class constructor
37 // UpdatableCRTP is called first. Because the Derived constructor hasn't
38 // been run yet, the dynamic type is just Updatable, not yet Derived.
39 // The undefined behavior sanitizer checks this dynamic type when the this
40 // pointer is casted to Derived using the CRTP macro, and thus causes an
41 // error.
42 // The constructor only casts and stores the pointer, it doesn't dereference
43 // it to call any of Derived methods, so I don't think that it's undefined
44 // behavior (and I don't know of a better way to do this).
45 // Also see https://stackoverflow.com/q/61061051/6356744
46
47 protected:
50 UpdatableCRTP() __attribute__((no_sanitize("undefined"))) {
51 updatables.append(CRTP(Derived));
52 }
53
55 __attribute__((no_sanitize("undefined")))
56 : DoublyLinkable<Derived>() {
57 updatables.append(CRTP(Derived));
58 }
59 UpdatableCRTP &operator=(const UpdatableCRTP &) { return *this; }
60
61 UpdatableCRTP(UpdatableCRTP &&) __attribute__((no_sanitize("undefined"))) {
62 updatables.append(CRTP(Derived));
63 }
64 UpdatableCRTP &operator=(UpdatableCRTP &&) { return *this; }
65
66 public:
68 virtual ~UpdatableCRTP() __attribute__((no_sanitize("undefined"))) {
69 if (updatables.couldContain(CRTP(Derived)))
70 updatables.remove(CRTP(Derived));
71 }
72
73#if defined(__GNUC__) && !defined(__clang__)
74#pragma GCC diagnostic pop
75#endif
76
77 public:
80
81 template <class... Args>
82 static void __attribute__((always_inline))
83 applyToAll(void (Derived::*method)(Args...), Args... args) {
84 for (auto &el : updatables)
85 (el.*method)(args...);
86 }
87
89
90 public:
93
96 void enable() {
97 if (isEnabled()) {
98 ERROR(F("Error: This element is already enabled."), 0x1212);
99 return; // LCOV_EXCL_LINE
100 }
101 updatables.append(CRTP(Derived));
102 }
103
106 void disable() {
107 if (!isEnabled()) {
108 ERROR(F("Error: This element is already disabled."), 0x1213);
109 return; // LCOV_EXCL_LINE
110 }
111 updatables.remove(CRTP(Derived));
112 }
113
120 bool isEnabled() const {
121 return updatables.couldContain(CRTP(const Derived));
122 }
123
125 static void enable(UpdatableCRTP *element) { element->enable(); }
127 static void enable(UpdatableCRTP &element) { element.enable(); }
129 template <class U, size_t N>
130 static void enable(U (&array)[N]) {
131 for (U &el : array)
132 enable(el);
133 }
134
136 static void disable(UpdatableCRTP *element) { element->disable(); }
138 static void disable(UpdatableCRTP &element) { element.disable(); }
140 template <class U, size_t N>
141 static void disable(U (&array)[N]) {
142 for (U &el : array)
143 disable(el);
144 }
145
147 void moveDown() { updatables.moveDown(CRTP(Derived)); }
148
150
151 protected:
153};
154
155template <class Derived>
157
159
168template <class T = NormalUpdatable>
169class Updatable : public UpdatableCRTP<Updatable<T>> {
170 public:
173
175 virtual void begin() = 0;
176
178 virtual void update() = 0;
179
182 static void beginAll() { Updatable::applyToAll(&Updatable::begin); }
183
186 static void updateAll() { Updatable::applyToAll(&Updatable::update); }
187
189};
190
#define CRTP(Derived)
Helper for the Curiously Recurring Template Pattern.
Definition: CRTP.hpp:4
#define END_AH_NAMESPACE
#define BEGIN_AH_NAMESPACE
A class that can be inherited from to allow inserting into a DoublyLinkedList.
Definition: LinkedList.hpp:317
void append(Node *node)
Append a node to a linked list.
Definition: LinkedList.hpp:116
bool couldContain(const Node *node) const
Check if the linked list could contain the given node.
Definition: LinkedList.hpp:280
void remove(Node *node)
Remove a node from the linked list.
Definition: LinkedList.hpp:199
void moveDown(Node *node)
Move down the given node in the linked list.
Definition: LinkedList.hpp:231
A super class for object that have to be updated regularly.
Definition: Updatable.hpp:28
static void enable(UpdatableCRTP &element)
Enable this updatable: insert it into the linked list of instances, so it gets updated automatically.
Definition: Updatable.hpp:127
UpdatableCRTP(UpdatableCRTP &&) __attribute__((no_sanitize("undefined")))
Definition: Updatable.hpp:61
static void enable(U(&array)[N])
Enable this updatable: insert it into the linked list of instances, so it gets updated automatically.
Definition: Updatable.hpp:130
UpdatableCRTP & operator=(UpdatableCRTP &&)
Definition: Updatable.hpp:64
UpdatableCRTP(const UpdatableCRTP &) __attribute__((no_sanitize("undefined")))
Definition: Updatable.hpp:54
UpdatableCRTP() __attribute__((no_sanitize("undefined")))
Constructor: create an Updatable and add it to the linked list of instances.
Definition: Updatable.hpp:50
void moveDown()
Move down this element in the list.
Definition: Updatable.hpp:147
void enable()
Enable this updatable: insert it into the linked list of instances, so it gets updated automatically.
Definition: Updatable.hpp:96
static DoublyLinkedList< Derived > updatables
Definition: Updatable.hpp:152
static void disable(UpdatableCRTP &element)
Disable this updatable: remove it from the linked list of instances, so it no longer gets updated aut...
Definition: Updatable.hpp:138
UpdatableCRTP & operator=(const UpdatableCRTP &)
Definition: Updatable.hpp:59
virtual ~UpdatableCRTP() __attribute__((no_sanitize("undefined")))
Destructor: remove the updatable from the linked list of instances.
Definition: Updatable.hpp:68
void disable()
Disable this updatable: remove it from the linked list of instances, so it no longer gets updated aut...
Definition: Updatable.hpp:106
bool isEnabled() const
Check if this updatable is enabled.
Definition: Updatable.hpp:120
static void disable(UpdatableCRTP *element)
Disable this updatable: remove it from the linked list of instances, so it no longer gets updated aut...
Definition: Updatable.hpp:136
static void disable(U(&array)[N])
Disable this updatable: remove it from the linked list of instances, so it no longer gets updated aut...
Definition: Updatable.hpp:141
static void enable(UpdatableCRTP *element)
Enable this updatable: insert it into the linked list of instances, so it gets updated automatically.
Definition: Updatable.hpp:125
A super class for object that have to be updated regularly.
Definition: Updatable.hpp:169
static void updateAll()
Update all enabled instances of this class.
Definition: Updatable.hpp:186
static void beginAll()
Begin all enabled instances of this class.
Definition: Updatable.hpp:182
virtual void update()=0
Update this updatable.
virtual void begin()=0
Initialize this updatable.
#define ERROR(msg, errc)
Print the error message and error code, and stop the execution if FATAL_ERRORS are enabled.
Definition: Error.hpp:39