LCOV - code coverage report
Current view: top level - sc/source/core/data - compressedarray.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 188 217 86.6 %
Date: 2014-11-03 Functions: 13 14 92.9 %
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 "compressedarray.hxx"
      21             : #include "address.hxx"
      22             : 
      23             : #include <algorithm>
      24             : 
      25             : template< typename A, typename D >
      26        2544 : ScCompressedArray<A,D>::ScCompressedArray( A nMaxAccessP, const D& rValue,
      27             :         size_t nDeltaP )
      28             :     : nCount(1)
      29             :     , nLimit(1)
      30             :     , nDelta( nDeltaP > 0 ? nDeltaP : 1)
      31             :     , pData( new DataEntry[1])
      32        2544 :     , nMaxAccess( nMaxAccessP)
      33             : {
      34        2544 :     pData[0].aValue = rValue;
      35        2544 :     pData[0].nEnd = nMaxAccess;
      36        2544 : }
      37             : 
      38             : template< typename A, typename D >
      39          40 : ScCompressedArray<A,D>::ScCompressedArray( A nMaxAccessP, const D* pDataArray,
      40             :         size_t nDataCount )
      41             :     : nCount(0)
      42             :     , nLimit( nDataCount)
      43             :     , nDelta( nScCompressedArrayDelta)
      44             :     , pData( new DataEntry[nDataCount])
      45          40 :     , nMaxAccess( nMaxAccessP)
      46             : {
      47          40 :     D aValue = pDataArray[0];
      48       41000 :     for (size_t j=0; j<nDataCount; ++j)
      49             :     {
      50       40960 :         if (!(aValue == pDataArray[j]))
      51             :         {
      52           0 :             pData[nCount].aValue = aValue;
      53           0 :             pData[nCount].nEnd = j-1;
      54           0 :             ++nCount;
      55           0 :             aValue = pDataArray[j];
      56             :         }
      57             :     }
      58          40 :     pData[nCount].aValue = aValue;
      59          40 :     pData[nCount].nEnd = nMaxAccess;
      60          40 :     ++nCount;
      61          40 :     Resize( nCount);
      62          40 : }
      63             : 
      64             : template< typename A, typename D >
      65        2580 : ScCompressedArray<A,D>::~ScCompressedArray()
      66             : {
      67        2580 :     delete[] pData;
      68        5160 : }
      69             : 
      70             : template< typename A, typename D >
      71          40 : void ScCompressedArray<A,D>::Resize( size_t nNewLimit)
      72             : {
      73          40 :     if ((nCount <= nNewLimit && nNewLimit < nLimit) || nLimit < nNewLimit)
      74             :     {
      75          40 :         nLimit = nNewLimit;
      76          40 :         DataEntry* pNewData = new DataEntry[nLimit];
      77          40 :         memcpy( pNewData, pData, nCount*sizeof(DataEntry));
      78          40 :         delete[] pData;
      79          40 :         pData = pNewData;
      80             :     }
      81          40 : }
      82             : 
      83             : template< typename A, typename D >
      84        9776 : size_t ScCompressedArray<A,D>::Search( A nAccess ) const
      85             : {
      86        9776 :     if (nAccess == 0)
      87        3502 :         return 0;
      88             : 
      89        6274 :     long nLo    = 0;
      90        6274 :     long nHi    = static_cast<long>(nCount) - 1;
      91        6274 :     long nStart = 0;
      92        6274 :     long nEnd   = 0;
      93        6274 :     long i      = 0;
      94        6274 :     bool bFound = (nCount == 1);
      95       16832 :     while (!bFound && nLo <= nHi)
      96             :     {
      97        4284 :         i = (nLo + nHi) / 2;
      98        4284 :         if (i > 0)
      99        3082 :             nStart = (long) pData[i - 1].nEnd;
     100             :         else
     101        1202 :             nStart = -1;
     102        4284 :         nEnd = (long) pData[i].nEnd;
     103        4284 :         if (nEnd < (long) nAccess)
     104        1656 :             nLo = ++i;
     105             :         else
     106        2628 :             if (nStart >= (long) nAccess)
     107         150 :                 nHi = --i;
     108             :             else
     109        2478 :                 bFound = true;
     110             :     }
     111        6274 :     return (bFound ? static_cast<size_t>(i) : (nAccess < 0 ? 0 : nCount-1));
     112             : }
     113             : 
     114             : template< typename A, typename D >
     115        1198 : void ScCompressedArray<A,D>::SetValue( A nStart, A nEnd, const D& rValue )
     116             : {
     117        1198 :     if (0 <= nStart && nStart <= nMaxAccess && 0 <= nEnd && nEnd <= nMaxAccess
     118             :             && nStart <= nEnd)
     119             :     {
     120        1198 :         if ((nStart == 0) && (nEnd == nMaxAccess))
     121         106 :             Reset( rValue);
     122             :         else
     123             :         {
     124             :             // Create a temporary copy in case we got a reference passed that
     125             :             // points to a part of the array to be reallocated.
     126        1092 :             D aNewVal( rValue);
     127        1092 :             size_t nNeeded = nCount + 2;
     128        1092 :             if (nLimit < nNeeded)
     129             :             {
     130         412 :                 nLimit += nDelta;
     131         412 :                 if (nLimit < nNeeded)
     132           0 :                     nLimit = nNeeded;
     133         412 :                 DataEntry* pNewData = new DataEntry[nLimit];
     134         412 :                 memcpy( pNewData, pData, nCount*sizeof(DataEntry));
     135         412 :                 delete[] pData;
     136         412 :                 pData = pNewData;
     137             :             }
     138             : 
     139             :             size_t ni;          // number of leading entries
     140             :             size_t nInsert;     // insert position (nMaxAccess+1 := no insert)
     141        1092 :             bool bCombined = false;
     142        1092 :             bool bSplit = false;
     143        1092 :             if (nStart > 0)
     144             :             {
     145             :                 // skip leading
     146         774 :                 ni = this->Search( nStart);
     147             : 
     148         774 :                 nInsert = nMaxAccess+1;
     149         774 :                 if (!(pData[ni].aValue == aNewVal))
     150             :                 {
     151         662 :                     if (ni == 0 || (pData[ni-1].nEnd < nStart - 1))
     152             :                     {   // may be a split or a simple insert or just a shrink,
     153             :                         // row adjustment is done further down
     154         146 :                         if (pData[ni].nEnd > nEnd)
     155         144 :                             bSplit = true;
     156         146 :                         ni++;
     157         146 :                         nInsert = ni;
     158             :                     }
     159         516 :                     else if (ni > 0 && pData[ni-1].nEnd == nStart - 1)
     160         516 :                         nInsert = ni;
     161             :                 }
     162         774 :                 if (ni > 0 && pData[ni-1].aValue == aNewVal)
     163             :                 {   // combine
     164         516 :                     pData[ni-1].nEnd = nEnd;
     165         516 :                     nInsert = nMaxAccess+1;
     166         516 :                     bCombined = true;
     167             :                 }
     168             :             }
     169             :             else
     170             :             {
     171         318 :                 nInsert = 0;
     172         318 :                 ni = 0;
     173             :             }
     174             : 
     175        1092 :             size_t nj = ni;     // stop position of range to replace
     176        2222 :             while (nj < nCount && pData[nj].nEnd <= nEnd)
     177          38 :                 nj++;
     178        1092 :             if (!bSplit)
     179             :             {
     180         948 :                 if (nj < nCount && pData[nj].aValue == aNewVal)
     181             :                 {   // combine
     182         258 :                     if (ni > 0)
     183             :                     {
     184          32 :                         if (pData[ni-1].aValue == aNewVal)
     185             :                         {   // adjacent entries
     186           0 :                             pData[ni-1].nEnd = pData[nj].nEnd;
     187           0 :                             nj++;
     188             :                         }
     189          32 :                         else if (ni == nInsert)
     190           2 :                             pData[ni-1].nEnd = nStart - 1;   // shrink
     191             :                     }
     192         258 :                     nInsert = nMaxAccess+1;
     193         258 :                     bCombined = true;
     194             :                 }
     195         690 :                 else if (ni > 0 && ni == nInsert)
     196           0 :                     pData[ni-1].nEnd = nStart - 1;   // shrink
     197             :             }
     198        1092 :             if (ni < nj)
     199             :             {   // remove middle entries
     200          38 :                 if (!bCombined)
     201             :                 {   // replace one entry
     202          26 :                     pData[ni].nEnd = nEnd;
     203          26 :                     pData[ni].aValue = aNewVal;
     204          26 :                     ni++;
     205          26 :                     nInsert = nMaxAccess+1;
     206             :                 }
     207          38 :                 if (ni < nj)
     208             :                 {   // remove entries
     209          12 :                     memmove( pData + ni, pData + nj,
     210          12 :                             (nCount - nj) * sizeof(DataEntry));
     211          12 :                     nCount -= nj - ni;
     212             :                 }
     213             :             }
     214             : 
     215        1092 :             if (nInsert < static_cast<size_t>(nMaxAccess+1))
     216             :             {   // insert or append new entry
     217         292 :                 if (nInsert <= nCount)
     218             :                 {
     219         292 :                     if (!bSplit)
     220         148 :                         memmove( pData + nInsert + 1, pData + nInsert,
     221         148 :                                 (nCount - nInsert) * sizeof(DataEntry));
     222             :                     else
     223             :                     {
     224         144 :                         memmove( pData + nInsert + 2, pData + nInsert,
     225         144 :                                 (nCount - nInsert) * sizeof(DataEntry));
     226         144 :                         pData[nInsert+1] = pData[nInsert-1];
     227         144 :                         nCount++;
     228             :                     }
     229             :                 }
     230         292 :                 if (nInsert)
     231         144 :                     pData[nInsert-1].nEnd = nStart - 1;
     232         292 :                 pData[nInsert].nEnd = nEnd;
     233         292 :                 pData[nInsert].aValue = aNewVal;
     234         292 :                 nCount++;
     235             :             }
     236             :         }
     237             :     }
     238        1198 : }
     239             : 
     240             : template< typename A, typename D >
     241         246 : void ScCompressedArray<A,D>::CopyFrom( const ScCompressedArray<A,D>& rArray, A nStart,
     242             :         A nEnd, long nSourceDy )
     243             : {
     244         246 :     size_t nIndex = 0;
     245             :     A nRegionEnd;
     246         532 :     for (A j=nStart; j<=nEnd; ++j)
     247             :     {
     248         246 :         const D& rValue = (j==nStart ?
     249             :                 rArray.GetValue( j+nSourceDy, nIndex, nRegionEnd) :
     250         532 :                 rArray.GetNextValue( nIndex, nRegionEnd));
     251         286 :         nRegionEnd -= nSourceDy;
     252         286 :         if (nRegionEnd > nEnd)
     253         130 :             nRegionEnd = nEnd;
     254         286 :         this->SetValue( j, nRegionEnd, rValue);
     255         286 :         j = nRegionEnd;
     256             :     }
     257         246 : }
     258             : 
     259             : template< typename A, typename D >
     260          80 : const D& ScCompressedArray<A,D>::Insert( A nStart, size_t nAccessCount )
     261             : {
     262          80 :     size_t nIndex = this->Search( nStart);
     263             :     // No real insertion is needed, simply extend the one entry and adapt all
     264             :     // following. In case nStart points to the start row of an entry, extend
     265             :     // the previous entry (inserting before nStart).
     266          80 :     if (nIndex > 0 && pData[nIndex-1].nEnd+1 == nStart)
     267           0 :         --nIndex;
     268          80 :     const D& rValue = pData[nIndex].aValue; // the value "copied"
     269          80 :     do
     270             :     {
     271          80 :         pData[nIndex].nEnd += nAccessCount;
     272          80 :         if (pData[nIndex].nEnd >= nMaxAccess)
     273             :         {
     274          80 :             pData[nIndex].nEnd = nMaxAccess;
     275          80 :             nCount = nIndex + 1;    // discard trailing entries
     276             :         }
     277             :     } while (++nIndex < nCount);
     278          80 :     return rValue;
     279             : }
     280             : 
     281             : template< typename A, typename D >
     282          72 : void ScCompressedArray<A,D>::Remove( A nStart, size_t nAccessCount )
     283             : {
     284          72 :     A nEnd = nStart + nAccessCount - 1;
     285          72 :     size_t nIndex = this->Search( nStart);
     286             :     // equalize/combine/remove all entries in between
     287          72 :     if (nEnd > pData[nIndex].nEnd)
     288           0 :         this->SetValue( nStart, nEnd, pData[nIndex].aValue);
     289             :     // remove an exactly matching entry by shifting up all following by one
     290          90 :     if ((nStart == 0 || (nIndex > 0 && nStart == pData[nIndex-1].nEnd+1)) &&
     291          18 :             pData[nIndex].nEnd == nEnd && nIndex < nCount-1)
     292             :     {
     293             :         // In case removing an entry results in two adjacent entries with
     294             :         // identical data, combine them into one. This is also necessary to
     295             :         // make the algorithm used in SetValue() work correctly, it relies on
     296             :         // the fact that consecutive values actually differ.
     297             :         size_t nRemove;
     298           0 :         if (nIndex > 0 && pData[nIndex-1].aValue == pData[nIndex+1].aValue)
     299             :         {
     300           0 :             nRemove = 2;
     301           0 :             --nIndex;
     302             :         }
     303             :         else
     304           0 :             nRemove = 1;
     305           0 :         memmove( pData + nIndex, pData + nIndex + nRemove, (nCount - (nIndex +
     306           0 :                         nRemove)) * sizeof(DataEntry));
     307           0 :         nCount -= nRemove;
     308             :     }
     309             :     // adjust end rows, nIndex still being valid
     310          72 :     do
     311             :     {
     312          72 :         pData[nIndex].nEnd -= nAccessCount;
     313             :     } while (++nIndex < nCount);
     314          72 :     pData[nCount-1].nEnd = nMaxAccess;
     315          72 : }
     316             : 
     317             : // === ScBitMaskCompressedArray ==============================================
     318             : 
     319             : template< typename A, typename D >
     320         228 : void ScBitMaskCompressedArray<A,D>::AndValue( A nStart, A nEnd,
     321             :         const D& rValueToAnd )
     322             : {
     323         228 :     if (nStart > nEnd)
     324         228 :         return;
     325             : 
     326         228 :     size_t nIndex = this->Search( nStart);
     327           0 :     do
     328             :     {
     329         228 :         if ((this->pData[nIndex].aValue & rValueToAnd) != this->pData[nIndex].aValue)
     330             :         {
     331           0 :             A nS = ::std::max( (nIndex>0 ? this->pData[nIndex-1].nEnd+1 : 0), nStart);
     332           0 :             A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
     333           0 :             this->SetValue( nS, nE, this->pData[nIndex].aValue & rValueToAnd);
     334           0 :             if (nE >= nEnd)
     335           0 :                 break;  // while
     336           0 :             nIndex = this->Search( nE + 1);
     337             :         }
     338         228 :         else if (this->pData[nIndex].nEnd >= nEnd)
     339         228 :             break;  // while
     340             :         else
     341           0 :             ++nIndex;
     342             :     } while (nIndex < this->nCount);
     343             : }
     344             : 
     345             : template< typename A, typename D >
     346         764 : void ScBitMaskCompressedArray<A,D>::OrValue( A nStart, A nEnd,
     347             :         const D& rValueToOr )
     348             : {
     349         764 :     if (nStart > nEnd)
     350         764 :         return;
     351             : 
     352         764 :     size_t nIndex = this->Search( nStart);
     353           0 :     do
     354             :     {
     355         764 :         if ((this->pData[nIndex].aValue | rValueToOr) != this->pData[nIndex].aValue)
     356             :         {
     357         734 :             A nS = ::std::max( (nIndex>0 ? this->pData[nIndex-1].nEnd+1 : 0), nStart);
     358         734 :             A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
     359         734 :             this->SetValue( nS, nE, this->pData[nIndex].aValue | rValueToOr);
     360         734 :             if (nE >= nEnd)
     361         734 :                 break;  // while
     362           0 :             nIndex = this->Search( nE + 1);
     363             :         }
     364          30 :         else if (this->pData[nIndex].nEnd >= nEnd)
     365          30 :             break;  // while
     366             :         else
     367           0 :             ++nIndex;
     368             :     } while (nIndex < this->nCount);
     369             : }
     370             : 
     371             : template< typename A, typename D >
     372         104 : void ScBitMaskCompressedArray<A,D>::CopyFromAnded(
     373             :         const ScBitMaskCompressedArray<A,D>& rArray, A nStart, A nEnd,
     374             :         const D& rValueToAnd, long nSourceDy )
     375             : {
     376         104 :     size_t nIndex = 0;
     377             :     A nRegionEnd;
     378         258 :     for (A j=nStart; j<=nEnd; ++j)
     379             :     {
     380         154 :         const D& rValue = (j==nStart ?
     381             :                 rArray.GetValue( j+nSourceDy, nIndex, nRegionEnd) :
     382         308 :                 rArray.GetNextValue( nIndex, nRegionEnd));
     383         154 :         nRegionEnd -= nSourceDy;
     384         154 :         if (nRegionEnd > nEnd)
     385         104 :             nRegionEnd = nEnd;
     386         154 :         this->SetValue( j, nRegionEnd, rValue & rValueToAnd);
     387         154 :         j = nRegionEnd;
     388             :     }
     389         104 : }
     390             : 
     391             : template< typename A, typename D >
     392         180 : A ScBitMaskCompressedArray<A,D>::GetLastAnyBitAccess( A nStart,
     393             :         const D& rBitMask ) const
     394             : {
     395         180 :     A nEnd = ::std::numeric_limits<A>::max();
     396         180 :     size_t nIndex = this->nCount-1;
     397             :     while (true)
     398             :     {
     399         190 :         if ((this->pData[nIndex].aValue & rBitMask) != 0)
     400             :         {
     401          16 :             nEnd = this->pData[nIndex].nEnd;
     402          16 :             break;  // while
     403             :         }
     404             :         else
     405             :         {
     406         174 :             if (nIndex > 0)
     407             :             {
     408          10 :                 --nIndex;
     409          10 :                 if (this->pData[nIndex].nEnd < nStart)
     410           0 :                     break;  // while
     411             :             }
     412             :             else
     413         164 :                 break;  // while
     414             :         }
     415             :     }
     416          10 :     return nEnd;
     417             : }
     418             : 
     419             : // === Force instantiation of specializations ================================
     420             : 
     421             : template class ScCompressedArray< SCROW, sal_uInt8>;             // flags, base class
     422             : template class ScBitMaskCompressedArray< SCROW, sal_uInt8>;      // flags
     423             : 
     424             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10