/*************************************************************************** * Copyright (c) 2002 Jürgen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library 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 Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ /** \file PyExport.h * \brief the python object export base class * \author Juergen Riegel * \version 0.1 * \date 5.2001 */ #ifndef BASE_PYEXPORT_H #define BASE_PYEXPORT_H // (re-)defined in pyconfig.h #if defined(_POSIX_C_SOURCE) #undef _POSIX_C_SOURCE #endif #if defined(_XOPEN_SOURCE) #undef _XOPEN_SOURCE #endif #include #ifdef FC_OS_MACOSX #undef toupper #undef tolower #undef isupper #undef islower #undef isspace #undef isalpha #undef isalnum #endif namespace Base { class PyObjectBase; /** The PyHandler class * This class is the base class of all FreeCAD classes * which exports into the python space. This class handles the * creation referencing of the python export object. * * @remark GetPyObject() returns the associated Python object to any C++ subclasses. As we cannot * determine for sure if we can increment the returned Python object from outside of GetPyObject() * we have specified that GetPyObject() does already the increment of the reference counter * if needed. * * E.g. if GetPyObject() always returns a new Python object then no increment is necessary, * because at construction time the reference counter is already set to 1. If the Python * interpreter stores this object pointer into a local variable and destroys this variable * then the reference counter gets decremented (to 0) and the object gets destroyed automatically. * In case we didn't make this specification and increment the Python object from outside once * again then the reference counter would be set to 2 and there would be no chance to destroy the * object again. * * The other case is that we have a member variable in our C++ class that holds the Python object * then we either can create this Python in the constructor or create it the first time when * GetPyObject() gets called. In the destructor then we must decrement the Python object to avoid a * memory leak while GetPyObject() then increments the Python object every time it gets called. * * @remark One big consequence of this specification is that the programmer must know whether the * Python interpreter gets the Python object or not. If the interpreter gets the object then it * decrements the counter later on when the internal variable is freed. In case the interpreter * doesn't get this object then the programmer must do the decrement on their own. * * @note To not to undermine this specification the programmer must make sure to get the Python * object always via GetPyObject(). * * @see PyHandle * @ */ // class BaseExport PyHandler //{ // public: // void IncRef(void); // void DecRef(void); // virtual ~PyHandler(); // virtual PyObjectBase *GetPyObject(void)=0; // // }; /** Python Object handle class * Using pointers on classes derived from PyObjectBase would * be potentionaly dangerous because you would have to take * care of the reference counting of python by your self. Hence * this class was designed. It takes care of references and * as long as a object of this class exists the handled class get * not destructed. That means a PyObjectBase derived object you can * only destruct by destructing all FCPyHandle and all python * references on it! * @see PyObjectBase */ template class PyHandle // NOLINT { public: //************************************************************************** // construction destruction /** pointer and default constructor * the good way would be not using pointer * instead using a overwritten new operator in the * HandledType class! But is not easy to enforce! */ PyHandle(HandledType* ToHandle = 0L) : _pHandles(ToHandle) { if (_pHandles) { _pHandles->IncRef(); } } /// Copy constructor PyHandle(const PyHandle& ToHandle) : _pHandles(ToHandle._pHandles) { if (_pHandles) { _pHandles->IncRef(); } } /** destructor * Release the reference count which cause, * if was the last one, the referenced object to * destruct! */ ~PyHandle() { if (_pHandles) { _pHandles->DecRef(); } } //************************************************************************** // operator implementation // assign operator from a pointer PyHandle& operator=(/*const*/ HandledType* other) { if (_pHandles) { _pHandles->DecRef(); } // FIXME: Should be without "->_pHandles", shouldn't it? (Werner) _pHandles = other; //_pHandles = other->_pHandles; if (_pHandles) { _pHandles->IncRef(); } return *this; } // assign operator from a handle PyHandle& operator=(const PyHandle& other) { if (_pHandles) { _pHandles->DecRef(); } _pHandles = other._pHandles; if (_pHandles) { _pHandles->IncRef(); } return *this; } /// dereference operators HandledType& operator*() { return *_pHandles; } /// dereference operators HandledType* operator->() { return _pHandles; } /// dereference operators const HandledType& operator*() const { return _pHandles; } /// dereference operators const HandledType* operator->() const { return _pHandles; } /** lower operator * needed for sorting in maps and sets */ bool operator<(const PyHandle& other) const { // return _pHandles<&other; // FIXME: Shouldn't we compare both pointers?. (Werner) return _pHandles < other._pHandles; } /// equal operator bool operator==(const PyHandle& other) const { // return _pHandles==&other; // FIXME: Shouldn't we compare both pointers?. (Werner) return _pHandles == other._pHandles; } /// returns the type as PyObject PyObject* getPyObject() const { // return (PyObject*) _pHandles; // FIXME: Shouldn't we return the pointer's object?. (Werner) return const_cast(_pHandles)->getPyObject(); // NOLINT } //************************************************************************** // checking on the state /// Test if it handles something bool IsValid() const { return _pHandles != 0; } /// Test if it not handles something bool IsNull() const { return _pHandles == 0; } private: /// the pointer on the handled object HandledType* _pHandles; }; } // namespace Base #endif // BASE_PYEXPORT_H