xref: /AOO41X/main/sc/source/core/data/compressedarray.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 #include "compressedarray.hxx"
32 #include "address.hxx"
33 
34 #include <algorithm>
35 
36 template< typename A, typename D >
37 ScCompressedArray<A,D>::ScCompressedArray( A nMaxAccessP, const D& rValue,
38         size_t nDeltaP )
39     : nCount(1)
40     , nLimit(1)
41     , nDelta( nDeltaP > 0 ? nDeltaP : 1)
42     , pData( new DataEntry[1])
43     , nMaxAccess( nMaxAccessP)
44 {
45     pData[0].aValue = rValue;
46     pData[0].nEnd = nMaxAccess;
47 }
48 
49 
50 template< typename A, typename D >
51 ScCompressedArray<A,D>::ScCompressedArray( A nMaxAccessP, const D* pDataArray,
52         size_t nDataCount )
53     : nCount(0)
54     , nLimit( nDataCount)
55     , nDelta( nScCompressedArrayDelta)
56     , pData( new DataEntry[nDataCount])
57     , nMaxAccess( nMaxAccessP)
58 {
59     D aValue = pDataArray[0];
60     for (size_t j=0; j<nDataCount; ++j)
61     {
62         if (!(aValue == pDataArray[j]))
63         {
64             pData[nCount].aValue = aValue;
65             pData[nCount].nEnd = j-1;
66             ++nCount;
67             aValue = pDataArray[j];
68         }
69     }
70     pData[nCount].aValue = aValue;
71     pData[nCount].nEnd = nMaxAccess;
72     ++nCount;
73     Resize( nCount);
74 }
75 
76 
77 template< typename A, typename D >
78 ScCompressedArray<A,D>::~ScCompressedArray()
79 {
80     delete[] pData;
81 }
82 
83 
84 template< typename A, typename D >
85 void ScCompressedArray<A,D>::Resize( size_t nNewLimit)
86 {
87     if ((nCount <= nNewLimit && nNewLimit < nLimit) || nLimit < nNewLimit)
88     {
89         nLimit = nNewLimit;
90         DataEntry* pNewData = new DataEntry[nLimit];
91         memcpy( pNewData, pData, nCount*sizeof(DataEntry));
92         delete[] pData;
93         pData = pNewData;
94     }
95 }
96 
97 
98 template< typename A, typename D >
99 size_t ScCompressedArray<A,D>::Search( A nAccess ) const
100 {
101     if (nAccess == 0)
102         return 0;
103 
104     long nLo    = 0;
105     long nHi    = static_cast<long>(nCount) - 1;
106     long nStart = 0;
107     long nEnd   = 0;
108     long i      = 0;
109     bool bFound = (nCount == 1);
110     while (!bFound && nLo <= nHi)
111     {
112         i = (nLo + nHi) / 2;
113         if (i > 0)
114             nStart = (long) pData[i - 1].nEnd;
115         else
116             nStart = -1;
117         nEnd = (long) pData[i].nEnd;
118         if (nEnd < (long) nAccess)
119             nLo = ++i;
120         else
121             if (nStart >= (long) nAccess)
122                 nHi = --i;
123             else
124                 bFound = true;
125     }
126     return (bFound ? static_cast<size_t>(i) : (nAccess < 0 ? 0 : nCount-1));
127 }
128 
129 
130 template< typename A, typename D >
131 void ScCompressedArray<A,D>::SetValue( A nStart, A nEnd, const D& rValue )
132 {
133     if (0 <= nStart && nStart <= nMaxAccess && 0 <= nEnd && nEnd <= nMaxAccess
134             && nStart <= nEnd)
135     {
136         if ((nStart == 0) && (nEnd == nMaxAccess))
137             Reset( rValue);
138         else
139         {
140             // Create a temporary copy in case we got a reference passed that
141             // points to a part of the array to be reallocated.
142             D aNewVal( rValue);
143             size_t nNeeded = nCount + 2;
144             if (nLimit < nNeeded)
145             {
146                 nLimit += nDelta;
147                 if (nLimit < nNeeded)
148                     nLimit = nNeeded;
149                 DataEntry* pNewData = new DataEntry[nLimit];
150                 memcpy( pNewData, pData, nCount*sizeof(DataEntry));
151                 delete[] pData;
152                 pData = pNewData;
153             }
154 
155             size_t ni;          // number of leading entries
156             size_t nInsert;     // insert position (nMaxAccess+1 := no insert)
157             bool bCombined = false;
158             bool bSplit = false;
159             if (nStart > 0)
160             {
161                 // skip leading
162                 ni = Search( nStart);
163 
164                 nInsert = nMaxAccess+1;
165                 if (!(pData[ni].aValue == aNewVal))
166                 {
167                     if (ni == 0 || (pData[ni-1].nEnd < nStart - 1))
168                     {   // may be a split or a simple insert or just a shrink,
169                         // row adjustment is done further down
170                         if (pData[ni].nEnd > nEnd)
171                             bSplit = true;
172                         ni++;
173                         nInsert = ni;
174                     }
175                     else if (ni > 0 && pData[ni-1].nEnd == nStart - 1)
176                         nInsert = ni;
177                 }
178                 if (ni > 0 && pData[ni-1].aValue == aNewVal)
179                 {   // combine
180                     pData[ni-1].nEnd = nEnd;
181                     nInsert = nMaxAccess+1;
182                     bCombined = true;
183                 }
184             }
185             else
186             {
187                 nInsert = 0;
188                 ni = 0;
189             }
190 
191             size_t nj = ni;     // stop position of range to replace
192             while (nj < nCount && pData[nj].nEnd <= nEnd)
193                 nj++;
194             if (!bSplit)
195             {
196                 if (nj < nCount && pData[nj].aValue == aNewVal)
197                 {   // combine
198                     if (ni > 0)
199                     {
200                         if (pData[ni-1].aValue == aNewVal)
201                         {   // adjacent entries
202                             pData[ni-1].nEnd = pData[nj].nEnd;
203                             nj++;
204                         }
205                         else if (ni == nInsert)
206                             pData[ni-1].nEnd = nStart - 1;   // shrink
207                     }
208                     nInsert = nMaxAccess+1;
209                     bCombined = true;
210                 }
211                 else if (ni > 0 && ni == nInsert)
212                     pData[ni-1].nEnd = nStart - 1;   // shrink
213             }
214             if (ni < nj)
215             {   // remove middle entries
216                 if (!bCombined)
217                 {   // replace one entry
218                     pData[ni].nEnd = nEnd;
219                     pData[ni].aValue = aNewVal;
220                     ni++;
221                     nInsert = nMaxAccess+1;
222                 }
223                 if (ni < nj)
224                 {   // remove entries
225                     memmove( pData + ni, pData + nj,
226                             (nCount - nj) * sizeof(DataEntry));
227                     nCount -= nj - ni;
228                 }
229             }
230 
231             if (nInsert < static_cast<size_t>(nMaxAccess+1))
232             {   // insert or append new entry
233                 if (nInsert <= nCount)
234                 {
235                     if (!bSplit)
236                         memmove( pData + nInsert + 1, pData + nInsert,
237                                 (nCount - nInsert) * sizeof(DataEntry));
238                     else
239                     {
240                         memmove( pData + nInsert + 2, pData + nInsert,
241                                 (nCount - nInsert) * sizeof(DataEntry));
242                         pData[nInsert+1] = pData[nInsert-1];
243                         nCount++;
244                     }
245                 }
246                 if (nInsert)
247                     pData[nInsert-1].nEnd = nStart - 1;
248                 pData[nInsert].nEnd = nEnd;
249                 pData[nInsert].aValue = aNewVal;
250                 nCount++;
251             }
252         }
253     }
254 }
255 
256 
257 template< typename A, typename D >
258 void ScCompressedArray<A,D>::CopyFrom( const ScCompressedArray<A,D>& rArray, A nStart,
259         A nEnd, long nSourceDy )
260 {
261     size_t nIndex;
262     A nRegionEnd;
263     for (A j=nStart; j<=nEnd; ++j)
264     {
265         const D& rValue = (j==nStart ?
266                 rArray.GetValue( j+nSourceDy, nIndex, nRegionEnd) :
267                 rArray.GetNextValue( nIndex, nRegionEnd));
268         nRegionEnd -= nSourceDy;
269         if (nRegionEnd > nEnd)
270             nRegionEnd = nEnd;
271         SetValue( j, nRegionEnd, rValue);
272         j = nRegionEnd;
273     }
274 }
275 
276 
277 template< typename A, typename D >
278 const D& ScCompressedArray<A,D>::Insert( A nStart, size_t nAccessCount )
279 {
280     size_t nIndex = Search( nStart);
281     // No real insertion is needed, simply extend the one entry and adapt all
282     // following. In case nStart points to the start row of an entry, extend
283     // the previous entry (inserting before nStart).
284     if (nIndex > 0 && pData[nIndex-1].nEnd+1 == nStart)
285         --nIndex;
286     const D& rValue = pData[nIndex].aValue; // the value "copied"
287     do
288     {
289         pData[nIndex].nEnd += nAccessCount;
290         if (pData[nIndex].nEnd >= nMaxAccess)
291         {
292             pData[nIndex].nEnd = nMaxAccess;
293             nCount = nIndex + 1;    // discard trailing entries
294         }
295     } while (++nIndex < nCount);
296     return rValue;
297 }
298 
299 
300 template< typename A, typename D >
301 void ScCompressedArray<A,D>::Remove( A nStart, size_t nAccessCount )
302 {
303     A nEnd = nStart + nAccessCount - 1;
304     size_t nIndex = Search( nStart);
305     // equalize/combine/remove all entries in between
306     if (nEnd > pData[nIndex].nEnd)
307         SetValue( nStart, nEnd, pData[nIndex].aValue);
308     // remove an exactly matching entry by shifting up all following by one
309     if ((nStart == 0 || (nIndex > 0 && nStart == pData[nIndex-1].nEnd+1)) &&
310             pData[nIndex].nEnd == nEnd && nIndex < nCount-1)
311     {
312         // In case removing an entry results in two adjacent entries with
313         // identical data, combine them into one. This is also necessary to
314         // make the algorithm used in SetValue() work correctly, it relies on
315         // the fact that consecutive values actually differ.
316         size_t nRemove;
317         if (nIndex > 0 && pData[nIndex-1].aValue == pData[nIndex+1].aValue)
318         {
319             nRemove = 2;
320             --nIndex;
321         }
322         else
323             nRemove = 1;
324         memmove( pData + nIndex, pData + nIndex + nRemove, (nCount - (nIndex +
325                         nRemove)) * sizeof(DataEntry));
326         nCount -= nRemove;
327     }
328     // adjust end rows, nIndex still being valid
329     do
330     {
331         pData[nIndex].nEnd -= nAccessCount;
332     } while (++nIndex < nCount);
333     pData[nCount-1].nEnd = nMaxAccess;
334 }
335 
336 
337 template< typename A, typename D >
338 A ScCompressedArray<A,D>::GetLastUnequalAccess( A nStart, const D& rCompare )
339 {
340     A nEnd = ::std::numeric_limits<A>::max();
341     size_t nIndex = nCount-1;
342     while (1)
343     {
344         if (pData[nIndex].aValue != rCompare)
345         {
346             nEnd = pData[nIndex].nEnd;
347             break;  // while
348         }
349         else
350         {
351             if (nIndex > 0)
352             {
353                 --nIndex;
354                 if (pData[nIndex].nEnd < nStart)
355                     break;  // while
356             }
357             else
358                 break;  // while
359         }
360     }
361     return nEnd;
362 }
363 
364 
365 // === ScSummableCompressedArray =============================================
366 
367 template< typename A, typename D >
368 unsigned long ScSummableCompressedArray<A,D>::SumValues( A nStart, A nEnd ) const
369 {
370     size_t nIndex = Search( nStart);
371     unsigned long nSum = SumValuesContinuation( nStart, nEnd, nIndex);
372     if (nEnd > this->nMaxAccess)
373         nSum += this->pData[this->nCount-1].aValue * (nEnd - this->nMaxAccess);
374     return nSum;
375 }
376 
377 
378 template< typename A, typename D >
379 unsigned long ScSummableCompressedArray<A,D>::SumValuesContinuation(
380         A nStart, A nEnd, size_t& nIndex ) const
381 {
382     unsigned long nSum = 0;
383     A nS = nStart;
384     while (nIndex < this->nCount && nS <= nEnd)
385     {
386         A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
387         // FIXME: test for overflow in a single region?
388         unsigned long nNew = (unsigned long) this->pData[nIndex].aValue * (nE - nS + 1);
389         nSum += nNew;
390         if (nSum < nNew)
391             return ::std::numeric_limits<unsigned long>::max();
392         nS = nE + 1;
393         if (nS <= nEnd)
394             ++nIndex;
395     }
396     return nSum;
397 }
398 
399 
400 template< typename A, typename D >
401 unsigned long ScSummableCompressedArray<A,D>::SumScaledValuesContinuation(
402         A nStart, A nEnd, size_t& nIndex, double fScale ) const
403 {
404     unsigned long nSum = 0;
405     A nS = nStart;
406     while (nIndex < this->nCount && nS <= nEnd)
407     {
408         A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
409         unsigned long nScaledVal = (unsigned long) (this->pData[nIndex].aValue * fScale);
410         // FIXME: test for overflow in a single region?
411         unsigned long nNew = nScaledVal * (nE - nS + 1);
412         nSum += nNew;
413         if (nSum < nNew)
414             return ::std::numeric_limits<unsigned long>::max();
415         nS = nE + 1;
416         if (nS <= nEnd)
417             ++nIndex;
418     }
419     return nSum;
420 }
421 
422 
423 // === ScBitMaskCompressedArray ==============================================
424 
425 template< typename A, typename D >
426 void ScBitMaskCompressedArray<A,D>::AndValue( A nStart, A nEnd,
427         const D& rValueToAnd )
428 {
429     if (nStart > nEnd)
430         return;
431 
432     size_t nIndex = Search( nStart);
433     do
434     {
435         if ((this->pData[nIndex].aValue & rValueToAnd) != this->pData[nIndex].aValue)
436         {
437             A nS = ::std::max( (nIndex>0 ? this->pData[nIndex-1].nEnd+1 : 0), nStart);
438             A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
439             SetValue( nS, nE, this->pData[nIndex].aValue & rValueToAnd);
440             if (nE >= nEnd)
441                 break;  // while
442             nIndex = Search( nE + 1);
443         }
444         else if (this->pData[nIndex].nEnd >= nEnd)
445             break;  // while
446         else
447             ++nIndex;
448     } while (nIndex < this->nCount);
449 }
450 
451 
452 template< typename A, typename D >
453 void ScBitMaskCompressedArray<A,D>::OrValue( A nStart, A nEnd,
454         const D& rValueToOr )
455 {
456     if (nStart > nEnd)
457         return;
458 
459     size_t nIndex = Search( nStart);
460     do
461     {
462         if ((this->pData[nIndex].aValue | rValueToOr) != this->pData[nIndex].aValue)
463         {
464             A nS = ::std::max( (nIndex>0 ? this->pData[nIndex-1].nEnd+1 : 0), nStart);
465             A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
466             SetValue( nS, nE, this->pData[nIndex].aValue | rValueToOr);
467             if (nE >= nEnd)
468                 break;  // while
469             nIndex = Search( nE + 1);
470         }
471         else if (this->pData[nIndex].nEnd >= nEnd)
472             break;  // while
473         else
474             ++nIndex;
475     } while (nIndex < this->nCount);
476 }
477 
478 
479 template< typename A, typename D >
480 void ScBitMaskCompressedArray<A,D>::CopyFromAnded(
481         const ScBitMaskCompressedArray<A,D>& rArray, A nStart, A nEnd,
482         const D& rValueToAnd, long nSourceDy )
483 {
484     size_t nIndex;
485     A nRegionEnd;
486     for (A j=nStart; j<=nEnd; ++j)
487     {
488         const D& rValue = (j==nStart ?
489                 rArray.GetValue( j+nSourceDy, nIndex, nRegionEnd) :
490                 rArray.GetNextValue( nIndex, nRegionEnd));
491         nRegionEnd -= nSourceDy;
492         if (nRegionEnd > nEnd)
493             nRegionEnd = nEnd;
494         SetValue( j, nRegionEnd, rValue & rValueToAnd);
495         j = nRegionEnd;
496     }
497 }
498 
499 
500 template< typename A, typename D >
501 void ScBitMaskCompressedArray<A,D>::CopyFromOred(
502         const ScBitMaskCompressedArray<A,D>& rArray, A nStart, A nEnd,
503         const D& rValueToOr, long nSourceDy )
504 {
505     size_t nIndex;
506     A nRegionEnd;
507     for (A j=nStart; j<=nEnd; ++j)
508     {
509         const D& rValue = (j==nStart ?
510                 rArray.GetValue( j+nSourceDy, nIndex, nRegionEnd) :
511                 rArray.GetNextValue( nIndex, nRegionEnd));
512         nRegionEnd -= nSourceDy;
513         if (nRegionEnd > nEnd)
514             nRegionEnd = nEnd;
515         SetValue( j, nRegionEnd, rValue | rValueToOr);
516         j = nRegionEnd;
517     }
518 }
519 
520 
521 template< typename A, typename D >
522 A ScBitMaskCompressedArray<A,D>::GetBitStateStart( A nEnd,
523         const D& rBitMask, const D& rMaskedCompare ) const
524 {
525     A nStart = ::std::numeric_limits<A>::max();
526     size_t nIndex = Search( nEnd);
527     while ((this->pData[nIndex].aValue & rBitMask) == rMaskedCompare)
528     {
529         if (nIndex > 0)
530         {
531             --nIndex;
532             nStart = this->pData[nIndex].nEnd + 1;
533         }
534         else
535         {
536             nStart = 0;
537             break;  // while
538         }
539     }
540     return nStart;
541 }
542 
543 
544 template< typename A, typename D >
545 A ScBitMaskCompressedArray<A,D>::GetBitStateEnd( A nStart,
546         const D& rBitMask, const D& rMaskedCompare ) const
547 {
548     A nEnd = ::std::numeric_limits<A>::max();
549     size_t nIndex = Search( nStart);
550     while (nIndex < this->nCount && (this->pData[nIndex].aValue & rBitMask) ==
551             rMaskedCompare)
552     {
553         nEnd = this->pData[nIndex].nEnd;
554         ++nIndex;
555     }
556     return nEnd;
557 }
558 
559 
560 template< typename A, typename D >
561 A ScBitMaskCompressedArray<A,D>::GetFirstForCondition( A nStart, A nEnd,
562         const D& rBitMask, const D& rMaskedCompare ) const
563 {
564     size_t nIndex = Search( nStart);
565     do
566     {
567         if ((this->pData[nIndex].aValue & rBitMask) == rMaskedCompare)
568         {
569             A nFound = nIndex > 0 ? this->pData[nIndex-1].nEnd + 1 : 0;
570             return ::std::max( nFound, nStart);
571         }
572         if (this->pData[nIndex].nEnd >= nEnd)
573             break;  // while
574         ++nIndex;
575     } while (nIndex < this->nCount);
576     return ::std::numeric_limits<A>::max();
577 }
578 
579 
580 template< typename A, typename D >
581 A ScBitMaskCompressedArray<A,D>::GetLastForCondition( A nStart, A nEnd,
582         const D& rBitMask, const D& rMaskedCompare ) const
583 {
584     size_t nIndex = Search( nEnd);
585     while (1)
586     {
587         if ((this->pData[nIndex].aValue & rBitMask) == rMaskedCompare)
588             return ::std::min( this->pData[nIndex].nEnd, nEnd);
589 
590         if (nIndex > 0)
591         {
592             --nIndex;
593             if (this->pData[nIndex].nEnd < nStart)
594                 break;  // while
595         }
596         else
597             break;  // while
598     }
599     return ::std::numeric_limits<A>::max();
600 }
601 
602 
603 template< typename A, typename D >
604 A ScBitMaskCompressedArray<A,D>::CountForCondition( A nStart, A nEnd,
605         const D& rBitMask, const D& rMaskedCompare ) const
606 {
607     A nRet = 0;
608     size_t nIndex = Search( nStart);
609     do
610     {
611         if ((this->pData[nIndex].aValue & rBitMask) == rMaskedCompare)
612         {
613             A nS = ::std::max( (nIndex>0 ? this->pData[nIndex-1].nEnd+1 : 0), nStart);
614             A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
615             nRet += nE - nS + 1;
616         }
617         if (this->pData[nIndex].nEnd >= nEnd)
618             break;  // while
619         ++nIndex;
620     } while (nIndex < this->nCount);
621     return nRet;
622 }
623 
624 
625 template< typename A, typename D >
626 size_t ScBitMaskCompressedArray<A,D>::FillArrayForCondition( A nStart, A nEnd,
627         const D& rBitMask, const D& rMaskedCompare,
628         A * pArray, size_t nArraySize ) const
629 {
630     size_t nUsed = 0;
631     size_t nIndex = Search( nStart);
632     while (nIndex < this->nCount && nUsed < nArraySize)
633     {
634         if ((this->pData[nIndex].aValue & rBitMask) == rMaskedCompare)
635         {
636             A nS = ::std::max( (nIndex>0 ? this->pData[nIndex-1].nEnd+1 : 0), nStart);
637             A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
638             while (nS <= nE && nUsed < nArraySize)
639                 pArray[nUsed++] = nS++;
640         }
641         if (this->pData[nIndex].nEnd >= nEnd)
642             break;  // while
643         ++nIndex;
644     }
645     return nUsed;
646 }
647 
648 
649 template< typename A, typename D >
650 bool ScBitMaskCompressedArray<A,D>::HasCondition( A nStart, A nEnd,
651         const D& rBitMask, const D& rMaskedCompare ) const
652 {
653     size_t nIndex = Search( nStart);
654     do
655     {
656         if ((this->pData[nIndex].aValue & rBitMask) == rMaskedCompare)
657             return true;
658         if (this->pData[nIndex].nEnd >= nEnd)
659             break;  // while
660         ++nIndex;
661     }  while (nIndex < this->nCount);
662     return false;
663 }
664 
665 
666 template< typename A, typename D >
667 A ScBitMaskCompressedArray<A,D>::CountForAnyBitCondition( A nStart, A nEnd,
668         const D& rBitMask ) const
669 {
670     A nRet = 0;
671     size_t nIndex = Search( nStart);
672     do
673     {
674         if ((this->pData[nIndex].aValue & rBitMask) != 0)
675         {
676             A nS = ::std::max( (nIndex>0 ? this->pData[nIndex-1].nEnd+1 : 0), nStart);
677             A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
678             nRet += nE - nS + 1;
679         }
680         if (this->pData[nIndex].nEnd >= nEnd)
681             break;  // while
682         ++nIndex;
683     } while (nIndex < this->nCount);
684     return nRet;
685 }
686 
687 
688 template< typename A, typename D >
689 A ScBitMaskCompressedArray<A,D>::GetLastAnyBitAccess( A nStart,
690         const D& rBitMask ) const
691 {
692     A nEnd = ::std::numeric_limits<A>::max();
693     size_t nIndex = this->nCount-1;
694     while (1)
695     {
696         if ((this->pData[nIndex].aValue & rBitMask) != 0)
697         {
698             nEnd = this->pData[nIndex].nEnd;
699             break;  // while
700         }
701         else
702         {
703             if (nIndex > 0)
704             {
705                 --nIndex;
706                 if (this->pData[nIndex].nEnd < nStart)
707                     break;  // while
708             }
709             else
710                 break;  // while
711         }
712     }
713     return nEnd;
714 }
715 
716 
717 template< typename A, typename D >
718 template< typename S >
719 unsigned long ScBitMaskCompressedArray<A,D>::SumCoupledArrayForCondition(
720         A nStart, A nEnd, const D& rBitMask, const D& rMaskedCompare,
721         const ScSummableCompressedArray<A,S>& rArray ) const
722 {
723     unsigned long nSum = 0;
724     A nS = nStart;
725     size_t nIndex1 = Search( nStart);
726     size_t nIndex2 = rArray.Search( nStart);
727     do
728     {
729         if ((this->pData[nIndex1].aValue & rBitMask) == rMaskedCompare)
730         {
731             while (nIndex2 < rArray.GetEntryCount() &&
732                     rArray.GetDataEntry(nIndex2).nEnd < nS)
733                 ++nIndex2;
734             unsigned long nNew = rArray.SumValuesContinuation( nS,
735                     ::std::min( this->pData[nIndex1].nEnd, nEnd), nIndex2);
736             nSum += nNew;
737             if (nSum < nNew)
738                 return ::std::numeric_limits<unsigned long>::max();
739         }
740         nS = this->pData[nIndex1].nEnd + 1;
741         ++nIndex1;
742     } while (nIndex1 < this->nCount && nS <= nEnd);
743     if (nEnd > this->nMaxAccess &&
744             (this->pData[this->GetEntryCount()-1].aValue & rBitMask) == rMaskedCompare)
745         nSum += rArray.GetDataEntry(rArray.GetEntryCount()-1).aValue * (nEnd -
746                 this->nMaxAccess);
747     return nSum;
748 }
749 
750 
751 template< typename A, typename D >
752 template< typename S >
753 unsigned long ScBitMaskCompressedArray<A,D>::SumScaledCoupledArrayForCondition(
754         A nStart, A nEnd, const D& rBitMask, const D& rMaskedCompare,
755         const ScSummableCompressedArray<A,S>& rArray, double fScale ) const
756 {
757     unsigned long nSum = 0;
758     A nS = nStart;
759     size_t nIndex1 = Search( nStart);
760     size_t nIndex2 = rArray.Search( nStart);
761     do
762     {
763         if ((this->pData[nIndex1].aValue & rBitMask) == rMaskedCompare)
764         {
765             while (nIndex2 < rArray.GetEntryCount() &&
766                     rArray.GetDataEntry(nIndex2).nEnd < nS)
767                 ++nIndex2;
768             unsigned long nNew = rArray.SumScaledValuesContinuation( nS,
769                     ::std::min( this->pData[nIndex1].nEnd, nEnd), nIndex2, fScale);
770             nSum += nNew;
771             if (nSum < nNew)
772                 return ::std::numeric_limits<unsigned long>::max();
773         }
774         nS = this->pData[nIndex1].nEnd + 1;
775         ++nIndex1;
776     } while (nIndex1 < this->nCount && nS <= nEnd);
777     if (nEnd > this->nMaxAccess &&
778             (this->pData[this->GetEntryCount()-1].aValue & rBitMask) == rMaskedCompare)
779         nSum += (unsigned long)
780             (rArray.GetDataEntry(rArray.GetEntryCount()-1).aValue * fScale) *
781             (nEnd - this->nMaxAccess);
782     return nSum;
783 }
784 
785 
786 // === ScCompressedArrayIterator =============================================
787 
788 template< typename A, typename D >
789 template< typename X >
790 void ScCompressedArrayIterator<A,D>::Follow(
791         const ScCompressedArrayIterator<A,X>& rIter )
792 {
793     nCurrent = rIter.GetPos();
794     if (GetRangeStart() <= nCurrent && nCurrent <= GetRangeEnd())
795         ; // nothing
796     else if (nCurrent > GetRangeEnd())
797     {
798         A nPos = nCurrent;  // nCurrent gets changed in NextRange()
799         bool bAdv;
800         do
801         {
802             bAdv = NextRange();
803         } while (bAdv && GetRangeEnd() < nPos);
804         nCurrent = nPos;
805     }
806     else
807         nIndex = rArray.Search( nCurrent);
808 }
809 
810 
811 // === ScCoupledCompressedArrayIterator ======================================
812 
813 template< typename A, typename D, typename S >
814 ScCoupledCompressedArrayIterator<A,D,S>::ScCoupledCompressedArrayIterator(
815         const ScBitMaskCompressedArray<A,D> & rArray1, A nStart, A nEnd,
816         const D& rBitMaskP, const D& rMaskedCompareP,
817         const ScCompressedArray<A,S> & rArray2 )
818     : aIter1( rArray1, nStart, nEnd )
819     , aIter2( rArray2, nStart, nEnd )
820     , rBitMask( rBitMaskP )
821     , rMaskedCompare( rMaskedCompareP )
822 {
823     InitLimits();
824 }
825 
826 
827 template< typename A, typename D, typename S >
828 void ScCoupledCompressedArrayIterator<A,D,S>::InitLimits()
829 {
830     bool bFound = true;
831     bool bMoved = false;
832     while (bFound && ((*aIter1 & rBitMask) != rMaskedCompare))
833     {
834         bFound = aIter1.NextRange();
835         bMoved = true;
836     }
837     if (bMoved && bFound)
838         aIter2.Follow( aIter1);
839 }
840 
841 
842 template< typename A, typename D, typename S >
843 void ScCoupledCompressedArrayIterator<A,D,S>::NewLimits( A nStart, A nEnd )
844 {
845     aIter1.NewLimits( nStart, nEnd);
846     aIter2.NewLimits( nStart, nEnd);
847     InitLimits();
848 }
849 
850 
851 template< typename A, typename D, typename S >
852 bool ScCoupledCompressedArrayIterator<A,D,S>::NextRange()
853 {
854     bool bAdv;
855     if (aIter1.GetRangeEnd() <= aIter2.GetRangeEnd())
856     {
857         // Advance bit mask array until condition is met, coupled array
858         // follows.
859         do
860         {
861             bAdv = aIter1.NextRange();
862         } while (bAdv && ((*aIter1 & rBitMask) != rMaskedCompare));
863         if (bAdv)
864             aIter2.Follow( aIter1);
865     }
866     else
867     {
868         // Make coupled array catch up with bit mask array.
869         do
870         {
871             bAdv = aIter2.NextRange();
872         } while (bAdv && aIter2.GetRangeEnd() < aIter1.GetRangeStart());
873         if (bAdv)
874             aIter1.Follow( aIter2);     // synchronize aIter1.nCurrent
875     }
876     return operator bool();
877 }
878 
879 
880 template< typename A, typename D, typename S >
881 void ScCoupledCompressedArrayIterator<A,D,S>::Resync( A nPos )
882 {
883     aIter1.Resync( nPos);
884     aIter2.Resync( nPos);
885     InitLimits();
886 }
887 
888 
889 // === Force instantiation of specializations ================================
890 
891 template class ScCompressedArray< SCROW, sal_uInt16>;           // heights, base class
892 template class ScSummableCompressedArray< SCROW, sal_uInt16>;   // heights
893 template class ScCompressedArray< SCROW, sal_uInt8>;             // flags, base class
894 template class ScBitMaskCompressedArray< SCROW, sal_uInt8>;      // flags
895 template unsigned long ScBitMaskCompressedArray< SCROW,
896     sal_uInt8>::SumCoupledArrayForCondition( SCROW, SCROW, const sal_uInt8&, const sal_uInt8&,
897             const ScSummableCompressedArray< SCROW, sal_uInt16>&) const;
898 template unsigned long ScBitMaskCompressedArray< SCROW,
899     sal_uInt8>::SumScaledCoupledArrayForCondition( SCROW, SCROW, const sal_uInt8&,
900             const sal_uInt8&, const ScSummableCompressedArray< SCROW, sal_uInt16>&,
901             double) const;
902 template void ScCompressedArrayIterator< SCROW, sal_uInt16>::Follow(
903         const ScCompressedArrayIterator< SCROW, sal_uInt8>&);
904 template class ScCoupledCompressedArrayIterator< SCROW, sal_uInt8, sal_uInt16>;
905 
906 // === EOF ===================================================================
907