LCOV - code coverage report
Current view: top level - libreoffice/sw/source/core/bastyp - swcache.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 120 150 80.0 %
Date: 2012-12-27 Functions: 14 17 82.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <rtl/strbuf.hxx>
      21             : #include <swcache.hxx>
      22             : #include <limits.h>     // USHRT_MAX
      23             : 
      24             : #ifdef DBG_UTIL
      25             : void SwCache::Check()
      26             : {
      27             :     if ( !pRealFirst )
      28             :         return;
      29             : 
      30             :     // consistency check
      31             :     SAL_WARN_IF( pLast->GetNext(), "sw.core", "Last but not last." );
      32             :     SAL_WARN_IF( pRealFirst->GetPrev(), "sw.core", "First but not first." );
      33             :     sal_uInt16 nCnt = 0;
      34             :     bool bFirstFound = false;
      35             :     SwCacheObj *pObj = pRealFirst;
      36             :     SwCacheObj *pRekursive = pObj;
      37             :     while ( pObj )
      38             :     {
      39             :         // the object must be found also when moving backwards
      40             :         SwCacheObj *pTmp = pLast;
      41             :         while ( pTmp && pTmp != pObj )
      42             :             pTmp = pTmp->GetPrev();
      43             :         SAL_WARN_IF( !pTmp, "sw.core", "Objekt not found." );
      44             : 
      45             :         ++nCnt;
      46             :         if ( pObj == pFirst )
      47             :             bFirstFound = true;
      48             :         if ( !pObj->GetNext() )
      49             :             SAL_WARN_IF( pObj != pLast, "sw.core", "Last not Found." );
      50             :         pObj = pObj->GetNext();
      51             :         SAL_WARN_IF( pObj == pRekursive, "sw.core", "Recursion in SwCache." );
      52             :     }
      53             :     SAL_WARN_IF( !bFirstFound, "sw.core", "First not Found." );
      54             :     SAL_WARN_IF( nCnt + aFreePositions.size() != size(), "sw.core", "Lost Chain." );
      55             :     SAL_WARN_IF(
      56             :         size() == nCurMax && nCurMax != aFreePositions.size() + nCnt, "sw.core",
      57             :         "Lost FreePositions." );
      58             : }
      59             : 
      60             : #define INCREMENT( nVar )   ++nVar
      61             : #define CHECK Check();
      62             : 
      63             : #else
      64             : #define INCREMENT( nVar )
      65             : #define CHECK
      66             : #endif
      67             : 
      68             : 
      69          40 : SwCache::SwCache( const sal_uInt16 nInitSize
      70             : #ifdef DBG_UTIL
      71             :     , const rtl::OString &rNm
      72             : #endif
      73             :     ) :
      74             :     m_aCacheObjects(),
      75             :     pRealFirst( 0 ),
      76             :     pFirst( 0 ),
      77             :     pLast( 0 ),
      78          40 :     nCurMax( nInitSize )
      79             : #ifdef DBG_UTIL
      80             :     , m_aName( rNm )
      81             :     , m_nAppend( 0 )
      82             :     , m_nInsertFree( 0 )
      83             :     , m_nReplace( 0 )
      84             :     , m_nGetSuccess( 0 )
      85             :     , m_nGetFail( 0 )
      86             :     , m_nToTop( 0 )
      87             :     , m_nDelete( 0 )
      88             :     , m_nGetSeek( 0 )
      89             :     , m_nAverageSeekCnt( 0 )
      90             :     , m_nFlushCnt( 0 )
      91             :     , m_nFlushedObjects( 0 )
      92             :     , m_nIncreaseMax( 0 )
      93             :     , m_nDecreaseMax( 0 )
      94             : #endif
      95             : {
      96          40 :     m_aCacheObjects.reserve( (sal_uInt8)nInitSize );
      97          40 : }
      98             : 
      99          80 : SwCache::~SwCache()
     100             : {
     101             : #ifdef DBG_UTIL
     102             :     {
     103             :         rtl::OStringBuffer sOut(m_aName);
     104             : 
     105             :         sOut.append('\n').
     106             :             append(RTL_CONSTASCII_STRINGPARAM(
     107             :                 "Number of new entries:                 ")).
     108             :             append(static_cast<sal_Int32>(m_nAppend)).
     109             :             append('\n').
     110             :             append(RTL_CONSTASCII_STRINGPARAM(
     111             :                 "Number of insert on free places:       ")).
     112             :             append(static_cast<sal_Int32>(m_nInsertFree)).
     113             :             append('\n').
     114             :             append(RTL_CONSTASCII_STRINGPARAM(
     115             :                 "Number of replacements:                ")).
     116             :             append(static_cast<sal_Int32>(m_nReplace)).
     117             :             append('\n').
     118             :             append(RTL_CONSTASCII_STRINGPARAM(
     119             :                 "Number of successful Get's:            ")).
     120             :             append(static_cast<sal_Int32>(m_nGetSuccess)).
     121             :             append('\n').
     122             :             append(RTL_CONSTASCII_STRINGPARAM(
     123             :                 "Number of failed Get's:                ")).
     124             :             append(static_cast<sal_Int32>(m_nGetFail)).
     125             :             append('\n').
     126             :             append(RTL_CONSTASCII_STRINGPARAM(
     127             :                 "Number or reordering (LRU):            ")).
     128             :             append(static_cast<sal_Int32>(m_nToTop)).
     129             :             append('\n').
     130             :             append(RTL_CONSTASCII_STRINGPARAM(
     131             :                 "Number of suppressions:                ")).
     132             :             append(static_cast<sal_Int32>(m_nDelete)).
     133             :             append('\n').
     134             :             append(RTL_CONSTASCII_STRINGPARAM(
     135             :                 "Number of Get's without Index:         ")).
     136             :             append(static_cast<sal_Int32>(m_nGetSeek)).
     137             :             append('\n').
     138             :             append(RTL_CONSTASCII_STRINGPARAM(
     139             :                 "Number of Seek for Get without Index:  ")).
     140             :             append(static_cast<sal_Int32>(m_nAverageSeekCnt)).
     141             :             append('\n').
     142             :             append(RTL_CONSTASCII_STRINGPARAM(
     143             :                 "Number of Flush calls:                 " )).
     144             :             append(static_cast<sal_Int32>(m_nFlushCnt)).
     145             :             append('\n').
     146             :             append(RTL_CONSTASCII_STRINGPARAM(
     147             :                 "Number of flushed objects:             ")).
     148             :             append(static_cast<sal_Int32>(m_nFlushedObjects)).
     149             :             append('\n').
     150             :             append(RTL_CONSTASCII_STRINGPARAM(
     151             :                 "Number of Cache expansions:            ")).
     152             :             append(static_cast<sal_Int32>(m_nIncreaseMax)).
     153             :             append('\n').
     154             :             append(RTL_CONSTASCII_STRINGPARAM(
     155             :                 "Number of Cache reductions:            ")).
     156             :             append(static_cast<sal_Int32>(m_nDecreaseMax)).
     157             :             append('\n');
     158             : 
     159             :         OSL_TRACE(sOut.getStr());
     160             :     }
     161             :     Check();
     162             : #endif
     163             : 
     164        1759 :     for(SwCacheObjArr::const_iterator it = m_aCacheObjects.begin(); it != m_aCacheObjects.end(); ++it)
     165        1719 :         delete *it;
     166          40 : }
     167             : 
     168         238 : void SwCache::Flush( const sal_uInt8 )
     169             : {
     170             :     INCREMENT( m_nFlushCnt );
     171         238 :     SwCacheObj *pObj = pRealFirst;
     172         238 :     pRealFirst = pFirst = pLast = 0;
     173             :     SwCacheObj *pTmp;
     174         826 :     while ( pObj )
     175             :     {
     176             : #ifdef DBG_UTIL
     177             :         if ( pObj->IsLocked() )
     178             :         {
     179             :             OSL_FAIL( "Flushing locked objects." );
     180             :             if ( !pRealFirst )
     181             :             {
     182             :                 pRealFirst = pFirst = pLast = pObj;
     183             :                 pTmp = pObj->GetNext();
     184             :                 pObj->SetNext( 0 ); pObj->SetPrev( 0 );
     185             :                 pObj = pTmp;
     186             :             }
     187             :             else
     188             :             {   pLast->SetNext( pObj );
     189             :                 pObj->SetPrev( pLast );
     190             :                 pLast = pObj;
     191             :                 pTmp = pObj->GetNext();
     192             :                 pObj->SetNext( 0 );
     193             :                 pObj = pTmp;
     194             :             }
     195             :         }
     196             :         else
     197             : #endif
     198             :         {
     199         350 :             pTmp = (SwCacheObj*)pObj;
     200         350 :             pObj = pTmp->GetNext();
     201         350 :             aFreePositions.push_back( pTmp->GetCachePos() );
     202         350 :             m_aCacheObjects[pTmp->GetCachePos()] = NULL;
     203         350 :             delete pTmp;
     204             :             INCREMENT( m_nFlushedObjects );
     205             :         }
     206             :     }
     207         238 : }
     208             : 
     209        6925 : void SwCache::ToTop( SwCacheObj *pObj )
     210             : {
     211             :     INCREMENT( m_nToTop );
     212             : 
     213             :     // cut object out of chain and insert at beginning
     214        6925 :     if ( pRealFirst == pObj )   // pFirst was checked by caller
     215             :     {
     216             :         CHECK;
     217           0 :         return;
     218             :     }
     219             : 
     220        6925 :     if ( !pRealFirst )
     221             :     {
     222             :         // the first will be inserted
     223             :         OSL_ENSURE( !pFirst && !pLast, "First not first." );
     224           0 :         pRealFirst = pFirst = pLast = pObj;
     225             :         CHECK;
     226           0 :         return;
     227             :     }
     228             : 
     229             :     // cut
     230        6925 :     if ( pObj == pLast )
     231             :     {
     232             :         OSL_ENSURE( pObj->GetPrev(), "Last but no Prev." );
     233         422 :         pLast = pObj->GetPrev();
     234         422 :         pLast->SetNext( 0 );
     235             :     }
     236             :     else
     237             :     {
     238        6503 :         if ( pObj->GetNext() )
     239        6503 :             pObj->GetNext()->SetPrev( pObj->GetPrev() );
     240        6503 :         if ( pObj->GetPrev() )
     241        6503 :             pObj->GetPrev()->SetNext( pObj->GetNext() );
     242             :     }
     243             : 
     244             :     // paste at the (virtual) beginning
     245        6925 :     if ( pRealFirst == pFirst )
     246             :     {
     247        6925 :         pRealFirst->SetPrev( pObj );
     248        6925 :         pObj->SetNext( pRealFirst );
     249        6925 :         pObj->SetPrev( 0 );
     250        6925 :         pRealFirst = pFirst = pObj;
     251             :         CHECK;
     252             :     }
     253             :     else
     254             :     {
     255             :         OSL_ENSURE( pFirst, "ToTop, First ist not RealFirst an Empty." );
     256             : 
     257           0 :         if ( pFirst->GetPrev() )
     258             :         {
     259           0 :             pFirst->GetPrev()->SetNext( pObj );
     260           0 :             pObj->SetPrev( pFirst->GetPrev() );
     261             :         }
     262             :         else
     263           0 :             pObj->SetPrev( 0 );
     264           0 :         pFirst->SetPrev( pObj );
     265           0 :         pObj->SetNext( pFirst );
     266           0 :         pFirst = pObj;
     267             :         CHECK;
     268             :     }
     269             : }
     270             : 
     271       33208 : SwCacheObj *SwCache::Get( const void *pOwner, const sal_uInt16 nIndex,
     272             :                           const sal_Bool bToTop )
     273             : {
     274             :     SwCacheObj *pRet;
     275       33208 :     if ( 0 != (pRet = (nIndex < m_aCacheObjects.size()) ? m_aCacheObjects[ nIndex ] : 0) )
     276             :     {
     277       32611 :         if ( !pRet->IsOwner( pOwner ) )
     278          35 :             pRet = 0;
     279       32576 :         else if ( bToTop && pRet != pFirst )
     280        1045 :             ToTop( pRet );
     281             :     }
     282             : 
     283             : #ifdef DBG_UTIL
     284             :         if ( pRet )
     285             :             ++m_nGetSuccess;
     286             :         else
     287             :             ++m_nGetFail;
     288             : #endif
     289             : 
     290       33208 :     return pRet;
     291             : }
     292             : 
     293       13599 : SwCacheObj *SwCache::Get( const void *pOwner, const sal_Bool bToTop )
     294             : {
     295       13599 :     SwCacheObj *pRet = pRealFirst;
     296       77347 :     while ( pRet && !pRet->IsOwner( pOwner ) )
     297             :     {
     298             :         INCREMENT( m_nAverageSeekCnt );
     299       50149 :         pRet = pRet->GetNext();
     300             :     }
     301             : 
     302       13599 :     if ( bToTop && pRet && pRet != pFirst )
     303        5880 :         ToTop( pRet );
     304             : 
     305             : #ifdef DBG_UTIL
     306             :     if ( pRet )
     307             :         ++m_nGetSuccess;
     308             :     else
     309             :         ++m_nGetFail;
     310             :     ++m_nGetSeek;
     311             : #endif
     312       13599 :     return pRet;
     313             : }
     314             : 
     315         646 : void SwCache::DeleteObj( SwCacheObj *pObj )
     316             : {
     317             :     CHECK;
     318             :     OSL_ENSURE( !pObj->IsLocked(), "SwCache::Delete: object is locked." );
     319         646 :     if ( pObj->IsLocked() )
     320         646 :         return;
     321             : 
     322         646 :     if ( pFirst == pObj )
     323             :     {
     324         202 :         if ( pFirst->GetNext() )
     325         197 :             pFirst = pFirst->GetNext();
     326             :         else
     327           5 :             pFirst = pFirst->GetPrev();
     328             :     }
     329         646 :     if ( pRealFirst == pObj )
     330         202 :         pRealFirst = pRealFirst->GetNext();
     331         646 :     if ( pLast == pObj )
     332          15 :         pLast = pLast->GetPrev();
     333         646 :     if ( pObj->GetPrev() )
     334         444 :         pObj->GetPrev()->SetNext( pObj->GetNext() );
     335         646 :     if ( pObj->GetNext() )
     336         631 :         pObj->GetNext()->SetPrev( pObj->GetPrev() );
     337             : 
     338         646 :     aFreePositions.push_back( pObj->GetCachePos() );
     339         646 :     m_aCacheObjects[pObj->GetCachePos()] = NULL;
     340         646 :     delete pObj;
     341             : 
     342             :     CHECK;
     343         646 :     if ( m_aCacheObjects.size() > nCurMax &&
     344           0 :          (nCurMax <= (m_aCacheObjects.size() - aFreePositions.size())) )
     345             :     {
     346             :         // Shrink if possible.To do so we need enough free positions.
     347             :         // Unpleasent side effect: positions will be moved and the owner of
     348             :         // these might not find them afterwards
     349           0 :         for ( sal_uInt16 i = 0; i < m_aCacheObjects.size(); ++i )
     350             :         {
     351           0 :             SwCacheObj *pTmpObj = m_aCacheObjects[i];
     352           0 :             if ( !pTmpObj )
     353           0 :             {   m_aCacheObjects.erase( m_aCacheObjects.begin() + i );
     354           0 :                 --i;
     355             :             }
     356             :             else
     357             :             {
     358           0 :                 pTmpObj->SetCachePos( i );
     359             :             }
     360             :         }
     361           0 :         aFreePositions.clear();
     362             :     }
     363             :     CHECK;
     364             : }
     365             : 
     366         646 : void SwCache::Delete( const void *pOwner )
     367             : {
     368             :     INCREMENT( m_nDelete );
     369             :     SwCacheObj *pObj;
     370         646 :     if ( 0 != (pObj = Get( pOwner, sal_Bool(sal_False) )) )
     371         646 :         DeleteObj( pObj );
     372         646 : }
     373             : 
     374        3746 : sal_Bool SwCache::Insert( SwCacheObj *pNew )
     375             : {
     376             :     CHECK;
     377             :     OSL_ENSURE( !pNew->GetPrev() && !pNew->GetNext(), "New but not new." );
     378             : 
     379             :     sal_uInt16 nPos;
     380        3746 :     if ( m_aCacheObjects.size() < nCurMax )
     381             :     {
     382             :         // there is still space; insert directly
     383             :         INCREMENT( m_nAppend );
     384        1719 :         nPos = m_aCacheObjects.size();
     385        1719 :         m_aCacheObjects.push_back(pNew);
     386             :     }
     387        2027 :     else if ( !aFreePositions.empty() )
     388             :     {
     389             :         // there are placeholders; use the last of those
     390             :         INCREMENT( m_nInsertFree );
     391         592 :         const sal_uInt16 nFreePos = aFreePositions.size() - 1;
     392         592 :         nPos = aFreePositions[ nFreePos ];
     393         592 :         m_aCacheObjects[nPos] = pNew;
     394         592 :         aFreePositions.erase( aFreePositions.begin() + nFreePos );
     395             :     }
     396             :     else
     397             :     {
     398             :         INCREMENT( m_nReplace );
     399             :         // the last of the LRU has to go
     400        1435 :         SwCacheObj *pObj = pLast;
     401             : 
     402        2930 :         while ( pObj && pObj->IsLocked() )
     403          60 :             pObj = pObj->GetPrev();
     404        1435 :         if ( !pObj )
     405             :         {
     406             :             OSL_FAIL( "Cache overflow." );
     407           0 :             return sal_False;
     408             :         }
     409             : 
     410        1435 :         nPos = pObj->GetCachePos();
     411        1435 :         if ( pObj == pLast )
     412             :         { OSL_ENSURE( pObj->GetPrev(), "Last but no Prev" );
     413        1415 :             pLast = pObj->GetPrev();
     414        1415 :             pLast->SetNext( 0 );
     415             :         }
     416             :         else
     417             :         {
     418          20 :             if ( pObj->GetPrev() )
     419          20 :                 pObj->GetPrev()->SetNext( pObj->GetNext() );
     420          20 :             if ( pObj->GetNext() )
     421          20 :                 pObj->GetNext()->SetPrev( pObj->GetPrev() );
     422             :         }
     423        1435 :         delete pObj;
     424        1435 :         m_aCacheObjects[nPos] = pNew;
     425             :     }
     426        3746 :     pNew->SetCachePos( nPos );
     427             : 
     428        3746 :     if ( pFirst )
     429             :     {
     430        3479 :         if ( pFirst->GetPrev() )
     431           0 :         {   pFirst->GetPrev()->SetNext( pNew );
     432           0 :             pNew->SetPrev( pFirst->GetPrev() );
     433             :         }
     434        3479 :         pFirst->SetPrev( pNew );
     435        3479 :         pNew->SetNext( pFirst );
     436             :     }
     437             :     else
     438             :     { OSL_ENSURE( !pLast, "Last but no First." );
     439         267 :         pLast = pNew;
     440             :     }
     441        3746 :     if ( pFirst == pRealFirst )
     442        3746 :         pRealFirst = pNew;
     443        3746 :     pFirst = pNew;
     444             : 
     445             :     CHECK;
     446        3746 :     return sal_True;
     447             : }
     448             : 
     449         432 : void SwCache::SetLRUOfst( const sal_uInt16 nOfst )
     450             : {
     451         432 :     if ( !pRealFirst || ((m_aCacheObjects.size() - aFreePositions.size()) < nOfst) )
     452         864 :         return;
     453             : 
     454             :     CHECK;
     455           0 :     pFirst = pRealFirst;
     456           0 :     for ( sal_uInt16 i = 0; i < m_aCacheObjects.size() && i < nOfst; ++i )
     457             :     {
     458           0 :         if ( pFirst->GetNext() && pFirst->GetNext()->GetNext() )
     459           0 :             pFirst = pFirst->GetNext();
     460             :         else
     461           0 :             break;
     462             :     }
     463             :     CHECK;
     464             : }
     465             : 
     466        3746 : SwCacheObj::SwCacheObj( const void *pOwn ) :
     467             :     pNext( 0 ),
     468             :     pPrev( 0 ),
     469             :     nCachePos( USHRT_MAX ),
     470             :     nLock( 0 ),
     471        3746 :     pOwner( pOwn )
     472             : {
     473        3746 : }
     474             : 
     475        3746 : SwCacheObj::~SwCacheObj()
     476             : {
     477        3746 : }
     478             : 
     479             : #ifdef DBG_UTIL
     480             : void SwCacheObj::Lock()
     481             : {
     482             :     OSL_ENSURE( nLock < UCHAR_MAX, "Too many Locks for CacheObject." );
     483             :     ++nLock;
     484             : }
     485             : 
     486             : void SwCacheObj::Unlock()
     487             : {
     488             :     OSL_ENSURE( nLock, "No more Locks available." );
     489             :     --nLock;
     490             : }
     491             : #endif
     492             : 
     493       27881 : SwCacheAccess::~SwCacheAccess()
     494             : {
     495       27881 :     if ( pObj )
     496       27881 :         pObj->Unlock();
     497       27881 : }
     498             : 
     499        3716 : void SwCacheAccess::_Get()
     500             : {
     501             :     OSL_ENSURE( !pObj, "SwCacheAcces Obj already available." );
     502             : 
     503        3716 :     pObj = NewObj();
     504        3716 :     if ( !rCache.Insert( pObj ) )
     505             :     {
     506           0 :         delete pObj;
     507           0 :         pObj = 0;
     508             :     }
     509             :     else
     510             :     {
     511        3716 :         pObj->Lock();
     512             :     }
     513        3716 : }
     514             : 
     515           0 : sal_Bool SwCacheAccess::IsAvailable() const
     516             : {
     517           0 :     return pObj != 0;
     518             : }
     519             : 
     520             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10