Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
Callback.h
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2019 ARM Limited 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 #ifndef MBED_CALLBACK_H 00018 #define MBED_CALLBACK_H 00019 00020 #include <string.h> 00021 #include <stdint.h> 00022 #include <new> 00023 #include "platform/mbed_assert.h" 00024 #include "platform/mbed_toolchain.h" 00025 00026 namespace mbed { 00027 /** \addtogroup platform-public-api */ 00028 /** @{*/ 00029 /** 00030 * \defgroup platform_Callback Callback class 00031 * @{ 00032 */ 00033 00034 /** Callback class based on template specialization 00035 * 00036 * @note Synchronization level: Not protected 00037 */ 00038 template <typename F> 00039 class Callback; 00040 00041 // Internal sfinae declarations 00042 // 00043 // These are used to eliminate overloads based on type attributes 00044 // 1. Does a function object have a call operator 00045 // 2. Does a function object fit in the available storage 00046 // 00047 // These eliminations are handled cleanly by the compiler and avoid 00048 // massive and misleading error messages when confronted with an 00049 // invalid type (or worse, runtime failures) 00050 namespace detail { 00051 struct nil {}; 00052 00053 template <bool B, typename R = nil> 00054 struct enable_if { 00055 typedef R type; 00056 }; 00057 00058 template <typename R> 00059 struct enable_if<false, R> {}; 00060 00061 template <typename M, M> 00062 struct is_type { 00063 static const bool value = true; 00064 }; 00065 } 00066 00067 #define MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M) \ 00068 typename detail::enable_if< \ 00069 detail::is_type<M, &F::operator()>::value && \ 00070 sizeof(F) <= sizeof(uintptr_t) \ 00071 >::type = detail::nil() 00072 00073 /** Callback class based on template specialization 00074 * 00075 * @note Synchronization level: Not protected 00076 */ 00077 template <typename R, typename... ArgTs> 00078 class Callback<R(ArgTs...)> { 00079 public: 00080 /** Create a Callback with a static function 00081 * @param func Static function to attach 00082 */ 00083 Callback(R(*func)(ArgTs...) = 0) 00084 { 00085 if (!func) { 00086 memset(this, 0, sizeof(Callback)); 00087 } else { 00088 generate(func); 00089 } 00090 } 00091 00092 /** Attach a Callback 00093 * @param func The Callback to attach 00094 */ 00095 Callback(const Callback<R(ArgTs...)> &func) 00096 { 00097 memset(this, 0, sizeof(Callback)); 00098 if (func._ops) { 00099 func._ops->move(this, &func); 00100 } 00101 _ops = func._ops; 00102 } 00103 00104 /** Create a Callback with a member function 00105 * @param obj Pointer to object to invoke member function on 00106 * @param method Member function to attach 00107 */ 00108 template<typename T, typename U> 00109 Callback(U *obj, R(T::*method)(ArgTs...)) 00110 { 00111 generate(method_context<T, R(T::*)(ArgTs...)>(obj, method)); 00112 } 00113 00114 /** Create a Callback with a member function 00115 * @param obj Pointer to object to invoke member function on 00116 * @param method Member function to attach 00117 */ 00118 template<typename T, typename U> 00119 Callback(const U *obj, R(T::*method)(ArgTs...) const) 00120 { 00121 generate(method_context<const T, R(T::*)(ArgTs...) const>(obj, method)); 00122 } 00123 00124 /** Create a Callback with a member function 00125 * @param obj Pointer to object to invoke member function on 00126 * @param method Member function to attach 00127 */ 00128 template<typename T, typename U> 00129 Callback(volatile U *obj, R(T::*method)(ArgTs...) volatile) 00130 { 00131 generate(method_context<volatile T, R(T::*)(ArgTs...) volatile>(obj, method)); 00132 } 00133 00134 /** Create a Callback with a member function 00135 * @param obj Pointer to object to invoke member function on 00136 * @param method Member function to attach 00137 */ 00138 template<typename T, typename U> 00139 Callback(const volatile U *obj, R(T::*method)(ArgTs...) const volatile) 00140 { 00141 generate(method_context<const volatile T, R(T::*)(ArgTs...) const volatile>(obj, method)); 00142 } 00143 00144 /** Create a Callback with a static function and bound pointer 00145 * @param func Static function to attach 00146 * @param arg Pointer argument to function 00147 */ 00148 template<typename T, typename U> 00149 Callback(R(*func)(T *, ArgTs...), U *arg) 00150 { 00151 generate(function_context<R(*)(T *, ArgTs...), T>(func, arg)); 00152 } 00153 00154 /** Create a Callback with a static function and bound pointer 00155 * @param func Static function to attach 00156 * @param arg Pointer argument to function 00157 */ 00158 template<typename T, typename U> 00159 Callback(R(*func)(const T *, ArgTs...), const U *arg) 00160 { 00161 generate(function_context<R(*)(const T *, ArgTs...), const T>(func, arg)); 00162 } 00163 00164 /** Create a Callback with a static function and bound pointer 00165 * @param func Static function to attach 00166 * @param arg Pointer argument to function 00167 */ 00168 template<typename T, typename U> 00169 Callback(R(*func)(volatile T *, ArgTs...), volatile U *arg) 00170 { 00171 generate(function_context<R(*)(volatile T *, ArgTs...), volatile T>(func, arg)); 00172 } 00173 00174 /** Create a Callback with a static function and bound pointer 00175 * @param func Static function to attach 00176 * @param arg Pointer argument to function 00177 */ 00178 template<typename T, typename U> 00179 Callback(R(*func)(const volatile T *, ArgTs...), const volatile U *arg) 00180 { 00181 generate(function_context<R(*)(const volatile T *, ArgTs...), const volatile T>(func, arg)); 00182 } 00183 00184 /** Create a Callback with a function object 00185 * @param f Function object to attach 00186 * @note The function object is limited to a single word of storage 00187 */ 00188 template <typename F> 00189 Callback(F f, MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, R(F::*)(ArgTs...))) 00190 { 00191 generate(f); 00192 } 00193 00194 /** Create a Callback with a function object 00195 * @param f Function object to attach 00196 * @note The function object is limited to a single word of storage 00197 */ 00198 template <typename F> 00199 Callback(const F f, MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, R(F::*)(ArgTs...) const)) 00200 { 00201 generate(f); 00202 } 00203 00204 /** Create a Callback with a function object 00205 * @param f Function object to attach 00206 * @note The function object is limited to a single word of storage 00207 */ 00208 template <typename F> 00209 Callback(volatile F f, MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, R(F::*)(ArgTs...) volatile)) 00210 { 00211 generate(f); 00212 } 00213 00214 /** Create a Callback with a function object 00215 * @param f Function object to attach 00216 * @note The function object is limited to a single word of storage 00217 */ 00218 template <typename F> 00219 Callback(const volatile F f, MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, R(F::*)(ArgTs...) const volatile)) 00220 { 00221 generate(f); 00222 } 00223 00224 /** Destroy a callback 00225 */ 00226 ~Callback() 00227 { 00228 if (_ops) { 00229 _ops->dtor(this); 00230 } 00231 } 00232 00233 /** Assign a callback 00234 */ 00235 Callback &operator=(const Callback &that) 00236 { 00237 if (this != &that) { 00238 this->~Callback(); 00239 new (this) Callback(that); 00240 } 00241 00242 return *this; 00243 } 00244 00245 /** Call the attached function 00246 */ 00247 R call(ArgTs... args) const 00248 { 00249 MBED_ASSERT(_ops); 00250 return _ops->call(this, args...); 00251 } 00252 00253 /** Call the attached function 00254 */ 00255 R operator()(ArgTs... args) const 00256 { 00257 return call(args...); 00258 } 00259 00260 /** Test if function has been attached 00261 */ 00262 operator bool() const 00263 { 00264 return _ops; 00265 } 00266 00267 /** Test for equality 00268 */ 00269 friend bool operator==(const Callback &l, const Callback &r) 00270 { 00271 return memcmp(&l, &r, sizeof(Callback)) == 0; 00272 } 00273 00274 /** Test for inequality 00275 */ 00276 friend bool operator!=(const Callback &l, const Callback &r) 00277 { 00278 return !(l == r); 00279 } 00280 00281 /** Static thunk for passing as C-style function 00282 * @param func Callback to call passed as void pointer 00283 * @param args Arguments to be called with function func 00284 * @return the value as determined by func which is of 00285 * type and determined by the signature of func 00286 */ 00287 static R thunk(void *func, ArgTs... args) 00288 { 00289 return static_cast<Callback *>(func)->call(args...); 00290 } 00291 00292 private: 00293 // Stored as pointer to function and pointer to optional object 00294 // Function pointer is stored as union of possible function types 00295 // to guarantee proper size and alignment 00296 struct _class; 00297 union { 00298 void (*_staticfunc)(ArgTs...); 00299 void (*_boundfunc)(_class *, ArgTs...); 00300 void (_class::*_methodfunc)(ArgTs...); 00301 } _func; 00302 void *_obj; 00303 00304 // Dynamically dispatched operations 00305 const struct ops { 00306 R(*call)(const void *, ArgTs...); 00307 void (*move)(void *, const void *); 00308 void (*dtor)(void *); 00309 } *_ops; 00310 00311 // Generate operations for function object 00312 template <typename F> 00313 void generate(const F &f) 00314 { 00315 static const ops ops = { 00316 &Callback::function_call<F>, 00317 &Callback::function_move<F>, 00318 &Callback::function_dtor<F>, 00319 }; 00320 00321 MBED_STATIC_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F), 00322 "Type F must not exceed the size of the Callback class"); 00323 memset(this, 0, sizeof(Callback)); 00324 new (this) F(f); 00325 _ops = &ops; 00326 } 00327 00328 // Function attributes 00329 template <typename F> 00330 static R function_call(const void *p, ArgTs... args) 00331 { 00332 return (*(F *)p)(args...); 00333 } 00334 00335 template <typename F> 00336 static void function_move(void *d, const void *p) 00337 { 00338 new (d) F(*(F *)p); 00339 } 00340 00341 template <typename F> 00342 static void function_dtor(void *p) 00343 { 00344 ((F *)p)->~F(); 00345 } 00346 00347 // Wrappers for functions with context 00348 template <typename O, typename M> 00349 struct method_context { 00350 M method; 00351 O *obj; 00352 00353 method_context(O *obj, M method) 00354 : method(method), obj(obj) {} 00355 00356 R operator()(ArgTs... args) const 00357 { 00358 return (obj->*method)(args...); 00359 } 00360 }; 00361 00362 template <typename F, typename A> 00363 struct function_context { 00364 F func; 00365 A *arg; 00366 00367 function_context(F func, A *arg) 00368 : func(func), arg(arg) {} 00369 00370 R operator()(ArgTs... args) const 00371 { 00372 return func(arg, args...); 00373 } 00374 }; 00375 }; 00376 00377 // Internally used event type 00378 typedef Callback<void(int)> event_callback_t; 00379 00380 00381 /** Create a callback class with type inferred from the arguments 00382 * 00383 * @param func Static function to attach 00384 * @return Callback with inferred type 00385 */ 00386 template <typename R, typename... ArgTs> 00387 Callback<R(ArgTs...)> callback(R(*func)(ArgTs...) = 0) 00388 { 00389 return Callback<R(ArgTs...)>(func); 00390 } 00391 00392 /** Create a callback class with type inferred from the arguments 00393 * 00394 * @param func Static function to attach 00395 * @return Callback with inferred type 00396 */ 00397 template <typename R, typename... ArgTs> 00398 Callback<R(ArgTs...)> callback(const Callback<R(ArgTs...)> &func) 00399 { 00400 return Callback<R(ArgTs...)>(func); 00401 } 00402 00403 /** Create a callback class with type inferred from the arguments 00404 * 00405 * @param obj Optional pointer to object to bind to function 00406 * @param method Member function to attach 00407 * @return Callback with inferred type 00408 */ 00409 template<typename T, typename U, typename R, typename... ArgTs> 00410 Callback<R(ArgTs...)> callback(U *obj, R(T::*method)(ArgTs...)) 00411 { 00412 return Callback<R(ArgTs...)>(obj, method); 00413 } 00414 00415 /** Create a callback class with type inferred from the arguments 00416 * 00417 * @param obj Optional pointer to object to bind to function 00418 * @param method Member function to attach 00419 * @return Callback with inferred type 00420 */ 00421 template<typename T, typename U, typename R, typename... ArgTs> 00422 Callback<R(ArgTs...)> callback(const U *obj, R(T::*method)(ArgTs...) const) 00423 { 00424 return Callback<R(ArgTs...)>(obj, method); 00425 } 00426 00427 /** Create a callback class with type inferred from the arguments 00428 * 00429 * @param obj Optional pointer to object to bind to function 00430 * @param method Member function to attach 00431 * @return Callback with inferred type 00432 */ 00433 template<typename T, typename U, typename R, typename... ArgTs> 00434 Callback<R(ArgTs...)> callback(volatile U *obj, R(T::*method)(ArgTs...) volatile) 00435 { 00436 return Callback<R(ArgTs...)>(obj, method); 00437 } 00438 00439 /** Create a callback class with type inferred from the arguments 00440 * 00441 * @param obj Optional pointer to object to bind to function 00442 * @param method Member function to attach 00443 * @return Callback with inferred type 00444 */ 00445 template<typename T, typename U, typename R, typename... ArgTs> 00446 Callback<R(ArgTs...)> callback(const volatile U *obj, R(T::*method)(ArgTs...) const volatile) 00447 { 00448 return Callback<R(ArgTs...)>(obj, method); 00449 } 00450 00451 /** Create a callback class with type inferred from the arguments 00452 * 00453 * @param func Static function to attach 00454 * @param arg Pointer argument to function 00455 * @return Callback with inferred type 00456 */ 00457 template <typename T, typename U, typename R, typename... ArgTs> 00458 Callback<R(ArgTs...)> callback(R(*func)(T *, ArgTs...), U *arg) 00459 { 00460 return Callback<R(ArgTs...)>(func, arg); 00461 } 00462 00463 /** Create a callback class with type inferred from the arguments 00464 * 00465 * @param func Static function to attach 00466 * @param arg Pointer argument to function 00467 * @return Callback with inferred type 00468 */ 00469 template <typename T, typename U, typename R, typename... ArgTs> 00470 Callback<R(ArgTs...)> callback(R(*func)(const T *, ArgTs...), const U *arg) 00471 { 00472 return Callback<R(ArgTs...)>(func, arg); 00473 } 00474 00475 /** Create a callback class with type inferred from the arguments 00476 * 00477 * @param func Static function to attach 00478 * @param arg Pointer argument to function 00479 * @return Callback with inferred type 00480 */ 00481 template <typename T, typename U, typename R, typename... ArgTs> 00482 Callback<R(ArgTs...)> callback(R(*func)(volatile T *, ArgTs...), volatile U *arg) 00483 { 00484 return Callback<R(ArgTs...)>(func, arg); 00485 } 00486 00487 /** Create a callback class with type inferred from the arguments 00488 * 00489 * @param func Static function to attach 00490 * @param arg Pointer argument to function 00491 * @return Callback with inferred type 00492 */ 00493 template <typename T, typename U, typename R, typename... ArgTs> 00494 Callback<R(ArgTs...)> callback(R(*func)(const volatile T *, ArgTs...), const volatile U *arg) 00495 { 00496 return Callback<R(ArgTs...)>(func, arg); 00497 } 00498 00499 /**@}*/ 00500 00501 /**@}*/ 00502 00503 } // namespace mbed 00504 00505 #endif
Generated on Tue Jul 12 2022 13:54:04 by
