LCOV - code coverage report
Current view: top level - solver/unxlngi6.pro/inc/vcl - lazydelete.hxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 42 54 77.8 %
Date: 2012-08-25 Functions: 26 36 72.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 54 112 48.2 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*************************************************************************
       3                 :            :  *
       4                 :            :  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       5                 :            :  *
       6                 :            :  * Copyright 2000, 2010 Oracle and/or its affiliates.
       7                 :            :  *
       8                 :            :  * OpenOffice.org - a multi-platform office productivity suite
       9                 :            :  *
      10                 :            :  * This file is part of OpenOffice.org.
      11                 :            :  *
      12                 :            :  * OpenOffice.org is free software: you can redistribute it and/or modify
      13                 :            :  * it under the terms of the GNU Lesser General Public License version 3
      14                 :            :  * only, as published by the Free Software Foundation.
      15                 :            :  *
      16                 :            :  * OpenOffice.org is distributed in the hope that it will be useful,
      17                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      18                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19                 :            :  * GNU Lesser General Public License version 3 for more details
      20                 :            :  * (a copy is included in the LICENSE file that accompanied this code).
      21                 :            :  *
      22                 :            :  * You should have received a copy of the GNU Lesser General Public License
      23                 :            :  * version 3 along with OpenOffice.org.  If not, see
      24                 :            :  * <http://www.openoffice.org/license.html>
      25                 :            :  * for a copy of the LGPLv3 License.
      26                 :            :  *
      27                 :            :  ************************************************************************/
      28                 :            : 
      29                 :            : #ifndef _VCL_LAZYDELETE_HXX
      30                 :            : #define _VCL_LAZYDELETE_HXX
      31                 :            : 
      32                 :            : #include "dllapi.h"
      33                 :            : 
      34                 :            : #include <vector>
      35                 :            : #include <boost/unordered_map.hpp>
      36                 :            : #include <algorithm>
      37                 :            : 
      38                 :            : #if OSL_DEBUG_LEVEL > 2
      39                 :            : #include <typeinfo>
      40                 :            : #include <stdio.h>
      41                 :            : #endif
      42                 :            : 
      43                 :            : #include <com/sun/star/lang/XComponent.hpp>
      44                 :            : 
      45                 :            : namespace vcl
      46                 :            : {
      47                 :            :     /* Helpers for lazy object deletion
      48                 :            : 
      49                 :            :     With vcl it is often necessary to delete objects (especially Windows)
      50                 :            :     in the right order as well as in a way ensuring that the deleted objects
      51                 :            :     are not still on the stack (e.g. deleting a Window in its key handler). To
      52                 :            :     make this easier a helper class is given here which takes care of both
      53                 :            :     sorting as well as lazy deletion.
      54                 :            : 
      55                 :            :     The grisly details:
      56                 :            :     LazyDelete is a class that LazyDeletor register to. When vcl's event
      57                 :            :     loop (that is Application::Yield or Application::Reschedule) comes out
      58                 :            :     of the last level, the LazyDelete::flush is called. This will cause
      59                 :            :     LazyDelete to delete all registered LazyDeletor objects.
      60                 :            : 
      61                 :            :     LazyDeletor<T> is a one instance object that contains a list of
      62                 :            :     <T> objects to be deleted in sorted order. It is derived from
      63                 :            :     LazyDeletorBase as to be able to register itself in LazyDelete.
      64                 :            : 
      65                 :            :     The user calls the static method LazyDeletor<T>::Delete( T* ) with the
      66                 :            :     object to be destroyed lazy. The static method creates the LazyDeletor<T>
      67                 :            :     (which in turn registers itself in LazyDelete) if this is the first time
      68                 :            :     a T* is to be destroyed lazy. It then inserts the object. When the LazyDeletor<T>
      69                 :            :     gets delte it will delete the stored objects in a fashion
      70                 :            :     that will ensure the correct order of deletion via the specialized is_less method
      71                 :            :     (e.g. if a Window is a child of another Window and therefore should be destroyed
      72                 :            :     first it is "less" in this sense)
      73                 :            : 
      74                 :            :     LazyDelete::flush will be called when the top of the nested event loop is
      75                 :            :     reached again and will then destroy each registered LazyDeletor<T> which
      76                 :            :     in turn destroys the objects needed to be destroyed lazily. After this
      77                 :            :     the state is as before entering the event loop.
      78                 :            : 
      79                 :            :     Preconditions:
      80                 :            :     - The class <T> of which objects are to be destroyed needs a virtual
      81                 :            :     destructor or must be final, else the wrong type will be destroyed.
      82                 :            :     - The destructor of <T> should call LazyDeletor<T>::Undelete( this ). This
      83                 :            :     prevents duplicate deletionin case someone destroys the object prematurely.
      84                 :            :     */
      85                 :            : 
      86                 :            :     class LazyDeletorBase;
      87                 :            :     class VCL_DLLPUBLIC LazyDelete
      88                 :            :     {
      89                 :            :         public:
      90                 :            :         /** flush all registered object lists
      91                 :            :         */
      92                 :            :         static void flush();
      93                 :            :         /** register an object list to be destroyed
      94                 :            :         */
      95                 :            :         static void addDeletor( LazyDeletorBase* pDeletor );
      96                 :            :     };
      97                 :            : 
      98                 :            :     class VCL_DLLPUBLIC LazyDeletorBase
      99                 :            :     {
     100                 :            :         friend void LazyDelete::flush();
     101                 :            :         protected:
     102                 :            :         LazyDeletorBase();
     103                 :            :         virtual ~LazyDeletorBase();
     104                 :            :     };
     105                 :            : 
     106                 :            :     template < typename T >
     107                 :            :     class VCL_DLLPUBLIC LazyDeletor : public LazyDeletorBase
     108                 :            :     {
     109                 :            :         static LazyDeletor< T >*     s_pOneInstance;
     110                 :            : 
     111                 :            :         struct DeleteObjectEntry
     112                 :            :         {
     113                 :            :             T*      m_pObject;
     114                 :            :             bool    m_bDeleted;
     115                 :            : 
     116                 :            :             DeleteObjectEntry() :
     117                 :            :                 m_pObject( NULL ),
     118                 :            :                 m_bDeleted( false )
     119                 :            :             {}
     120                 :            : 
     121                 :       3459 :             DeleteObjectEntry( T* i_pObject ) :
     122                 :            :                 m_pObject( i_pObject ),
     123                 :       3459 :                 m_bDeleted( false )
     124                 :       3459 :             {}
     125                 :            :         };
     126                 :            : 
     127                 :            :         std::vector< DeleteObjectEntry >    m_aObjects;
     128                 :            :         typedef boost::unordered_map< sal_IntPtr, unsigned int > PtrToIndexMap;
     129                 :            :         PtrToIndexMap                       m_aPtrToIndex;
     130                 :            : 
     131                 :            :         /** strict weak ordering funtion to bring objects to be destroyed lazily
     132                 :            :         in correct order, e.g. for Window objects children before parents
     133                 :            :         */
     134                 :            :         static bool is_less( T* left, T* right );
     135                 :            : 
     136 [ +  - ][ +  - ]:       1486 :         LazyDeletor()  { LazyDelete::addDeletor( this ); }
                 [ +  - ]
     137                 :       2874 :         virtual ~LazyDeletor()
     138                 :            :         {
     139                 :            :             #if OSL_DEBUG_LEVEL > 2
     140                 :            :             fprintf( stderr, "%s %p deleted\n",
     141                 :            :                      typeid(*this).name(), this );
     142                 :            :             #endif
     143         [ +  - ]:       1437 :             if( s_pOneInstance == this ) // sanity check
     144                 :       1437 :                 s_pOneInstance = NULL;
     145                 :            : 
     146                 :            :             // do the actual work
     147                 :       1437 :             unsigned int nCount = m_aObjects.size();
     148         [ +  - ]:       1437 :             std::vector<T*> aRealDelete;
     149         [ +  - ]:       1437 :             aRealDelete.reserve( nCount );
     150         [ +  + ]:       4547 :             for( unsigned int i = 0; i < nCount; i++ )
     151                 :            :             {
     152 [ +  - ][ +  + ]:       3110 :                 if( ! m_aObjects[i].m_bDeleted )
     153                 :            :                 {
     154 [ +  - ][ +  - ]:        162 :                     aRealDelete.push_back( m_aObjects[i].m_pObject );
     155                 :            :                 }
     156                 :            :             }
     157                 :            :             // sort the vector of objects to be destroyed
     158         [ +  - ]:       1437 :             std::sort( aRealDelete.begin(), aRealDelete.end(), is_less );
     159                 :       1437 :             nCount = aRealDelete.size();
     160         [ +  + ]:       1599 :             for( unsigned int n = 0; n < nCount; n++ )
     161                 :            :             {
     162                 :            :                 #if OSL_DEBUG_LEVEL > 2
     163                 :            :                 fprintf( stderr, "%s deletes object %p of type %s\n",
     164                 :            :                          typeid(*this).name(),
     165                 :            :                          aRealDelete[n],
     166                 :            :                          typeid(*aRealDelete[n]).name() );
     167                 :            :                 #endif
     168                 :            :                 // check if the object to be deleted is not already destroyed
     169                 :            :                 // as a side effect of a previous lazily destroyed object
     170 [ +  - ][ +  - ]:        162 :                 if( ! m_aObjects[ m_aPtrToIndex[ reinterpret_cast<sal_IntPtr>(aRealDelete[n]) ] ].m_bDeleted )
         [ +  - ][ +  - ]
     171 [ +  - ][ +  - ]:       3036 :                     delete aRealDelete[n];
         [ +  - ][ -  + ]
     172                 :            :             }
     173         [ +  - ]:       4311 :         }
     174                 :            : 
     175                 :            :         public:
     176                 :            :         /** mark an object for lazy deletion
     177                 :            :         */
     178                 :       3543 :         static void Delete( T* i_pObject )
     179                 :            :         {
     180         [ +  + ]:       3543 :             if( s_pOneInstance == NULL )
     181 [ +  - ][ +  - ]:       1486 :                 s_pOneInstance = new LazyDeletor<T>();
     182                 :            : 
     183                 :            :             // is this object already in the list ?
     184                 :            :             // if so mark it as not to be deleted; else insert it
     185         [ +  - ]:       3543 :             PtrToIndexMap::const_iterator dup = s_pOneInstance->m_aPtrToIndex.find( reinterpret_cast<sal_IntPtr>(i_pObject) );
     186 [ +  + ][ +  - ]:       3543 :             if( dup != s_pOneInstance->m_aPtrToIndex.end() )
     187                 :            :             {
     188 [ +  - ][ +  - ]:         84 :                 s_pOneInstance->m_aObjects[ dup->second ].m_bDeleted = false;
     189                 :            :             }
     190                 :            :             else
     191                 :            :             {
     192         [ +  - ]:       3459 :                 s_pOneInstance->m_aPtrToIndex[ reinterpret_cast<sal_IntPtr>(i_pObject) ] = s_pOneInstance->m_aObjects.size();
     193 [ +  - ][ +  - ]:       3459 :                 s_pOneInstance->m_aObjects.push_back( DeleteObjectEntry( i_pObject ) );
     194                 :            :             }
     195                 :       3543 :         }
     196                 :            :         /** unmark an object already marked for lazy deletion
     197                 :            :         */
     198                 :     188328 :         static void Undelete( T* i_pObject )
     199                 :            :         {
     200         [ +  + ]:     188328 :             if( s_pOneInstance )
     201                 :            :             {
     202         [ +  - ]:     111032 :                 PtrToIndexMap::const_iterator it = s_pOneInstance->m_aPtrToIndex.find( reinterpret_cast<sal_IntPtr>(i_pObject) );
     203 [ +  + ][ +  - ]:     111032 :                 if( it != s_pOneInstance->m_aPtrToIndex.end() )
     204 [ +  - ][ +  - ]:     111032 :                     s_pOneInstance->m_aObjects[ it->second ].m_bDeleted = true;
     205                 :            :             }
     206                 :     188328 :         }
     207                 :            :     };
     208                 :            : 
     209                 :            :     /*
     210                 :            :     class DeleteOnDeinit matches a similar need as LazyDelete for static objects:
     211                 :            :     you may not access vcl objects after DeInitVCL has been called this includes their destruction
     212                 :            :     therefore disallowing the existance of static vcl object like e.g. a static BitmapEx
     213                 :            :     To work around this use DeleteOnDeinit<BitmapEx> which will allow you to have a static object container,
     214                 :            :     that will have its contents destroyed on DeinitVCL. The single drawback is that you need to check on the
     215                 :            :     container object whether it still contains content before actually accessing it.
     216                 :            : 
     217                 :            :     caveat: when constructing a vcl object, you certainly want to ensure that InitVCL has run already.
     218                 :            :     However this is not necessarily the case when using a class static member or a file level static variable.
     219                 :            :     In these cases make judicious use of the set() method of DeleteOnDeinit, but beware of the changing
     220                 :            :     ownership.
     221                 :            : 
     222                 :            :     example use case: use a lazy initialized on call BitmapEx in a paint method. Of course a paint method
     223                 :            :     would not normally be called after DeInitVCL anyway, so the check might not be necessary in a
     224                 :            :     Window::Paint implementation, but always checking is a good idea.
     225                 :            : 
     226                 :            :     SomeWindow::Paint()
     227                 :            :     {
     228                 :            :         static vcl::DeleteOnDeinit< BitmapEx > aBmp( new BitmapEx( ResId( 1000, myResMgr ) ) );
     229                 :            : 
     230                 :            :         if( aBmp.get() ) // check whether DeInitVCL has been called already
     231                 :            :             DrawBitmapEx( Point( 10, 10 ), *aBmp.get() );
     232                 :            :     }
     233                 :            :     */
     234                 :            : 
     235                 :        684 :     class VCL_DLLPUBLIC DeleteOnDeinitBase
     236                 :            :     {
     237                 :            :     public:
     238                 :            :         static void SAL_DLLPRIVATE ImplDeleteOnDeInit();
     239                 :            :         virtual ~DeleteOnDeinitBase();
     240                 :            :     protected:
     241                 :            :         static void addDeinitContainer( DeleteOnDeinitBase* i_pContainer );
     242                 :            : 
     243                 :            :         virtual void doCleanup() = 0;
     244                 :            :     };
     245                 :            : 
     246                 :            :     template < typename T >
     247                 :            :     class DeleteOnDeinit : public DeleteOnDeinitBase
     248                 :            :     {
     249                 :            :         T* m_pT;
     250 [ +  + ][ +  - ]:        512 :         virtual void doCleanup() { delete m_pT; m_pT = NULL; }
     251                 :            :     public:
     252 [ +  - ][ +  - ]:        684 :         DeleteOnDeinit( T* i_pT ) : m_pT( i_pT ) { addDeinitContainer( this ); }
     253 [ -  + ][ -  + ]:        684 :         virtual ~DeleteOnDeinit() {}
     254                 :            : 
     255                 :            :         // get contents
     256                 :      46362 :         T* get() { return m_pT; }
     257                 :            : 
     258                 :            :         // set contents, returning old contents
     259                 :            :         // ownership is transfered !
     260                 :         23 :         T* set( T* i_pNew ) { T* pOld = m_pT; m_pT = i_pNew; return pOld; }
     261                 :            : 
     262                 :            :         // set contents, deleting old contents
     263                 :            :         // ownership is transfered !
     264                 :         60 :         void reset( T* i_pNew = NULL )
     265         [ -  + ]:         60 :             { OSL_ASSERT( i_pNew != m_pT || i_pNew == NULL ); T* pOld = m_pT; m_pT = i_pNew; delete pOld; }
     266                 :            :     };
     267                 :            : 
     268                 :            :     /** Similar to DeleteOnDeinit, the DeleteUnoReferenceOnDeinit
     269                 :            :         template class makes sure that a static UNO object is disposed
     270                 :            :         and released at the right time.
     271                 :            : 
     272                 :            :         Use like
     273                 :            :             static DeleteUnoReferenceOnDeinit<lang::XMultiServiceFactory>
     274                 :            :                 xStaticFactory (<create factory object>);
     275                 :            :             Reference<lang::XMultiServiceFactory> xFactory (xStaticFactory.get());
     276                 :            :             if (xFactory.is())
     277                 :            :                 <do something with xFactory>
     278                 :            :     */
     279                 :            :     template <typename I>
     280                 :            :     class DeleteUnoReferenceOnDeinit : public ::vcl::DeleteOnDeinitBase
     281                 :            :     {
     282                 :            :         ::com::sun::star::uno::Reference<I> m_xI;
     283         [ #  # ]:          0 :         virtual void doCleanup() { set(NULL); }
     284                 :            :     public:
     285                 :          0 :         DeleteUnoReferenceOnDeinit(const ::com::sun::star::uno::Reference<I>& r_xI ) : m_xI( r_xI ) {
     286         [ #  # ]:          0 :             addDeinitContainer( this ); }
     287         [ #  # ]:          0 :         virtual ~DeleteUnoReferenceOnDeinit() {}
     288                 :            : 
     289                 :          0 :         ::com::sun::star::uno::Reference<I> get (void) { return m_xI; }
     290                 :            : 
     291                 :          0 :         void set (const ::com::sun::star::uno::Reference<I>& r_xNew )
     292                 :            :         {
     293         [ #  # ]:          0 :             ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent> xComponent (m_xI, ::com::sun::star::uno::UNO_QUERY);
     294         [ #  # ]:          0 :             m_xI = r_xNew;
     295         [ #  # ]:          0 :             if (xComponent.is()) try
     296                 :            :             {
     297 [ #  # ][ #  # ]:          0 :                 xComponent->dispose();
     298                 :            :             }
     299         [ #  # ]:          0 :             catch( ::com::sun::star::uno::Exception& )
     300                 :            :             {
     301                 :            :             }
     302         [ #  # ]:          0 :         }
     303                 :            :     };
     304                 :            : }
     305                 :            : 
     306                 :            : #endif
     307                 :            : 
     308                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10