WPILibC++ 2023.4.3-108-ge5452e3
SimCallbackRegistry.h
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <memory>
8#include <utility>
9
10#include <wpi/Compiler.h>
11#include <wpi/UidVector.h>
12#include <wpi/spinlock.h>
13
15
16namespace hal {
17
18namespace impl {
19
21 public:
22 using RawFunctor = void (*)();
23
24 protected:
26
27 public:
28 void Cancel(int32_t uid) {
29 std::scoped_lock lock(m_mutex);
30 if (m_callbacks && uid > 0) {
31 m_callbacks->erase(uid - 1);
32 }
33 }
34
35 void Reset() {
36 std::scoped_lock lock(m_mutex);
37 DoReset();
38 }
39
41
42 protected:
43 int32_t DoRegister(RawFunctor callback, void* param) {
44 // Must return -1 on a null callback for error handling
45 if (callback == nullptr) {
46 return -1;
47 }
48 if (!m_callbacks) {
49 m_callbacks = std::make_unique<CallbackVector>();
50 }
51 return m_callbacks->emplace_back(param, callback) + 1;
52 }
53
55 if (m_callbacks) {
56 m_callbacks->clear();
57 }
58 }
59
61 std::unique_ptr<CallbackVector> m_callbacks;
62};
63
64} // namespace impl
65
66/**
67 * Simulation callback registry. Provides callback functionality.
68 *
69 * @tparam CallbackFunction callback function type (e.g. HAL_BufferCallback)
70 * @tparam GetName function that returns a const char* for the name
71 */
72template <typename CallbackFunction, const char* (*GetName)()>
74 public:
75 int32_t Register(CallbackFunction callback, void* param) {
76 std::scoped_lock lock(m_mutex);
77 return DoRegister(reinterpret_cast<RawFunctor>(callback), param);
78 }
79
80 template <typename... U>
81 void Invoke(U&&... u) const {
82#ifdef _MSC_VER // work around VS2019 16.4.0 bug
83 std::scoped_lock<wpi::recursive_spinlock> lock(m_mutex);
84#else
85 std::scoped_lock lock(m_mutex);
86#endif
87 if (m_callbacks) {
88 const char* name = GetName();
89 for (auto&& cb : *m_callbacks) {
90 reinterpret_cast<CallbackFunction>(cb.callback)(name, cb.param,
91 std::forward<U>(u)...);
92 }
93 }
94 }
95
96 template <typename... U>
98 return Invoke(std::forward<U>(u)...);
99 }
100};
101
102/**
103 * Define a name functor for use with SimCallbackRegistry.
104 * This creates a function named GetNAMEName() that returns "NAME".
105 * @param NAME the name to return
106 */
107#define HAL_SIMCALLBACKREGISTRY_DEFINE_NAME(NAME) \
108 static LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr const char* \
109 Get##NAME##Name() { \
110 return #NAME; \
111 }
112
113/**
114 * Define a standard C API for SimCallbackRegistry.
115 *
116 * Functions defined:
117 * - int32 NS_RegisterCAPINAMECallback(
118 * int32_t index, TYPE callback, void* param)
119 * - void NS_CancelCAPINAMECallback(int32_t index, int32_t uid)
120 *
121 * @param TYPE the underlying callback type (e.g. HAL_BufferCallback)
122 * @param NS the "namespace" (e.g. HALSIM)
123 * @param CAPINAME the C API name (usually first letter capitalized)
124 * @param DATA the backing data array
125 * @param LOWERNAME the lowercase name of the backing data registry
126 */
127#define HAL_SIMCALLBACKREGISTRY_DEFINE_CAPI(TYPE, NS, CAPINAME, DATA, \
128 LOWERNAME) \
129 int32_t NS##_Register##CAPINAME##Callback(int32_t index, TYPE callback, \
130 void* param) { \
131 return DATA[index].LOWERNAME.Register(callback, param); \
132 } \
133 \
134 void NS##_Cancel##CAPINAME##Callback(int32_t index, int32_t uid) { \
135 DATA[index].LOWERNAME.Cancel(uid); \
136 }
137
138/**
139 * Define a standard C API for SimCallbackRegistry (no index variant).
140 *
141 * Functions defined:
142 * - int32 NS_RegisterCAPINAMECallback(TYPE callback, void* param)
143 * - void NS_CancelCAPINAMECallback(int32_t uid)
144 *
145 * @param TYPE the underlying callback type (e.g. HAL_BufferCallback)
146 * @param NS the "namespace" (e.g. HALSIM)
147 * @param CAPINAME the C API name (usually first letter capitalized)
148 * @param DATA the backing data pointer
149 * @param LOWERNAME the lowercase name of the backing data registry
150 */
151#define HAL_SIMCALLBACKREGISTRY_DEFINE_CAPI_NOINDEX(TYPE, NS, CAPINAME, DATA, \
152 LOWERNAME) \
153 int32_t NS##_Register##CAPINAME##Callback(TYPE callback, void* param) { \
154 return DATA->LOWERNAME.Register(callback, param); \
155 } \
156 \
157 void NS##_Cancel##CAPINAME##Callback(int32_t uid) { \
158 DATA->LOWERNAME.Cancel(uid); \
159 }
160
161/**
162 * Define a stub standard C API for SimCallbackRegistry.
163 *
164 * Functions defined:
165 * - int32 NS_RegisterCAPINAMECallback(
166 * int32_t index, TYPE callback, void* param)
167 * - void NS_CancelCAPINAMECallback(int32_t index, int32_t uid)
168 *
169 * @param TYPE the underlying callback type (e.g. HAL_BufferCallback)
170 * @param NS the "namespace" (e.g. HALSIM)
171 * @param CAPINAME the C API name (usually first letter capitalized)
172 */
173#define HAL_SIMCALLBACKREGISTRY_STUB_CAPI(TYPE, NS, CAPINAME) \
174 int32_t NS##_Register##CAPINAME##Callback(int32_t index, TYPE callback, \
175 void* param) { \
176 return 0; \
177 } \
178 \
179 void NS##_Cancel##CAPINAME##Callback(int32_t index, int32_t uid) {}
180
181/**
182 * Define a stub standard C API for SimCallbackRegistry (no index variant).
183 *
184 * Functions defined:
185 * - int32 NS_RegisterCAPINAMECallback(TYPE callback, void* param)
186 * - void NS_CancelCAPINAMECallback(int32_t uid)
187 *
188 * @param TYPE the underlying callback type (e.g. HAL_BufferCallback)
189 * @param NS the "namespace" (e.g. HALSIM)
190 * @param CAPINAME the C API name (usually first letter capitalized)
191 */
192#define HAL_SIMCALLBACKREGISTRY_STUB_CAPI_NOINDEX(TYPE, NS, CAPINAME) \
193 int32_t NS##_Register##CAPINAME##Callback(TYPE callback, void* param) { \
194 return 0; \
195 } \
196 \
197 void NS##_Cancel##CAPINAME##Callback(int32_t uid) {}
198
199} // namespace hal
#define LLVM_ATTRIBUTE_ALWAYS_INLINE
LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do so, mark a method "always...
Definition: Compiler.h:274
Simulation callback registry.
Definition: SimCallbackRegistry.h:73
void Invoke(U &&... u) const
Definition: SimCallbackRegistry.h:81
LLVM_ATTRIBUTE_ALWAYS_INLINE void operator()(U &&... u) const
Definition: SimCallbackRegistry.h:97
int32_t Register(CallbackFunction callback, void *param)
Definition: SimCallbackRegistry.h:75
Definition: SimCallbackRegistry.h:20
void Cancel(int32_t uid)
Definition: SimCallbackRegistry.h:28
wpi::recursive_spinlock & GetMutex()
Definition: SimCallbackRegistry.h:40
LLVM_ATTRIBUTE_ALWAYS_INLINE void DoReset()
Definition: SimCallbackRegistry.h:54
wpi::recursive_spinlock m_mutex
Definition: SimCallbackRegistry.h:60
void(*)() RawFunctor
Definition: SimCallbackRegistry.h:22
int32_t DoRegister(RawFunctor callback, void *param)
Definition: SimCallbackRegistry.h:43
void Reset()
Definition: SimCallbackRegistry.h:35
std::unique_ptr< CallbackVector > m_callbacks
Definition: SimCallbackRegistry.h:61
Vector which provides an integrated freelist for removal and reuse of individual elements.
Definition: UidVector.h:73
A recursive spinlock mutex.
Definition: spinlock.h:46
::int32_t int32_t
Definition: Meta.h:57
WPILib Hardware Abstraction Layer (HAL) namespace.
Definition: ChipObject.h:40