Dependents:   sensomed

Committer:
switches
Date:
Tue Nov 08 18:27:11 2016 +0000
Revision:
0:0e018d759a2a
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
switches 0:0e018d759a2a 1 /* mbed Microcontroller Library
switches 0:0e018d759a2a 2 * Copyright (c) 2006-2013 ARM Limited
switches 0:0e018d759a2a 3 *
switches 0:0e018d759a2a 4 * Licensed under the Apache License, Version 2.0 (the "License");
switches 0:0e018d759a2a 5 * you may not use this file except in compliance with the License.
switches 0:0e018d759a2a 6 * You may obtain a copy of the License at
switches 0:0e018d759a2a 7 *
switches 0:0e018d759a2a 8 * http://www.apache.org/licenses/LICENSE-2.0
switches 0:0e018d759a2a 9 *
switches 0:0e018d759a2a 10 * Unless required by applicable law or agreed to in writing, software
switches 0:0e018d759a2a 11 * distributed under the License is distributed on an "AS IS" BASIS,
switches 0:0e018d759a2a 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
switches 0:0e018d759a2a 13 * See the License for the specific language governing permissions and
switches 0:0e018d759a2a 14 * limitations under the License.
switches 0:0e018d759a2a 15 */
switches 0:0e018d759a2a 16 #ifndef MBED_CALLCHAIN_OF_FUNCTION_POINTERS_WITH_CONTEXT_H
switches 0:0e018d759a2a 17 #define MBED_CALLCHAIN_OF_FUNCTION_POINTERS_WITH_CONTEXT_H
switches 0:0e018d759a2a 18
switches 0:0e018d759a2a 19 #include <string.h>
switches 0:0e018d759a2a 20 #include "FunctionPointerWithContext.h"
switches 0:0e018d759a2a 21 #include "SafeBool.h"
switches 0:0e018d759a2a 22
switches 0:0e018d759a2a 23
switches 0:0e018d759a2a 24 /** Group one or more functions in an instance of a CallChainOfFunctionPointersWithContext, then call them in
switches 0:0e018d759a2a 25 * sequence using CallChainOfFunctionPointersWithContext::call(). Used mostly by the interrupt chaining code,
switches 0:0e018d759a2a 26 * but can be used for other purposes.
switches 0:0e018d759a2a 27 *
switches 0:0e018d759a2a 28 * Example:
switches 0:0e018d759a2a 29 * @code
switches 0:0e018d759a2a 30 *
switches 0:0e018d759a2a 31 * CallChainOfFunctionPointersWithContext<void *> chain;
switches 0:0e018d759a2a 32 *
switches 0:0e018d759a2a 33 * void first(void *context) {
switches 0:0e018d759a2a 34 * printf("'first' function.\n");
switches 0:0e018d759a2a 35 * }
switches 0:0e018d759a2a 36 *
switches 0:0e018d759a2a 37 * void second(void *context) {
switches 0:0e018d759a2a 38 * printf("'second' function.\n");
switches 0:0e018d759a2a 39 * }
switches 0:0e018d759a2a 40 *
switches 0:0e018d759a2a 41 * class Test {
switches 0:0e018d759a2a 42 * public:
switches 0:0e018d759a2a 43 * void f(void *context) {
switches 0:0e018d759a2a 44 * printf("A::f (class member).\n");
switches 0:0e018d759a2a 45 * }
switches 0:0e018d759a2a 46 * };
switches 0:0e018d759a2a 47 *
switches 0:0e018d759a2a 48 * int main() {
switches 0:0e018d759a2a 49 * Test test;
switches 0:0e018d759a2a 50 *
switches 0:0e018d759a2a 51 * chain.add(second);
switches 0:0e018d759a2a 52 * chain.add_front(first);
switches 0:0e018d759a2a 53 * chain.add(&test, &Test::f);
switches 0:0e018d759a2a 54 * chain.call();
switches 0:0e018d759a2a 55 * }
switches 0:0e018d759a2a 56 * @endcode
switches 0:0e018d759a2a 57 */
switches 0:0e018d759a2a 58 template <typename ContextType>
switches 0:0e018d759a2a 59 class CallChainOfFunctionPointersWithContext : public SafeBool<CallChainOfFunctionPointersWithContext<ContextType> > {
switches 0:0e018d759a2a 60 public:
switches 0:0e018d759a2a 61 /**
switches 0:0e018d759a2a 62 * The type of each callback in the callchain.
switches 0:0e018d759a2a 63 */
switches 0:0e018d759a2a 64 typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t;
switches 0:0e018d759a2a 65
switches 0:0e018d759a2a 66 public:
switches 0:0e018d759a2a 67 /**
switches 0:0e018d759a2a 68 * Create an empty chain.
switches 0:0e018d759a2a 69 */
switches 0:0e018d759a2a 70 CallChainOfFunctionPointersWithContext() : chainHead(NULL) {
switches 0:0e018d759a2a 71 /* empty */
switches 0:0e018d759a2a 72 }
switches 0:0e018d759a2a 73
switches 0:0e018d759a2a 74 virtual ~CallChainOfFunctionPointersWithContext() {
switches 0:0e018d759a2a 75 clear();
switches 0:0e018d759a2a 76 }
switches 0:0e018d759a2a 77
switches 0:0e018d759a2a 78 /**
switches 0:0e018d759a2a 79 * Add a function at the front of the chain.
switches 0:0e018d759a2a 80 *
switches 0:0e018d759a2a 81 * @param[in] function
switches 0:0e018d759a2a 82 * A pointer to a void function.
switches 0:0e018d759a2a 83 *
switches 0:0e018d759a2a 84 * @return The function object created for @p function.
switches 0:0e018d759a2a 85 */
switches 0:0e018d759a2a 86 pFunctionPointerWithContext_t add(void (*function)(ContextType context)) {
switches 0:0e018d759a2a 87 return common_add(new FunctionPointerWithContext<ContextType>(function));
switches 0:0e018d759a2a 88 }
switches 0:0e018d759a2a 89
switches 0:0e018d759a2a 90 /**
switches 0:0e018d759a2a 91 * Add a function at the front of the chain.
switches 0:0e018d759a2a 92 *
switches 0:0e018d759a2a 93 * @param[in] tptr
switches 0:0e018d759a2a 94 * Pointer to the object to call the member function on.
switches 0:0e018d759a2a 95 * @param[in] mptr
switches 0:0e018d759a2a 96 * Pointer to the member function to be called.
switches 0:0e018d759a2a 97 *
switches 0:0e018d759a2a 98 * @return The function object created for @p tptr and @p mptr.
switches 0:0e018d759a2a 99 */
switches 0:0e018d759a2a 100 template<typename T>
switches 0:0e018d759a2a 101 pFunctionPointerWithContext_t add(T *tptr, void (T::*mptr)(ContextType context)) {
switches 0:0e018d759a2a 102 return common_add(new FunctionPointerWithContext<ContextType>(tptr, mptr));
switches 0:0e018d759a2a 103 }
switches 0:0e018d759a2a 104
switches 0:0e018d759a2a 105 /**
switches 0:0e018d759a2a 106 * Add a function at the front of the chain.
switches 0:0e018d759a2a 107 *
switches 0:0e018d759a2a 108 * @param[in] func
switches 0:0e018d759a2a 109 * The FunctionPointerWithContext to add.
switches 0:0e018d759a2a 110 *
switches 0:0e018d759a2a 111 * @return The function object created for @p func.
switches 0:0e018d759a2a 112 */
switches 0:0e018d759a2a 113 pFunctionPointerWithContext_t add(const FunctionPointerWithContext<ContextType>& func) {
switches 0:0e018d759a2a 114 return common_add(new FunctionPointerWithContext<ContextType>(func));
switches 0:0e018d759a2a 115 }
switches 0:0e018d759a2a 116
switches 0:0e018d759a2a 117 /**
switches 0:0e018d759a2a 118 * Detach a function pointer from a callchain.
switches 0:0e018d759a2a 119 *
switches 0:0e018d759a2a 120 * @param[in] toDetach
switches 0:0e018d759a2a 121 * FunctionPointerWithContext to detach from this callchain.
switches 0:0e018d759a2a 122 *
switches 0:0e018d759a2a 123 * @return true if a function pointer has been detached and false otherwise.
switches 0:0e018d759a2a 124 *
switches 0:0e018d759a2a 125 * @note It is safe to remove a function pointer while the chain is
switches 0:0e018d759a2a 126 * traversed by call(ContextType).
switches 0:0e018d759a2a 127 */
switches 0:0e018d759a2a 128 bool detach(const FunctionPointerWithContext<ContextType>& toDetach) {
switches 0:0e018d759a2a 129 pFunctionPointerWithContext_t current = chainHead;
switches 0:0e018d759a2a 130 pFunctionPointerWithContext_t previous = NULL;
switches 0:0e018d759a2a 131
switches 0:0e018d759a2a 132 while (current) {
switches 0:0e018d759a2a 133 if(*current == toDetach) {
switches 0:0e018d759a2a 134 if(previous == NULL) {
switches 0:0e018d759a2a 135 if(currentCalled == current) {
switches 0:0e018d759a2a 136 currentCalled = NULL;
switches 0:0e018d759a2a 137 }
switches 0:0e018d759a2a 138 chainHead = current->getNext();
switches 0:0e018d759a2a 139 } else {
switches 0:0e018d759a2a 140 if(currentCalled == current) {
switches 0:0e018d759a2a 141 currentCalled = previous;
switches 0:0e018d759a2a 142 }
switches 0:0e018d759a2a 143 previous->chainAsNext(current->getNext());
switches 0:0e018d759a2a 144 }
switches 0:0e018d759a2a 145 delete current;
switches 0:0e018d759a2a 146 return true;
switches 0:0e018d759a2a 147 }
switches 0:0e018d759a2a 148
switches 0:0e018d759a2a 149 previous = current;
switches 0:0e018d759a2a 150 current = current->getNext();
switches 0:0e018d759a2a 151 }
switches 0:0e018d759a2a 152
switches 0:0e018d759a2a 153 return false;
switches 0:0e018d759a2a 154 }
switches 0:0e018d759a2a 155
switches 0:0e018d759a2a 156 /**
switches 0:0e018d759a2a 157 * Clear the call chain (remove all functions in the chain).
switches 0:0e018d759a2a 158 */
switches 0:0e018d759a2a 159 void clear(void) {
switches 0:0e018d759a2a 160 pFunctionPointerWithContext_t fptr = chainHead;
switches 0:0e018d759a2a 161 while (fptr) {
switches 0:0e018d759a2a 162 pFunctionPointerWithContext_t deadPtr = fptr;
switches 0:0e018d759a2a 163 fptr = deadPtr->getNext();
switches 0:0e018d759a2a 164 delete deadPtr;
switches 0:0e018d759a2a 165 }
switches 0:0e018d759a2a 166
switches 0:0e018d759a2a 167 chainHead = NULL;
switches 0:0e018d759a2a 168 }
switches 0:0e018d759a2a 169
switches 0:0e018d759a2a 170 /**
switches 0:0e018d759a2a 171 * Check whether the callchain contains any callbacks.
switches 0:0e018d759a2a 172 *
switches 0:0e018d759a2a 173 * @return true if the callchain is not empty and false otherwise.
switches 0:0e018d759a2a 174 */
switches 0:0e018d759a2a 175 bool hasCallbacksAttached(void) const {
switches 0:0e018d759a2a 176 return (chainHead != NULL);
switches 0:0e018d759a2a 177 }
switches 0:0e018d759a2a 178
switches 0:0e018d759a2a 179 /**
switches 0:0e018d759a2a 180 * Call all the functions in the chain in sequence.
switches 0:0e018d759a2a 181 */
switches 0:0e018d759a2a 182 void call(ContextType context) {
switches 0:0e018d759a2a 183 ((const CallChainOfFunctionPointersWithContext*) this)->call(context);
switches 0:0e018d759a2a 184 }
switches 0:0e018d759a2a 185
switches 0:0e018d759a2a 186 /**
switches 0:0e018d759a2a 187 * Same as call() above, but const.
switches 0:0e018d759a2a 188 */
switches 0:0e018d759a2a 189 void call(ContextType context) const {
switches 0:0e018d759a2a 190 currentCalled = chainHead;
switches 0:0e018d759a2a 191
switches 0:0e018d759a2a 192 while(currentCalled) {
switches 0:0e018d759a2a 193 currentCalled->call(context);
switches 0:0e018d759a2a 194 // if this was the head and the call removed the head
switches 0:0e018d759a2a 195 if(currentCalled == NULL) {
switches 0:0e018d759a2a 196 currentCalled = chainHead;
switches 0:0e018d759a2a 197 } else {
switches 0:0e018d759a2a 198 currentCalled = currentCalled->getNext();
switches 0:0e018d759a2a 199 }
switches 0:0e018d759a2a 200 }
switches 0:0e018d759a2a 201 }
switches 0:0e018d759a2a 202
switches 0:0e018d759a2a 203 /**
switches 0:0e018d759a2a 204 * Same as call(), but with function call operator.
switches 0:0e018d759a2a 205 * @code
switches 0:0e018d759a2a 206 *
switches 0:0e018d759a2a 207 * void first(bool);
switches 0:0e018d759a2a 208 * void second(bool);
switches 0:0e018d759a2a 209 *
switches 0:0e018d759a2a 210 * CallChainOfFunctionPointerWithContext<bool> foo;
switches 0:0e018d759a2a 211 *
switches 0:0e018d759a2a 212 * foo.attach(first);
switches 0:0e018d759a2a 213 * foo.attach(second);
switches 0:0e018d759a2a 214 *
switches 0:0e018d759a2a 215 * // call the callchain like a function
switches 0:0e018d759a2a 216 * foo(true);
switches 0:0e018d759a2a 217 *
switches 0:0e018d759a2a 218 * @endcode
switches 0:0e018d759a2a 219 */
switches 0:0e018d759a2a 220 void operator()(ContextType context) const {
switches 0:0e018d759a2a 221 call(context);
switches 0:0e018d759a2a 222 }
switches 0:0e018d759a2a 223
switches 0:0e018d759a2a 224 /**
switches 0:0e018d759a2a 225 * Bool conversion operation.
switches 0:0e018d759a2a 226 *
switches 0:0e018d759a2a 227 * @return true if the callchain is not empty and false otherwise.
switches 0:0e018d759a2a 228 */
switches 0:0e018d759a2a 229 bool toBool() const {
switches 0:0e018d759a2a 230 return chainHead != NULL;
switches 0:0e018d759a2a 231 }
switches 0:0e018d759a2a 232
switches 0:0e018d759a2a 233 private:
switches 0:0e018d759a2a 234 /**
switches 0:0e018d759a2a 235 * Add a callback to the head of the callchain.
switches 0:0e018d759a2a 236 *
switches 0:0e018d759a2a 237 * @return A pointer to the head of the callchain.
switches 0:0e018d759a2a 238 */
switches 0:0e018d759a2a 239 pFunctionPointerWithContext_t common_add(pFunctionPointerWithContext_t pf) {
switches 0:0e018d759a2a 240 if (chainHead == NULL) {
switches 0:0e018d759a2a 241 chainHead = pf;
switches 0:0e018d759a2a 242 } else {
switches 0:0e018d759a2a 243 pf->chainAsNext(chainHead);
switches 0:0e018d759a2a 244 chainHead = pf;
switches 0:0e018d759a2a 245 }
switches 0:0e018d759a2a 246
switches 0:0e018d759a2a 247 return chainHead;
switches 0:0e018d759a2a 248 }
switches 0:0e018d759a2a 249
switches 0:0e018d759a2a 250 private:
switches 0:0e018d759a2a 251 /**
switches 0:0e018d759a2a 252 * A pointer to the first callback in the callchain or NULL if the callchain is empty.
switches 0:0e018d759a2a 253 */
switches 0:0e018d759a2a 254 pFunctionPointerWithContext_t chainHead;
switches 0:0e018d759a2a 255
switches 0:0e018d759a2a 256 /**
switches 0:0e018d759a2a 257 * Iterator during a function call, this has to be mutable because the call function is const.
switches 0:0e018d759a2a 258 *
switches 0:0e018d759a2a 259 * @note Mutable is the correct behaviour here, the iterator never leaks outside the object.
switches 0:0e018d759a2a 260 * so the object can still be seen as logically const even if it is modified.
switches 0:0e018d759a2a 261 */
switches 0:0e018d759a2a 262 mutable pFunctionPointerWithContext_t currentCalled;
switches 0:0e018d759a2a 263
switches 0:0e018d759a2a 264
switches 0:0e018d759a2a 265 /* Disallow copy constructor and assignment operators. */
switches 0:0e018d759a2a 266 private:
switches 0:0e018d759a2a 267 CallChainOfFunctionPointersWithContext(const CallChainOfFunctionPointersWithContext &);
switches 0:0e018d759a2a 268 CallChainOfFunctionPointersWithContext & operator = (const CallChainOfFunctionPointersWithContext &);
switches 0:0e018d759a2a 269 };
switches 0:0e018d759a2a 270
switches 0:0e018d759a2a 271 #endif