BLE_API

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 template <typename ContextType>
00059 class CallChainOfFunctionPointersWithContext : public SafeBool<CallChainOfFunctionPointersWithContext<ContextType> > {
00060 public:
00061     /**
00062      * The type of each callback in the callchain.
00063      */
00064     typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t;
00065 
00066 public:
00067     /**
00068      * Create an empty chain.
00069      */
00070     CallChainOfFunctionPointersWithContext() : chainHead(NULL) {
00071         /* empty */
00072     }
00073 
00074     virtual ~CallChainOfFunctionPointersWithContext() {
00075         clear();
00076     }
00077 
00078     /**
00079      * Add a function at the front of the chain.
00080      *
00081      * @param[in]  function
00082      *              A pointer to a void function.
00083      *
00084      * @return  The function object created for @p function.
00085      */
00086     pFunctionPointerWithContext_t  add(void (*function)(ContextType context)) {
00087         return common_add(new FunctionPointerWithContext<ContextType>(function));
00088     }
00089 
00090     /**
00091      * Add a function at the front of the chain.
00092      *
00093      * @param[in] tptr
00094      *              Pointer to the object to call the member function on.
00095      * @param[in] mptr
00096      *              Pointer to the member function to be called.
00097      *
00098      * @return  The function object created for @p tptr and @p mptr.
00099      */
00100     template<typename T>
00101     pFunctionPointerWithContext_t  add(T *tptr, void (T::*mptr)(ContextType context)) {
00102         return common_add(new FunctionPointerWithContext<ContextType>(tptr, mptr));
00103     }
00104 
00105     /**
00106      * Add a function at the front of the chain.
00107      *
00108      * @param[in] func
00109      *              The FunctionPointerWithContext to add.
00110      *
00111      * @return  The function object created for @p func.
00112      */
00113     pFunctionPointerWithContext_t  add(const FunctionPointerWithContext<ContextType>& func) {
00114         return common_add(new FunctionPointerWithContext<ContextType>(func));
00115     }
00116 
00117     /**
00118      * Detach a function pointer from a callchain.
00119      *
00120      * @param[in] toDetach
00121      *              FunctionPointerWithContext to detach from this callchain.
00122      *
00123      * @return true if a function pointer has been detached and false otherwise.
00124      *
00125      * @note It is safe to remove a function pointer while the chain is
00126      *       traversed by call(ContextType).
00127      */
00128     bool detach(const FunctionPointerWithContext<ContextType>& toDetach) {
00129         pFunctionPointerWithContext_t  current = chainHead;
00130         pFunctionPointerWithContext_t  previous = NULL;
00131 
00132         while (current) {
00133             if(*current == toDetach) {
00134                 if(previous == NULL) {
00135                     if(currentCalled == current) {
00136                         currentCalled = NULL;
00137                     }
00138                     chainHead = current->getNext();
00139                 } else {
00140                     if(currentCalled == current) {
00141                         currentCalled = previous;
00142                     }
00143                     previous->chainAsNext(current->getNext());
00144                 }
00145                 delete current;
00146                 return true;
00147             }
00148 
00149             previous = current;
00150             current = current->getNext();
00151         }
00152 
00153         return false;
00154     }
00155 
00156     /**
00157      * Clear the call chain (remove all functions in the chain).
00158      */
00159     void clear(void) {
00160         pFunctionPointerWithContext_t  fptr = chainHead;
00161         while (fptr) {
00162             pFunctionPointerWithContext_t  deadPtr = fptr;
00163             fptr = deadPtr->getNext();
00164             delete deadPtr;
00165         }
00166 
00167         chainHead = NULL;
00168     }
00169 
00170     /**
00171      * Check whether the callchain contains any callbacks.
00172      *
00173      * @return true if the callchain is not empty and false otherwise.
00174      */
00175     bool hasCallbacksAttached(void) const {
00176         return (chainHead != NULL);
00177     }
00178 
00179     /**
00180      * Call all the functions in the chain in sequence.
00181      */
00182     void call(ContextType context) {
00183         ((const CallChainOfFunctionPointersWithContext*) this)->call(context);
00184     }
00185 
00186     /**
00187      * Same as call() above, but const.
00188      */
00189     void call(ContextType context) const {
00190         currentCalled = chainHead;
00191 
00192         while(currentCalled) {
00193             currentCalled->call(context);
00194             // if this was the head and the call removed the head
00195             if(currentCalled == NULL) {
00196                 currentCalled = chainHead;
00197             } else {
00198                 currentCalled = currentCalled->getNext();
00199             }
00200         }
00201     }
00202 
00203     /**
00204      * Same as call(), but with function call operator.
00205      * @code
00206      *
00207      * void first(bool);
00208      * void second(bool);
00209      *
00210      * CallChainOfFunctionPointerWithContext<bool> foo;
00211      *
00212      * foo.attach(first);
00213      * foo.attach(second);
00214      *
00215      * // call the callchain like a function
00216      * foo(true);
00217      *
00218      * @endcode
00219      */
00220     void operator()(ContextType context) const {
00221         call(context);
00222     }
00223 
00224     /**
00225      * Bool conversion operation.
00226      *
00227      * @return true if the callchain is not empty and false otherwise.
00228      */
00229     bool toBool() const {
00230         return chainHead != NULL;
00231     }
00232 
00233 private:
00234     /**
00235      * Add a callback to the head of the callchain.
00236      *
00237      * @return A pointer to the head of the callchain.
00238      */
00239     pFunctionPointerWithContext_t common_add(pFunctionPointerWithContext_t pf) {
00240         if (chainHead == NULL) {
00241             chainHead = pf;
00242         } else {
00243             pf->chainAsNext(chainHead);
00244             chainHead = pf;
00245         }
00246 
00247         return chainHead;
00248     }
00249 
00250 private:
00251     /**
00252      * A pointer to the first callback in the callchain or NULL if the callchain is empty.
00253      */
00254     pFunctionPointerWithContext_t chainHead;
00255 
00256     /**
00257      * Iterator during a function call, this has to be mutable because the call function is const.
00258      *
00259      * @note Mutable is the correct behaviour here, the iterator never leaks outside the object.
00260      *       so the object can still be seen as logically const even if it is modified.
00261      */
00262     mutable pFunctionPointerWithContext_t currentCalled;
00263 
00264 
00265     /* Disallow copy constructor and assignment operators. */
00266 private:
00267     CallChainOfFunctionPointersWithContext(const CallChainOfFunctionPointersWithContext &);
00268     CallChainOfFunctionPointersWithContext & operator = (const CallChainOfFunctionPointersWithContext &);
00269 };
00270 
00271 #endif