Main Page Modules Namespace List Class Hierarchy Alphabetical List Compound List File List Namespace Members Compound Members File Members Related Pages

# THandle.h

Go to the documentation of this file.

    00001 ///////////////////////////////////////////////////////////////////////////////
    00002 /// @file THANDLE.h
    00003 ///
    00004 /// @brief
    00005 ///
    00006 /// @author trajar
    00007 ///
    00008 /// This file is the intellectual property of Novus Delta, LLC.. Usage of the
    00009 /// contents of this file is subject to the Destiny3D Member License which
    00010 /// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
    00011 ///
    00012 /// This file is distributed "AS IS" without warranty of any kind.  Novus
    00013 /// Delta, LLC. does not guarantee the fitness of the contents of this file
    00014 /// for any particular purpose.
    00015 ///
    00016 /// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
    00017 ///
    00018 /// <hr>
    00019 ///                                 Change History
    00020 /// <hr>
    00021 ///
    00022 /// @date Jun 2002
    00023 /// @author trajar
    00024 /// @remarks Creation
    00025 ///
    00026 ///////////////////////////////////////////////////////////////////////////////
    00027
    00028 #ifndef _THANDLE_H
    00029 #define _THANDLE_H
    00030
    00031 #include    <assert.H>
    00032
    00033 #ifndef     _VECTOR_
    00034  #include   <vector>
    00035 #endif
    00036
    00037 #pragma warning( disable : 4786 )
    00038 #pragma warning( disable : 4285 )
    00039
    00040 #define  SAFE_DELETE(p)       { if(p) { delete (p);     (p)=NULL; } }
    00041 #define  SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
    00042 #define  SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }
    00043
    00044 typedef unsigned long DWORD;
    00045
    00046 enum EraseType
    00047 {
    00048     ERASE_UNKNOWN,
    00049     ERASE_NORMAL,
    00050     ERASE_DELETE,
    00051     ERASE_DELETE_ARRAY,
    00052     ERASE_RELEASE
    00053 };
    00054
    00055 //--------------------------------------------------
    00056 // THandleMgr
    00057 //--------------------------------------------------
    00058 template <typename DATA, typename HANDLE>
    00059 class THandleMgr
    00060 {
    00061 public:
    00062
    00063     // public types
    00064     typedef std::vector <DATA>              DataVec;
    00065     typedef std::vector <unsigned int>      MagicVec;
    00066     typedef std::vector <unsigned int>      FreeVec;
    00067     typedef std::vector <int>               RefVec;
    00068
    00069     // Lifetime.
    00070
    00071     THandleMgr( void )   {  assert(!m_Singleton);
    00072                             m_Singleton = this;
    00073                             m_EraseType = ERASE_UNKNOWN; }
    00074
    00075     ~THandleMgr( void )  { EraseEntries(); m_Singleton = NULL; }
    00076
    00077     DATA *       GetDataAt(int Index)              { return (m_UserData.begin() + Index); }
    00078     void         SetEraseMethod( EraseType pType ) { assert(pType != ERASE_UNKNOWN); m_EraseType = pType; }
    00079     unsigned int GetUsedHandleCount( void ) const  {  return ( m_MagicNumbers.size() - m_FreeSlots.size() );  }
    00080     bool         HasUsedHandles( void ) const      {  return ( !!GetUsedHandleCount() );  }
    00081
    00082     //-----------------------------------------------------------------
    00083     // AddReference( HANDLE& )
    00084     //
    00085     // - adds a references to a handle
    00086     // - returns the current reference count
    00087     //-----------------------------------------------------------------
    00088     int     AddReference( HANDLE& pHandle )
    00089             {
    00090                 if( !pHandle.IsNull() )
    00091                 {
    00092                     unsigned int index = pHandle.GetIndex();
    00093
    00094                     if( (index < m_UserData.size()) ||
    00095                         (m_MagicNumbers[ index ] == pHandle.GetMagic()) )
    00096                     {
    00097                         int&     count = m_References[index];
    00098                         return   count++;
    00099                     }
    00100                     else
    00101                         return -1;
    00102                 }
    00103                 else
    00104                     return -1;
    00105             }
    00106
    00107     //-----------------------------------------------------------------
    00108     // ReleaseReference( HANDLE& )
    00109     //
    00110     // - releases a reference to a handle
    00111     // - if no more references are found, the in release the handle
    00112     // - returns the current reference count
    00113     //-----------------------------------------------------------------
    00114     int     ReleaseReference( HANDLE& pHandle )
    00115             {
    00116                 if( !pHandle.IsNull() )
    00117                 {
    00118                     unsigned int index = pHandle.GetIndex();
    00119                              int& count = m_References[index];
    00120
    00121                      if(    (index < m_UserData.size()) ||
    00122                          (m_MagicNumbers[ index ] == pHandle.GetMagic()) )
    00123                      {
    00124                         count--;
    00125                         if( count == 0 )  // release it
    00126                         {
    00127                             Release(pHandle);
    00128                             pHandle = HANDLE();
    00129                             m_References[index] = -1;
    00130                             return 0;
    00131                         }
    00132                         else
    00133                             return count;
    00134                      }
    00135                      else
    00136                          return -1;
    00137                 }
    00138                 else
    00139                     return -1;
    00140             }
    00141
    00142     //-----------------------------------------------------------------
    00143     // DATA * Acquire( HANDLE& )
    00144     //
    00145     // Adds/returns handle AND address of data
    00146     //
    00147     // * NOTE * if data is a ptr, changing it will not
    00148     //          change the data in this mgr
    00149     //-----------------------------------------------------------------
    00150     DATA*   Acquire( HANDLE& handle )
    00151             {
    00152                 assert( !handle.IsNull() );
    00153
    00154                 // if free list is empty, add a new one otherwise use first one found
    00155
    00156                 unsigned int index;
    00157                 if ( m_FreeSlots.empty() )
    00158                 {
    00159                     index = m_MagicNumbers.size();
    00160                     handle.Init( index );
    00161                     m_UserData.push_back( DATA() );
    00162                     m_References.push_back(1);
    00163                     m_MagicNumbers.push_back( handle.GetMagic() );
    00164                 }
    00165                 else
    00166                 {
    00167                     index = m_FreeSlots.back();
    00168                     handle.Init( index );
    00169                     m_References[ index ] = 1;
    00170                     m_FreeSlots.pop_back();
    00171                     m_MagicNumbers[ index ] = handle.GetMagic();
    00172                 }
    00173                 return ( m_UserData.begin() + index );
    00174             }
    00175
    00176     //-----------------------------------------------------------------
    00177     // bool AddItem( HANDLE, const DATA )
    00178     //
    00179     // Adds a data item to the manager and returns the handle
    00180     //      - returns true if successful
    00181     //-----------------------------------------------------------------
    00182     DATA *  AddItem( HANDLE& handle, const DATA& data )
    00183             {
    00184                 bool bOK = false;
    00185                 // if free list is empty, add a new one otherwise use first one found
    00186
    00187                 unsigned int index;
    00188                 if ( m_FreeSlots.empty() )
    00189                 {
    00190                     index = m_MagicNumbers.size();
    00191                     handle.Init( index );
    00192                     m_UserData.push_back( data );
    00193                     m_References.push_back(1);
    00194                     m_MagicNumbers.push_back( handle.GetMagic() );
    00195                     bOK = true;
    00196                 }
    00197                 else
    00198                 {
    00199                     index = m_FreeSlots.back();
    00200                     handle.Init( index );
    00201                     m_FreeSlots.pop_back();
    00202                     m_References[ index ] = 1;
    00203                     m_MagicNumbers[ index ] = handle.GetMagic();
    00204                     m_UserData[ index ] = data;
    00205                     bOK = true;
    00206                 }
    00207
    00208                 m_References[index] = 1;
    00209
    00210                 return ( m_UserData.begin() + index );
    00211             }
    00212
    00213     //-----------------------------------------------------------------
    00214     // Release( HANDLE  handle )
    00215     //-----------------------------------------------------------------
    00216     void    Release( HANDLE&  handle )
    00217             {
    00218                 // which one?
    00219                 unsigned int index = handle.GetIndex();
    00220
    00221                 if( handle.IsNull() )
    00222                     return;
    00223
    00224                 // make sure it's valid
    00225                 if( (index < m_UserData.size()) ||
    00226                     (m_MagicNumbers[ index ] == handle.GetMagic()) )
    00227                 {
    00228                     assert( m_EraseType != ERASE_UNKNOWN );
    00229
    00230                     // clear up the numbers before we delete/release
    00231                     m_MagicNumbers[ index ] = 0;
    00232                     m_References[ index ] = -1;
    00233                     m_FreeSlots.push_back( index );
    00234                     handle = HANDLE();
    00235
    00236                     // ok remove it - tag as unused and add to free list
    00237                     switch( m_EraseType )
    00238                     {
    00239                     case ERASE_DELETE:
    00240                         //SAFE_DELETE(m_UserData[index]);
    00241                         assert(false);
    00242                         break;
    00243
    00244                     case ERASE_DELETE_ARRAY:
    00245                         //SAFE_DELETE_ARRAY(m_UserData[index]);
    00246                         assert(false);
    00247                         break;
    00248
    00249                     case ERASE_RELEASE:
    00250                         assert(false);
    00251                         break;
    00252                     }
    00253                 }
    00254                 else
    00255                 {
    00256                     assert( false );
    00257                 }
    00258             }
    00259
    00260     //-----------------------------------------------------------------
    00261     // DATA *   GetData( HANDLE handle )
    00262     //
    00263     // dereferencing
    00264     //-----------------------------------------------------------------
    00265     DATA *  GetData( HANDLE handle )
    00266             {
    00267                 assert( !handle.IsNull() );
    00268
    00269                 if ( handle.IsNull() )  return ( 0 );
    00270
    00271                 unsigned int index = handle.GetIndex();
    00272
    00273             #if _DEBUG
    00274                 // check handle validity - $ this check can be removed for speed
    00275                 // if you can assume all handle references are always valid.
    00276                 if (   ( index >= m_UserData.size() )
    00277                     || ( m_MagicNumbers[ index ] != handle.GetMagic() ) )
    00278                 {
    00279                     // no good! invalid handle == client programming error
    00280                     return ( 0 );
    00281                 }
    00282             #endif
    00283
    00284                 return ( m_UserData.begin() + index );
    00285             }
    00286
    00287     //-----------------------------------------------------------------
    00288     // const DATA * GetData( HANDLE handle ) const
    00289     //
    00290     // dereferencing
    00291     //-----------------------------------------------------------------
    00292     const DATA* GetData( HANDLE handle ) const
    00293             {
    00294                 // this lazy cast is ok - non-const version does not modify anything
    00295                 return ( const_cast<THandleMgr<DATA, HANDLE>*> ( this )->GetData( handle ) );
    00296             }
    00297
    00298     //-----------------------------------------------------------------
    00299     // EraseEntries(void)
    00300     //-----------------------------------------------------------------
    00301     void    EraseEntries(void)
    00302             {
    00303                 int i = 0;
    00304                 int cnt = m_UserData.size();
    00305
    00306                 assert( m_EraseType != ERASE_UNKNOWN );
    00307
    00308                 switch( m_EraseType )
    00309                 {
    00310                 case ERASE_DELETE:
    00311                     //for( i=0; i<cnt; i++ )
    00312                     //  SAFE_DELETE(m_UserData[i]);
    00313                     assert(false);
    00314                     break;
    00315
    00316                 case ERASE_DELETE_ARRAY:
    00317                     //for( i=0; i<cnt; i++ )
    00318                     //  SAFE_DELETE_ARRAY(m_UserData[i]);
    00319                     assert(false);
    00320                     break;
    00321
    00322                 case ERASE_RELEASE:
    00323                     //for( i=0; i<cnt; i++ )
    00324                     //  SAFE_RELEASE(m_UserData[i]);
    00325                     assert(false);
    00326                     break;
    00327                 }
    00328
    00329                 m_UserData.clear();
    00330                 m_MagicNumbers.clear();
    00331                 m_FreeSlots.clear();
    00332                 m_References.clear();
    00333             }
    00334
    00335     static THandleMgr<DATA, HANDLE> * GetHandleMgr(void) {  //assert(m_Singleton);
    00336                                                             return m_Singleton; }
    00337
    00338 protected:
    00339     // private data
    00340     EraseType   m_EraseType;
    00341     DataVec     m_UserData;     // data we're going to get to
    00342     MagicVec    m_MagicNumbers; // corresponding magic numbers
    00343     FreeVec     m_FreeSlots;    // keeps track of free slots in the db
    00344     RefVec      m_References;
    00345
    00346     static  THandleMgr<DATA, HANDLE> * m_Singleton;
    00347 };
    00348
    00349
    00350 //-----------------------------------------------------
    00351
    00352
    00353 //--------------------------------------------------
    00354 // THandle base
    00355 //--------------------------------------------------
    00356 template <typename TAG>
    00357 class THandle
    00358 {
    00359 private:
    00360     union
    00361     {
    00362         enum
    00363         {
    00364             // sizes to use for bit fields
    00365             MAX_BITS_INDEX = 16,
    00366             MAX_BITS_MAGIC = 16,
    00367
    00368             // sizes to compare against for asserting dereferences
    00369             MAX_INDEX = ( 1 << MAX_BITS_INDEX) - 1,
    00370             MAX_MAGIC = ( 1 << MAX_BITS_MAGIC) - 1,
    00371         };
    00372
    00373         struct
    00374         {
    00375             unsigned m_Index : MAX_BITS_INDEX;  // index into resource array
    00376             unsigned m_Magic : MAX_BITS_MAGIC;  // magic number to check
    00377         };
    00378         unsigned long m_Handle;
    00379     };
    00380
    00381     typedef THandleMgr< TAG, THandle<TAG> > ThisMgrType;
    00382     typedef THandle<TAG>                    ThisType;
    00383
    00384 public:
    00385
    00386     THandle (void) : m_Handle( 0 ) {  }
    00387     ~THandle(void)
    00388     {
    00389         m_Handle = 0;
    00390     }
    00391     //--------------------------------------------------
    00392     // Init( U16 )
    00393     //
    00394     // Inits the handle with given index
    00395     //--------------------------------------------------
    00396     void    Init( unsigned int index )
    00397             {
    00398                 assert( IsNull() );             // don't allow reassignment
    00399                 assert( index <= MAX_INDEX );   // verify range
    00400
    00401                 static unsigned int s_AutoMagic = 0;
    00402                 if ( ++s_AutoMagic > MAX_MAGIC )
    00403                 {
    00404                     s_AutoMagic = 1;    // 0 is used for "null handle"
    00405                 }
    00406
    00407                 m_Index = index;
    00408                 m_Magic = s_AutoMagic;
    00409             }
    00410
    00411     unsigned int    GetIndex ( void ) const  { return (  m_Index  ); }
    00412     unsigned int    GetMagic ( void ) const  { return (  m_Magic  ); }
    00413     unsigned long   GetHandle( void ) const  { return (  m_Handle ); }
    00414     TAG *           GetData  ( void ) const  { return (  (ThisMgrType::GetHandleMgr()->GetData( *this ))); }
    00415     bool            IsNull   ( void ) const  { return ( !m_Handle ); }
    00416
    00417     operator unsigned int ( void ) const  { return (  m_Handle );  }
    00418
    00419     THandle<TAG>& operator = ( const THandle<TAG>& r )
    00420     {
    00421         m_Handle = r.m_Handle;
    00422         return *this;
    00423     }
    00424
    00425     THandle<TAG>& operator = ( const DWORD& r )
    00426     {
    00427         m_Handle = r;
    00428         return *this;
    00429     }
    00430
    00431
    00432     friend bool operator != ( const THandle<TAG>& l, const THandle<TAG>& r )
    00433                     {  return ( l.m_Handle != r.m_Handle );  }
    00434
    00435     friend bool operator == ( const THandle<TAG>& l, const THandle<TAG>& r )
    00436                     {  return ( l.m_Handle == r.m_Handle );  }
    00437
    00438     friend bool operator != ( const DWORD& l, const THandle<TAG>& r )
    00439                     {  return ( l != r.m_Handle );  }
    00440
    00441     friend bool operator == ( const DWORD& l, const THandle<TAG>& r )
    00442                     {  return ( l == r.m_Handle );  }
    00443
    00444     friend bool operator != ( const THandle<TAG>& l, const DWORD& r )
    00445                     {  return ( l.m_Handle != r );  }
    00446
    00447     friend bool operator == ( const THandle<TAG>& l, const DWORD& r )
    00448                     {  return ( l.m_Handle == r );  }
    00449 };
    00450
    00451 #endif