1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26
27
28 #include <tools/debug.hxx>
29 #include <errhdl.hxx>
30 #include <swcache.hxx>
31
32 SV_IMPL_PTRARR(SwCacheObjArr,SwCacheObj*);
33
34 #ifndef DBG_UTIL
35 #define INCREMENT( nVar )
36 #else
37 #define INCREMENT( nVar ) ++nVar
38 #endif
39
40 /*************************************************************************
41 |*
42 |* SwCache::Check()
43 |*
44 |* Ersterstellung MA 23. Mar. 94
45 |* Letzte Aenderung MA 23. Mar. 94
46 |*
47 |*************************************************************************/
48
49 #ifdef DBG_UTIL
50
Check()51 void SwCache::Check()
52 {
53 if ( !pRealFirst )
54 return;
55
56 //Konsistenspruefung.
57 ASSERT( !pLast->GetNext(), "Last but not last." );
58 ASSERT( !pRealFirst->GetPrev(), "First but not first." );
59 sal_uInt16 nCnt = 0;
60 sal_Bool bFirstFound = sal_False;
61 SwCacheObj *pObj = pRealFirst;
62 SwCacheObj *pRekursive = pObj;
63 while ( pObj )
64 {
65 //Das Objekt muss auch auf dem Rueckwaertsweg gefunden werden.
66 SwCacheObj *pTmp = pLast;
67 while ( pTmp && pTmp != pObj )
68 pTmp = pTmp->GetPrev();
69 ASSERT( pTmp, "Objekt not found." );
70
71 ++nCnt;
72 if ( pObj == pFirst )
73 bFirstFound = sal_True;
74 if ( !pObj->GetNext() )
75 ASSERT( pObj == pLast, "Last not Found." );
76 pObj = pObj->GetNext();
77 ASSERT( pObj != pRekursive, "Recursion in SwCache." );
78 }
79 ASSERT( bFirstFound, "First not Found." );
80 ASSERT( (nCnt + aFreePositions.Count()) == Count(), "Lost Chain." );
81 if ( Count() == nCurMax )
82 ASSERT( (nCurMax - nCnt) == aFreePositions.Count(), "Lost FreePositions." );
83 }
84 #endif
85
86 #if defined(DBG_UTIL) && defined(MADEBUG)
87 #define CHECK Check();
88 #else
89 #define CHECK
90 #endif
91
92 /*************************************************************************
93 |*
94 |* SwCache::SwCache(), ~SwCache()
95 |*
96 |* Ersterstellung MA 15. Mar. 94
97 |* Letzte Aenderung MA 15. Mar. 94
98 |*
99 |*************************************************************************/
100
101
SwCache(const sal_uInt16 nInitSize,const sal_uInt16 nGrowSize,const ByteString & rNm)102 SwCache::SwCache( const sal_uInt16 nInitSize, const sal_uInt16 nGrowSize
103 #ifdef DBG_UTIL
104 , const ByteString &rNm
105 #endif
106 ) :
107 SwCacheObjArr( (sal_uInt8)nInitSize, (sal_uInt8)nGrowSize ),
108 aFreePositions( 5, 5 ),
109 pRealFirst( 0 ),
110 pFirst( 0 ),
111 pLast( 0 ),
112 nMax( nInitSize ),
113 nCurMax( nInitSize )
114 #ifdef DBG_UTIL
115 , aName( rNm ),
116 nAppend( 0 ),
117 nInsertFree( 0 ),
118 nReplace( 0 ),
119 nGetSuccess( 0 ),
120 nGetFail( 0 ),
121 nToTop( 0 ),
122 nDelete( 0 ),
123 nGetSeek( 0 ),
124 nAverageSeekCnt( 0 ),
125 nFlushCnt( 0 ),
126 nFlushedObjects( 0 ),
127 nIncreaseMax( 0 ),
128 nDecreaseMax( 0 )
129 #endif
130 {
131 }
132
133 #ifdef DBG_UTIL
134
135
~SwCache()136 SwCache::~SwCache()
137 {
138 #if OSL_DEBUG_LEVEL > 1
139 {
140 ByteString sOut( aName ); sOut += '\n';
141 (( sOut += "Anzahl neuer Eintraege: " )
142 += ByteString::CreateFromInt32( nAppend ))+= '\n';
143 (( sOut += "Anzahl Insert auf freie Plaetze: " )
144 += ByteString::CreateFromInt32( nInsertFree ))+= '\n';
145 (( sOut += "Anzahl Ersetzungen: " )
146 += ByteString::CreateFromInt32( nReplace ))+= '\n';
147 (( sOut += "Anzahl Erfolgreicher Get's: " )
148 += ByteString::CreateFromInt32( nGetSuccess ))+= '\n';
149 (( sOut += "Anzahl Fehlgeschlagener Get's: " )
150 += ByteString::CreateFromInt32( nGetFail ))+= '\n';
151 (( sOut += "Anzahl Umsortierungen (LRU): " )
152 += ByteString::CreateFromInt32( nToTop ))+= '\n';
153 (( sOut += "Anzahl Loeschungen: " )
154 += ByteString::CreateFromInt32( nDelete ))+= '\n';
155 (( sOut += "Anzahl Get's ohne Index: " )
156 += ByteString::CreateFromInt32( nGetSeek ))+= '\n';
157 (( sOut += "Anzahl Seek fuer Get ohne Index: " )
158 += ByteString::CreateFromInt32( nAverageSeekCnt ))+= '\n';
159 (( sOut += "Anzahl Flush-Aufrufe: " )
160 += ByteString::CreateFromInt32( nFlushCnt ))+= '\n';
161 (( sOut += "Anzahl geflush'ter Objekte: " )
162 += ByteString::CreateFromInt32( nFlushedObjects ))+= '\n';
163 (( sOut += "Anzahl Cache-Erweiterungen: " )
164 += ByteString::CreateFromInt32( nIncreaseMax ))+= '\n';
165 (( sOut += "Anzahl Cache-Verkleinerungen: " )
166 += ByteString::CreateFromInt32( nDecreaseMax ))+= '\n';
167
168 DBG_ERROR( sOut.GetBuffer() );
169 }
170 Check();
171 #endif
172 }
173 #endif
174
175 /*************************************************************************
176 |*
177 |* SwCache::Flush()
178 |*
179 |* Ersterstellung MA 15. Mar. 94
180 |* Letzte Aenderung MA 15. Mar. 94
181 |*
182 |*************************************************************************/
183
184
Flush(const sal_uInt8)185 void SwCache::Flush( const sal_uInt8 )
186 {
187 INCREMENT( nFlushCnt );
188 SwCacheObj *pObj = pRealFirst;
189 pRealFirst = pFirst = pLast = 0;
190 SwCacheObj *pTmp;
191 while ( pObj )
192 {
193 #ifdef DBG_UTIL
194 if ( pObj->IsLocked() )
195 {
196 ASSERT( sal_True, "Flushing locked objects." );
197 if ( !pRealFirst )
198 {
199 pRealFirst = pFirst = pLast = pObj;
200 pTmp = pObj->GetNext();
201 pObj->SetNext( 0 ); pObj->SetPrev( 0 );
202 pObj = pTmp;
203 }
204 else
205 { pLast->SetNext( pObj );
206 pObj->SetPrev( pLast );
207 pLast = pObj;
208 pTmp = pObj->GetNext();
209 pObj->SetNext( 0 );
210 pObj = pTmp;
211 }
212 }
213 else
214 #endif
215 {
216 pTmp = (SwCacheObj*)pObj;
217 pObj = pTmp->GetNext();
218 aFreePositions.Insert( pTmp->GetCachePos(), aFreePositions.Count() );
219 *(pData + pTmp->GetCachePos()) = (void*)0;
220 delete pTmp;
221 INCREMENT( nFlushedObjects );
222 }
223 }
224 }
225
226 /*************************************************************************
227 |*
228 |* SwCache::ToTop()
229 |*
230 |* Ersterstellung MA 15. Mar. 94
231 |* Letzte Aenderung MA 24. Apr. 95
232 |*
233 |*************************************************************************/
234
235
ToTop(SwCacheObj * pObj)236 void SwCache::ToTop( SwCacheObj *pObj )
237 {
238 INCREMENT( nToTop );
239
240 //Objekt aus der LRU-Kette ausschneiden und am Anfang einfuegen.
241 if ( pRealFirst == pObj ) //pFirst wurde vom Aufrufer geprueft!
242 { CHECK;
243 return;
244 }
245
246 if ( !pRealFirst )
247 { //Der erste wird eingetragen.
248 ASSERT( !pFirst && !pLast, "First not first." );
249 pRealFirst = pFirst = pLast = pObj;
250 CHECK;
251 return;
252 }
253
254 //Ausschneiden.
255 if ( pObj == pLast )
256 {
257 ASSERT( pObj->GetPrev(), "Last but no Prev." );
258 pLast = pObj->GetPrev();
259 pLast->SetNext( 0 );
260 }
261 else
262 {
263 if ( pObj->GetNext() )
264 pObj->GetNext()->SetPrev( pObj->GetPrev() );
265 if ( pObj->GetPrev() )
266 pObj->GetPrev()->SetNext( pObj->GetNext() );
267 }
268
269 //Am (virtuellen) Anfang einfuegen.
270 if ( pRealFirst == pFirst )
271 {
272 pRealFirst->SetPrev( pObj );
273 pObj->SetNext( pRealFirst );
274 pObj->SetPrev( 0 );
275 pRealFirst = pFirst = pObj;
276 CHECK;
277 }
278 else
279 {
280 ASSERT( pFirst, "ToTop, First ist not RealFirst an Empty." );
281
282 if ( pFirst->GetPrev() )
283 {
284 pFirst->GetPrev()->SetNext( pObj );
285 pObj->SetPrev( pFirst->GetPrev() );
286 }
287 else
288 pObj->SetPrev( 0 );
289 pFirst->SetPrev( pObj );
290 pObj->SetNext( pFirst );
291 pFirst = pObj;
292 CHECK;
293 }
294 }
295
296 /*************************************************************************
297 |*
298 |* SwCache::Get()
299 |*
300 |* Ersterstellung MA 15. Mar. 94
301 |* Letzte Aenderung MA 22. Aug. 94
302 |*
303 |*************************************************************************/
304
305
Get(const void * pOwner,const sal_uInt16 nIndex,const sal_Bool bToTop)306 SwCacheObj *SwCache::Get( const void *pOwner, const sal_uInt16 nIndex,
307 const sal_Bool bToTop )
308 {
309 SwCacheObj *pRet;
310 if ( 0 != (pRet = nIndex < Count() ? operator[]( nIndex ) : 0) )
311 {
312 if ( !pRet->IsOwner( pOwner ) )
313 pRet = 0;
314 else if ( bToTop && pRet != pFirst )
315 ToTop( pRet );
316 }
317
318 #ifdef DBG_UTIL
319 if ( pRet )
320 ++nGetSuccess;
321 else
322 ++nGetFail;
323 #endif
324
325 return pRet;
326 }
327
328
329
Get(const void * pOwner,const sal_Bool bToTop)330 SwCacheObj *SwCache::Get( const void *pOwner, const sal_Bool bToTop )
331 {
332 SwCacheObj *pRet = pRealFirst;
333 while ( pRet && !pRet->IsOwner( pOwner ) )
334 {
335 INCREMENT( nAverageSeekCnt );
336 pRet = pRet->GetNext();
337 }
338
339 if ( bToTop && pRet && pRet != pFirst )
340 ToTop( pRet );
341
342 #ifdef DBG_UTIL
343 if ( pRet )
344 ++nGetSuccess;
345 else
346 ++nGetFail;
347 ++nGetSeek;
348 #endif
349 return pRet;
350 }
351
352 /*************************************************************************
353 |*
354 |* SwCache::Delete()
355 |*
356 |* Ersterstellung MA 15. Mar. 94
357 |* Letzte Aenderung MA 15. Mar. 94
358 |*
359 |*************************************************************************/
360
361
DeleteObj(SwCacheObj * pObj)362 void SwCache::DeleteObj( SwCacheObj *pObj )
363 {
364 CHECK;
365 ASSERT( !pObj->IsLocked(), "SwCache::Delete: Object ist Locked." );
366 if ( pObj->IsLocked() )
367 return;
368
369 if ( pFirst == pObj )
370 {
371 if ( pFirst->GetNext() )
372 pFirst = pFirst->GetNext();
373 else
374 pFirst = pFirst->GetPrev();
375 }
376 if ( pRealFirst == pObj )
377 pRealFirst = pRealFirst->GetNext();
378 if ( pLast == pObj )
379 pLast = pLast->GetPrev();
380 if ( pObj->GetPrev() )
381 pObj->GetPrev()->SetNext( pObj->GetNext() );
382 if ( pObj->GetNext() )
383 pObj->GetNext()->SetPrev( pObj->GetPrev() );
384
385 aFreePositions.Insert( pObj->GetCachePos(), aFreePositions.Count() );
386 *(pData + pObj->GetCachePos()) = (void*)0;
387 delete pObj;
388
389 CHECK;
390 if ( Count() > nCurMax &&
391 (nCurMax <= (Count() - aFreePositions.Count())) )
392 {
393 //Falls moeglich wieder verkleinern, dazu muessen allerdings ausreichend
394 //Freie Positionen bereitstehen.
395 //Unangenehmer Nebeneffekt ist, das die Positionen verschoben werden
396 //muessen, und die Eigentuemer der Objekte diese wahrscheinlich nicht
397 //wiederfinden werden.
398 for ( sal_uInt16 i = 0; i < Count(); ++i )
399 {
400 SwCacheObj *pTmpObj = operator[](i);
401 if ( !pTmpObj )
402 { SwCacheObjArr::Remove( i, 1 );
403 --i;
404 }
405 else
406 pTmpObj->SetCachePos( i );
407 }
408 aFreePositions.Remove( 0, aFreePositions.Count() );
409 }
410 CHECK;
411 }
412
413 /*
414
415
416 void SwCache::Delete( const void *pOwner, const sal_uInt16 nIndex )
417 {
418 INCREMENT( nDelete );
419 SwCacheObj *pObj;
420 if ( 0 != (pObj = Get( pOwner, nIndex, sal_False )) )
421 DeleteObj( pObj );
422 }
423 */
424
425
426
Delete(const void * pOwner)427 void SwCache::Delete( const void *pOwner )
428 {
429 INCREMENT( nDelete );
430 SwCacheObj *pObj;
431 if ( 0 != (pObj = Get( pOwner, sal_Bool(sal_False) )) )
432 DeleteObj( pObj );
433 }
434
435
436 /*************************************************************************
437 |*
438 |* SwCache::Insert()
439 |*
440 |* Ersterstellung MA 15. Mar. 94
441 |* Letzte Aenderung MA 20. Sep. 94
442 |*
443 |*************************************************************************/
444
445
Insert(SwCacheObj * pNew)446 sal_Bool SwCache::Insert( SwCacheObj *pNew )
447 {
448 CHECK;
449 ASSERT( !pNew->GetPrev() && !pNew->GetNext(), "New but not new." );
450
451 sal_uInt16 nPos;//Wird hinter den if's zum setzen am Obj benutzt.
452 if ( Count() < nCurMax )
453 {
454 //Es ist noch Platz frei, also einfach einfuegen.
455 INCREMENT( nAppend );
456 nPos = Count();
457 SwCacheObjArr::C40_INSERT( SwCacheObj, pNew, nPos );
458 }
459 else if ( aFreePositions.Count() )
460 {
461 //Es exitieren Platzhalter, also den letzten benutzen.
462 INCREMENT( nInsertFree );
463 const sal_uInt16 nFreePos = aFreePositions.Count() - 1;
464 nPos = aFreePositions[ nFreePos ];
465 *(pData + nPos) = pNew;
466 aFreePositions.Remove( nFreePos );
467 }
468 else
469 {
470 INCREMENT( nReplace );
471 //Der letzte des LRU fliegt raus.
472 SwCacheObj *pObj = pLast;
473
474 while ( pObj && pObj->IsLocked() )
475 pObj = pObj->GetPrev();
476 if ( !pObj )
477 {
478 ASSERT( sal_False, "Cache overflow." );
479 return sal_False;
480 }
481
482 nPos = pObj->GetCachePos();
483 if ( pObj == pLast )
484 { ASSERT( pObj->GetPrev(), "Last but no Prev" );
485 pLast = pObj->GetPrev();
486 pLast->SetNext( 0 );
487 }
488 else
489 {
490 if ( pObj->GetPrev() )
491 pObj->GetPrev()->SetNext( pObj->GetNext() );
492 if ( pObj->GetNext() )
493 pObj->GetNext()->SetPrev( pObj->GetPrev() );
494 }
495 delete pObj;
496 *(pData + nPos) = pNew;
497 }
498 pNew->SetCachePos( nPos );
499
500 //Anstelle von ToTop, einfach als pFirst einfuegen.
501 // ToTop( nPos );
502 if ( pFirst )
503 {
504 if ( pFirst->GetPrev() )
505 { pFirst->GetPrev()->SetNext( pNew );
506 pNew->SetPrev( pFirst->GetPrev() );
507 }
508 pFirst->SetPrev( pNew );
509 pNew->SetNext( pFirst );
510 }
511 else
512 { ASSERT( !pLast, "Last but no First." );
513 pLast = pNew;
514 }
515 if ( pFirst == pRealFirst )
516 pRealFirst = pNew;
517 pFirst = pNew;
518
519 CHECK;
520 return sal_True;
521 }
522
523 /*************************************************************************
524 |*
525 |* SwCache::SetLRUOfst()
526 |*
527 |* Ersterstellung MA 15. Mar. 94
528 |* Letzte Aenderung MA 15. Mar. 94
529 |*
530 |*************************************************************************/
531
532
SetLRUOfst(const sal_uInt16 nOfst)533 void SwCache::SetLRUOfst( const sal_uInt16 nOfst )
534 {
535 if ( !pRealFirst || ((Count() - aFreePositions.Count()) < nOfst) )
536 return;
537
538 CHECK;
539 pFirst = pRealFirst;
540 for ( sal_uInt16 i = 0; i < Count() && i < nOfst; ++i )
541 {
542 if ( pFirst->GetNext() && pFirst->GetNext()->GetNext() )
543 pFirst = pFirst->GetNext();
544 else
545 break;
546 }
547 CHECK;
548 }
549
550 /*************************************************************************
551 |*
552 |* SwCacheObj::SwCacheObj()
553 |*
554 |* Ersterstellung MA 15. Mar. 94
555 |* Letzte Aenderung MA 24. Nov. 95
556 |*
557 |*************************************************************************/
558
559
SwCacheObj(const void * pOwn)560 SwCacheObj::SwCacheObj( const void *pOwn ) :
561 pNext( 0 ),
562 pPrev( 0 ),
563 nCachePos( USHRT_MAX ),
564 nLock( 0 ),
565 pOwner( pOwn )
566 {
567 }
568
569
570
~SwCacheObj()571 SwCacheObj::~SwCacheObj()
572 {
573 }
574
575 /*************************************************************************
576 |*
577 |* SwCacheObj::SetLock(), Unlock()
578 |*
579 |* Ersterstellung MA 15. Mar. 94
580 |* Letzte Aenderung MA 15. Mar. 94
581 |*
582 |*************************************************************************/
583
584 #ifdef DBG_UTIL
585
586
587
Lock()588 void SwCacheObj::Lock()
589 {
590 ASSERT( nLock < UCHAR_MAX, "To many Locks for CacheObject." );
591 ++nLock;
592 }
593
594
595
Unlock()596 void SwCacheObj::Unlock()
597 {
598 ASSERT( nLock, "No more Locks available." );
599 --nLock;
600 }
601 #endif
602
603
~SwCacheAccess()604 SwCacheAccess::~SwCacheAccess()
605 {
606 if ( pObj )
607 pObj->Unlock();
608 }
609
610 /*************************************************************************
611 |*
612 |* SwCacheAccess::Get()
613 |*
614 |* Ersterstellung MA 15. Mar. 94
615 |* Letzte Aenderung MA 04. Apr. 95
616 |*
617 |*************************************************************************/
618
619
_Get()620 void SwCacheAccess::_Get()
621 {
622 ASSERT( !pObj, "SwCacheAcces Obj already available." );
623
624 pObj = NewObj();
625 if ( !rCache.Insert( pObj ) )
626 {
627 delete pObj;
628 pObj = 0;
629 }
630 else
631 pObj->Lock();
632 }
633
634 /*************************************************************************
635 |*
636 |* SwCacheAccess::IsAvailable()
637 |*
638 |* Ersterstellung MA 23. Mar. 94
639 |* Letzte Aenderung MA 23. Mar. 94
640 |*
641 |*************************************************************************/
642
643
IsAvailable() const644 sal_Bool SwCacheAccess::IsAvailable() const
645 {
646 return pObj != 0;
647 }
648
649
650
651
652
653