extend
Fork of BLE_API by
ble/FunctionPointerWithContext.h@848:47c11ba90ff4, 2015-11-02 (annotated)
- Committer:
- rgrover1
- Date:
- Mon Nov 02 09:09:05 2015 +0000
- Revision:
- 848:47c11ba90ff4
- Parent:
- 716:11b41f651697
- Child:
- 849:0f5972e454b2
Synchronized with git rev 57c160c2
Author: Vincent Coubard
Reduce the memory size consummed by a FunctionPointerWithContext to 20
bytes (oryginally, it was 32 bytes !).
Enforce alignement constraints of the embedded pointer to member function.
Symplify and unify call mecanic, everything is delegated uniformally to the actual
implementation.
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 | 710:b2e1a2660ec2 | 21 | |
rgrover1 | 710:b2e1a2660ec2 | 22 | |
rgrover1 | 848:47c11ba90ff4 | 23 | |
rgrover1 | 710:b2e1a2660ec2 | 24 | /** A class for storing and calling a pointer to a static or member void function |
rgrover1 | 710:b2e1a2660ec2 | 25 | * which takes a context. |
rgrover1 | 710:b2e1a2660ec2 | 26 | */ |
rgrover1 | 710:b2e1a2660ec2 | 27 | template <typename ContextType> |
rgrover1 | 710:b2e1a2660ec2 | 28 | class FunctionPointerWithContext { |
rgrover1 | 710:b2e1a2660ec2 | 29 | public: |
rgrover1 | 710:b2e1a2660ec2 | 30 | typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t; |
rgrover1 | 710:b2e1a2660ec2 | 31 | typedef void (*pvoidfcontext_t)(ContextType context); |
rgrover1 | 710:b2e1a2660ec2 | 32 | |
rgrover1 | 710:b2e1a2660ec2 | 33 | /** Create a FunctionPointerWithContext, attaching a static function |
rgrover1 | 710:b2e1a2660ec2 | 34 | * |
rgrover1 | 710:b2e1a2660ec2 | 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 | 848:47c11ba90ff4 | 38 | _function(NULL), _caller(NULL), _next(NULL) { |
rgrover1 | 710:b2e1a2660ec2 | 39 | attach(function); |
rgrover1 | 710:b2e1a2660ec2 | 40 | } |
rgrover1 | 710:b2e1a2660ec2 | 41 | |
rgrover1 | 710:b2e1a2660ec2 | 42 | /** Create a FunctionPointerWithContext, attaching a member function |
rgrover1 | 710:b2e1a2660ec2 | 43 | * |
rgrover1 | 710:b2e1a2660ec2 | 44 | * @param object The object pointer to invoke the member function on (i.e. the this pointer) |
rgrover1 | 710:b2e1a2660ec2 | 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 | 848:47c11ba90ff4 | 49 | _memberFunctionAndPointer(), _caller(NULL), _next(NULL) { |
rgrover1 | 710:b2e1a2660ec2 | 50 | attach(object, member); |
rgrover1 | 710:b2e1a2660ec2 | 51 | } |
rgrover1 | 710:b2e1a2660ec2 | 52 | |
rgrover1 | 710:b2e1a2660ec2 | 53 | /** Attach a static function |
rgrover1 | 710:b2e1a2660ec2 | 54 | * |
rgrover1 | 710:b2e1a2660ec2 | 55 | * @param function The void static function to attach (default is none) |
rgrover1 | 710:b2e1a2660ec2 | 56 | */ |
rgrover1 | 710:b2e1a2660ec2 | 57 | void attach(void (*function)(ContextType context) = NULL) { |
rgrover1 | 710:b2e1a2660ec2 | 58 | _function = function; |
rgrover1 | 848:47c11ba90ff4 | 59 | _caller = functioncaller; |
rgrover1 | 710:b2e1a2660ec2 | 60 | } |
rgrover1 | 710:b2e1a2660ec2 | 61 | |
rgrover1 | 710:b2e1a2660ec2 | 62 | /** Attach a member function |
rgrover1 | 710:b2e1a2660ec2 | 63 | * |
rgrover1 | 710:b2e1a2660ec2 | 64 | * @param object The object pointer to invoke the member function on (i.e. the this pointer) |
rgrover1 | 710:b2e1a2660ec2 | 65 | * @param function The address of the void member function to attach |
rgrover1 | 710:b2e1a2660ec2 | 66 | */ |
rgrover1 | 710:b2e1a2660ec2 | 67 | template<typename T> |
rgrover1 | 710:b2e1a2660ec2 | 68 | void attach(T *object, void (T::*member)(ContextType context)) { |
rgrover1 | 848:47c11ba90ff4 | 69 | _memberFunctionAndPointer._object = static_cast<void *>(object); |
rgrover1 | 848:47c11ba90ff4 | 70 | memcpy(_memberFunctionAndPointer._memberFunction, (char*) &member, sizeof(member)); |
rgrover1 | 848:47c11ba90ff4 | 71 | _caller = &FunctionPointerWithContext::membercaller<T>; |
rgrover1 | 710:b2e1a2660ec2 | 72 | } |
rgrover1 | 710:b2e1a2660ec2 | 73 | |
rgrover1 | 710:b2e1a2660ec2 | 74 | /** Call the attached static or member function; and if there are chained |
rgrover1 | 710:b2e1a2660ec2 | 75 | * FunctionPointers their callbacks are invoked as well. |
rgrover1 | 710:b2e1a2660ec2 | 76 | * @Note: all chained callbacks stack up; so hopefully there won't be too |
rgrover1 | 710:b2e1a2660ec2 | 77 | * many FunctionPointers in a chain. */ |
rgrover1 | 710:b2e1a2660ec2 | 78 | void call(ContextType context) { |
rgrover1 | 848:47c11ba90ff4 | 79 | _caller(this, context); |
rgrover1 | 710:b2e1a2660ec2 | 80 | |
rgrover1 | 710:b2e1a2660ec2 | 81 | /* Propagate the call to next in the chain. */ |
rgrover1 | 710:b2e1a2660ec2 | 82 | if (_next) { |
rgrover1 | 710:b2e1a2660ec2 | 83 | _next->call(context); |
rgrover1 | 710:b2e1a2660ec2 | 84 | } |
rgrover1 | 710:b2e1a2660ec2 | 85 | } |
rgrover1 | 710:b2e1a2660ec2 | 86 | |
rgrover1 | 710:b2e1a2660ec2 | 87 | /** |
rgrover1 | 710:b2e1a2660ec2 | 88 | * Setup an external FunctionPointer as a next in the chain of related |
rgrover1 | 710:b2e1a2660ec2 | 89 | * callbacks. Invoking call() on the head FunctionPointer will invoke all |
rgrover1 | 710:b2e1a2660ec2 | 90 | * chained callbacks. |
rgrover1 | 710:b2e1a2660ec2 | 91 | * |
rgrover1 | 710:b2e1a2660ec2 | 92 | * Refer to 'CallChain' as an alternative. |
rgrover1 | 710:b2e1a2660ec2 | 93 | */ |
rgrover1 | 710:b2e1a2660ec2 | 94 | void chainAsNext(pFunctionPointerWithContext_t next) { |
rgrover1 | 710:b2e1a2660ec2 | 95 | _next = next; |
rgrover1 | 710:b2e1a2660ec2 | 96 | } |
rgrover1 | 710:b2e1a2660ec2 | 97 | |
rgrover1 | 710:b2e1a2660ec2 | 98 | pFunctionPointerWithContext_t getNext(void) const { |
rgrover1 | 710:b2e1a2660ec2 | 99 | return _next; |
rgrover1 | 710:b2e1a2660ec2 | 100 | } |
rgrover1 | 710:b2e1a2660ec2 | 101 | |
rgrover1 | 710:b2e1a2660ec2 | 102 | pvoidfcontext_t get_function() const { |
rgrover1 | 710:b2e1a2660ec2 | 103 | return (pvoidfcontext_t)_function; |
rgrover1 | 710:b2e1a2660ec2 | 104 | } |
rgrover1 | 710:b2e1a2660ec2 | 105 | |
rgrover1 | 710:b2e1a2660ec2 | 106 | private: |
rgrover1 | 710:b2e1a2660ec2 | 107 | template<typename T> |
rgrover1 | 848:47c11ba90ff4 | 108 | static void membercaller(FunctionPointerWithContext* self, ContextType context) { |
rgrover1 | 848:47c11ba90ff4 | 109 | if(self->_memberFunctionAndPointer._object) { |
rgrover1 | 848:47c11ba90ff4 | 110 | T *o = static_cast<T *>(self->_memberFunctionAndPointer._object); |
rgrover1 | 848:47c11ba90ff4 | 111 | void (T::*m)(ContextType); |
rgrover1 | 848:47c11ba90ff4 | 112 | memcpy((char*) &m, self->_memberFunctionAndPointer._memberFunction, sizeof(m)); |
rgrover1 | 848:47c11ba90ff4 | 113 | (o->*m)(context); |
rgrover1 | 848:47c11ba90ff4 | 114 | } |
rgrover1 | 848:47c11ba90ff4 | 115 | } |
rgrover1 | 848:47c11ba90ff4 | 116 | |
rgrover1 | 848:47c11ba90ff4 | 117 | static void functioncaller(FunctionPointerWithContext* self, ContextType context) { |
rgrover1 | 848:47c11ba90ff4 | 118 | if(self->_function) { |
rgrover1 | 848:47c11ba90ff4 | 119 | self->_function(context); |
rgrover1 | 848:47c11ba90ff4 | 120 | } |
rgrover1 | 710:b2e1a2660ec2 | 121 | } |
rgrover1 | 710:b2e1a2660ec2 | 122 | |
rgrover1 | 848:47c11ba90ff4 | 123 | struct MemberFunctionAndPtr { |
rgrover1 | 848:47c11ba90ff4 | 124 | /* |
rgrover1 | 848:47c11ba90ff4 | 125 | * forward declaration of a class and a member function to this class. |
rgrover1 | 848:47c11ba90ff4 | 126 | * Because the compiler doesnt know anything about the member function, it |
rgrover1 | 848:47c11ba90ff4 | 127 | * will always take the biggest size that a member function can take. |
rgrover1 | 848:47c11ba90ff4 | 128 | * This also guarantee that the proper alignement will be chosen |
rgrover1 | 848:47c11ba90ff4 | 129 | */ |
rgrover1 | 848:47c11ba90ff4 | 130 | class UndefinedClass; |
rgrover1 | 848:47c11ba90ff4 | 131 | typedef void (UndefinedClass::*UndefinedMemberFunction)(ContextType); |
rgrover1 | 848:47c11ba90ff4 | 132 | |
rgrover1 | 848:47c11ba90ff4 | 133 | |
rgrover1 | 848:47c11ba90ff4 | 134 | void* _object; |
rgrover1 | 848:47c11ba90ff4 | 135 | union { |
rgrover1 | 848:47c11ba90ff4 | 136 | char _memberFunction[sizeof(UndefinedMemberFunction)]; |
rgrover1 | 848:47c11ba90ff4 | 137 | UndefinedMemberFunction _allignement; |
rgrover1 | 848:47c11ba90ff4 | 138 | }; |
rgrover1 | 848:47c11ba90ff4 | 139 | }; |
rgrover1 | 848:47c11ba90ff4 | 140 | |
rgrover1 | 848:47c11ba90ff4 | 141 | |
rgrover1 | 848:47c11ba90ff4 | 142 | |
rgrover1 | 848:47c11ba90ff4 | 143 | union { |
rgrover1 | 848:47c11ba90ff4 | 144 | void (*_function)(ContextType context); /**< static function pointer - NULL if none attached */ |
rgrover1 | 848:47c11ba90ff4 | 145 | /** |
rgrover1 | 848:47c11ba90ff4 | 146 | * object this pointer and pointer to member - |
rgrover1 | 848:47c11ba90ff4 | 147 | * _memberFunctionAndPointer._object will be NULL if none attached |
rgrover1 | 848:47c11ba90ff4 | 148 | */ |
rgrover1 | 848:47c11ba90ff4 | 149 | MemberFunctionAndPtr _memberFunctionAndPointer; |
rgrover1 | 848:47c11ba90ff4 | 150 | }; |
rgrover1 | 848:47c11ba90ff4 | 151 | |
rgrover1 | 848:47c11ba90ff4 | 152 | void (*_caller)(FunctionPointerWithContext*, ContextType); |
rgrover1 | 848:47c11ba90ff4 | 153 | |
rgrover1 | 710:b2e1a2660ec2 | 154 | pFunctionPointerWithContext_t _next; /**< Optional link to make a chain out of functionPointers; this |
rgrover1 | 710:b2e1a2660ec2 | 155 | * allows chaining function pointers without requiring |
rgrover1 | 710:b2e1a2660ec2 | 156 | * external memory to manage the chain. Also refer to |
rgrover1 | 710:b2e1a2660ec2 | 157 | * 'CallChain' as an alternative. */ |
rgrover1 | 710:b2e1a2660ec2 | 158 | }; |
rgrover1 | 710:b2e1a2660ec2 | 159 | |
rgrover1 | 710:b2e1a2660ec2 | 160 | #endif // ifndef MBED_FUNCTIONPOINTER_WITH_CONTEXT_H |