| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| #ifndef SC_COMPRESSEDARRAY_HXX |
| #define SC_COMPRESSEDARRAY_HXX |
| |
| #ifndef INCLUDED_CSTDDEF |
| #include <cstddef> |
| #define INCLUDED_CSTDDEF |
| #endif |
| |
| #ifndef INCLUDED_ALGORITHM |
| #include <algorithm> |
| #define INCLUDED_ALGORITHM |
| #endif |
| #include "scdllapi.h" |
| |
| const size_t nScCompressedArrayDelta = 4; |
| |
| template< typename A, typename D > class ScCompressedArrayIterator; |
| |
| /** Compressed array of row (or column) entries, e.g. heights, flags, ... |
| |
| The array stores ranges of values such that consecutive values occupy only |
| one entry. Initially it consists of one DataEntry with an implied start |
| row/column of 0 and an end row/column of access type maximum value. |
| |
| typename A := access type, e.g. SCROW or SCCOL, must be a POD. |
| |
| typename D := data type, e.g. sal_uInt16 or sal_uInt8 or whatever, may also be a |
| struct or class. |
| |
| D::operator==() and D::operator=() must be implemented. Force template |
| instantiation for a specific type in source/core/data/compressedarray.cxx |
| |
| TODO: Currently the allocated memory never shrinks, must manually invoke |
| Resize() if needed. |
| */ |
| |
| template< typename A, typename D > class ScCompressedArray |
| { |
| public: |
| struct DataEntry |
| { |
| A nEnd; // start is end of previous entry + 1 |
| D aValue; |
| DataEntry() {} //! uninitialized |
| }; |
| |
| /** Construct with nMaxAccess=MAXROW, for example. */ |
| ScCompressedArray( A nMaxAccess, |
| const D& rValue, |
| size_t nDelta = nScCompressedArrayDelta ); |
| /** Construct from a plain array of D */ |
| ScCompressedArray( A nMaxAccess, |
| const D* pDataArray, size_t nDataCount ); |
| virtual ~ScCompressedArray(); |
| void Resize( size_t nNewSize ); |
| void Reset( const D& rValue ); |
| void SetValue( A nPos, const D& rValue ); |
| void SetValue( A nStart, A nEnd, const D& rValue ); |
| const D& GetValue( A nPos ) const; |
| |
| /** Get value for a row, and it's region end row */ |
| const D& GetValue( A nPos, size_t& nIndex, A& nEnd ) const; |
| |
| /** Get value for a row, and it's region start row and end row */ |
| const D& GetValue( A nPos, size_t& nIndex, A& nStart, A& nEnd ) const; |
| |
| /** Get next value and it's region end row. If nIndex<nCount, nIndex is |
| incremented first. If the resulting nIndex>=nCount, the value of the |
| last entry is returned again. */ |
| const D& GetNextValue( size_t& nIndex, A& nEnd ) const; |
| |
| /** Get previous value and it's region start row. If nIndex==0, nIndex is |
| not decremented and the value of the first entry is returned again. */ |
| const D& GetPrevValue( size_t& nIndex, A& nStart ) const; |
| |
| /** Return the last row where an entry meets the condition: |
| (aValue != rCompare). If no entry meets this condition |
| ::std::numeric_limits<A>::max() is returned. */ |
| A GetLastUnequalAccess( A nStart, const D& rCompare ); |
| |
| /** Insert rows before nStart and copy value for inserted rows from |
| nStart-1, return that value. */ |
| const D& Insert( A nStart, size_t nCount ); |
| |
| void Remove( A nStart, size_t nCount ); |
| |
| /** Copy rArray.nStart+nSourceDy to this.nStart */ |
| void CopyFrom( const ScCompressedArray& rArray, |
| A nStart, A nEnd, long nSourceDy = 0 ); |
| |
| |
| // methods public for the coupled array sum methods |
| /** Obtain index into entries for nPos */ |
| SC_DLLPUBLIC size_t Search( A nPos ) const; |
| /** Get number of entries */ |
| size_t GetEntryCount() const; |
| /** Get data entry for an index */ |
| const DataEntry& GetDataEntry( size_t nIndex ) const; |
| |
| protected: |
| |
| friend class ScCompressedArrayIterator<A,D>; |
| |
| size_t nCount; |
| size_t nLimit; |
| size_t nDelta; |
| DataEntry* pData; |
| A nMaxAccess; |
| }; |
| |
| |
| template< typename A, typename D > |
| void ScCompressedArray<A,D>::Reset( const D& rValue ) |
| { |
| // Create a temporary copy in case we got a reference passed that points to |
| // a part of the array to be reallocated. |
| D aTmpVal( rValue); |
| delete[] pData; |
| nCount = nLimit = 1; |
| pData = new DataEntry[1]; |
| pData[0].aValue = aTmpVal; |
| pData[0].nEnd = nMaxAccess; |
| } |
| |
| |
| template< typename A, typename D > |
| void ScCompressedArray<A,D>::SetValue( A nPos, const D& rValue ) |
| { |
| SetValue( nPos, nPos, rValue); |
| } |
| |
| |
| template< typename A, typename D > |
| const D& ScCompressedArray<A,D>::GetValue( A nPos ) const |
| { |
| size_t nIndex = Search( nPos); |
| return pData[nIndex].aValue; |
| } |
| |
| |
| template< typename A, typename D > |
| const D& ScCompressedArray<A,D>::GetValue( A nPos, size_t& nIndex, A& nEnd ) const |
| { |
| nIndex = Search( nPos); |
| nEnd = pData[nIndex].nEnd; |
| return pData[nIndex].aValue; |
| } |
| |
| |
| template< typename A, typename D > |
| const D& ScCompressedArray<A,D>::GetValue( A nPos, size_t& nIndex, A& nStart, |
| A& nEnd ) const |
| { |
| nIndex = Search( nPos); |
| nStart = (nIndex > 0 ? pData[nIndex-1].nEnd + 1 : 0); |
| nEnd = pData[nIndex].nEnd; |
| return pData[nIndex].aValue; |
| } |
| |
| |
| template< typename A, typename D > |
| const D& ScCompressedArray<A,D>::GetNextValue( size_t& nIndex, A& nEnd ) const |
| { |
| if (nIndex < nCount) |
| ++nIndex; |
| size_t nEntry = (nIndex < nCount ? nIndex : nCount-1); |
| nEnd = pData[nEntry].nEnd; |
| return pData[nEntry].aValue; |
| } |
| |
| |
| template< typename A, typename D > |
| const D& ScCompressedArray<A,D>::GetPrevValue( size_t& nIndex, A& nStart ) const |
| { |
| if (nIndex > 0) |
| --nIndex; |
| nStart = (nIndex > 0 ? pData[nIndex-1].nEnd + 1 : 0); |
| return pData[nIndex].aValue; |
| } |
| |
| |
| template< typename A, typename D > |
| size_t ScCompressedArray<A,D>::GetEntryCount() const |
| { |
| return nCount; |
| } |
| |
| |
| template< typename A, typename D > |
| const typename ScCompressedArray<A,D>::DataEntry& |
| ScCompressedArray<A,D>::GetDataEntry( size_t nIndex ) const |
| { |
| return pData[nIndex]; |
| } |
| |
| |
| // === ScCompressedArrayIterator ============================================= |
| |
| /** Iterator for ScCompressedArray. |
| |
| @ATTENTION: the iterator is not persistant if the underlying |
| ScCompressedArray happens to be changed by any means, for example by |
| setting new values or adding or removing or combining entries. If you do |
| such things inside a loop you MUST resynchronize the iterator by calling |
| <method>Resync()</method> with the row where resynchronization should |
| start. After doing so, <method>GetRangeStart()</method> and |
| <method>GetRangeEnd()</method> may not point to the previous access points |
| anymore. Use with care. |
| */ |
| |
| template< typename A, typename D > class ScCompressedArrayIterator |
| { |
| public: |
| ScCompressedArrayIterator( |
| const ScCompressedArray<A,D> & rArray, |
| A nStart, A nEnd ); |
| /// Set new start and end, position on start. |
| void NewLimits( A nStart, A nEnd ); |
| A GetIterStart() const; |
| A GetIterEnd() const; |
| /// Advance by a single access point (e.g. row). |
| bool operator ++(); |
| A GetPos() const; |
| operator bool() const; |
| const D& operator *() const; |
| /// Advance an entire range, one entry of the array. |
| bool NextRange(); |
| A GetRangeStart() const; |
| A GetRangeEnd() const; |
| /// Resync to underlying array, calling Search(). |
| void Resync( A nPos ); |
| /** Set position without resyncing, avoid calling Search() if possible. |
| Position obtained from steering coupled iterator is NOT checked for |
| iterator bounds. */ |
| template< typename X > |
| void Follow( const ScCompressedArrayIterator<A,X>& ); |
| |
| private: |
| const ScCompressedArray<A,D> & rArray; |
| size_t nIndex; |
| A nIterStart; |
| A nIterEnd; |
| A nCurrent; |
| bool bEnd; |
| }; |
| |
| |
| template< typename A, typename D > |
| ScCompressedArrayIterator<A,D>::ScCompressedArrayIterator( |
| const ScCompressedArray<A,D> & rArrayP, A nStart, A nEnd ) |
| : rArray( rArrayP ) |
| // other values set in NewLimits() |
| { |
| NewLimits( nStart, nEnd); |
| } |
| |
| |
| template< typename A, typename D > |
| void ScCompressedArrayIterator<A,D>::NewLimits( A nStart, A nEnd ) |
| { |
| nIterStart = nStart; |
| nIterEnd = nEnd; |
| nIndex = rArray.Search( nStart); |
| nCurrent = GetRangeStart(); |
| bEnd = (nIterEnd < nIterStart); |
| } |
| |
| |
| template< typename A, typename D > |
| A ScCompressedArrayIterator<A,D>::GetIterStart() const |
| { |
| return nIterStart; |
| } |
| |
| |
| template< typename A, typename D > |
| A ScCompressedArrayIterator<A,D>::GetIterEnd() const |
| { |
| return nIterEnd; |
| } |
| |
| |
| template< typename A, typename D > |
| bool ScCompressedArrayIterator<A,D>::operator++() |
| { |
| if (nCurrent < GetRangeEnd()) |
| { |
| ++nCurrent; |
| return true; |
| } |
| else |
| return NextRange(); |
| } |
| |
| |
| template< typename A, typename D > |
| A ScCompressedArrayIterator<A,D>::GetPos() const |
| { |
| return nCurrent; |
| } |
| |
| |
| template< typename A, typename D > |
| bool ScCompressedArrayIterator<A,D>::NextRange() |
| { |
| if (!operator bool()) |
| return false; |
| |
| if (rArray.pData[nIndex].nEnd >= nIterEnd) |
| bEnd = true; |
| else if (++nIndex >= rArray.GetEntryCount()) |
| { |
| nIndex = rArray.GetEntryCount() - 1; |
| bEnd = true; |
| } |
| nCurrent = bEnd ? nIterEnd : GetRangeStart(); |
| return operator bool(); |
| } |
| |
| |
| template< typename A, typename D > |
| ScCompressedArrayIterator<A,D>::operator bool() const |
| { |
| return !bEnd; |
| } |
| |
| |
| template< typename A, typename D > |
| const D& ScCompressedArrayIterator<A,D>::operator*() const |
| { |
| return rArray.pData[nIndex].aValue; |
| } |
| |
| |
| template< typename A, typename D > |
| A ScCompressedArrayIterator<A,D>::GetRangeStart() const |
| { |
| if (nIndex == 0) |
| return nIterStart > 0 ? nIterStart : 0; |
| else |
| return nIterStart > rArray.pData[nIndex-1].nEnd ? nIterStart : |
| rArray.pData[nIndex-1].nEnd + 1; |
| } |
| |
| |
| template< typename A, typename D > |
| A ScCompressedArrayIterator<A,D>::GetRangeEnd() const |
| { |
| return nIterEnd < rArray.pData[nIndex].nEnd ? nIterEnd : |
| rArray.pData[nIndex].nEnd; |
| } |
| |
| |
| template< typename A, typename D > |
| void ScCompressedArrayIterator<A,D>::Resync( A nPos ) |
| { |
| if (nPos < nIterStart) |
| nPos = nIterStart; |
| else if (nPos > nIterEnd) |
| nPos = nIterEnd; |
| nCurrent = nPos; |
| bEnd = (nIterEnd < nIterStart); |
| nIndex = rArray.Search( nPos); |
| } |
| |
| |
| // === ScSummableCompressedArray ============================================= |
| |
| /** Data type D must be of a type that is convertable to unsigned long. The |
| advantage is that specialized methods exist to act on a region of values |
| for performance reasons. |
| */ |
| |
| template< typename A, typename D > class ScSummableCompressedArray : public ScCompressedArray<A,D> |
| { |
| public: |
| ScSummableCompressedArray( A nMaxAccessP, |
| const D& rValue, |
| size_t nDeltaP = nScCompressedArrayDelta ) |
| : ScCompressedArray<A,D>( nMaxAccessP, |
| rValue, nDeltaP) |
| {} |
| ScSummableCompressedArray( A nMaxAccessP, |
| const D* pDataArray, size_t nDataCount ) |
| : ScCompressedArray<A,D>( nMaxAccessP, |
| pDataArray, nDataCount) |
| {} |
| |
| /** Returns the sum of all values for a region. If an overflow would occur, |
| ::std::numeric_limits<unsigned long>::max() is returned. */ |
| unsigned long SumValues( A nStart, A nEnd ) const; |
| |
| /** Returns the sum of all values for a region. If an overflow would occur, |
| ::std::numeric_limits<unsigned long>::max() is returned. |
| The caller has to assure that nIndex matches an entry belonging to |
| nStart, for example, by calling Search(nStart) first! */ |
| unsigned long SumValuesContinuation( A nStart, A nEnd, |
| size_t& nIndex ) const; |
| |
| /** Returns the sum of all scaled values for a region. If an overflow would |
| occur, ::std::numeric_limits<unsigned long>::max() is returned. |
| Summed values are treated as if for each row the expression |
| (sum += (unsigned long) (scale * value)) had been applied. |
| The caller has to assure that nIndex matches an entry belonging to |
| nStart, for example, by calling Search(nStart) first! */ |
| unsigned long SumScaledValuesContinuation( A nStart, A nEnd, |
| size_t& nIndex, double fScale ) const; |
| |
| }; |
| |
| |
| // === ScBitMaskCompressedArray ============================================== |
| |
| /** The data type represents bits, managable by bitwise operations. |
| */ |
| |
| template< typename A, typename D > class ScBitMaskCompressedArray : public ScCompressedArray<A,D> |
| { |
| public: |
| ScBitMaskCompressedArray( A nMaxAccessP, |
| const D& rValue, |
| size_t nDeltaP = nScCompressedArrayDelta ) |
| : ScCompressedArray<A,D>( nMaxAccessP, rValue, nDeltaP) |
| {} |
| ScBitMaskCompressedArray( A nMaxAccessP, |
| const D* pDataArray, size_t nDataCount ) |
| : ScCompressedArray<A,D>( nMaxAccessP, |
| pDataArray, nDataCount) |
| {} |
| void AndValue( A nPos, const D& rValueToAnd ); |
| void OrValue( A nPos, const D& rValueToOr ); |
| void AndValue( A nStart, A nEnd, const D& rValueToAnd ); |
| void OrValue( A nStart, A nEnd, const D& rValueToOr ); |
| |
| /** Copy values from rArray and bitwise AND them with rValueToAnd. */ |
| void CopyFromAnded( |
| const ScBitMaskCompressedArray& rArray, |
| A nStart, A nEnd, const D& rValueToAnd, |
| long nSourceDy = 0 ); |
| |
| /** Copy values from rArray and bitwise OR them with rValueToOr. */ |
| void CopyFromOred( |
| const ScBitMaskCompressedArray& rArray, |
| A nStart, A nEnd, const D& rValueToOr, |
| long nSourceDy = 0 ); |
| |
| /** Return the start row of a region where all entries meet the condition: |
| ((aValue & rBitMask) == rMaskedCompare). If not even nEnd meets |
| this condition, ::std::numeric_limits<A>::max() is returned. */ |
| A GetBitStateStart( A nEnd, const D& rBitMask, |
| const D& rMaskedCompare ) const; |
| |
| /** Return the end row of a region where all entries meet the condition: |
| ((aValue & rBitMask) == rMaskedCompare). If not even nStart meets |
| this condition, ::std::numeric_limits<A>::max() is returned. */ |
| A GetBitStateEnd( A nStart, const D& rBitMask, |
| const D& rMaskedCompare ) const; |
| |
| /** Return the first row where an entry meets the condition: |
| ((aValue & rBitMask) == rMaskedCompare), searching between nStart and |
| nEnd. If no entry meets this condition, ::std::numeric_limits<A>::max() |
| is returned. */ |
| SC_DLLPUBLIC A GetFirstForCondition( A nStart, A nEnd, |
| const D& rBitMask, |
| const D& rMaskedCompare ) const; |
| |
| /** Return the last row where an entry meets the condition: |
| ((aValue & rBitMask) == rMaskedCompare), searching between nStart and |
| nEnd. If no entry meets this condition, ::std::numeric_limits<A>::max() |
| is returned. */ |
| SC_DLLPUBLIC A GetLastForCondition( A nStart, A nEnd, |
| const D& rBitMask, |
| const D& rMaskedCompare ) const; |
| |
| /** Count rows between nStart and nEnd where entries meet the condition: |
| ((aValue & rBitMask) == rMaskedCompare) */ |
| A CountForCondition( A nStart, A nEnd, |
| const D& rBitMask, |
| const D& rMaskedCompare ) const; |
| |
| /** Whether there is any entry between nStart and nEnd where the condition |
| is met: ((aValue & rBitMask) == rMaskedCompare) */ |
| SC_DLLPUBLIC bool HasCondition( A nStart, A nEnd, |
| const D& rBitMask, |
| const D& rMaskedCompare ) const; |
| |
| /** Fill an array with row numbers between nStart and nEnd where entries |
| meet the condition: ((aValue & rBitMask) == rMaskedCompare). |
| @return the count of used elements in array. */ |
| size_t FillArrayForCondition( A nStart, A nEnd, |
| const D& rBitMask, |
| const D& rMaskedCompare, |
| A * pArray, size_t nArraySize ) const; |
| |
| /** Count rows between nStart and nEnd where entries meet the condition: |
| ((aValue & rBitMask) != 0) */ |
| A CountForAnyBitCondition( A nStart, A nEnd, |
| const D& rBitMask ) const; |
| |
| /** Return the last row where an entry meets the condition: |
| ((aValue & rBitMask) != 0), start searching at nStart. If no entry |
| meets this condition, ::std::numeric_limits<A>::max() is returned. */ |
| A GetLastAnyBitAccess( A nStart, |
| const D& rBitMask ) const; |
| |
| /** Sum values of a ScSummableCompressedArray for each row where in *this* |
| array the condition is met: ((aValue & rBitMask) == rMaskedCompare). */ |
| template< typename S > |
| SC_DLLPUBLIC unsigned long SumCoupledArrayForCondition( A nStart, A nEnd, |
| const D& rBitMask, const D& rMaskedCompare, |
| const ScSummableCompressedArray<A,S>& rArray ) const; |
| |
| /** Sum scaled values of a ScSummableCompressedArray for each row where in |
| *this* array the condition is met: ((aValue & rBitMask) == rMaskedCompare). */ |
| template< typename S > |
| SC_DLLPUBLIC unsigned long SumScaledCoupledArrayForCondition( A nStart, A nEnd, |
| const D& rBitMask, const D& rMaskedCompare, |
| const ScSummableCompressedArray<A,S>& rArray, |
| double fScale ) const; |
| }; |
| |
| |
| template< typename A, typename D > |
| void ScBitMaskCompressedArray<A,D>::AndValue( A nPos, const D& rValueToAnd ) |
| { |
| const D& rValue = this->GetValue( nPos); |
| if ((rValue & rValueToAnd) != rValue) |
| this->SetValue( nPos, rValue & rValueToAnd); |
| } |
| |
| |
| template< typename A, typename D > |
| void ScBitMaskCompressedArray<A,D>::OrValue( A nPos, const D& rValueToOr ) |
| { |
| const D& rValue = this->GetValue( nPos); |
| if ((rValue | rValueToOr) != rValue) |
| this->SetValue( nPos, rValue | rValueToOr); |
| } |
| |
| |
| // === ScCoupledCompressedArrayIterator ====================================== |
| |
| /** Iterate over a ScBitMaskCompressedArray and retrieve values from a coupled |
| array for positions where in the bit mask array the condition ((*aIter1 & |
| rBitMask) == rMaskedCompare) is met. |
| */ |
| |
| template< typename A, typename D, typename S > class ScCoupledCompressedArrayIterator |
| { |
| public: |
| SC_DLLPUBLIC ScCoupledCompressedArrayIterator( |
| const ScBitMaskCompressedArray<A,D> & rArray1, |
| A nStart, A nEnd, |
| const D& rBitMask, |
| const D& rMaskedCompare, |
| const ScCompressedArray<A,S> & rArray2 ); |
| void NewLimits( A nStart, A nEnd ); |
| A GetIterStart() const; |
| A GetIterEnd() const; |
| bool operator ++(); |
| A GetPos() const; |
| operator bool() const; |
| const S& operator *() const; |
| SC_DLLPUBLIC bool NextRange(); |
| A GetRangeStart() const; |
| A GetRangeEnd() const; |
| void Resync( A nPos ); |
| |
| private: |
| ScCompressedArrayIterator<A,D> aIter1; |
| ScCompressedArrayIterator<A,S> aIter2; |
| const D& rBitMask; |
| const D& rMaskedCompare; |
| |
| void InitLimits(); |
| }; |
| |
| |
| template< typename A, typename D, typename S > |
| A ScCoupledCompressedArrayIterator<A,D,S>::GetIterStart() const |
| { |
| return aIter1.GetIterStart(); |
| } |
| |
| |
| template< typename A, typename D, typename S > |
| A ScCoupledCompressedArrayIterator<A,D,S>::GetIterEnd() const |
| { |
| return aIter1.GetIterEnd(); |
| } |
| |
| |
| template< typename A, typename D, typename S > |
| ScCoupledCompressedArrayIterator<A,D,S>::operator bool() const |
| { |
| return aIter1 && aIter2; |
| } |
| |
| |
| template< typename A, typename D, typename S > |
| const S& ScCoupledCompressedArrayIterator<A,D,S>::operator*() const |
| { |
| return *aIter2; |
| } |
| |
| |
| template< typename A, typename D, typename S > |
| bool ScCoupledCompressedArrayIterator<A,D,S>::operator ++() |
| { |
| if (aIter1.GetPos() < aIter1.GetRangeEnd()) |
| { |
| ++aIter1; |
| ++aIter2; |
| return operator bool(); |
| } |
| else |
| return NextRange(); |
| } |
| |
| |
| template< typename A, typename D, typename S > |
| A ScCoupledCompressedArrayIterator<A,D,S>::GetPos() const |
| { |
| return aIter2.GetPos(); |
| } |
| |
| |
| template< typename A, typename D, typename S > |
| A ScCoupledCompressedArrayIterator<A,D,S>::GetRangeStart() const |
| { |
| return ::std::max( aIter1.GetRangeStart(), aIter2.GetRangeStart()); |
| } |
| |
| |
| template< typename A, typename D, typename S > |
| A ScCoupledCompressedArrayIterator<A,D,S>::GetRangeEnd() const |
| { |
| return ::std::min( aIter1.GetRangeEnd(), aIter2.GetRangeEnd()); |
| } |
| |
| |
| #endif // SC_COMPRESSEDARRAY_HXX |