/*************************************************************************** * Copyright (C) 2012, 2013, 2014, 2105, 2106 by Terraneo Federico * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * As a special exception, if other files instantiate templates or use * * macros or inline functions from this file, or you compile this file * * and link it with other works to produce a work based on this file, * * this file does not by itself cause the resulting work to be covered * * by the GNU General Public License. However the source code for this * * file must still be made available in accordance with the GNU General * * Public License. This exception does not invalidate any other reasons * * why a work based on this file might be covered by the GNU General * * Public License. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see * ***************************************************************************/ #ifndef CALLBACK_H #define CALLBACK_H #include namespace miosix { /** * This class is to extract from Callback code that * does not depend on the template parameter N. */ class CallbackBase { protected: /** * Possible operations performed by TypeDependentOperation::operation() */ enum Op { CALL, ASSIGN, DESTROY }; /** * This class is part of the any idiom used by Callback. */ template class TypeDependentOperation { public: /** * Perform the type-dependent operations * \param a storage for the any object, stores the function object * \param b storage for the source object for the copy constructor * \param op operation */ static void operation(int32_t *a, const int32_t *b, Op op) { T *o1=reinterpret_cast(a); const T *o2=reinterpret_cast(b); switch(op) { case CALL: (*o1)(); break; case ASSIGN: //This used to be simply *o1=*o2 when we were using //tr1/functional, but in C++11 the type returned by bind //due to having a move constructor doesn't like being //assigned, only copy construction works so we have to //use placement new new (o1) T(*o2); break; case DESTROY: o1->~T(); break; } } }; }; /** * A Callback works just like an std::function, but has some additional * limitations. First, it can only accept function objects that take void * as a parameter and return void, and second if the size of the * implementation-defined type returned by bind is larger than N a * compile-time error is generated. Also, calling an empty Callback does * nothing, while doing the same on a function results in an exception * being thrown. * * The reason why one would want to use this class is because, other than the * limitations, this class also offers a guarantee: it will never allocate * data on the heap. It is not just a matter of code speed: in Miosix calling * new/delete/malloc/free from an interrupt routine produces undefined * behaviour, so this class enables binding function calls form an interrupt * safely. * * \param N the size in bytes that an instance of this class reserves to * store the function objects. If the line starting with 'typedef char check1' * starts failing it means it is time to increase this number. The size * of an instance of this object is N+sizeof(void (*)()), but with N rounded * by excess to four byte boundaries. */ template class Callback : private CallbackBase { public: /** * Default constructor. Produces an empty callback. */ Callback() : operation(0) {} /** * Constructor. Not explicit by design. * \param functor function object a copy of which is stored internally */ template Callback(T functor) : operation(0) { *this=functor; } /** * Copy constructor * \param rhs object to copy */ Callback(const Callback& rhs) { operation=rhs.operation; if(operation) operation(any,rhs.any,ASSIGN); } /** * Operator = * \param rhs object to copy * \return *this */ Callback& operator= (const Callback& rhs); /** * Assignment operation, assigns a function object to this callback. * \param funtor function object a copy of which is stored internally */ template Callback& operator= (T functor); /** * Removes any function object stored in this class */ void clear() { if(operation) operation(any,0,DESTROY); operation=0; } /** * Call the callback, or do nothing if no callback is set */ void operator() () { if(operation) operation(any,0,CALL); } /** * Call the callback, generating undefined behaviour if no callback is set */ void call() { operation(any,0,CALL); } //Safe bool idiom struct SafeBoolStruct { void* b; }; typedef void* SafeBoolStruct::* SafeBool; /** * \return true if the object contains a callback */ operator SafeBool() const { return operation==0 ? 0 : &SafeBoolStruct::b; } /** * Destructor */ ~Callback() { if(operation) operation(any,0,DESTROY); } private: /// This declaration is done like that to save memory. On 32 bit systems /// the size of a pointer is 4 bytes, but the strictest alignment is 8 /// which is that of double and long long. Using an array of doubles would /// have guaranteed alignment but the array size would have been a multiple /// of 8 bytes, and by summing the 4 bytes of the operation pointer there /// would have been 4 bytes of slack space left unused when declaring arrays /// of callbacks. Therefore any is declared as an array of ints but aligned /// to 8 bytes. This allows i.e. declaring Callback<20> with 20 bytes of /// useful storage and 4 bytes of pointer, despite 20 is not a multiple of 8 int32_t any[(N+3)/4] __attribute__((aligned(8))); void (*operation)(int32_t *a, const int32_t *b, Op op); }; template Callback& Callback::operator= (const Callback& rhs) { if(this==&rhs) return *this; //Handle assignmento to self if(operation) operation(any,0,DESTROY); operation=rhs.operation; if(operation) operation(any,rhs.any,ASSIGN); return *this; } template template Callback& Callback::operator= (T functor) { //If an error is reported about this line an attempt to store a too large //object is made. Increase N. static_assert(sizeof(any)>=sizeof(T),""); //This should not fail unless something has a stricter alignment than double static_assert(__alignof__(any)>=__alignof__(T),""); if(operation) operation(any,0,DESTROY); new (reinterpret_cast(any)) T(functor); operation=TypeDependentOperation::operation; return *this; } } //namespace miosix #endif //CALLBACK_H