just a fork
Fork of BLE_API by
ble/FunctionPointerWithContext.h@993:4d62b7967c11, 2015-12-02 (annotated)
- Committer:
- rgrover1
- Date:
- Wed Dec 02 10:29:44 2015 +0000
- Revision:
- 993:4d62b7967c11
- Parent:
- 992:ca834f7ae8ed
- Child:
- 1042:21a86ac7f5b1
Synchronized with git rev 12e27cd4
Author: Rohit Grover
Release 2.1.3
=============
* Improvements to CallChainOfFunctionPointerswithContext:
- add a `detach` function to be able to remove callbacks.
- detach function now return true if a function has been detached and
false otherwise.
- add a function call operator.
- use safe-bool idiom. see : http://www.artima.com/cppsource/safebool.html
* Add SafeBool class which allow to easily declare a safe bool operator in
c++03.
* Improvements to FunctionPointerWithContext:
- fix call propagation
- use safe bool idiom
* Add config file for generating Doxygen.
* Setup for onRadioNotification callback does not call initRadioNotification
anymore.
* GapAdvertisementData now handles replacement and appending of data fields
based on type. Some fields can be replaced with new values, and others
require the payload to be appended.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
rgrover1 | 710:b2e1a2660ec2 | 1 | /* mbed Microcontroller Library |
rgrover1 | 710:b2e1a2660ec2 | 2 | * Copyright (c) 2006-2013 ARM Limited |
rgrover1 | 710:b2e1a2660ec2 | 3 | * |
rgrover1 | 710:b2e1a2660ec2 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
rgrover1 | 710:b2e1a2660ec2 | 5 | * you may not use this file except in compliance with the License. |
rgrover1 | 710:b2e1a2660ec2 | 6 | * You may obtain a copy of the License at |
rgrover1 | 710:b2e1a2660ec2 | 7 | * |
rgrover1 | 710:b2e1a2660ec2 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
rgrover1 | 710:b2e1a2660ec2 | 9 | * |
rgrover1 | 710:b2e1a2660ec2 | 10 | * Unless required by applicable law or agreed to in writing, software |
rgrover1 | 710:b2e1a2660ec2 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
rgrover1 | 710:b2e1a2660ec2 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
rgrover1 | 710:b2e1a2660ec2 | 13 | * See the License for the specific language governing permissions and |
rgrover1 | 710:b2e1a2660ec2 | 14 | * limitations under the License. |
rgrover1 | 710:b2e1a2660ec2 | 15 | */ |
rgrover1 | 710:b2e1a2660ec2 | 16 | |
rgrover1 | 710:b2e1a2660ec2 | 17 | #ifndef MBED_FUNCTIONPOINTER_WITH_CONTEXT_H |
rgrover1 | 710:b2e1a2660ec2 | 18 | #define MBED_FUNCTIONPOINTER_WITH_CONTEXT_H |
rgrover1 | 710:b2e1a2660ec2 | 19 | |
rgrover1 | 710:b2e1a2660ec2 | 20 | #include <string.h> |
rgrover1 | 993:4d62b7967c11 | 21 | #include "SafeBool.h" |
rgrover1 | 710:b2e1a2660ec2 | 22 | |
rgrover1 | 710:b2e1a2660ec2 | 23 | /** A class for storing and calling a pointer to a static or member void function |
rgrover1 | 993:4d62b7967c11 | 24 | * that takes a context. |
rgrover1 | 710:b2e1a2660ec2 | 25 | */ |
rgrover1 | 710:b2e1a2660ec2 | 26 | template <typename ContextType> |
rgrover1 | 993:4d62b7967c11 | 27 | class FunctionPointerWithContext : public SafeBool<FunctionPointerWithContext<ContextType> > { |
rgrover1 | 710:b2e1a2660ec2 | 28 | public: |
rgrover1 | 710:b2e1a2660ec2 | 29 | typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t; |
rgrover1 | 993:4d62b7967c11 | 30 | typedef const FunctionPointerWithContext<ContextType> *cpFunctionPointerWithContext_t; |
rgrover1 | 710:b2e1a2660ec2 | 31 | typedef void (*pvoidfcontext_t)(ContextType context); |
rgrover1 | 710:b2e1a2660ec2 | 32 | |
rgrover1 | 993:4d62b7967c11 | 33 | /** Create a FunctionPointerWithContext, attaching a static function. |
rgrover1 | 710:b2e1a2660ec2 | 34 | * |
rgrover1 | 993:4d62b7967c11 | 35 | * @param function The void static function to attach (default is none). |
rgrover1 | 710:b2e1a2660ec2 | 36 | */ |
rgrover1 | 710:b2e1a2660ec2 | 37 | FunctionPointerWithContext(void (*function)(ContextType context) = NULL) : |
rgrover1 | 993:4d62b7967c11 | 38 | _memberFunctionAndPointer(), _caller(NULL), _next(NULL) { |
rgrover1 | 710:b2e1a2660ec2 | 39 | attach(function); |
rgrover1 | 710:b2e1a2660ec2 | 40 | } |
rgrover1 | 710:b2e1a2660ec2 | 41 | |
rgrover1 | 993:4d62b7967c11 | 42 | /** Create a FunctionPointerWithContext, attaching a member function. |
rgrover1 | 710:b2e1a2660ec2 | 43 | * |
rgrover1 | 993:4d62b7967c11 | 44 | * @param object The object pointer to invoke the member function on (the "this" pointer). |
rgrover1 | 993:4d62b7967c11 | 45 | * @param function The address of the void member function to attach. |
rgrover1 | 710:b2e1a2660ec2 | 46 | */ |
rgrover1 | 710:b2e1a2660ec2 | 47 | template<typename T> |
rgrover1 | 710:b2e1a2660ec2 | 48 | FunctionPointerWithContext(T *object, void (T::*member)(ContextType context)) : |
rgrover1 | 897:838e1375dbaa | 49 | _memberFunctionAndPointer(), _caller(NULL), _next(NULL) { |
rgrover1 | 710:b2e1a2660ec2 | 50 | attach(object, member); |
rgrover1 | 710:b2e1a2660ec2 | 51 | } |
rgrover1 | 710:b2e1a2660ec2 | 52 | |
rgrover1 | 993:4d62b7967c11 | 53 | FunctionPointerWithContext(const FunctionPointerWithContext& that) : |
rgrover1 | 993:4d62b7967c11 | 54 | _memberFunctionAndPointer(that._memberFunctionAndPointer), _caller(that._caller), _next(NULL) { |
rgrover1 | 993:4d62b7967c11 | 55 | } |
rgrover1 | 993:4d62b7967c11 | 56 | |
rgrover1 | 993:4d62b7967c11 | 57 | FunctionPointerWithContext& operator=(const FunctionPointerWithContext& that) { |
rgrover1 | 993:4d62b7967c11 | 58 | _memberFunctionAndPointer = that._memberFunctionAndPointer; |
rgrover1 | 993:4d62b7967c11 | 59 | _caller = that._caller; |
rgrover1 | 993:4d62b7967c11 | 60 | _next = NULL; |
rgrover1 | 993:4d62b7967c11 | 61 | return *this; |
rgrover1 | 993:4d62b7967c11 | 62 | } |
rgrover1 | 993:4d62b7967c11 | 63 | |
rgrover1 | 993:4d62b7967c11 | 64 | /** Attach a static function. |
rgrover1 | 710:b2e1a2660ec2 | 65 | * |
rgrover1 | 993:4d62b7967c11 | 66 | * @param function The void static function to attach (default is none). |
rgrover1 | 710:b2e1a2660ec2 | 67 | */ |
rgrover1 | 710:b2e1a2660ec2 | 68 | void attach(void (*function)(ContextType context) = NULL) { |
rgrover1 | 710:b2e1a2660ec2 | 69 | _function = function; |
rgrover1 | 897:838e1375dbaa | 70 | _caller = functioncaller; |
rgrover1 | 710:b2e1a2660ec2 | 71 | } |
rgrover1 | 710:b2e1a2660ec2 | 72 | |
rgrover1 | 993:4d62b7967c11 | 73 | /** Attach a member function. |
rgrover1 | 710:b2e1a2660ec2 | 74 | * |
rgrover1 | 993:4d62b7967c11 | 75 | * @param object The object pointer to invoke the member function on (the "this" pointer). |
rgrover1 | 993:4d62b7967c11 | 76 | * @param function The address of the void member function to attach. |
rgrover1 | 710:b2e1a2660ec2 | 77 | */ |
rgrover1 | 710:b2e1a2660ec2 | 78 | template<typename T> |
rgrover1 | 710:b2e1a2660ec2 | 79 | void attach(T *object, void (T::*member)(ContextType context)) { |
rgrover1 | 897:838e1375dbaa | 80 | _memberFunctionAndPointer._object = static_cast<void *>(object); |
rgrover1 | 897:838e1375dbaa | 81 | memcpy(_memberFunctionAndPointer._memberFunction, (char*) &member, sizeof(member)); |
rgrover1 | 897:838e1375dbaa | 82 | _caller = &FunctionPointerWithContext::membercaller<T>; |
rgrover1 | 710:b2e1a2660ec2 | 83 | } |
rgrover1 | 710:b2e1a2660ec2 | 84 | |
rgrover1 | 993:4d62b7967c11 | 85 | /** Call the attached static or member function; if there are chained |
rgrover1 | 710:b2e1a2660ec2 | 86 | * FunctionPointers their callbacks are invoked as well. |
rgrover1 | 993:4d62b7967c11 | 87 | * @Note: All chained callbacks stack up, so hopefully there won't be too |
rgrover1 | 710:b2e1a2660ec2 | 88 | * many FunctionPointers in a chain. */ |
rgrover1 | 993:4d62b7967c11 | 89 | void call(ContextType context) const { |
rgrover1 | 952:8a6c287de1be | 90 | _caller(this, context); |
rgrover1 | 990:53ac0ac3aa39 | 91 | } |
rgrover1 | 990:53ac0ac3aa39 | 92 | |
rgrover1 | 990:53ac0ac3aa39 | 93 | /** |
rgrover1 | 993:4d62b7967c11 | 94 | * @brief Same as above |
rgrover1 | 993:4d62b7967c11 | 95 | */ |
rgrover1 | 993:4d62b7967c11 | 96 | void operator()(ContextType context) const { |
rgrover1 | 993:4d62b7967c11 | 97 | call(context); |
rgrover1 | 993:4d62b7967c11 | 98 | } |
rgrover1 | 993:4d62b7967c11 | 99 | |
rgrover1 | 993:4d62b7967c11 | 100 | /** Same as above, workaround for mbed os FunctionPointer implementation. */ |
rgrover1 | 993:4d62b7967c11 | 101 | void call(ContextType context) { |
rgrover1 | 993:4d62b7967c11 | 102 | ((const FunctionPointerWithContext*) this)->call(context); |
rgrover1 | 993:4d62b7967c11 | 103 | } |
rgrover1 | 993:4d62b7967c11 | 104 | |
rgrover1 | 993:4d62b7967c11 | 105 | typedef void (FunctionPointerWithContext::*bool_type)() const; |
rgrover1 | 993:4d62b7967c11 | 106 | |
rgrover1 | 993:4d62b7967c11 | 107 | /** |
rgrover1 | 993:4d62b7967c11 | 108 | * implementation of safe bool operator |
rgrover1 | 993:4d62b7967c11 | 109 | */ |
rgrover1 | 993:4d62b7967c11 | 110 | bool toBool() const { |
rgrover1 | 993:4d62b7967c11 | 111 | return (_function || _memberFunctionAndPointer._object); |
rgrover1 | 993:4d62b7967c11 | 112 | } |
rgrover1 | 993:4d62b7967c11 | 113 | |
rgrover1 | 993:4d62b7967c11 | 114 | /** |
rgrover1 | 993:4d62b7967c11 | 115 | * Set up an external FunctionPointer as a next in the chain of related |
rgrover1 | 710:b2e1a2660ec2 | 116 | * callbacks. Invoking call() on the head FunctionPointer will invoke all |
rgrover1 | 710:b2e1a2660ec2 | 117 | * chained callbacks. |
rgrover1 | 710:b2e1a2660ec2 | 118 | * |
rgrover1 | 710:b2e1a2660ec2 | 119 | * Refer to 'CallChain' as an alternative. |
rgrover1 | 710:b2e1a2660ec2 | 120 | */ |
rgrover1 | 710:b2e1a2660ec2 | 121 | void chainAsNext(pFunctionPointerWithContext_t next) { |
rgrover1 | 710:b2e1a2660ec2 | 122 | _next = next; |
rgrover1 | 710:b2e1a2660ec2 | 123 | } |
rgrover1 | 710:b2e1a2660ec2 | 124 | |
rgrover1 | 710:b2e1a2660ec2 | 125 | pFunctionPointerWithContext_t getNext(void) const { |
rgrover1 | 710:b2e1a2660ec2 | 126 | return _next; |
rgrover1 | 710:b2e1a2660ec2 | 127 | } |
rgrover1 | 710:b2e1a2660ec2 | 128 | |
rgrover1 | 710:b2e1a2660ec2 | 129 | pvoidfcontext_t get_function() const { |
rgrover1 | 710:b2e1a2660ec2 | 130 | return (pvoidfcontext_t)_function; |
rgrover1 | 710:b2e1a2660ec2 | 131 | } |
rgrover1 | 710:b2e1a2660ec2 | 132 | |
rgrover1 | 993:4d62b7967c11 | 133 | friend bool operator==(const FunctionPointerWithContext& lhs, const FunctionPointerWithContext& rhs) { |
rgrover1 | 993:4d62b7967c11 | 134 | return rhs._caller == lhs._caller && |
rgrover1 | 993:4d62b7967c11 | 135 | memcmp( |
rgrover1 | 993:4d62b7967c11 | 136 | &rhs._memberFunctionAndPointer, |
rgrover1 | 993:4d62b7967c11 | 137 | &lhs._memberFunctionAndPointer, |
rgrover1 | 993:4d62b7967c11 | 138 | sizeof(rhs._memberFunctionAndPointer) |
rgrover1 | 993:4d62b7967c11 | 139 | ) == 0; |
rgrover1 | 993:4d62b7967c11 | 140 | } |
rgrover1 | 993:4d62b7967c11 | 141 | |
rgrover1 | 710:b2e1a2660ec2 | 142 | private: |
rgrover1 | 710:b2e1a2660ec2 | 143 | template<typename T> |
rgrover1 | 993:4d62b7967c11 | 144 | static void membercaller(cpFunctionPointerWithContext_t self, ContextType context) { |
rgrover1 | 897:838e1375dbaa | 145 | if (self->_memberFunctionAndPointer._object) { |
rgrover1 | 897:838e1375dbaa | 146 | T *o = static_cast<T *>(self->_memberFunctionAndPointer._object); |
rgrover1 | 897:838e1375dbaa | 147 | void (T::*m)(ContextType); |
rgrover1 | 897:838e1375dbaa | 148 | memcpy((char*) &m, self->_memberFunctionAndPointer._memberFunction, sizeof(m)); |
rgrover1 | 897:838e1375dbaa | 149 | (o->*m)(context); |
rgrover1 | 897:838e1375dbaa | 150 | } |
rgrover1 | 897:838e1375dbaa | 151 | } |
rgrover1 | 897:838e1375dbaa | 152 | |
rgrover1 | 993:4d62b7967c11 | 153 | static void functioncaller(cpFunctionPointerWithContext_t self, ContextType context) { |
rgrover1 | 897:838e1375dbaa | 154 | if (self->_function) { |
rgrover1 | 897:838e1375dbaa | 155 | self->_function(context); |
rgrover1 | 897:838e1375dbaa | 156 | } |
rgrover1 | 710:b2e1a2660ec2 | 157 | } |
rgrover1 | 710:b2e1a2660ec2 | 158 | |
rgrover1 | 897:838e1375dbaa | 159 | struct MemberFunctionAndPtr { |
rgrover1 | 897:838e1375dbaa | 160 | /* |
rgrover1 | 993:4d62b7967c11 | 161 | * Forward declaration of a class and a member function to this class. |
rgrover1 | 897:838e1375dbaa | 162 | * Because the compiler doesn't know anything about the forwarded member |
rgrover1 | 897:838e1375dbaa | 163 | * function, it will always use the biggest size and the biggest alignment |
rgrover1 | 897:838e1375dbaa | 164 | * that a member function can take for objects of type UndefinedMemberFunction. |
rgrover1 | 897:838e1375dbaa | 165 | */ |
rgrover1 | 897:838e1375dbaa | 166 | class UndefinedClass; |
rgrover1 | 897:838e1375dbaa | 167 | typedef void (UndefinedClass::*UndefinedMemberFunction)(ContextType); |
rgrover1 | 897:838e1375dbaa | 168 | |
rgrover1 | 897:838e1375dbaa | 169 | void* _object; |
rgrover1 | 897:838e1375dbaa | 170 | union { |
rgrover1 | 897:838e1375dbaa | 171 | char _memberFunction[sizeof(UndefinedMemberFunction)]; |
rgrover1 | 897:838e1375dbaa | 172 | UndefinedMemberFunction _alignment; |
rgrover1 | 897:838e1375dbaa | 173 | }; |
rgrover1 | 897:838e1375dbaa | 174 | }; |
rgrover1 | 897:838e1375dbaa | 175 | |
rgrover1 | 897:838e1375dbaa | 176 | union { |
rgrover1 | 993:4d62b7967c11 | 177 | pvoidfcontext_t _function; /**< Static function pointer - NULL if none attached */ |
rgrover1 | 897:838e1375dbaa | 178 | /** |
rgrover1 | 897:838e1375dbaa | 179 | * object this pointer and pointer to member - |
rgrover1 | 897:838e1375dbaa | 180 | * _memberFunctionAndPointer._object will be NULL if none attached |
rgrover1 | 897:838e1375dbaa | 181 | */ |
rgrover1 | 993:4d62b7967c11 | 182 | mutable MemberFunctionAndPtr _memberFunctionAndPointer; |
rgrover1 | 897:838e1375dbaa | 183 | }; |
rgrover1 | 897:838e1375dbaa | 184 | |
rgrover1 | 993:4d62b7967c11 | 185 | void (*_caller)(const FunctionPointerWithContext*, ContextType); |
rgrover1 | 897:838e1375dbaa | 186 | |
rgrover1 | 993:4d62b7967c11 | 187 | pFunctionPointerWithContext_t _next; /**< Optional link to make a chain out of functionPointers. This |
rgrover1 | 710:b2e1a2660ec2 | 188 | * allows chaining function pointers without requiring |
rgrover1 | 993:4d62b7967c11 | 189 | * external memory to manage the chain. Refer to |
rgrover1 | 710:b2e1a2660ec2 | 190 | * 'CallChain' as an alternative. */ |
rgrover1 | 710:b2e1a2660ec2 | 191 | }; |
rgrover1 | 710:b2e1a2660ec2 | 192 | |
rgrover1 | 993:4d62b7967c11 | 193 | /** |
rgrover1 | 993:4d62b7967c11 | 194 | * @brief Create a new FunctionPointerWithContext which bind an instance and a |
rgrover1 | 993:4d62b7967c11 | 195 | * a member function together. |
rgrover1 | 993:4d62b7967c11 | 196 | * @details This little helper is a just here to eliminate the need to write the |
rgrover1 | 993:4d62b7967c11 | 197 | * FunctionPointerWithContext type each time you want to create one by kicking |
rgrover1 | 993:4d62b7967c11 | 198 | * automatic type deduction of function templates. With this function, it is easy |
rgrover1 | 993:4d62b7967c11 | 199 | * to write only one entry point for functions which expect a FunctionPointer |
rgrover1 | 993:4d62b7967c11 | 200 | * in parameters. |
rgrover1 | 993:4d62b7967c11 | 201 | * |
rgrover1 | 993:4d62b7967c11 | 202 | * @param object to bound with member function |
rgrover1 | 993:4d62b7967c11 | 203 | * @param member The member function called |
rgrover1 | 993:4d62b7967c11 | 204 | * @return a new FunctionPointerWithContext |
rgrover1 | 993:4d62b7967c11 | 205 | */ |
rgrover1 | 993:4d62b7967c11 | 206 | template<typename T, typename ContextType> |
rgrover1 | 993:4d62b7967c11 | 207 | FunctionPointerWithContext<ContextType> makeFunctionPointer(T *object, void (T::*member)(ContextType context)) |
rgrover1 | 993:4d62b7967c11 | 208 | { |
rgrover1 | 993:4d62b7967c11 | 209 | return FunctionPointerWithContext<ContextType>(object, member); |
rgrover1 | 993:4d62b7967c11 | 210 | } |
rgrover1 | 993:4d62b7967c11 | 211 | |
rgrover1 | 710:b2e1a2660ec2 | 212 | #endif // ifndef MBED_FUNCTIONPOINTER_WITH_CONTEXT_H |