Lancaster University's fork of the mbed BLE API. Lives on github, https://github.com/lancaster-university/BLE_API

Dependents:   microbit-dal microbit-dal microbit-ble-open microbit-dal ... more

Fork of BLE_API by Bluetooth Low Energy

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers CallChainOfFunctionPointersWithContext.h Source File

CallChainOfFunctionPointersWithContext.h

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #ifndef MBED_CALLCHAIN_OF_FUNCTION_POINTERS_WITH_CONTEXT_H
00017 #define MBED_CALLCHAIN_OF_FUNCTION_POINTERS_WITH_CONTEXT_H
00018 
00019 #include <string.h>
00020 #include "FunctionPointerWithContext.h"
00021 #include "SafeBool.h"
00022 
00023 
00024 /** Group one or more functions in an instance of a CallChainOfFunctionPointersWithContext, then call them in
00025  * sequence using CallChainOfFunctionPointersWithContext::call(). Used mostly by the interrupt chaining code,
00026  * but can be used for other purposes.
00027  *
00028  * Example:
00029  * @code
00030  *
00031  * CallChainOfFunctionPointersWithContext<void *> chain;
00032  *
00033  * void first(void *context) {
00034  *     printf("'first' function.\n");
00035  * }
00036  *
00037  * void second(void *context) {
00038  *     printf("'second' function.\n");
00039  * }
00040  *
00041  * class Test {
00042  * public:
00043  *     void f(void *context) {
00044  *         printf("A::f (class member).\n");
00045  *     }
00046  * };
00047  *
00048  * int main() {
00049  *     Test test;
00050  *
00051  *     chain.add(second);
00052  *     chain.add_front(first);
00053  *     chain.add(&test, &Test::f);
00054  *     chain.call();
00055  * }
00056  * @endcode
00057  */
00058 
00059 template <typename ContextType>
00060 class CallChainOfFunctionPointersWithContext : public SafeBool<CallChainOfFunctionPointersWithContext<ContextType> > {
00061 public:
00062     typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t;
00063 
00064 public:
00065     /** Create an empty chain.
00066      *
00067      *  @param size (optional) Initial size of the chain.
00068      */
00069     CallChainOfFunctionPointersWithContext() : chainHead(NULL) {
00070         /* empty */
00071     }
00072 
00073     virtual ~CallChainOfFunctionPointersWithContext() {
00074         clear();
00075     }
00076 
00077     /** Add a function at the front of the chain.
00078      *
00079      *  @param function A pointer to a void function.
00080      *
00081      *  @returns
00082      *  The function object created for 'function'.
00083      */
00084     pFunctionPointerWithContext_t  add(void (*function)(ContextType context)) {
00085         return common_add(new FunctionPointerWithContext<ContextType>(function));
00086     }
00087 
00088     /** Add a function at the front of the chain.
00089      *
00090      *  @param tptr Pointer to the object to call the member function on.
00091      *  @param mptr Pointer to the member function to be called.
00092      *
00093      *  @returns
00094      *  The function object created for 'tptr' and 'mptr'.
00095      */
00096     template<typename T>
00097     pFunctionPointerWithContext_t  add(T *tptr, void (T::*mptr)(ContextType context)) {
00098         return common_add(new FunctionPointerWithContext<ContextType>(tptr, mptr));
00099     }
00100 
00101     /** Add a function at the front of the chain.
00102      *
00103      *  @param func The FunctionPointerWithContext to add.
00104      */
00105     pFunctionPointerWithContext_t  add(const FunctionPointerWithContext<ContextType>& func) {
00106         return common_add(new FunctionPointerWithContext<ContextType>(func));
00107     }
00108 
00109     /** 
00110      * Detach a function pointer from a callchain
00111      * 
00112      * @oaram toDetach FunctionPointerWithContext to detach from this callchain
00113      * 
00114      * @return true if a function pointer has been detached and false otherwise
00115      */ 
00116     bool detach(const FunctionPointerWithContext<ContextType>& toDetach) { 
00117         pFunctionPointerWithContext_t  current = chainHead;
00118         pFunctionPointerWithContext_t  previous = NULL;
00119 
00120         while (current) {
00121             if(*current == toDetach) { 
00122                 if(previous == NULL) {
00123                     if(currentCalled == current) { 
00124                         currentCalled = NULL;
00125                     }
00126                     chainHead = current->getNext();
00127                 } else {
00128                     if(currentCalled == current) { 
00129                         currentCalled = previous;
00130                     }
00131                     previous->chainAsNext(current->getNext());
00132                 }
00133                 delete current;
00134                 return true;
00135             }
00136 
00137             previous = current;
00138             current = current->getNext();
00139         }
00140 
00141         return false;
00142     }
00143 
00144     /** Clear the call chain (remove all functions in the chain).
00145      */
00146     void clear(void) {
00147         pFunctionPointerWithContext_t  fptr = chainHead;
00148         while (fptr) {
00149             pFunctionPointerWithContext_t  deadPtr = fptr;
00150             fptr = deadPtr->getNext();
00151             delete deadPtr;
00152         }
00153 
00154         chainHead = NULL;
00155     }
00156 
00157     bool hasCallbacksAttached(void) const {
00158         return (chainHead != NULL);
00159     }
00160 
00161     /** Call all the functions in the chain in sequence
00162      */
00163     void call(ContextType context) {
00164         ((const CallChainOfFunctionPointersWithContext*) this)->call(context);
00165     }
00166 
00167     /**
00168      * @brief same as above but const 
00169      */
00170     void call(ContextType context) const {
00171         currentCalled = chainHead;
00172 
00173         while(currentCalled) { 
00174             currentCalled->call(context);
00175             // if this was the head and the call removed the head
00176             if(currentCalled == NULL) { 
00177                 currentCalled = chainHead;
00178             } else {
00179                 currentCalled = currentCalled->getNext();
00180             }
00181         }
00182     }
00183 
00184     /**
00185      * @brief same as above but with function call operator
00186      * \code
00187      * 
00188      * void first(bool);
00189      * void second(bool);
00190      * 
00191      * CallChainOfFunctionPointerWithContext<bool> foo;
00192      * 
00193      * foo.attach(first);
00194      * foo.attach(second);
00195      * 
00196      * // call the callchain like a function
00197      * foo(true);
00198      * 
00199      * \endcode
00200      */
00201     void operator()(ContextType context) const {
00202         call(context);
00203     }
00204 
00205     /**
00206      * @brief bool conversion operation
00207      */
00208     bool toBool() const {
00209         return chainHead != NULL;
00210     }
00211 
00212 private:
00213     pFunctionPointerWithContext_t common_add(pFunctionPointerWithContext_t pf) {
00214         if (chainHead == NULL) {
00215             chainHead = pf;
00216         } else {
00217             pf->chainAsNext(chainHead);
00218             chainHead = pf;
00219         }
00220 
00221         return chainHead;
00222     }
00223 
00224 private:
00225     pFunctionPointerWithContext_t chainHead;
00226     // iterator during a function call, this has to be mutable because the call function is const.
00227     // Note: mutable is the correct behaviour here, the iterator never leak outside the object.
00228     // So the object can still be seen as logically const even if it change its internal state
00229     mutable pFunctionPointerWithContext_t currentCalled;
00230 
00231 
00232     /* Disallow copy constructor and assignment operators. */
00233 private:
00234     CallChainOfFunctionPointersWithContext(const CallChainOfFunctionPointersWithContext &);
00235     CallChainOfFunctionPointersWithContext & operator = (const CallChainOfFunctionPointersWithContext &);
00236 };
00237 
00238 #endif