Logo Search packages:      
Sourcecode: qbankmanager version File versions  Download package

refpointer.h

/***************************************************************************
 $RCSfile: refpointer.h,v $
                             -------------------
    cvs         : $Id: refpointer.h,v 1.3 2005/02/21 00:27:35 aquamaniac Exp $
    begin       : Tue Dec 13 2001
    copyright   : (C) 2001 by Martin Preuss
    email       : martin@aquamaniac.de

 ***************************************************************************
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Lesser General Public            *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 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     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
 *   MA  02111-1307  USA                                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef REFPOINTER_H
#define REFPOINTER_H

/** @file pointer.h
 *
 * @short Smart pointer RefPointer with helper classes. No C wrappers.*/

#include <assert.h>
#include <gwenhywfar/debug.h>

#ifdef __cplusplus
#include <stdio.h> /* DEBUG */
#include <string>


class RefPointerBase;
class RefPointerObject;
template <class T> class RefPointerCastBase;
template <class T, class U> class RefPointerCast;

#ifndef DOXYGEN_HIDE

/**
 * This internal class is created by RefPointer. It holds the real pointer
 * and an usage counter. You can neither create nor destroy such an object.
 * @author Martin Preuss<martin@aquamaniac.de>
 */
class RefPointerObject {
    friend class RefPointerBase;
private:
    void *_object;
    int _counter;
    bool _delete;
    std::string _descr;

    RefPointerObject(void *obj, std::string descr=""):
        _object(obj),_counter(0)
        ,_delete(true)
        ,_descr(descr){
        };
        ~RefPointerObject(){
        };

        void setDescription(std::string descr) {
              /* if (_descr.empty()) */
            _descr=descr;
        };

        const std::string &description() const {
            return _descr;
        };

public:

};


#endif /* DOXYGEN_HIDE */




/**
 * @short Base class for the smart pointer template class.
 *
 * This is the base class to be inherited by a template class. This
 * cannot be used directly.
 *
 * @author Martin Preuss<martin@aquamaniac.de> */
class RefPointerBase {
#ifndef DOXYGEN_HIDE
private:
    RefPointerObject *_ptr;
    std::string _descr;

protected:
    void _attach(RefPointerObject &p) {
      _ptr=&p;
      if (_ptr) {
        _ptr->_counter++;
        if (_descr.empty())
          _descr=_ptr->_descr;
      }
      else {
        DBG_ERROR(0, "Pointer::_attach(&): No object for %s (%s)",
                  _descr.c_str(),objectDescription().c_str());
        abort();
      }
    };

    void _attach(RefPointerObject *p) {
        _ptr=p;
        if (_ptr) {
            _ptr->_counter++;
            if (_descr.empty())
                _descr=_ptr->_descr;
        }
        else {
          DBG_ERROR(0, "Pointer::_attach(*): No object for %s",
                    _descr.c_str());
          abort();
        }
    };

    void _detach() {
        if (_ptr) {
            if (_ptr->_counter>0) {
                _ptr->_counter--;
                if (_ptr->_counter<1) {
                if (_ptr->_delete)
                  if (_ptr->_object)
                      _deleteObject(_ptr->_object);
                delete _ptr;
            }
          }
      }
      _ptr=0;
    };

    /**
     * This frees the object pointed to by this pointer, regardless of
     * the state of the autoDelete flag. You should use this instead of
     * setting the autodelete flag and deleting the object yourself, because
     * in that case the program might simply crash, if any other pointer tries
     * to use the object. By using this method here you would get an exception
     * which could tell you more about the cause of the crash.
     */
    void _release() {
      if (_ptr) {
      if (_ptr->_delete) {
        if (_ptr->_object)
          _deleteObject(_ptr->_object);
      }
      _ptr->_object=0;
      }
    };

    /**
     * This method actually deletes the object. Since the base class
     * does not know the type of this object, we have to make this method
     * virtual. The template class MUST override this.
     */
    virtual void _deleteObject(void *p) {
    };

    RefPointerBase(RefPointerBase &p): _ptr(0) {
      _descr=p._descr;
      if (p._ptr)
        _attach(p._ptr);
    };

    RefPointerBase(const RefPointerBase &p) : _ptr(0) {
      _descr=p._descr;
        if (p._ptr)
            _attach(p._ptr);
    };

  /**
   * This operator handles the case where you give another pointer as argument.
   * (like pointer1=pointer2).
   * @author Martin Preuss<martin@aquamaniac.de>
   */
    void operator=(RefPointerBase &p) {
        _detach();
        if (_descr.empty())
            _descr=p._descr;
        if (p._ptr)
            _attach(p._ptr);
    };

    void operator=(const RefPointerBase &p) {
        _detach();
        if (_descr.empty())
            _descr=p._descr;
        if (p._ptr)
            _attach(p._ptr);
    };

    /**
     * This operator handles the case where you do something like this:<BR>
     * pointer=new structXYZ;<BR>
     * @author Martin Preuss<martin@aquamaniac.de>
     */
    void operator=(void* obj) {
        RefPointerObject *p;
        if (_ptr)
            _detach();
        _ptr=0;
        if (obj==0)
            return;
        p=new RefPointerObject(obj,_descr);
        _attach(p);
    };

    /**
     * Constructor.
     */
    RefPointerBase(): _ptr(0) {};

    RefPointerBase(void *obj): _ptr(0) {
        RefPointerObject *p;
        p=new RefPointerObject(obj,_descr);
        _attach(p);
    };
#endif /* DOXYGEN_HIDE */

public:
    /**
     * Destructor.
     * If this one gets called, it automagically decrements the usage
     * counter of the object pointed to. If it reaches zero, then no other
     * pointer points to the object and the object faces deletion.
     * @author Martin Preuss<martin@aquamaniac.de>
     */
    virtual ~RefPointerBase() {
    };

    /**
     *  Set the description of this pointer. 
     *
     * Useful for debugging purposes.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    void setDescription(std::string descr) {
        _descr=descr;
    };

    /**
     *  Get the description of this pointer.
     *
     * Useful for debugging purposes.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    const std::string &description() const {
        return _descr;
    };

    /**
     *  Set the description of the object this pointer points to.
     *
     * Useful for debugging purposes.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    void setObjectDescription(std::string descr) {
        if (!descr.empty())
            if (_ptr)
                _ptr->setDescription(descr);
    };

    /**
     *  Returns the description of the object. 
     *
     * Useful for debugging purposes.
     * @author Martin Preuss<martin@libchipcard.de>
     */
    std::string objectDescription() const {
        if (_ptr)
            return _ptr->description();
        else
            return "";
    };

    virtual int refCount() const {
      if (_ptr)
      return _ptr->_counter;
      else
      return -1;
    };

    /**
     *  Equality operator for the object pointed to.
     *
     * This operator checks whether another pointer and this one are
     * pointing to the same data.
     *
     * @author Martin Preuss<martin@aquamaniac.de> */
    bool operator==(const RefPointerBase &p) const {
        if (_ptr && p._ptr)
            return _ptr->_object==p._ptr->_object;
        else
            return false;
    };

    /**
     *  Checks whether both pointers share their data object.
     *
     * @author Martin Preuss<martin@aquamaniac.de>
     */
    bool sharingData(const RefPointerBase &p) const {
        return (_ptr==p._ptr);
    };

    /**
     *  Inequality operator for the object pointed to.
     *
     * This operator checks whether another pointer and this one are
     * not pointing to the same data.
     *
     * @author Martin Preuss<martin@aquamaniac.de> */
    bool operator!=(const RefPointerBase &p) const {
        if (_ptr && p._ptr)
            return _ptr->_object!=p._ptr->_object;
        else
            return true;
    };

    /**
     *  Returns a raw pointer to the stored data. 
     *
     * You should not really use this, but if you do so please NEVER
     * delete the object the pointer points to !  AND you should make
     * sure that as long as you are using the pointer returned there
     * is still a RefPointer pointing to it (because if the last RefPointer
     * stops pointing to an object that object gets deleted) !!
     *
     * @author Martin Preuss<martin@aquamaniac.de> */
    virtual void* voidptr() const {
        if (!_ptr)
            return 0;
        if (!(_ptr->_object))
            return 0;
        return _ptr->_object;
    };


    /** 
     *  Set the auto-deletion behaviour.
     * 
     * Set the auto-deletion behaviour of the RefPointerObject (the
     * wrapper object around the "real" object pointed to) that is
     * pointed to by this RefPointer.
     *
     * By default, this is set to setAutoDeletion(true), i.e. the
     * object will automatically be deleted when its last
     * RefPointer gets deleted. On the other hand, when you call
     * this with b=false, then the object this pointer points to will
     * not be deleted by the last RefPointer.
     *
     * This might be useful if you are pointing to constant objects,
     * or if you need to continue using this object through raw
     * pointers elsewhere.
     * 
     * This flag is a property of the RefPointerObject, i.e. even for
     * multiple RefPointer's pointing to the same object there is
     * only *one* autoDelete flag per object. Changes to this flag
     * affect all of the RefPointer's at the same time.
     *
     * This RefPointer MUST already point to an object (a NULL
     * pointer is not allowed at this point) since the autodelete flag
     * is a property of the class RefPointerObject. If called on an
     * invalid RefPointer, this method will abort()
     *
     * @param b True to set automatic deletion to be enabled, 
     * false to disable it.
     * @author Martin Preuss<martin@aquamaniac.de> */
    void setAutoDelete(bool b) {
      if (_ptr) {
        if (_ptr->_object)
          _ptr->_delete=b;
      }
      else {
        DBG_ERROR(0, "No object in pointer (%s)",
                  description().c_str());
        abort();
      }
    };

    /**
     *  Returns true if this RefPointer is valid.
     *
     * This tells you if this pointer is pointing to accessible data.
     * @author Martin Preuss<martin@aquamaniac.de>
     * @return true if data is accessible, false if no data
     */
    bool isValid() const {
        if (_ptr)
            if (_ptr->_object)
                return true;
        return false;
    };


};


/**
 * @short A smart pointer template class.
 *
 * This class serves as a smart pointer class that is used
 * to avoid memory leaks. It does automatic reference counting for the
 * objects pointed to, like so: Each time a new RefPointer to the same
 * object is created, the reference counter is incremented. Each time
 * a RefPointer to an object is deleted, the reference counter is
 * decremented. When the reference counter reaches zero, the object is
 * deleted.
 *
 * Use it instead of normal pointers, for example:
 * instead of 
 *
 * <code>structXYZ *pointer; <BR>
 * pointer = new structXYZ; </code>
 *
 * use this one:
 *
 * <code>Pointer<structXYZ> pointer; <BR>
 * pointer = new structXYZ; </code>
 *
 * You can access the data easily by using the "*" operator, e.g:
 *
 * <code>structXYZ xyz = *pointer;</code> 
 * 
 * To access members of the object, either use the "*" operator or the
 * ref() method:
 *
 * <code>a = (*pointer).a; </code> or<br>
 * <code>b = pointer.ref().a;</code>
 *
 * @author Martin Preuss<martin@aquamaniac.de> */
template <class T> class RefPointer: public RefPointerBase {
    friend class RefPointerCastBase<T>;
private:
protected:
    /**
     * This method actually deletes the object. Since the base class
     * does not know the type of this object, we have to make this method
     * virtual. The template class MUST override this.
     */
    virtual void _deleteObject(void *p) {
        delete (T*) p;
    };

    RefPointer(const RefPointerBase &p): RefPointerBase(p) {
    };

public:
    /**
     *  Empty Constructor.
     */
    RefPointer(): RefPointerBase(){};

    /**
     *  Constructor with object to be pointing to.
     */
    RefPointer(T *obj): RefPointerBase(obj) {
    };

    /**  Copy constructor */
    RefPointer(const RefPointer<T> &p) : RefPointerBase(p) {
    };

    /**
     *  Destructor.
     *
     * If this one gets called, it automagically decrements the usage
     * counter of the object pointed to. If it reaches zero, then no other
     * pointer points to the object and the object will be deleted.
     * @author Martin Preuss<martin@aquamaniac.de>
     */
    virtual ~RefPointer() {
        _detach();
    };

    /** @name Copy Operators */
    /*@{*/
    /**
     *  Copy operator with object pointed to.
     *
     * This operator handles the case where you do something like this:<BR>
     * pointer=new structXYZ;<BR>
     * @author Martin Preuss<martin@aquamaniac.de>
     */
    void operator=(T* obj) {
        RefPointerBase::operator=(obj);
    };

    /**
     *  Copy operator with another RefPointer.
     *
     * This operator handles the case where you give another pointer
     * as argument.  (like pointer1=pointer2).
     *
     * @author Martin Preuss<martin@aquamaniac.de> */
    void operator=(RefPointer<T> &p) {
        RefPointerBase::operator=(p);
    };

    /**
     *  Copy operator with another const RefPointer.
     *
     * This operator handles the case where you give another pointer
     * as argument.  (like pointer1=pointer2).
     *
     * @author Martin Preuss<martin@aquamaniac.de> */
    void operator=(const RefPointer<T> &p) {
        RefPointerBase::operator=(p);
    };

    /**
     * Compare operator.
     */
    bool operator<(const RefPointer<T> &p) {
      return (ref()<p.ref());
    };


    /*@}*/

    /** @name Object Access */
    /*@{*/
    /**
     *  Returns a reference to the object pointed to.
     *
     * If the RefPointer is invalid, abort.
     */
    T& ref() const {
        T* p;

      p=ptr();
        assert(p);
      if (!p) {
          DBG_ERROR(0, "No object in pointer (%s)",
                    description().c_str());
          abort();
        }

        return *p;
    };

    /**
     *  Returns a reference to the object pointed to.
     *
     * If the RefPointer is invalid, this aborts.
     */
    T& operator*() const {
        return ref();
    };

    /**  Returns a raw pointer to the stored data. 
     *
     * If you can continue using only RefPointer's, you should not
     * really need to use this. This method is necessary if and only
     * if you need to use a "raw C pointer" of the object pointed to.
     *
     * So if you need to use this method while there is still a
     * RefPointer pointing to it, please <i>never</i> delete the object
     * returned. The last remaining RefPointer's will take care of
     * deletion.
     *
     * On the other hand, if you need to use this pointer longer than
     * the last RefPointer would exist, then either try to keep a RefPointer
     * around long enough, or you need to consider setting
     * RefPointerBase::setAutoDelete appropriately. (Because if the last
     * RefPointer stops pointing to an object, then that object will get
     * deleted unless RefPointerBase::setAutoDelete was changed.)
     *
     * @author Martin Preuss<martin@aquamaniac.de> */
    virtual T* ptr() const {
        return (T*)RefPointerBase::voidptr();
    };

    virtual int refCount() const {
      return RefPointerBase::refCount();
    }

    /**
     * This frees the object pointed to by this pointer, regardless of
     * the state of the autoDelete flag. You should use this instead of
     * setting the autodelete flag and deleting the object yourself, because
     * in that case the program might simply crash, if any other pointer tries
     * to use the object. By using this method here you would get an exception
     * which could tell you more about the cause of the crash.
     */
    void release() {
      RefPointerBase::_release();
    };

    /*@}*/

    /** @name Type cast */
    /*@{*/
    /**
     * @short Returns a type-safe casted RefPointer of the given type.
     *
     * This method returns a type-safe casted RefPointer of the given
     * type.  This obeys the same rules as a
     * <code>dynamic_cast<TARGET_TYPE></code>, and in fact internally
     * a <code>dynamic_cast</code> is used.
     *
     * Use it like this:
     * <pre>
     * class type_X;
     * class type_Y : public type_X;
     *
     * RefPointer<type_X> pX;
     * RefPointer<type_Y> pY = new type_Y;
     * pX = pY.cast<type_X>();
     * </pre>
     *
     * The casting fails if it is impossibe to safely cast the
     * "type_Y" to "type_X". In that case, abort() will be called.
     * (also if you call this method on an invalid
     * RefPointer)
     *
     * @author Martin Preuss<martin@aquamaniac.de> */
    template <class U> RefPointer<U> cast() const {
      return RefPointerCast<U,T>::cast(*this);

    };
    /*@}*/

    /** @name Equality */
    /*@{*/
    /**
     *  Equality operator for the object pointed to.
     *
     * This operator checks whether another pointer and this one are
     * pointing to the same data.
     *
     * @author Martin Preuss<martin@aquamaniac.de> */
    bool operator==(const RefPointer<T> &p) const {
        return RefPointerBase::operator==(p);
    };

    /**
     *  Inequality operator for the object pointed to.
     *
     * This operator checks whether another pointer and this one are
     * not pointing to the same data.
     *
     * @author Martin Preuss<martin@aquamaniac.de> */
    bool operator!=(const RefPointer<T> &p) const {
        return RefPointerBase::operator!=(p);
    };

    /**
     *  Checks whether both pointers share their data object.
     *
     * This method checks whether another pointer and this one share
     * the same internal data object and thus also the same data
     * pointed to. This is a stronger condition than
     * <code>operator==</code>. This method returns true only if one
     * RefPointer has been copied to other RefPointer's. But as soon as some
     * "raw C pointers" have been assigned to different RefPointer, this
     * method would return false.  In that latter case, the
     * <code>operator==</code> would still return true, so that is why
     * the <code>operator==</code> is more likely to be useful.
     *
     * @author Martin Preuss<martin@aquamaniac.de> */
    bool sharingData(const RefPointer<T> &p) const {
        return RefPointerBase::sharingData(p);
    };
    /*@}*/

};


#ifndef DOXYGEN_HIDE

/**
 *
 */
template <class T> class RefPointerCastBase {
protected:
    RefPointerCastBase();
    ~RefPointerCastBase();

    static RefPointer<T> makePointer(const RefPointerBase &p) {
      return RefPointer<T>(p);
    };
};


/**
 * This class lets you safely cast one RefPointer to another one.
 * It will automatically perform type checking. If this class is unable to
 * cast then it aborts.
 * You can use this if you have a RefPointer for an object but
 * you need a pointer for a base object. For example:
 * <pre>
 * class BaseClass {
 *   BaseClass();
 *   ~BaseClass();
 * };
 *
 * class InheritingClass: public BaseClass {
 *   InheritingClass();
 *   ~InheritingClass();
 * };
 *
 * RefPointer<InheritingClass> pInheriting;
 * RefPointer<BaseClass> pBase;
 *
 * pInheriting=new InheritingClass();
 * pBase==PointerCast<BaseClass,InheritingClass>::cast(pInheriting);
 * </pre>
 * @author Martin Preuss<martin@libchipcard.de>
 */
template <class T, class U> class RefPointerCast
:public RefPointerCastBase<T>
{
public:
    /**
     * If the first template parameter is the base class to the second
     * template parameter then this method will cast a pointer to an
     * inheriting class into a pointer to the base class (downcast).
     * If you want just the opposite then you only need to exchange the order
     * of the template parameters (upcast).
     * @author Martin Preuss<martin@libchipcard.de>
     */
    static RefPointer<T> cast(const RefPointer<U> &u) {
        U *uo;
        T *t;
        RefPointer<T> np;

        /* check if given pointer is valid */
        if (!u.isValid()) {
          DBG_WARN(0, "Casting an invalid pointer (%s)",
                   u.description().c_str());
          return 0;
        }

        /* then try to cast the pointer */
        uo=u.ptr();
        t=dynamic_cast<T*>(uo);

      /* could we cast it ? */
        assert(t!=0);
        if (t==0) {
          /* no, throw */
          DBG_ERROR(0, "Bad cast (%s)", u.description().c_str());
          abort(t);
        }
        /* otherwise create a new pointer */
        np=makePointer(u);
        np.setDescription("Casted from "+u.description());
        return np;
    };

};

#endif /* DOXYGEN_HIDE */

#endif /* __cplusplus */
#endif /* REFPOINTER_H */


Generated by  Doxygen 1.6.0   Back to index