Control Surface new-input
MIDI Control Surface library for Arduino
Updatable.hpp
Go to the documentation of this file.
1 /* ✔ */
2 
3 #pragma once
4 
6 
7 AH_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 
31 template <class Derived>
32 class 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;
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;
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 
159 template <class Derived>
161 
162 struct NormalUpdatable {};
163 
172 template <class T = NormalUpdatable>
173 class 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 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 & operator=(UpdatableCRTP &&)
Definition: Updatable.hpp:68
UpdatableCRTP & operator=(const UpdatableCRTP &)
Definition: Updatable.hpp:63
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(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
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
#define ERROR(msg, errc)
Print the error message and error code, and stop the execution if FATAL_ERRORS are enabled.
Definition: Error.hpp:42