Control Surface main
MIDI Control Surface library for Arduino
Loading...
Searching...
No Matches
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")))
57 updatables.append(CRTP(Derived));
58 }
59 UpdatableCRTP &operator=(const UpdatableCRTP &) { return *this; }
60
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 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:19
A class for serial-in/parallel-out shift registers, like the 74HC595 that are connected to the SPI bu...
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.
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.
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.
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
static void disable(UpdatableCRTP &element)
Disable this updatable: remove it from the linked list of instances, so it no longer gets updated aut...
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...
bool isEnabled() const
Check if this updatable is enabled.
static void disable(UpdatableCRTP *element)
Disable this updatable: remove it from the linked list of instances, so it no longer gets updated aut...
static void disable(U(&array)[N])
Disable this updatable: remove it from the linked list of instances, so it no longer gets updated aut...
static void enable(UpdatableCRTP *element)
Enable this updatable: insert it into the linked list of instances, so it gets updated automatically.
A super class for object that have to be updated regularly.
static void updateAll()
Update all enabled instances of this class.
static void beginAll()
Begin all enabled instances of this class.
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.