Control Surface master
MIDI Control Surface library for Arduino
Updatable.hpp
Go to the documentation of this file.
1/* ✔ */
2
3#pragma once
4
6
7AH_DIAGNOSTIC_WERROR() // Enable errors on warnings
8
9#include <AH/Containers/CRTP.hpp>
11#include <AH/Error/Error.hpp>
12#include <AH/STL/type_traits>
13#include <AH/STL/utility> // std::forward
15#include <stddef.h>
16
18
31template <class Derived>
32class UpdatableCRTP : public DoublyLinkable<Derived> {
33
34 public:
35#if defined(__GNUC__) && !defined(__clang__)
36#pragma GCC diagnostic push
37#pragma GCC diagnostic ignored "-Wattributes"
38#endif
39
40 // When a Derived instance is constructed, the base class constructor
41 // UpdatableCRTP is called first. Because the Derived constructor hasn't
42 // been run yet, the dynamic type is just Updatable, not yet Derived.
43 // The undefined behavior sanitizer checks this dynamic type when the this
44 // pointer is casted to Derived using the CRTP macro, and thus causes an
45 // error.
46 // The constructor only casts and stores the pointer, it doesn't dereference
47 // it to call any of Derived methods, so I don't think that it's undefined
48 // behavior (and I don't know of a better way to do this).
49 // Also see https://stackoverflow.com/q/61061051/6356744
50
51 protected:
54 UpdatableCRTP() __attribute__((no_sanitize("undefined"))) {
55 updatables.append(CRTP(Derived));
56 }
57
59 __attribute__((no_sanitize("undefined")))
60 : DoublyLinkable<Derived>() {
61 updatables.append(CRTP(Derived));
62 }
63 UpdatableCRTP &operator=(const UpdatableCRTP &) { return *this; }
64
65 UpdatableCRTP(UpdatableCRTP &&) __attribute__((no_sanitize("undefined"))) {
66 updatables.append(CRTP(Derived));
67 }
68 UpdatableCRTP &operator=(UpdatableCRTP &&) { return *this; }
69
70 public:
72 virtual ~UpdatableCRTP() __attribute__((no_sanitize("undefined"))) {
73 if (updatables.couldContain(CRTP(Derived)))
74 updatables.remove(CRTP(Derived));
75 }
76
77#if defined(__GNUC__) && !defined(__clang__)
78#pragma GCC diagnostic pop
79#endif
80
81 public:
84
85 template <class... Args>
86 static void __attribute__((always_inline))
87 applyToAll(void (Derived::*method)(Args...), Args... args) {
88 for (auto &el : updatables)
89 (el.*method)(args...);
90 }
91
93
94 public:
97
100 void enable() {
101 if (isEnabled()) {
102 ERROR(F("Error: This element is already enabled."), 0x1212);
103 return; // LCOV_EXCL_LINE
104 }
105 updatables.append(CRTP(Derived));
106 }
107
110 void disable() {
111 if (!isEnabled()) {
112 ERROR(F("Error: This element is already disabled."), 0x1213);
113 return; // LCOV_EXCL_LINE
114 }
115 updatables.remove(CRTP(Derived));
116 }
117
124 bool isEnabled() const {
125 return updatables.couldContain(CRTP(const Derived));
126 }
127
129 static void enable(UpdatableCRTP *element) { element->enable(); }
131 static void enable(UpdatableCRTP &element) { element.enable(); }
133 template <class U, size_t N>
134 static void enable(U (&array)[N]) {
135 for (U &el : array)
136 enable(el);
137 }
138
140 static void disable(UpdatableCRTP *element) { element->disable(); }
142 static void disable(UpdatableCRTP &element) { element.disable(); }
144 template <class U, size_t N>
145 static void disable(U (&array)[N]) {
146 for (U &el : array)
147 disable(el);
148 }
149
151 void moveDown() { updatables.moveDown(CRTP(Derived)); }
152
154
155 protected:
157};
158
159template <class Derived>
161
163
172template <class T = NormalUpdatable>
173class Updatable : public UpdatableCRTP<Updatable<T>> {
174 public:
177
179 virtual void begin() = 0;
180
182 virtual void update() = 0;
183
186 static void beginAll() { Updatable::applyToAll(&Updatable::begin); }
187
190 static void updateAll() { Updatable::applyToAll(&Updatable::update); }
191
193};
194
196
#define END_AH_NAMESPACE
#define BEGIN_AH_NAMESPACE
#define CRTP(Derived)
Helper for the Curiously Recurring Template Pattern.
Definition: CRTP.hpp:4
#define ERROR(msg, errc)
Definition: Error.hpp:22
#define AH_DIAGNOSTIC_POP()
Definition: Warnings.hpp:36
#define AH_DIAGNOSTIC_WERROR()
Definition: Warnings.hpp:35
A super class for object that have to be updated regularly.
Definition: Updatable.hpp:32
static void enable(UpdatableCRTP &element)
Enable this updatable: insert it into the linked list of instances, so it gets updated automatically.
Definition: Updatable.hpp:131
UpdatableCRTP(UpdatableCRTP &&) __attribute__((no_sanitize("undefined")))
Definition: Updatable.hpp:65
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:134
UpdatableCRTP & operator=(UpdatableCRTP &&)
Definition: Updatable.hpp:68
UpdatableCRTP(const UpdatableCRTP &) __attribute__((no_sanitize("undefined")))
Definition: Updatable.hpp:58
UpdatableCRTP() __attribute__((no_sanitize("undefined")))
Constructor: create an Updatable and add it to the linked list of instances.
Definition: Updatable.hpp:54
void moveDown()
Move down this element in the list.
Definition: Updatable.hpp:151
void enable()
Enable this updatable: insert it into the linked list of instances, so it gets updated automatically.
Definition: Updatable.hpp:100
static DoublyLinkedList< Derived > updatables
Definition: Updatable.hpp:156
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:142
UpdatableCRTP & operator=(const UpdatableCRTP &)
Definition: Updatable.hpp:63
virtual ~UpdatableCRTP() __attribute__((no_sanitize("undefined")))
Destructor: remove the updatable from the linked list of instances.
Definition: Updatable.hpp:72
void disable()
Disable this updatable: remove it from the linked list of instances, so it no longer gets updated aut...
Definition: Updatable.hpp:110
bool isEnabled() const
Check if this updatable is enabled.
Definition: Updatable.hpp:124
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:140
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:145
static void enable(UpdatableCRTP *element)
Enable this updatable: insert it into the linked list of instances, so it gets updated automatically.
Definition: Updatable.hpp:129
A super class for object that have to be updated regularly.
Definition: Updatable.hpp:173
static void updateAll()
Update all enabled instances of this class.
Definition: Updatable.hpp:190
static void beginAll()
Begin all enabled instances of this class.
Definition: Updatable.hpp:186
virtual void update()=0
Update this updatable.
virtual void begin()=0
Initialize this updatable.
A class that can be inherited from to allow inserting into a DoublyLinkedList.
Definition: LinkedList.hpp:321
A class for doubly linked lists.
Definition: LinkedList.hpp:25