gcache.cpp

Go to the documentation of this file.
00001 // $Id: gcache.cpp 754 2006-04-01 15:29:59Z alex $
00003 //
00004 // GCache.cpp
00005 //
00007 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00008 ================================XARAHEADERSTART===========================
00009  
00010                Xara LX, a vector drawing and manipulation program.
00011                     Copyright (C) 1993-2006 Xara Group Ltd.
00012        Copyright on certain contributions may be held in joint with their
00013               respective authors. See AUTHORS file for details.
00014 
00015 LICENSE TO USE AND MODIFY SOFTWARE
00016 ----------------------------------
00017 
00018 This file is part of Xara LX.
00019 
00020 Xara LX is free software; you can redistribute it and/or modify it
00021 under the terms of the GNU General Public License version 2 as published
00022 by the Free Software Foundation.
00023 
00024 Xara LX and its component source files are distributed in the hope
00025 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00026 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00027 See the GNU General Public License for more details.
00028 
00029 You should have received a copy of the GNU General Public License along
00030 with Xara LX (see the file GPL in the root directory of the
00031 distribution); if not, write to the Free Software Foundation, Inc., 51
00032 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00033 
00034 
00035 ADDITIONAL RIGHTS
00036 -----------------
00037 
00038 Conditional upon your continuing compliance with the GNU General Public
00039 License described above, Xara Group Ltd grants to you certain additional
00040 rights. 
00041 
00042 The additional rights are to use, modify, and distribute the software
00043 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00044 library and any other such library that any version of Xara LX relased
00045 by Xara Group Ltd requires in order to compile and execute, including
00046 the static linking of that library to XaraLX. In the case of the
00047 "CDraw" library, you may satisfy obligation under the GNU General Public
00048 License to provide source code by providing a binary copy of the library
00049 concerned and a copy of the license accompanying it.
00050 
00051 Nothing in this section restricts any of the rights you have under
00052 the GNU General Public License.
00053 
00054 
00055 SCOPE OF LICENSE
00056 ----------------
00057 
00058 This license applies to this program (XaraLX) and its constituent source
00059 files only, and does not necessarily apply to other Xara products which may
00060 in part share the same code base, and are subject to their own licensing
00061 terms.
00062 
00063 This license does not apply to files in the wxXtra directory, which
00064 are built into a separate library, and are subject to the wxWindows
00065 license contained within that directory in the file "WXXTRA-LICENSE".
00066 
00067 This license does not apply to the binary libraries (if any) within
00068 the "libs" directory, which are subject to a separate license contained
00069 within that directory in the file "LIBS-LICENSE".
00070 
00071 
00072 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00073 ----------------------------------------------
00074 
00075 Subject to the terms of the GNU Public License (see above), you are
00076 free to do whatever you like with your modifications. However, you may
00077 (at your option) wish contribute them to Xara's source tree. You can
00078 find details of how to do this at:
00079   http://www.xaraxtreme.org/developers/
00080 
00081 Prior to contributing your modifications, you will need to complete our
00082 contributor agreement. This can be found at:
00083   http://www.xaraxtreme.org/developers/contribute/
00084 
00085 Please note that Xara will not accept modifications which modify any of
00086 the text between the start and end of this header (marked
00087 XARAHEADERSTART and XARAHEADEREND).
00088 
00089 
00090 MARKS
00091 -----
00092 
00093 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00094 designs are registered or unregistered trademarks, design-marks, and/or
00095 service marks of Xara Group Ltd. All rights in these marks are reserved.
00096 
00097 
00098       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00099                         http://www.xara.com/
00100 
00101 =================================XARAHEADEREND============================
00102  */
00103 
00104 #include "camtypes.h"
00105 //#include <afxwin.h>
00106 #include <iostream>
00107 //#include "gcmaths.h"
00108 #include "gcache.h"
00109 
00112 
00113 CamCache::CamCache( size_t Size, UINT32 Log2MaxEntries )
00114 {
00115     HashTableSize = 1<<Log2MaxEntries ;
00116     HashTableMask = HashTableSize-1 ;
00117     HashTable     = NULL ;
00118     CacheStart    = NULL ;
00119 
00120     HashTable   = new ( CacheBlock* [HashTableSize] ) ;
00121     CacheStart  = (CacheBlock*) new BYTE[Size+2*FreeCacheBlockSize] ;
00122 
00123     if (!HashTable || !CacheStart)
00124     {
00125         if (HashTable)
00126         {
00127             delete [] HashTable  ; HashTable  = NULL ;
00128         }
00129         if (CacheStart)
00130         {
00131             delete [] CacheStart ; CacheStart = NULL ;
00132         }
00133         return ;
00134     }
00135     for ( size_t i=0 ; i<HashTableSize ; i++ )
00136         HashTable[i] = NULL ;
00137     CacheBlock *FreeBlock ;
00138     FreeBlock   = (CacheBlock*) ((BYTE*)CacheStart+FreeCacheBlockSize) ;
00139     CacheEnd    = (CacheBlock*) ((BYTE*)CacheStart+Size-FreeCacheBlockSize) ;
00140     CacheStart->Prev        = CacheStart ;
00141                               CacheEnd->Next        = CacheEnd ;
00142     CacheStart->Next        = CacheEnd->Prev        =
00143     CacheStart->NextFree    = CacheEnd->PrevFree    = FreeBlock ;
00144     CacheStart->PrevFree    = CacheEnd->NextFree    = NULL ;
00145     CacheStart->State       = CacheEnd->State       = 0 ;
00146     FreeBlock->Prev         = FreeBlock->PrevFree   = CacheStart ;
00147     FreeBlock->Next         = FreeBlock->NextFree   = CacheEnd ;
00148     FreeBlock->State        = FREE ;
00149     LeastUsed = MostUsed = NULL ;
00150 }
00151 
00153 //
00154 // Verify should be used after creation of a CamCache object to ensure that it was created OK.
00155 //
00156 BOOL CamCache::Verify()
00157 {
00158     return HashTable && CacheStart ;
00159 }
00160 
00162 
00163 CamCache::~CamCache()
00164 {
00165     delete [] HashTable  ; HashTable  = NULL ;
00166     delete [] CacheStart ; CacheStart = NULL ;
00167 }
00168 
00171 
00172 BOOL CamCache::FindPath( UINT32 Handle, INT32* &Points, BYTE* &Types, UINT32 &Length )
00173 {
00174     INT32 *Object = (INT32*) FindEntry( Handle ) ;
00175     if ( Object )
00176     {
00177         Length = *Object ;
00178         Points = ++Object ;
00179         Types = (BYTE*) (Object+2*Length) ;
00180     }
00181     return Object!=NULL ;
00182 }
00183 
00184 void CamCache::AddPath( UINT32 Handle, INT32* Points, BYTE* Types, UINT32 Length )
00185 {
00186     INT32 *DPtr = (INT32*) AddEntry( Handle,Length*9+4 ) ;
00187     *DPtr++ = Length ;
00188     INT32 *SPtr = Points ;
00189     size_t i;
00190     for ( i=0 ; i<2*Length ; i++ )
00191         *DPtr++ = *SPtr++ ;
00192     SPtr = (INT32*) Types ;
00193     Length = (Length+3)>>2 ;                    /* Word length */
00194     for ( i=0 ; i<Length ; i++ )
00195         *DPtr++ = *SPtr++ ;
00196 }
00197 
00200 
00201 PORTNOTE("other","not used - removed because AddString looks dodgy")
00202 #ifndef EXCLUDE_FROM_XARALX
00203 
00204 char* CamCache::FindString( UINT32 Handle )
00205 {
00206     return (char*) FindEntry( Handle ) ;
00207 }
00208 
00209 void CamCache::AddString( UINT32 Handle, char* String )
00210 {
00211     size_t StringLength = cc_strlenBytes(String)+1 ;    /* Byte length */
00212     INT32 *SPtr = (INT32*) String ;
00213     INT32 *DPtr = (INT32*) AddEntry( Handle,StringLength ) ;
00214     StringLength = (StringLength+3)>>2 ;        /* Word length */
00215     for ( size_t i=0 ; i<StringLength ; i++ )
00216         *DPtr++ = *SPtr++ ;
00217 }
00218 #endif
00219 
00222 
00223 // converted from asm function in gcmaths
00224 UINT32 Hash(UINT32 val)
00225 {
00226     val ^= (val <<  7) | (val >> 25);
00227     val ^= (val << 11) | (val >> 21);
00228     val ^= (val << 19) | (val >> 13);
00229     val ^= (val << 16) | (val >> 16);
00230     return val;
00231 }
00232 
00233 void* CamCache::FindEntry( UINT32 Handle )
00234 {
00235     UINT32 HashIndex = Hash( Handle ) & HashTableMask ;
00236     CacheBlock *Ptr = HashTable[HashIndex] ;
00237     while ( Ptr )
00238         if ( Ptr->Handle == Handle )
00239         {
00240             if ( Ptr != MostUsed )
00241             {
00242                 /* Make this the most recently used object */
00243                 if ( Ptr==LeastUsed )
00244                     LeastUsed = Ptr->NextUsed ;
00245                 else
00246                     Ptr->PrevUsed->NextUsed = Ptr->NextUsed ;
00247                 Ptr->NextUsed->PrevUsed = Ptr->PrevUsed ;
00248                 Ptr->NextUsed = NULL ;
00249                 Ptr->PrevUsed = MostUsed ;
00250                 MostUsed->NextUsed = Ptr ;
00251                 MostUsed = Ptr ;
00252             }
00253             return Ptr->Object ;
00254         }
00255         else
00256             Ptr = Ptr->Link ;
00257 
00258     return NULL ;
00259 }
00260 
00262 
00263 void* CamCache::AddEntry( UINT32 Handle, size_t ObjectSize )
00264 {
00265     UINT32 HashIndex = Hash( Handle ) & HashTableMask ;
00266     CacheBlock *Ptr = HashTable[HashIndex] ;
00267     while ( Ptr )
00268         if ( Ptr->Handle == Handle )
00269             return Ptr->Object ;                    /* Entry already exists */
00270         else
00271             Ptr = Ptr->Link ;
00272     CacheBlock *FreeBlock = CacheStart->NextFree ;
00273     size_t ObjectBlockSize = (ObjectSize+UsedCacheBlockSize+3) & ~3 ;
00274     while ( ObjectBlockSize > BlockSize(FreeBlock) )
00275         if ( !(FreeBlock=FreeBlock->NextFree) )
00276         {
00277             /* Remove least recently used object from hash table */
00278             UINT32 HashIndex = Hash( LeastUsed->Handle ) & HashTableMask ;
00279             CacheBlock *Ptr = HashTable[HashIndex] ;
00280             if ( Ptr == LeastUsed )
00281                 HashTable[HashIndex] = LeastUsed->Link ;
00282             else
00283             {
00284                 while ( Ptr->Link != LeastUsed )
00285                     Ptr = Ptr->Link ;
00286                 Ptr->Link = LeastUsed->Link ;
00287             }               
00288             /* Merge least recently used object with adjacent free blocks and try again */
00289             FreeBlock = LeastUsed ;
00290             LeastUsed = LeastUsed->NextUsed ;
00291             LeastUsed->PrevUsed = NULL ;
00292             FreeBlock->State = FREE ;
00293             CacheStart->NextFree->PrevFree = FreeBlock ;
00294             FreeBlock->NextFree = CacheStart->NextFree ;
00295             FreeBlock->PrevFree = CacheStart ;
00296             CacheStart->NextFree = FreeBlock ;
00297             CacheBlock *NextBlock = FreeBlock->Next ;
00298             CacheBlock *PrevBlock = FreeBlock->Prev ;
00299             if ( NextBlock->State == FREE )
00300             {
00301                 NextBlock->PrevFree->NextFree = NextBlock->NextFree ;
00302                 NextBlock->NextFree->PrevFree = NextBlock->PrevFree ;
00303                 FreeBlock->Next = NextBlock->Next ;
00304                 NextBlock->Next->Prev = FreeBlock ;
00305             }
00306             if ( PrevBlock->State == FREE )
00307             {
00308                 FreeBlock->PrevFree->NextFree = FreeBlock->NextFree ;
00309                 FreeBlock->NextFree->PrevFree = FreeBlock->PrevFree ;
00310                 PrevBlock->Next = FreeBlock->Next ;
00311                 FreeBlock->Next->Prev = PrevBlock ;
00312                 FreeBlock = PrevBlock ;
00313             }
00314         }
00315     /* Add object */
00316     if ( ObjectBlockSize+FreeCacheBlockSize > BlockSize(FreeBlock) )
00317     {
00318         FreeBlock->PrevFree->NextFree = FreeBlock->NextFree ;
00319         FreeBlock->NextFree->PrevFree = FreeBlock->PrevFree ;
00320     }
00321     else
00322     {
00323         CacheBlock *NewBlock = (CacheBlock*) ((BYTE*)FreeBlock+ObjectBlockSize) ;
00324         NewBlock->Prev      = FreeBlock ;
00325         NewBlock->Next      = FreeBlock->Next ;
00326         NewBlock->State     = FREE ;
00327         NewBlock->NextFree  = FreeBlock->NextFree ;
00328         NewBlock->PrevFree  = FreeBlock->PrevFree ;
00329         NewBlock->NextFree->PrevFree = NewBlock->PrevFree->NextFree = NewBlock ;
00330         FreeBlock->Next     = NewBlock->Next->Prev = NewBlock ;
00331     }
00332     FreeBlock->Link     = HashTable[HashIndex] ;
00333     FreeBlock->PrevUsed = MostUsed ;
00334     FreeBlock->NextUsed = NULL ;
00335     FreeBlock->Handle   = Handle ;
00336     HashTable[HashIndex] = FreeBlock ;
00337     if ( MostUsed )
00338         MostUsed->NextUsed = FreeBlock ;
00339     MostUsed = FreeBlock ;
00340     if ( !LeastUsed )
00341         LeastUsed = FreeBlock ;
00342     return FreeBlock->Object ;
00343 }
00344 
00347 
00348 #ifdef _DEBUG
00349 
00350 ostream& operator << ( ostream& os, CamCache& Cache )
00351 {
00352     for ( size_t i=0 ; i<Cache.HashTableSize ; i++ )
00353     {
00354         os << Cache.HashTable[i] << " " ;
00355         if ( (i & 7) == 7 )
00356             os << endl ;
00357     }
00358     os << "Start : " << Cache.CacheStart
00359                      << ", " << Cache.CacheStart->Prev     << "," << Cache.CacheStart->Next
00360                      << ", " << Cache.CacheStart->PrevFree << "," << Cache.CacheStart->NextFree << endl ;
00361     CacheBlock *Ptr = Cache.CacheStart->Next ;
00362     while ( Ptr != Cache.CacheEnd )
00363     {
00364         if ( Ptr->State == FREE )
00365             cout << "FREE  : " << Ptr << ", " << Ptr->Prev     << "," << Ptr->Next
00366                                       << ", " << Ptr->PrevFree << "," << Ptr->NextFree
00367                                       << " (" << hex
00368                                       << Cache.BlockSize(Ptr)-FreeCacheBlockSize
00369                                       << dec << ")" << endl ;
00370         else
00371             cout << "USED  : " << Ptr << ", " << Ptr->Prev     << "," << Ptr->Next
00372                                       << ", " << Ptr->PrevUsed << "," << Ptr->NextUsed
00373                                       << ", " << Ptr->Link     << "," << Ptr->Handle
00374                                       << ", " << (char*) Ptr->Object << " (" << hex
00375 #ifndef EXCLUDE_FROM_XARALX
00376                                       << Cache.BlockSize(Ptr)-UsedCacheBlockSize-cc_strlenBytes((char*)Ptr->Object)-1
00377 #endif
00378                                       << dec << ")" << endl ;
00379         Ptr = Ptr->Next ;
00380     }
00381     os << "End   : " << Cache.CacheEnd
00382                      << ", " << Cache.CacheEnd->Prev     << "," << Cache.CacheEnd->Next
00383                      << ", " << Cache.CacheEnd->PrevFree << "," << Cache.CacheEnd->NextFree << endl ;
00384     os << "LeastUsed : " << Cache.LeastUsed << endl ;
00385     os << " MostUsed : " << Cache. MostUsed << endl ;
00386     return os ;
00387 }
00388 
00389 #endif
00390 

Generated on Sat Nov 10 03:45:25 2007 for Camelot by  doxygen 1.4.4