Control Surface  1.2.0
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/Containers/Mutex.hpp>
12 #include <AH/Error/Error.hpp>
13 #include <AH/STL/type_traits>
14 #include <AH/STL/utility> // std::forward
16 #include <stddef.h>
17 
19 
32 template <class Derived, bool ThreadSafe = false>
33 class UpdatableCRTP : public DoublyLinkable<Derived> {
34 
35  public:
36  using Mutex =
37  typename std::conditional<ThreadSafe, DefaultMutEx, EmptyMutex>::type;
38  using LockGuard =
39  typename std::conditional<ThreadSafe, DefaultLockGuard<Mutex>,
40  EmptyLockGuard<Mutex>>::type;
41 
42 #if defined(__GNUC__) && !defined(__clang__)
43 #pragma GCC diagnostic push
44 #pragma GCC diagnostic ignored "-Wattributes"
45 #endif
46 
47  // When a Derived instance is constructed, the base class constructor
48  // UpdatableCRTP is called first. Because the Derived constructor hasn't
49  // been run yet, the dynamic type is just Updatable, not yet Derived.
50  // The undefined behavior sanitizer checks this dynamic type when the this
51  // pointer is casted to Derived using the CRTP macro, and thus causes an
52  // error.
53  // The constructor only casts and stores the pointer, it doesn't dereference
54  // it to call any of Derived methods, so I don't think that it's undefined
55  // behavior (and I don't know of a better way to do this).
56  // Also see https://stackoverflow.com/q/61061051/6356744
57 
58  protected:
61  UpdatableCRTP() __attribute__((no_sanitize("undefined"))) {
62  LockGuard lock(mutex);
63  updatables.append(CRTP(Derived));
64  }
65 
66  public:
68  virtual ~UpdatableCRTP() __attribute__((no_sanitize("undefined"))) {
69  LockGuard lock(mutex);
70  if (updatables.couldContain(CRTP(Derived)))
71  updatables.remove(CRTP(Derived));
72  }
73 
74 #if defined(__GNUC__) && !defined(__clang__)
75 #pragma GCC diagnostic pop
76 #endif
77 
78  public:
79  static Mutex &getMutex() { return mutex; }
80 
83 
84  template <class... Args>
85  static void applyToAll(const LockGuard &,
86  void (Derived::*method)(Args &&...),
87  Args &&... args) {
88  for (auto &el : updatables)
89  (el.*method)(std::forward<Args>(args)...);
90  }
91 
92  template <class... Args>
93  static void applyToAll(void (Derived::*method)(Args &&...),
94  Args &&... args) {
95  applyToAll(LockGuard(mutex), method, std::forward<Args>(args)...);
96  }
97 
99 
100  public:
103 
106  void enable(const LockGuard &lock) {
107  if (isEnabled(lock)) {
108  ERROR(F("Error: This element is already enabled."), 0x1212);
109  return;
110  }
111  updatables.append(CRTP(Derived));
112  }
113 
115  void enable() { enable(LockGuard(mutex)); }
116 
119  void disable(const LockGuard &lock) {
120  if (!isEnabled(lock)) {
121  ERROR(F("Error: This element is already disabled."), 0x1213);
122  return;
123  }
124  updatables.remove(CRTP(Derived));
125  }
126 
128  void disable() { disable(LockGuard(mutex)); }
129 
136  bool isEnabled(const LockGuard &) const {
137  return updatables.couldContain(CRTP(const Derived));
138  }
139 
141  bool isEnabled() { return isEnabled(LockGuard(mutex)); }
142 
144  static void enable(UpdatableCRTP *element) { element->enable(); }
146  static void enable(UpdatableCRTP &element) { element.enable(); }
148  template <class U, size_t N>
149  static void enable(U (&array)[N]) {
150  for (U &el : array)
151  enable(el);
152  }
153 
155  static void disable(UpdatableCRTP *element) { element->disable(); }
157  static void disable(UpdatableCRTP &element) { element.disable(); }
159  template <class U, size_t N>
160  static void disable(U (&array)[N]) {
161  for (U &el : array)
162  disable(el);
163  }
164 
166  void moveDown(const LockGuard &) { updatables.moveDown(CRTP(Derived)); }
168  void moveDown() { moveDown(LockGuard(mutex)); }
169 
171 
172  protected:
174  static Mutex mutex;
175 };
176 
177 template <class Derived, bool ThreadSafe>
179 
180 template <class Derived, bool ThreadSafe>
183 
184 struct NormalUpdatable {};
185 
194 template <class T = NormalUpdatable, bool ThreadSafe = false>
195 class Updatable : public UpdatableCRTP<Updatable<T, ThreadSafe>, ThreadSafe> {
196  public:
199 
201  virtual void begin() = 0;
202 
204  virtual void update() = 0;
205 
208  static void beginAll() { Updatable::applyToAll(&Updatable::begin); }
209 
212  static void updateAll() { Updatable::applyToAll(&Updatable::update); }
213 
215 };
216 
218 
AH::UpdatableCRTP< Updatable< Potentiometer, false >, false >::LockGuard
typename std::conditional< ThreadSafe, DefaultLockGuard< Mutex >, EmptyLockGuard< Mutex > >::type LockGuard
Definition: Updatable.hpp:40
AH::Updatable
A super class for object that have to be updated regularly.
Definition: Updatable.hpp:195
Warnings.hpp
Error.hpp
AH::UpdatableCRTP::disable
void disable()
Disable this updatable: remove it from the linked list of instances, so it no longer gets updated aut...
Definition: Updatable.hpp:128
AH::UpdatableCRTP::~UpdatableCRTP
virtual ~UpdatableCRTP() __attribute__((no_sanitize("undefined")))
Destructor: remove the updatable from the linked list of instances.
Definition: Updatable.hpp:68
AH::UpdatableCRTP::isEnabled
bool isEnabled(const LockGuard &) const
Check if this updatable is enabled.
Definition: Updatable.hpp:136
AH::NormalUpdatable
Definition: Updatable.hpp:184
SettingsWrapper.hpp
AH::Updatable::updateAll
static void updateAll()
Update all enabled instances of this class.
Definition: Updatable.hpp:212
AH::UpdatableCRTP::getMutex
static Mutex & getMutex()
Definition: Updatable.hpp:79
AH_DIAGNOSTIC_POP
#define AH_DIAGNOSTIC_POP()
Definition: Warnings.hpp:36
AH::UpdatableCRTP
A super class for object that have to be updated regularly.
Definition: Updatable.hpp:33
AH::UpdatableCRTP::UpdatableCRTP
UpdatableCRTP() __attribute__((no_sanitize("undefined")))
Constructor: create an Updatable and add it to the linked list of instances.
Definition: Updatable.hpp:61
AH::UpdatableCRTP::enable
static void enable(UpdatableCRTP &element)
Enable this updatable: insert it into the linked list of instances, so it gets updated automatically.
Definition: Updatable.hpp:146
AH::UpdatableCRTP::disable
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:160
LinkedList.hpp
AH::Updatable::begin
virtual void begin()=0
Initialize this updatable.
ERROR
#define ERROR(msg, errc)
Print the error message and error code, and stop the execution if FATAL_ERRORS are enabled.
Definition: Error.hpp:42
Mutex.hpp
AH::UpdatableCRTP::enable
static void enable(UpdatableCRTP *element)
Enable this updatable: insert it into the linked list of instances, so it gets updated automatically.
Definition: Updatable.hpp:144
AH::Updatable::beginAll
static void beginAll()
Begin all enabled instances of this class.
Definition: Updatable.hpp:208
AH::UpdatableCRTP::mutex
static Mutex mutex
Definition: Updatable.hpp:174
AH::UpdatableCRTP::enable
void enable()
Enable this updatable: insert it into the linked list of instances, so it gets updated automatically.
Definition: Updatable.hpp:115
AH::UpdatableCRTP::enable
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:149
CRTP
#define CRTP(Derived)
Helper for the Curiously Recurring Template Pattern.
Definition: AH/Containers/CRTP.hpp:4
AH::UpdatableCRTP::isEnabled
bool isEnabled()
Check if this updatable is enabled.
Definition: Updatable.hpp:141
AH::UpdatableCRTP::disable
void disable(const LockGuard &lock)
Disable this updatable: remove it from the linked list of instances, so it no longer gets updated aut...
Definition: Updatable.hpp:119
AH::UpdatableCRTP::disable
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:155
AH::UpdatableCRTP< Updatable< Potentiometer, false >, false >::Mutex
typename std::conditional< ThreadSafe, DefaultMutEx, EmptyMutex >::type Mutex
Definition: Updatable.hpp:37
MIDI_Notes::F
constexpr int8_t F
Definition: Notes.hpp:23
DoublyLinkedList< Derived >
EmptyLockGuard
Lock guard that doesn't lock it's mutex, used on single-core systems.
Definition: Mutex.hpp:11
DoublyLinkable
A class that can be inherited from to allow inserting into a DoublyLinkedList.
Definition: LinkedList.hpp:320
AH::UpdatableCRTP::disable
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:157
AH_DIAGNOSTIC_WERROR
#define AH_DIAGNOSTIC_WERROR()
Definition: Warnings.hpp:35
AH::UpdatableCRTP::enable
void enable(const LockGuard &lock)
Enable this updatable: insert it into the linked list of instances, so it gets updated automatically.
Definition: Updatable.hpp:106
BEGIN_AH_NAMESPACE
#define BEGIN_AH_NAMESPACE
Definition: AH/Settings/NamespaceSettings.hpp:9
AH::Updatable::update
virtual void update()=0
Update this updatable.
END_AH_NAMESPACE
#define END_AH_NAMESPACE
Definition: AH/Settings/NamespaceSettings.hpp:10
AH::UpdatableCRTP::moveDown
void moveDown()
Move down this element in the list.
Definition: Updatable.hpp:168
AH::UpdatableCRTP::applyToAll
static void applyToAll(const LockGuard &, void(Derived::*method)(Args &&...), Args &&... args)
Definition: Updatable.hpp:85
AH::UpdatableCRTP::moveDown
void moveDown(const LockGuard &)
Move down this element in the list.
Definition: Updatable.hpp:166
AH::UpdatableCRTP::applyToAll
static void applyToAll(void(Derived::*method)(Args &&...), Args &&... args)
Definition: Updatable.hpp:93
AH::UpdatableCRTP::updatables
static DoublyLinkedList< Derived > updatables
Definition: Updatable.hpp:173