Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Callback.h Source File

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