Pinned to some recent date

Committer:
Simon Cooksey
Date:
Thu Nov 17 16:43:53 2016 +0000
Revision:
0:fb7af294d5d9
Initial commit

Who changed what in which revision?

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