mbed-os

Dependents:   cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more

Committer:
be_bryan
Date:
Mon Dec 11 17:54:04 2017 +0000
Revision:
0:b74591d5ab33
motor ++

Who changed what in which revision?

UserRevisionLine numberNew contents of line
be_bryan 0:b74591d5ab33 1 /* mbed Microcontroller Library
be_bryan 0:b74591d5ab33 2 * Copyright (c) 2006-2013 ARM Limited
be_bryan 0:b74591d5ab33 3 *
be_bryan 0:b74591d5ab33 4 * Licensed under the Apache License, Version 2.0 (the "License");
be_bryan 0:b74591d5ab33 5 * you may not use this file except in compliance with the License.
be_bryan 0:b74591d5ab33 6 * You may obtain a copy of the License at
be_bryan 0:b74591d5ab33 7 *
be_bryan 0:b74591d5ab33 8 * http://www.apache.org/licenses/LICENSE-2.0
be_bryan 0:b74591d5ab33 9 *
be_bryan 0:b74591d5ab33 10 * Unless required by applicable law or agreed to in writing, software
be_bryan 0:b74591d5ab33 11 * distributed under the License is distributed on an "AS IS" BASIS,
be_bryan 0:b74591d5ab33 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
be_bryan 0:b74591d5ab33 13 * See the License for the specific language governing permissions and
be_bryan 0:b74591d5ab33 14 * limitations under the License.
be_bryan 0:b74591d5ab33 15 */
be_bryan 0:b74591d5ab33 16 #ifndef MBED_CALLCHAIN_OF_FUNCTION_POINTERS_WITH_CONTEXT_H
be_bryan 0:b74591d5ab33 17 #define MBED_CALLCHAIN_OF_FUNCTION_POINTERS_WITH_CONTEXT_H
be_bryan 0:b74591d5ab33 18
be_bryan 0:b74591d5ab33 19 #include <string.h>
be_bryan 0:b74591d5ab33 20 #include "FunctionPointerWithContext.h"
be_bryan 0:b74591d5ab33 21 #include "SafeBool.h"
be_bryan 0:b74591d5ab33 22
be_bryan 0:b74591d5ab33 23 /**
be_bryan 0:b74591d5ab33 24 * @addtogroup ble
be_bryan 0:b74591d5ab33 25 * @{
be_bryan 0:b74591d5ab33 26 * @addtogroup common
be_bryan 0:b74591d5ab33 27 * @{
be_bryan 0:b74591d5ab33 28 */
be_bryan 0:b74591d5ab33 29
be_bryan 0:b74591d5ab33 30 /**
be_bryan 0:b74591d5ab33 31 * Function like object hosting a list of FunctionPointerWithContext.
be_bryan 0:b74591d5ab33 32 *
be_bryan 0:b74591d5ab33 33 * Upon call, each FunctionPointerWithContext instance present in the object will
be_bryan 0:b74591d5ab33 34 * be called in sequence with the initial parameters.
be_bryan 0:b74591d5ab33 35 *
be_bryan 0:b74591d5ab33 36 * It can be seen as a variation of the observer pattern this object being the
be_bryan 0:b74591d5ab33 37 * observable, instances of the FunctionPointerWithContext being the observable
be_bryan 0:b74591d5ab33 38 * and the notify/update operation being the function call.
be_bryan 0:b74591d5ab33 39 *
be_bryan 0:b74591d5ab33 40 * Example:
be_bryan 0:b74591d5ab33 41 * @code
be_bryan 0:b74591d5ab33 42 *
be_bryan 0:b74591d5ab33 43 * CallChainOfFunctionPointersWithContext<void *> chain;
be_bryan 0:b74591d5ab33 44 *
be_bryan 0:b74591d5ab33 45 * void first(void *context) {
be_bryan 0:b74591d5ab33 46 * printf("'first' function.\n");
be_bryan 0:b74591d5ab33 47 * }
be_bryan 0:b74591d5ab33 48 *
be_bryan 0:b74591d5ab33 49 * void second(void *context) {
be_bryan 0:b74591d5ab33 50 * printf("'second' function.\n");
be_bryan 0:b74591d5ab33 51 * }
be_bryan 0:b74591d5ab33 52 *
be_bryan 0:b74591d5ab33 53 * class Test {
be_bryan 0:b74591d5ab33 54 * public:
be_bryan 0:b74591d5ab33 55 * void f(void *context) {
be_bryan 0:b74591d5ab33 56 * printf("A::f (class member).\n");
be_bryan 0:b74591d5ab33 57 * }
be_bryan 0:b74591d5ab33 58 * };
be_bryan 0:b74591d5ab33 59 *
be_bryan 0:b74591d5ab33 60 * int main() {
be_bryan 0:b74591d5ab33 61 * Test test;
be_bryan 0:b74591d5ab33 62 *
be_bryan 0:b74591d5ab33 63 * chain.add(second);
be_bryan 0:b74591d5ab33 64 * chain.add_front(first);
be_bryan 0:b74591d5ab33 65 * chain.add(&test, &Test::f);
be_bryan 0:b74591d5ab33 66 *
be_bryan 0:b74591d5ab33 67 * // will print:
be_bryan 0:b74591d5ab33 68 * // 'second' function.
be_bryan 0:b74591d5ab33 69 * // 'first' function.
be_bryan 0:b74591d5ab33 70 * // A::f (class member).
be_bryan 0:b74591d5ab33 71 * chain.call();
be_bryan 0:b74591d5ab33 72 * }
be_bryan 0:b74591d5ab33 73 * @endcode
be_bryan 0:b74591d5ab33 74 *
be_bryan 0:b74591d5ab33 75 * @note memory allocation is used to add new function like objects into the
be_bryan 0:b74591d5ab33 76 * call chain.
be_bryan 0:b74591d5ab33 77 *
be_bryan 0:b74591d5ab33 78 * @tparam ContextType Type of the parameter accepted by the callbacks hosted
be_bryan 0:b74591d5ab33 79 * in the object.
be_bryan 0:b74591d5ab33 80 */
be_bryan 0:b74591d5ab33 81 template <typename ContextType>
be_bryan 0:b74591d5ab33 82 class CallChainOfFunctionPointersWithContext :
be_bryan 0:b74591d5ab33 83 public SafeBool<CallChainOfFunctionPointersWithContext<ContextType> > {
be_bryan 0:b74591d5ab33 84 public:
be_bryan 0:b74591d5ab33 85 /**
be_bryan 0:b74591d5ab33 86 * Alias of the FunctionPointerWithContext type this object can store.
be_bryan 0:b74591d5ab33 87 */
be_bryan 0:b74591d5ab33 88 typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t;
be_bryan 0:b74591d5ab33 89
be_bryan 0:b74591d5ab33 90 public:
be_bryan 0:b74591d5ab33 91 /**
be_bryan 0:b74591d5ab33 92 * Create an empty callchain.
be_bryan 0:b74591d5ab33 93 */
be_bryan 0:b74591d5ab33 94 CallChainOfFunctionPointersWithContext() : chainHead(NULL) { }
be_bryan 0:b74591d5ab33 95
be_bryan 0:b74591d5ab33 96 /**
be_bryan 0:b74591d5ab33 97 * Destruction of the callchain.
be_bryan 0:b74591d5ab33 98 */
be_bryan 0:b74591d5ab33 99 virtual ~CallChainOfFunctionPointersWithContext()
be_bryan 0:b74591d5ab33 100 {
be_bryan 0:b74591d5ab33 101 clear();
be_bryan 0:b74591d5ab33 102 }
be_bryan 0:b74591d5ab33 103
be_bryan 0:b74591d5ab33 104 /**
be_bryan 0:b74591d5ab33 105 * Add a function pointer at the front of the chain.
be_bryan 0:b74591d5ab33 106 *
be_bryan 0:b74591d5ab33 107 * @param[in] function A pointer to a void function.
be_bryan 0:b74591d5ab33 108 *
be_bryan 0:b74591d5ab33 109 * @return The FunctionPointerWithContext object created from @p function.
be_bryan 0:b74591d5ab33 110 */
be_bryan 0:b74591d5ab33 111 pFunctionPointerWithContext_t add(void (*function)(ContextType context))
be_bryan 0:b74591d5ab33 112 {
be_bryan 0:b74591d5ab33 113 return common_add(new FunctionPointerWithContext<ContextType>(function));
be_bryan 0:b74591d5ab33 114 }
be_bryan 0:b74591d5ab33 115
be_bryan 0:b74591d5ab33 116 /**
be_bryan 0:b74591d5ab33 117 * Add a member function bound to its instance at the front of the chain.
be_bryan 0:b74591d5ab33 118 *
be_bryan 0:b74591d5ab33 119 * @param[in] tptr Pointer to the object to call the member function on.
be_bryan 0:b74591d5ab33 120 * @param[in] mptr Pointer to the member function to be called.
be_bryan 0:b74591d5ab33 121 *
be_bryan 0:b74591d5ab33 122 * @return The FunctionPointerWithContext object created from @p tptr and
be_bryan 0:b74591d5ab33 123 * @p mptr.
be_bryan 0:b74591d5ab33 124 */
be_bryan 0:b74591d5ab33 125 template<typename T>
be_bryan 0:b74591d5ab33 126 pFunctionPointerWithContext_t add(T *tptr, void (T::*mptr)(ContextType context))
be_bryan 0:b74591d5ab33 127 {
be_bryan 0:b74591d5ab33 128 return common_add(new FunctionPointerWithContext<ContextType>(tptr, mptr));
be_bryan 0:b74591d5ab33 129 }
be_bryan 0:b74591d5ab33 130
be_bryan 0:b74591d5ab33 131 /**
be_bryan 0:b74591d5ab33 132 * Add a FunctionPointerWithContext at the front of the chain.
be_bryan 0:b74591d5ab33 133 *
be_bryan 0:b74591d5ab33 134 * @param[in] func The FunctionPointerWithContext to add.
be_bryan 0:b74591d5ab33 135 *
be_bryan 0:b74591d5ab33 136 * @return The function object created for @p func.
be_bryan 0:b74591d5ab33 137 */
be_bryan 0:b74591d5ab33 138 pFunctionPointerWithContext_t add(const FunctionPointerWithContext<ContextType> &func)
be_bryan 0:b74591d5ab33 139 {
be_bryan 0:b74591d5ab33 140 return common_add(new FunctionPointerWithContext<ContextType>(func));
be_bryan 0:b74591d5ab33 141 }
be_bryan 0:b74591d5ab33 142
be_bryan 0:b74591d5ab33 143 /**
be_bryan 0:b74591d5ab33 144 * Detach a function pointer from a callchain.
be_bryan 0:b74591d5ab33 145 *
be_bryan 0:b74591d5ab33 146 * @param[in] toDetach FunctionPointerWithContext instance to detach from
be_bryan 0:b74591d5ab33 147 * this callchain.
be_bryan 0:b74591d5ab33 148 *
be_bryan 0:b74591d5ab33 149 * @return true if a function pointer has been detached and false otherwise.
be_bryan 0:b74591d5ab33 150 *
be_bryan 0:b74591d5ab33 151 * @note It is safe to remove a function pointer while
be_bryan 0:b74591d5ab33 152 * call(ContextType) is traversing the chain.
be_bryan 0:b74591d5ab33 153 */
be_bryan 0:b74591d5ab33 154 bool detach(const FunctionPointerWithContext<ContextType> &toDetach)
be_bryan 0:b74591d5ab33 155 {
be_bryan 0:b74591d5ab33 156 pFunctionPointerWithContext_t current = chainHead;
be_bryan 0:b74591d5ab33 157 pFunctionPointerWithContext_t previous = NULL;
be_bryan 0:b74591d5ab33 158
be_bryan 0:b74591d5ab33 159 while (current) {
be_bryan 0:b74591d5ab33 160 if(*current == toDetach) {
be_bryan 0:b74591d5ab33 161 if(previous == NULL) {
be_bryan 0:b74591d5ab33 162 if(currentCalled == current) {
be_bryan 0:b74591d5ab33 163 currentCalled = NULL;
be_bryan 0:b74591d5ab33 164 }
be_bryan 0:b74591d5ab33 165 chainHead = current->getNext();
be_bryan 0:b74591d5ab33 166 } else {
be_bryan 0:b74591d5ab33 167 if(currentCalled == current) {
be_bryan 0:b74591d5ab33 168 currentCalled = previous;
be_bryan 0:b74591d5ab33 169 }
be_bryan 0:b74591d5ab33 170 previous->chainAsNext(current->getNext());
be_bryan 0:b74591d5ab33 171 }
be_bryan 0:b74591d5ab33 172 delete current;
be_bryan 0:b74591d5ab33 173 return true;
be_bryan 0:b74591d5ab33 174 }
be_bryan 0:b74591d5ab33 175
be_bryan 0:b74591d5ab33 176 previous = current;
be_bryan 0:b74591d5ab33 177 current = current->getNext();
be_bryan 0:b74591d5ab33 178 }
be_bryan 0:b74591d5ab33 179
be_bryan 0:b74591d5ab33 180 return false;
be_bryan 0:b74591d5ab33 181 }
be_bryan 0:b74591d5ab33 182
be_bryan 0:b74591d5ab33 183 /**
be_bryan 0:b74591d5ab33 184 * Remove all functions registered in the chain.
be_bryan 0:b74591d5ab33 185 */
be_bryan 0:b74591d5ab33 186 void clear(void)
be_bryan 0:b74591d5ab33 187 {
be_bryan 0:b74591d5ab33 188 pFunctionPointerWithContext_t fptr = chainHead;
be_bryan 0:b74591d5ab33 189 while (fptr) {
be_bryan 0:b74591d5ab33 190 pFunctionPointerWithContext_t deadPtr = fptr;
be_bryan 0:b74591d5ab33 191 fptr = deadPtr->getNext();
be_bryan 0:b74591d5ab33 192 delete deadPtr;
be_bryan 0:b74591d5ab33 193 }
be_bryan 0:b74591d5ab33 194
be_bryan 0:b74591d5ab33 195 chainHead = NULL;
be_bryan 0:b74591d5ab33 196 }
be_bryan 0:b74591d5ab33 197
be_bryan 0:b74591d5ab33 198 /**
be_bryan 0:b74591d5ab33 199 * Check whether the callchain contains any callbacks.
be_bryan 0:b74591d5ab33 200 *
be_bryan 0:b74591d5ab33 201 * @return true if the callchain is not empty and false otherwise.
be_bryan 0:b74591d5ab33 202 */
be_bryan 0:b74591d5ab33 203 bool hasCallbacksAttached(void) const
be_bryan 0:b74591d5ab33 204 {
be_bryan 0:b74591d5ab33 205 return (chainHead != NULL);
be_bryan 0:b74591d5ab33 206 }
be_bryan 0:b74591d5ab33 207
be_bryan 0:b74591d5ab33 208 /**
be_bryan 0:b74591d5ab33 209 * Call sequentially each member of the chain.
be_bryan 0:b74591d5ab33 210 *
be_bryan 0:b74591d5ab33 211 * @param[in] context Parameter to pass to the functions called.
be_bryan 0:b74591d5ab33 212 */
be_bryan 0:b74591d5ab33 213 void call(ContextType context)
be_bryan 0:b74591d5ab33 214 {
be_bryan 0:b74591d5ab33 215 ((const CallChainOfFunctionPointersWithContext*) this)->call(context);
be_bryan 0:b74591d5ab33 216 }
be_bryan 0:b74591d5ab33 217
be_bryan 0:b74591d5ab33 218 /**
be_bryan 0:b74591d5ab33 219 * Call sequentially each member of the chain.
be_bryan 0:b74591d5ab33 220 *
be_bryan 0:b74591d5ab33 221 * @param[in] context Parameter to pass to the functions called.
be_bryan 0:b74591d5ab33 222 */
be_bryan 0:b74591d5ab33 223 void call(ContextType context) const
be_bryan 0:b74591d5ab33 224 {
be_bryan 0:b74591d5ab33 225 currentCalled = chainHead;
be_bryan 0:b74591d5ab33 226
be_bryan 0:b74591d5ab33 227 while(currentCalled) {
be_bryan 0:b74591d5ab33 228 currentCalled->call(context);
be_bryan 0:b74591d5ab33 229 // if this was the head and the call removed the head
be_bryan 0:b74591d5ab33 230 if(currentCalled == NULL) {
be_bryan 0:b74591d5ab33 231 currentCalled = chainHead;
be_bryan 0:b74591d5ab33 232 } else {
be_bryan 0:b74591d5ab33 233 currentCalled = currentCalled->getNext();
be_bryan 0:b74591d5ab33 234 }
be_bryan 0:b74591d5ab33 235 }
be_bryan 0:b74591d5ab33 236 }
be_bryan 0:b74591d5ab33 237
be_bryan 0:b74591d5ab33 238 /**
be_bryan 0:b74591d5ab33 239 * Call sequentially each member of the chain.
be_bryan 0:b74591d5ab33 240 *
be_bryan 0:b74591d5ab33 241 * @param[in] context Parameter to pass to the functions called.
be_bryan 0:b74591d5ab33 242 *
be_bryan 0:b74591d5ab33 243 * @code
be_bryan 0:b74591d5ab33 244 *
be_bryan 0:b74591d5ab33 245 * void first(bool);
be_bryan 0:b74591d5ab33 246 * void second(bool);
be_bryan 0:b74591d5ab33 247 *
be_bryan 0:b74591d5ab33 248 * CallChainOfFunctionPointerWithContext<bool> foo;
be_bryan 0:b74591d5ab33 249 *
be_bryan 0:b74591d5ab33 250 * foo.attach(first);
be_bryan 0:b74591d5ab33 251 * foo.attach(second);
be_bryan 0:b74591d5ab33 252 *
be_bryan 0:b74591d5ab33 253 * // call the callchain like a function
be_bryan 0:b74591d5ab33 254 * foo(true);
be_bryan 0:b74591d5ab33 255 *
be_bryan 0:b74591d5ab33 256 * @endcode
be_bryan 0:b74591d5ab33 257 */
be_bryan 0:b74591d5ab33 258 void operator()(ContextType context) const
be_bryan 0:b74591d5ab33 259 {
be_bryan 0:b74591d5ab33 260 call(context);
be_bryan 0:b74591d5ab33 261 }
be_bryan 0:b74591d5ab33 262
be_bryan 0:b74591d5ab33 263 /**
be_bryan 0:b74591d5ab33 264 * Test if the callchain is empty or not.
be_bryan 0:b74591d5ab33 265 *
be_bryan 0:b74591d5ab33 266 * @return true if the callchain is not empty and false otherwise.
be_bryan 0:b74591d5ab33 267 *
be_bryan 0:b74591d5ab33 268 * @note used by SafeBool to offer a safe boolean conversion.
be_bryan 0:b74591d5ab33 269 *
be_bryan 0:b74591d5ab33 270 * @code
be_bryan 0:b74591d5ab33 271 * CallChainOfFunctionPointersWithContext<void *> chain;
be_bryan 0:b74591d5ab33 272 *
be_bryan 0:b74591d5ab33 273 * if (!chain) {
be_bryan 0:b74591d5ab33 274 * // Do something if the chain is empty.
be_bryan 0:b74591d5ab33 275 * }
be_bryan 0:b74591d5ab33 276 *
be_bryan 0:b74591d5ab33 277 * if (chain) {
be_bryan 0:b74591d5ab33 278 * // Do something if the chain is not empty.
be_bryan 0:b74591d5ab33 279 * }
be_bryan 0:b74591d5ab33 280 * @endcode
be_bryan 0:b74591d5ab33 281 *
be_bryan 0:b74591d5ab33 282 */
be_bryan 0:b74591d5ab33 283 bool toBool() const
be_bryan 0:b74591d5ab33 284 {
be_bryan 0:b74591d5ab33 285 return chainHead != NULL;
be_bryan 0:b74591d5ab33 286 }
be_bryan 0:b74591d5ab33 287
be_bryan 0:b74591d5ab33 288 private:
be_bryan 0:b74591d5ab33 289 /**
be_bryan 0:b74591d5ab33 290 * Add a callback to the head of the callchain.
be_bryan 0:b74591d5ab33 291 *
be_bryan 0:b74591d5ab33 292 * @return A pointer to the head of the callchain.
be_bryan 0:b74591d5ab33 293 */
be_bryan 0:b74591d5ab33 294 pFunctionPointerWithContext_t common_add(pFunctionPointerWithContext_t pf)
be_bryan 0:b74591d5ab33 295 {
be_bryan 0:b74591d5ab33 296 if (chainHead == NULL) {
be_bryan 0:b74591d5ab33 297 chainHead = pf;
be_bryan 0:b74591d5ab33 298 } else {
be_bryan 0:b74591d5ab33 299 pf->chainAsNext(chainHead);
be_bryan 0:b74591d5ab33 300 chainHead = pf;
be_bryan 0:b74591d5ab33 301 }
be_bryan 0:b74591d5ab33 302
be_bryan 0:b74591d5ab33 303 return chainHead;
be_bryan 0:b74591d5ab33 304 }
be_bryan 0:b74591d5ab33 305
be_bryan 0:b74591d5ab33 306 private:
be_bryan 0:b74591d5ab33 307 /**
be_bryan 0:b74591d5ab33 308 * Pointer to the first callback of the callchain or NULL if the callchain
be_bryan 0:b74591d5ab33 309 * is empty.
be_bryan 0:b74591d5ab33 310 */
be_bryan 0:b74591d5ab33 311 pFunctionPointerWithContext_t chainHead;
be_bryan 0:b74591d5ab33 312
be_bryan 0:b74591d5ab33 313 /**
be_bryan 0:b74591d5ab33 314 * Pointer to the function being called.
be_bryan 0:b74591d5ab33 315 *
be_bryan 0:b74591d5ab33 316 * It is used to maintain the data structure integrity if a function is
be_bryan 0:b74591d5ab33 317 * removed during the call() operation.
be_bryan 0:b74591d5ab33 318 *
be_bryan 0:b74591d5ab33 319 * @note It has to be mutable to accomodate the const version of call(). The
be_bryan 0:b74591d5ab33 320 * iterator doesn't leak outside the object; therefore, it remains seen as
be_bryan 0:b74591d5ab33 321 * const from an external standpoint.
be_bryan 0:b74591d5ab33 322 */
be_bryan 0:b74591d5ab33 323 mutable pFunctionPointerWithContext_t currentCalled;
be_bryan 0:b74591d5ab33 324
be_bryan 0:b74591d5ab33 325
be_bryan 0:b74591d5ab33 326 /* Disallow copy constructor and assignment operators. */
be_bryan 0:b74591d5ab33 327 private:
be_bryan 0:b74591d5ab33 328 CallChainOfFunctionPointersWithContext(
be_bryan 0:b74591d5ab33 329 const CallChainOfFunctionPointersWithContext&
be_bryan 0:b74591d5ab33 330 );
be_bryan 0:b74591d5ab33 331 CallChainOfFunctionPointersWithContext &operator=(
be_bryan 0:b74591d5ab33 332 const CallChainOfFunctionPointersWithContext&
be_bryan 0:b74591d5ab33 333 );
be_bryan 0:b74591d5ab33 334 };
be_bryan 0:b74591d5ab33 335
be_bryan 0:b74591d5ab33 336 /**
be_bryan 0:b74591d5ab33 337 * @}
be_bryan 0:b74591d5ab33 338 * @}
be_bryan 0:b74591d5ab33 339 */
be_bryan 0:b74591d5ab33 340
be_bryan 0:b74591d5ab33 341 #endif