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.
Fork of BLE_API by
ble/CallChainOfFunctionPointersWithContext.h@953:f6eb43f524b2, 2015-11-26 (annotated)
- Committer:
- rgrover1
- Date:
- Thu Nov 26 12:52:33 2015 +0000
- Revision:
- 953:f6eb43f524b2
- Parent:
- 952:8a6c287de1be
- Child:
- 961:259acb1c9d04
Synchronized with git rev dfc03ce0
Author: Vincent Coubard
Convert Gap::timeout callback to a callback chain. Add 'boolean'
conversion and function operator syntax to
CallChainOfFunctionPointerWithContext
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 | #ifndef MBED_CALLCHAIN_OF_FUNCTION_POINTERS_WITH_CONTEXT_H |
rgrover1 | 710:b2e1a2660ec2 | 17 | #define MBED_CALLCHAIN_OF_FUNCTION_POINTERS_WITH_CONTEXT_H |
rgrover1 | 710:b2e1a2660ec2 | 18 | |
rgrover1 | 710:b2e1a2660ec2 | 19 | #include <string.h> |
rgrover1 | 710:b2e1a2660ec2 | 20 | #include "FunctionPointerWithContext.h" |
rgrover1 | 710:b2e1a2660ec2 | 21 | |
rgrover1 | 710:b2e1a2660ec2 | 22 | |
rgrover1 | 710:b2e1a2660ec2 | 23 | /** Group one or more functions in an instance of a CallChainOfFunctionPointersWithContext, then call them in |
rgrover1 | 710:b2e1a2660ec2 | 24 | * sequence using CallChainOfFunctionPointersWithContext::call(). Used mostly by the interrupt chaining code, |
rgrover1 | 710:b2e1a2660ec2 | 25 | * but can be used for other purposes. |
rgrover1 | 710:b2e1a2660ec2 | 26 | * |
rgrover1 | 710:b2e1a2660ec2 | 27 | * Example: |
rgrover1 | 710:b2e1a2660ec2 | 28 | * @code |
rgrover1 | 710:b2e1a2660ec2 | 29 | * |
rgrover1 | 710:b2e1a2660ec2 | 30 | * CallChainOfFunctionPointersWithContext<void *> chain; |
rgrover1 | 710:b2e1a2660ec2 | 31 | * |
rgrover1 | 710:b2e1a2660ec2 | 32 | * void first(void *context) { |
rgrover1 | 710:b2e1a2660ec2 | 33 | * printf("'first' function.\n"); |
rgrover1 | 710:b2e1a2660ec2 | 34 | * } |
rgrover1 | 710:b2e1a2660ec2 | 35 | * |
rgrover1 | 710:b2e1a2660ec2 | 36 | * void second(void *context) { |
rgrover1 | 710:b2e1a2660ec2 | 37 | * printf("'second' function.\n"); |
rgrover1 | 710:b2e1a2660ec2 | 38 | * } |
rgrover1 | 710:b2e1a2660ec2 | 39 | * |
rgrover1 | 710:b2e1a2660ec2 | 40 | * class Test { |
rgrover1 | 710:b2e1a2660ec2 | 41 | * public: |
rgrover1 | 710:b2e1a2660ec2 | 42 | * void f(void *context) { |
rgrover1 | 710:b2e1a2660ec2 | 43 | * printf("A::f (class member).\n"); |
rgrover1 | 710:b2e1a2660ec2 | 44 | * } |
rgrover1 | 710:b2e1a2660ec2 | 45 | * }; |
rgrover1 | 710:b2e1a2660ec2 | 46 | * |
rgrover1 | 710:b2e1a2660ec2 | 47 | * int main() { |
rgrover1 | 710:b2e1a2660ec2 | 48 | * Test test; |
rgrover1 | 710:b2e1a2660ec2 | 49 | * |
rgrover1 | 710:b2e1a2660ec2 | 50 | * chain.add(second); |
rgrover1 | 710:b2e1a2660ec2 | 51 | * chain.add_front(first); |
rgrover1 | 710:b2e1a2660ec2 | 52 | * chain.add(&test, &Test::f); |
rgrover1 | 710:b2e1a2660ec2 | 53 | * chain.call(); |
rgrover1 | 710:b2e1a2660ec2 | 54 | * } |
rgrover1 | 710:b2e1a2660ec2 | 55 | * @endcode |
rgrover1 | 710:b2e1a2660ec2 | 56 | */ |
rgrover1 | 710:b2e1a2660ec2 | 57 | |
rgrover1 | 710:b2e1a2660ec2 | 58 | template <typename ContextType> |
rgrover1 | 949:1902cbd0dd83 | 59 | class CallChainOfFunctionPointersWithContext { |
rgrover1 | 710:b2e1a2660ec2 | 60 | public: |
rgrover1 | 710:b2e1a2660ec2 | 61 | typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t; |
rgrover1 | 710:b2e1a2660ec2 | 62 | |
rgrover1 | 710:b2e1a2660ec2 | 63 | public: |
rgrover1 | 937:4932e700daf2 | 64 | /** Create an empty chain. |
rgrover1 | 710:b2e1a2660ec2 | 65 | * |
rgrover1 | 937:4932e700daf2 | 66 | * @param size (optional) Initial size of the chain. |
rgrover1 | 710:b2e1a2660ec2 | 67 | */ |
rgrover1 | 710:b2e1a2660ec2 | 68 | CallChainOfFunctionPointersWithContext() : chainHead(NULL) { |
rgrover1 | 710:b2e1a2660ec2 | 69 | /* empty */ |
rgrover1 | 710:b2e1a2660ec2 | 70 | } |
rgrover1 | 710:b2e1a2660ec2 | 71 | |
rgrover1 | 710:b2e1a2660ec2 | 72 | virtual ~CallChainOfFunctionPointersWithContext() { |
rgrover1 | 710:b2e1a2660ec2 | 73 | clear(); |
rgrover1 | 710:b2e1a2660ec2 | 74 | } |
rgrover1 | 710:b2e1a2660ec2 | 75 | |
rgrover1 | 937:4932e700daf2 | 76 | /** Add a function at the front of the chain. |
rgrover1 | 710:b2e1a2660ec2 | 77 | * |
rgrover1 | 937:4932e700daf2 | 78 | * @param function A pointer to a void function. |
rgrover1 | 710:b2e1a2660ec2 | 79 | * |
rgrover1 | 710:b2e1a2660ec2 | 80 | * @returns |
rgrover1 | 937:4932e700daf2 | 81 | * The function object created for 'function'. |
rgrover1 | 710:b2e1a2660ec2 | 82 | */ |
rgrover1 | 710:b2e1a2660ec2 | 83 | pFunctionPointerWithContext_t add(void (*function)(ContextType context)) { |
rgrover1 | 710:b2e1a2660ec2 | 84 | return common_add(new FunctionPointerWithContext<ContextType>(function)); |
rgrover1 | 710:b2e1a2660ec2 | 85 | } |
rgrover1 | 710:b2e1a2660ec2 | 86 | |
rgrover1 | 937:4932e700daf2 | 87 | /** Add a function at the front of the chain. |
rgrover1 | 710:b2e1a2660ec2 | 88 | * |
rgrover1 | 937:4932e700daf2 | 89 | * @param tptr Pointer to the object to call the member function on. |
rgrover1 | 937:4932e700daf2 | 90 | * @param mptr Pointer to the member function to be called. |
rgrover1 | 710:b2e1a2660ec2 | 91 | * |
rgrover1 | 710:b2e1a2660ec2 | 92 | * @returns |
rgrover1 | 937:4932e700daf2 | 93 | * The function object created for 'tptr' and 'mptr'. |
rgrover1 | 710:b2e1a2660ec2 | 94 | */ |
rgrover1 | 710:b2e1a2660ec2 | 95 | template<typename T> |
rgrover1 | 710:b2e1a2660ec2 | 96 | pFunctionPointerWithContext_t add(T *tptr, void (T::*mptr)(ContextType context)) { |
rgrover1 | 710:b2e1a2660ec2 | 97 | return common_add(new FunctionPointerWithContext<ContextType>(tptr, mptr)); |
rgrover1 | 710:b2e1a2660ec2 | 98 | } |
rgrover1 | 710:b2e1a2660ec2 | 99 | |
rgrover1 | 953:f6eb43f524b2 | 100 | /** Add a function at the front of the chain. |
rgrover1 | 953:f6eb43f524b2 | 101 | * |
rgrover1 | 953:f6eb43f524b2 | 102 | * @param func The FunctionPointerWithContext to add. |
rgrover1 | 953:f6eb43f524b2 | 103 | */ |
rgrover1 | 953:f6eb43f524b2 | 104 | void add(const FunctionPointerWithContext<ContextType>& func) { |
rgrover1 | 953:f6eb43f524b2 | 105 | common_add(new FunctionPointerWithContext<ContextType>(func)); |
rgrover1 | 953:f6eb43f524b2 | 106 | } |
rgrover1 | 953:f6eb43f524b2 | 107 | |
rgrover1 | 952:8a6c287de1be | 108 | /** |
rgrover1 | 952:8a6c287de1be | 109 | * Detach a function pointer from a callchain |
rgrover1 | 952:8a6c287de1be | 110 | * |
rgrover1 | 952:8a6c287de1be | 111 | * @oaram toDetach FunctionPointerWithContext to detach from this callchain |
rgrover1 | 952:8a6c287de1be | 112 | * |
rgrover1 | 952:8a6c287de1be | 113 | * @return true if a function pointer has been detached and false otherwise |
rgrover1 | 952:8a6c287de1be | 114 | */ |
rgrover1 | 952:8a6c287de1be | 115 | void detach(const FunctionPointerWithContext<ContextType>& toDetach) { |
rgrover1 | 952:8a6c287de1be | 116 | pFunctionPointerWithContext_t current = chainHead; |
rgrover1 | 952:8a6c287de1be | 117 | pFunctionPointerWithContext_t previous = NULL; |
rgrover1 | 952:8a6c287de1be | 118 | |
rgrover1 | 952:8a6c287de1be | 119 | while (current) { |
rgrover1 | 952:8a6c287de1be | 120 | if(*current == toDetach) { |
rgrover1 | 952:8a6c287de1be | 121 | if(previous == NULL) { |
rgrover1 | 952:8a6c287de1be | 122 | chainHead = current->getNext(); |
rgrover1 | 952:8a6c287de1be | 123 | } else { |
rgrover1 | 952:8a6c287de1be | 124 | previous->chainAsNext(current->getNext()); |
rgrover1 | 952:8a6c287de1be | 125 | } |
rgrover1 | 952:8a6c287de1be | 126 | delete current; |
rgrover1 | 952:8a6c287de1be | 127 | return true; |
rgrover1 | 952:8a6c287de1be | 128 | } |
rgrover1 | 952:8a6c287de1be | 129 | |
rgrover1 | 952:8a6c287de1be | 130 | previous = current; |
rgrover1 | 952:8a6c287de1be | 131 | current = current->getNext(); |
rgrover1 | 952:8a6c287de1be | 132 | } |
rgrover1 | 952:8a6c287de1be | 133 | return false; |
rgrover1 | 952:8a6c287de1be | 134 | } |
rgrover1 | 952:8a6c287de1be | 135 | |
rgrover1 | 710:b2e1a2660ec2 | 136 | /** Clear the call chain (remove all functions in the chain). |
rgrover1 | 710:b2e1a2660ec2 | 137 | */ |
rgrover1 | 710:b2e1a2660ec2 | 138 | void clear(void) { |
rgrover1 | 710:b2e1a2660ec2 | 139 | pFunctionPointerWithContext_t fptr = chainHead; |
rgrover1 | 710:b2e1a2660ec2 | 140 | while (fptr) { |
rgrover1 | 710:b2e1a2660ec2 | 141 | pFunctionPointerWithContext_t deadPtr = fptr; |
rgrover1 | 710:b2e1a2660ec2 | 142 | fptr = deadPtr->getNext(); |
rgrover1 | 710:b2e1a2660ec2 | 143 | delete deadPtr; |
rgrover1 | 710:b2e1a2660ec2 | 144 | } |
rgrover1 | 710:b2e1a2660ec2 | 145 | |
rgrover1 | 710:b2e1a2660ec2 | 146 | chainHead = NULL; |
rgrover1 | 710:b2e1a2660ec2 | 147 | } |
rgrover1 | 710:b2e1a2660ec2 | 148 | |
rgrover1 | 710:b2e1a2660ec2 | 149 | bool hasCallbacksAttached(void) const { |
rgrover1 | 710:b2e1a2660ec2 | 150 | return (chainHead != NULL); |
rgrover1 | 710:b2e1a2660ec2 | 151 | } |
rgrover1 | 710:b2e1a2660ec2 | 152 | |
rgrover1 | 710:b2e1a2660ec2 | 153 | /** Call all the functions in the chain in sequence |
rgrover1 | 949:1902cbd0dd83 | 154 | * @Note: The stack frames of all the callbacks within the chained |
rgrover1 | 949:1902cbd0dd83 | 155 | * FunctionPointers will stack up. Hopefully there won't be too many |
rgrover1 | 949:1902cbd0dd83 | 156 | * chained FunctionPointers. |
rgrover1 | 710:b2e1a2660ec2 | 157 | */ |
rgrover1 | 710:b2e1a2660ec2 | 158 | void call(ContextType context) { |
rgrover1 | 949:1902cbd0dd83 | 159 | if (chainHead) { |
rgrover1 | 949:1902cbd0dd83 | 160 | chainHead->call(context); |
rgrover1 | 921:ea542e6519bb | 161 | } |
rgrover1 | 921:ea542e6519bb | 162 | } |
rgrover1 | 921:ea542e6519bb | 163 | |
rgrover1 | 953:f6eb43f524b2 | 164 | /** |
rgrover1 | 953:f6eb43f524b2 | 165 | * @brief same as above but const |
rgrover1 | 953:f6eb43f524b2 | 166 | */ |
rgrover1 | 953:f6eb43f524b2 | 167 | void call(ContextType context) const { |
rgrover1 | 953:f6eb43f524b2 | 168 | if (chainHead) { |
rgrover1 | 953:f6eb43f524b2 | 169 | chainHead->call(context); |
rgrover1 | 953:f6eb43f524b2 | 170 | } |
rgrover1 | 953:f6eb43f524b2 | 171 | } |
rgrover1 | 953:f6eb43f524b2 | 172 | |
rgrover1 | 953:f6eb43f524b2 | 173 | /** |
rgrover1 | 953:f6eb43f524b2 | 174 | * @brief same as above but with function call operator |
rgrover1 | 953:f6eb43f524b2 | 175 | */ |
rgrover1 | 953:f6eb43f524b2 | 176 | void operator()(ContextType context) const { |
rgrover1 | 953:f6eb43f524b2 | 177 | call(context); |
rgrover1 | 953:f6eb43f524b2 | 178 | } |
rgrover1 | 953:f6eb43f524b2 | 179 | |
rgrover1 | 953:f6eb43f524b2 | 180 | typedef void (CallChainOfFunctionPointersWithContext::*bool_type)() const; |
rgrover1 | 953:f6eb43f524b2 | 181 | void True() const {} |
rgrover1 | 953:f6eb43f524b2 | 182 | |
rgrover1 | 953:f6eb43f524b2 | 183 | operator bool_type() const { |
rgrover1 | 953:f6eb43f524b2 | 184 | return chainHead == NULL ? 0 : &CallChainOfFunctionPointersWithContext::True; |
rgrover1 | 953:f6eb43f524b2 | 185 | } |
rgrover1 | 953:f6eb43f524b2 | 186 | |
rgrover1 | 710:b2e1a2660ec2 | 187 | private: |
rgrover1 | 710:b2e1a2660ec2 | 188 | pFunctionPointerWithContext_t common_add(pFunctionPointerWithContext_t pf) { |
rgrover1 | 710:b2e1a2660ec2 | 189 | if (chainHead == NULL) { |
rgrover1 | 710:b2e1a2660ec2 | 190 | chainHead = pf; |
rgrover1 | 710:b2e1a2660ec2 | 191 | } else { |
rgrover1 | 710:b2e1a2660ec2 | 192 | pf->chainAsNext(chainHead); |
rgrover1 | 710:b2e1a2660ec2 | 193 | chainHead = pf; |
rgrover1 | 710:b2e1a2660ec2 | 194 | } |
rgrover1 | 710:b2e1a2660ec2 | 195 | |
rgrover1 | 710:b2e1a2660ec2 | 196 | return chainHead; |
rgrover1 | 710:b2e1a2660ec2 | 197 | } |
rgrover1 | 710:b2e1a2660ec2 | 198 | |
rgrover1 | 710:b2e1a2660ec2 | 199 | private: |
rgrover1 | 710:b2e1a2660ec2 | 200 | pFunctionPointerWithContext_t chainHead; |
rgrover1 | 932:68a113707ba5 | 201 | |
rgrover1 | 937:4932e700daf2 | 202 | /* Disallow copy constructor and assignment operators. */ |
rgrover1 | 710:b2e1a2660ec2 | 203 | private: |
rgrover1 | 710:b2e1a2660ec2 | 204 | CallChainOfFunctionPointersWithContext(const CallChainOfFunctionPointersWithContext &); |
rgrover1 | 710:b2e1a2660ec2 | 205 | CallChainOfFunctionPointersWithContext & operator = (const CallChainOfFunctionPointersWithContext &); |
rgrover1 | 710:b2e1a2660ec2 | 206 | }; |
rgrover1 | 710:b2e1a2660ec2 | 207 | |
rgrover1 | 710:b2e1a2660ec2 | 208 | #endif |