1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <rtl/strbuf.hxx>
21 #include <swcache.hxx>
22 #include <limits.h> // USHRT_MAX
31 SAL_WARN_IF( pLast
->GetNext(), "sw.core", "Last but not last." );
32 SAL_WARN_IF( pRealFirst
->GetPrev(), "sw.core", "First but not first." );
34 bool bFirstFound
= false;
35 SwCacheObj
*pObj
= pRealFirst
;
36 SwCacheObj
*pRekursive
= pObj
;
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." );
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." );
53 SAL_WARN_IF( !bFirstFound
, "sw.core", "First not Found." );
54 SAL_WARN_IF( nCnt
+ aFreePositions
.size() != size(), "sw.core", "Lost Chain." );
56 size() == nCurMax
&& nCurMax
!= aFreePositions
.size() + nCnt
, "sw.core",
57 "Lost FreePositions." );
60 #define INCREMENT( nVar ) ++nVar
61 #define CHECK Check();
64 #define INCREMENT( nVar )
69 SwCache::SwCache( const sal_uInt16 nInitSize
71 , const rtl::OString
&rNm
89 , m_nAverageSeekCnt( 0 )
91 , m_nFlushedObjects( 0 )
96 m_aCacheObjects
.reserve( (sal_uInt8
)nInitSize
);
103 rtl::OStringBuffer
sOut(m_aName
);
106 append(RTL_CONSTASCII_STRINGPARAM(
107 "Number of new entries: ")).
108 append(static_cast<sal_Int32
>(m_nAppend
)).
110 append(RTL_CONSTASCII_STRINGPARAM(
111 "Number of insert on free places: ")).
112 append(static_cast<sal_Int32
>(m_nInsertFree
)).
114 append(RTL_CONSTASCII_STRINGPARAM(
115 "Number of replacements: ")).
116 append(static_cast<sal_Int32
>(m_nReplace
)).
118 append(RTL_CONSTASCII_STRINGPARAM(
119 "Number of successful Get's: ")).
120 append(static_cast<sal_Int32
>(m_nGetSuccess
)).
122 append(RTL_CONSTASCII_STRINGPARAM(
123 "Number of failed Get's: ")).
124 append(static_cast<sal_Int32
>(m_nGetFail
)).
126 append(RTL_CONSTASCII_STRINGPARAM(
127 "Number or reordering (LRU): ")).
128 append(static_cast<sal_Int32
>(m_nToTop
)).
130 append(RTL_CONSTASCII_STRINGPARAM(
131 "Number of suppressions: ")).
132 append(static_cast<sal_Int32
>(m_nDelete
)).
134 append(RTL_CONSTASCII_STRINGPARAM(
135 "Number of Get's without Index: ")).
136 append(static_cast<sal_Int32
>(m_nGetSeek
)).
138 append(RTL_CONSTASCII_STRINGPARAM(
139 "Number of Seek for Get without Index: ")).
140 append(static_cast<sal_Int32
>(m_nAverageSeekCnt
)).
142 append(RTL_CONSTASCII_STRINGPARAM(
143 "Number of Flush calls: " )).
144 append(static_cast<sal_Int32
>(m_nFlushCnt
)).
146 append(RTL_CONSTASCII_STRINGPARAM(
147 "Number of flushed objects: ")).
148 append(static_cast<sal_Int32
>(m_nFlushedObjects
)).
150 append(RTL_CONSTASCII_STRINGPARAM(
151 "Number of Cache expansions: ")).
152 append(static_cast<sal_Int32
>(m_nIncreaseMax
)).
154 append(RTL_CONSTASCII_STRINGPARAM(
155 "Number of Cache reductions: ")).
156 append(static_cast<sal_Int32
>(m_nDecreaseMax
)).
159 OSL_TRACE(sOut
.getStr());
164 for(SwCacheObjArr::const_iterator it
= m_aCacheObjects
.begin(); it
!= m_aCacheObjects
.end(); ++it
)
168 void SwCache::Flush( const sal_uInt8
)
170 INCREMENT( m_nFlushCnt
);
171 SwCacheObj
*pObj
= pRealFirst
;
172 pRealFirst
= pFirst
= pLast
= 0;
177 if ( pObj
->IsLocked() )
179 OSL_FAIL( "Flushing locked objects." );
182 pRealFirst
= pFirst
= pLast
= pObj
;
183 pTmp
= pObj
->GetNext();
184 pObj
->SetNext( 0 ); pObj
->SetPrev( 0 );
188 { pLast
->SetNext( pObj
);
189 pObj
->SetPrev( pLast
);
191 pTmp
= pObj
->GetNext();
199 pTmp
= (SwCacheObj
*)pObj
;
200 pObj
= pTmp
->GetNext();
201 aFreePositions
.push_back( pTmp
->GetCachePos() );
202 m_aCacheObjects
[pTmp
->GetCachePos()] = NULL
;
204 INCREMENT( m_nFlushedObjects
);
209 void SwCache::ToTop( SwCacheObj
*pObj
)
211 INCREMENT( m_nToTop
);
213 // cut object out of chain and insert at beginning
214 if ( pRealFirst
== pObj
) // pFirst was checked by caller
222 // the first will be inserted
223 OSL_ENSURE( !pFirst
&& !pLast
, "First not first." );
224 pRealFirst
= pFirst
= pLast
= pObj
;
232 OSL_ENSURE( pObj
->GetPrev(), "Last but no Prev." );
233 pLast
= pObj
->GetPrev();
238 if ( pObj
->GetNext() )
239 pObj
->GetNext()->SetPrev( pObj
->GetPrev() );
240 if ( pObj
->GetPrev() )
241 pObj
->GetPrev()->SetNext( pObj
->GetNext() );
244 // paste at the (virtual) beginning
245 if ( pRealFirst
== pFirst
)
247 pRealFirst
->SetPrev( pObj
);
248 pObj
->SetNext( pRealFirst
);
250 pRealFirst
= pFirst
= pObj
;
255 OSL_ENSURE( pFirst
, "ToTop, First ist not RealFirst an Empty." );
257 if ( pFirst
->GetPrev() )
259 pFirst
->GetPrev()->SetNext( pObj
);
260 pObj
->SetPrev( pFirst
->GetPrev() );
264 pFirst
->SetPrev( pObj
);
265 pObj
->SetNext( pFirst
);
271 SwCacheObj
*SwCache::Get( const void *pOwner
, const sal_uInt16 nIndex
,
272 const sal_Bool bToTop
)
275 if ( 0 != (pRet
= nIndex
< m_aCacheObjects
.size() ? m_aCacheObjects
[ nIndex
] : 0) )
277 if ( !pRet
->IsOwner( pOwner
) )
279 else if ( bToTop
&& pRet
!= pFirst
)
293 SwCacheObj
*SwCache::Get( const void *pOwner
, const sal_Bool bToTop
)
295 SwCacheObj
*pRet
= pRealFirst
;
296 while ( pRet
&& !pRet
->IsOwner( pOwner
) )
298 INCREMENT( m_nAverageSeekCnt
);
299 pRet
= pRet
->GetNext();
302 if ( bToTop
&& pRet
&& pRet
!= pFirst
)
315 void SwCache::DeleteObj( SwCacheObj
*pObj
)
318 OSL_ENSURE( !pObj
->IsLocked(), "SwCache::Delete: object is locked." );
319 if ( pObj
->IsLocked() )
322 if ( pFirst
== pObj
)
324 if ( pFirst
->GetNext() )
325 pFirst
= pFirst
->GetNext();
327 pFirst
= pFirst
->GetPrev();
329 if ( pRealFirst
== pObj
)
330 pRealFirst
= pRealFirst
->GetNext();
332 pLast
= pLast
->GetPrev();
333 if ( pObj
->GetPrev() )
334 pObj
->GetPrev()->SetNext( pObj
->GetNext() );
335 if ( pObj
->GetNext() )
336 pObj
->GetNext()->SetPrev( pObj
->GetPrev() );
338 aFreePositions
.push_back( pObj
->GetCachePos() );
339 m_aCacheObjects
[pObj
->GetCachePos()] = NULL
;
343 if ( m_aCacheObjects
.size() > nCurMax
&&
344 (nCurMax
<= (m_aCacheObjects
.size() - aFreePositions
.size())) )
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 for ( sal_uInt16 i
= 0; i
< m_aCacheObjects
.size(); ++i
)
351 SwCacheObj
*pTmpObj
= m_aCacheObjects
[i
];
353 { m_aCacheObjects
.erase( m_aCacheObjects
.begin() + i
);
358 pTmpObj
->SetCachePos( i
);
361 aFreePositions
.clear();
366 void SwCache::Delete( const void *pOwner
)
368 INCREMENT( m_nDelete
);
370 if ( 0 != (pObj
= Get( pOwner
, sal_Bool(sal_False
) )) )
374 sal_Bool
SwCache::Insert( SwCacheObj
*pNew
)
377 OSL_ENSURE( !pNew
->GetPrev() && !pNew
->GetNext(), "New but not new." );
380 if ( m_aCacheObjects
.size() < nCurMax
)
382 // there is still space; insert directly
383 INCREMENT( m_nAppend
);
384 nPos
= m_aCacheObjects
.size();
385 m_aCacheObjects
.push_back(pNew
);
387 else if ( !aFreePositions
.empty() )
389 // there are placeholders; use the last of those
390 INCREMENT( m_nInsertFree
);
391 const sal_uInt16 nFreePos
= aFreePositions
.size() - 1;
392 nPos
= aFreePositions
[ nFreePos
];
393 m_aCacheObjects
[nPos
] = pNew
;
394 aFreePositions
.erase( aFreePositions
.begin() + nFreePos
);
398 INCREMENT( m_nReplace
);
399 // the last of the LRU has to go
400 SwCacheObj
*pObj
= pLast
;
402 while ( pObj
&& pObj
->IsLocked() )
403 pObj
= pObj
->GetPrev();
406 OSL_FAIL( "Cache overflow." );
410 nPos
= pObj
->GetCachePos();
412 { OSL_ENSURE( pObj
->GetPrev(), "Last but no Prev" );
413 pLast
= pObj
->GetPrev();
418 if ( pObj
->GetPrev() )
419 pObj
->GetPrev()->SetNext( pObj
->GetNext() );
420 if ( pObj
->GetNext() )
421 pObj
->GetNext()->SetPrev( pObj
->GetPrev() );
424 m_aCacheObjects
[nPos
] = pNew
;
426 pNew
->SetCachePos( nPos
);
430 if ( pFirst
->GetPrev() )
431 { pFirst
->GetPrev()->SetNext( pNew
);
432 pNew
->SetPrev( pFirst
->GetPrev() );
434 pFirst
->SetPrev( pNew
);
435 pNew
->SetNext( pFirst
);
438 { OSL_ENSURE( !pLast
, "Last but no First." );
441 if ( pFirst
== pRealFirst
)
449 void SwCache::SetLRUOfst( const sal_uInt16 nOfst
)
451 if ( !pRealFirst
|| ((m_aCacheObjects
.size() - aFreePositions
.size()) < nOfst
) )
456 for ( sal_uInt16 i
= 0; i
< m_aCacheObjects
.size() && i
< nOfst
; ++i
)
458 if ( pFirst
->GetNext() && pFirst
->GetNext()->GetNext() )
459 pFirst
= pFirst
->GetNext();
466 SwCacheObj::SwCacheObj( const void *pOwn
) :
469 nCachePos( USHRT_MAX
),
475 SwCacheObj::~SwCacheObj()
480 void SwCacheObj::Lock()
482 OSL_ENSURE( nLock
< UCHAR_MAX
, "Too many Locks for CacheObject." );
486 void SwCacheObj::Unlock()
488 OSL_ENSURE( nLock
, "No more Locks available." );
493 SwCacheAccess::~SwCacheAccess()
499 void SwCacheAccess::_Get()
501 OSL_ENSURE( !pObj
, "SwCacheAcces Obj already available." );
504 if ( !rCache
.Insert( pObj
) )
515 sal_Bool
SwCacheAccess::IsAvailable() const
520 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */