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