Preliminary main mbed library for nexpaq development

Committer:
nexpaq
Date:
Fri Nov 04 20:27:58 2016 +0000
Revision:
0:6c56fb4bc5f0
Moving to library for sharing updates

Who changed what in which revision?

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