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 #ifndef SC_COMPRESSEDARRAY_HXX
25 #define SC_COMPRESSEDARRAY_HXX
26
27 #ifndef INCLUDED_CSTDDEF
28 #include <cstddef>
29 #define INCLUDED_CSTDDEF
30 #endif
31
32 #ifndef INCLUDED_ALGORITHM
33 #include <algorithm>
34 #define INCLUDED_ALGORITHM
35 #endif
36 #include "scdllapi.h"
37
38 const size_t nScCompressedArrayDelta = 4;
39
40 template< typename A, typename D > class ScCompressedArrayIterator;
41
42 /** Compressed array of row (or column) entries, e.g. heights, flags, ...
43
44 The array stores ranges of values such that consecutive values occupy only
45 one entry. Initially it consists of one DataEntry with an implied start
46 row/column of 0 and an end row/column of access type maximum value.
47
48 typename A := access type, e.g. SCROW or SCCOL, must be a POD.
49
50 typename D := data type, e.g. sal_uInt16 or sal_uInt8 or whatever, may also be a
51 struct or class.
52
53 D::operator==() and D::operator=() must be implemented. Force template
54 instantiation for a specific type in source/core/data/compressedarray.cxx
55
56 TODO: Currently the allocated memory never shrinks, must manually invoke
57 Resize() if needed.
58 */
59
60 template< typename A, typename D > class ScCompressedArray
61 {
62 public:
63 struct DataEntry
64 {
65 A nEnd; // start is end of previous entry + 1
66 D aValue;
DataEntryScCompressedArray::DataEntry67 DataEntry() {} //! uninitialized
68 };
69
70 /** Construct with nMaxAccess=MAXROW, for example. */
71 ScCompressedArray( A nMaxAccess,
72 const D& rValue,
73 size_t nDelta = nScCompressedArrayDelta );
74 /** Construct from a plain array of D */
75 ScCompressedArray( A nMaxAccess,
76 const D* pDataArray, size_t nDataCount );
77 virtual ~ScCompressedArray();
78 void Resize( size_t nNewSize );
79 void Reset( const D& rValue );
80 void SetValue( A nPos, const D& rValue );
81 void SetValue( A nStart, A nEnd, const D& rValue );
82 const D& GetValue( A nPos ) const;
83
84 /** Get value for a row, and it's region end row */
85 const D& GetValue( A nPos, size_t& nIndex, A& nEnd ) const;
86
87 /** Get value for a row, and it's region start row and end row */
88 const D& GetValue( A nPos, size_t& nIndex, A& nStart, A& nEnd ) const;
89
90 /** Get next value and it's region end row. If nIndex<nCount, nIndex is
91 incremented first. If the resulting nIndex>=nCount, the value of the
92 last entry is returned again. */
93 const D& GetNextValue( size_t& nIndex, A& nEnd ) const;
94
95 /** Get previous value and it's region start row. If nIndex==0, nIndex is
96 not decremented and the value of the first entry is returned again. */
97 const D& GetPrevValue( size_t& nIndex, A& nStart ) const;
98
99 /** Return the last row where an entry meets the condition:
100 (aValue != rCompare). If no entry meets this condition
101 ::std::numeric_limits<A>::max() is returned. */
102 A GetLastUnequalAccess( A nStart, const D& rCompare );
103
104 /** Insert rows before nStart and copy value for inserted rows from
105 nStart-1, return that value. */
106 const D& Insert( A nStart, size_t nCount );
107
108 void Remove( A nStart, size_t nCount );
109
110 /** Copy rArray.nStart+nSourceDy to this.nStart */
111 void CopyFrom( const ScCompressedArray& rArray,
112 A nStart, A nEnd, long nSourceDy = 0 );
113
114
115 // methods public for the coupled array sum methods
116 /** Obtain index into entries for nPos */
117 SC_DLLPUBLIC size_t Search( A nPos ) const;
118 /** Get number of entries */
119 size_t GetEntryCount() const;
120 /** Get data entry for an index */
121 const DataEntry& GetDataEntry( size_t nIndex ) const;
122
123 protected:
124
125 friend class ScCompressedArrayIterator<A,D>;
126
127 size_t nCount;
128 size_t nLimit;
129 size_t nDelta;
130 DataEntry* pData;
131 A nMaxAccess;
132 };
133
134
135 template< typename A, typename D >
Reset(const D & rValue)136 void ScCompressedArray<A,D>::Reset( const D& rValue )
137 {
138 // Create a temporary copy in case we got a reference passed that points to
139 // a part of the array to be reallocated.
140 D aTmpVal( rValue);
141 delete[] pData;
142 nCount = nLimit = 1;
143 pData = new DataEntry[1];
144 pData[0].aValue = aTmpVal;
145 pData[0].nEnd = nMaxAccess;
146 }
147
148
149 template< typename A, typename D >
SetValue(A nPos,const D & rValue)150 void ScCompressedArray<A,D>::SetValue( A nPos, const D& rValue )
151 {
152 SetValue( nPos, nPos, rValue);
153 }
154
155
156 template< typename A, typename D >
GetValue(A nPos) const157 const D& ScCompressedArray<A,D>::GetValue( A nPos ) const
158 {
159 size_t nIndex = Search( nPos);
160 return pData[nIndex].aValue;
161 }
162
163
164 template< typename A, typename D >
GetValue(A nPos,size_t & nIndex,A & nEnd) const165 const D& ScCompressedArray<A,D>::GetValue( A nPos, size_t& nIndex, A& nEnd ) const
166 {
167 nIndex = Search( nPos);
168 nEnd = pData[nIndex].nEnd;
169 return pData[nIndex].aValue;
170 }
171
172
173 template< typename A, typename D >
GetValue(A nPos,size_t & nIndex,A & nStart,A & nEnd) const174 const D& ScCompressedArray<A,D>::GetValue( A nPos, size_t& nIndex, A& nStart,
175 A& nEnd ) const
176 {
177 nIndex = Search( nPos);
178 nStart = (nIndex > 0 ? pData[nIndex-1].nEnd + 1 : 0);
179 nEnd = pData[nIndex].nEnd;
180 return pData[nIndex].aValue;
181 }
182
183
184 template< typename A, typename D >
GetNextValue(size_t & nIndex,A & nEnd) const185 const D& ScCompressedArray<A,D>::GetNextValue( size_t& nIndex, A& nEnd ) const
186 {
187 if (nIndex < nCount)
188 ++nIndex;
189 size_t nEntry = (nIndex < nCount ? nIndex : nCount-1);
190 nEnd = pData[nEntry].nEnd;
191 return pData[nEntry].aValue;
192 }
193
194
195 template< typename A, typename D >
GetPrevValue(size_t & nIndex,A & nStart) const196 const D& ScCompressedArray<A,D>::GetPrevValue( size_t& nIndex, A& nStart ) const
197 {
198 if (nIndex > 0)
199 --nIndex;
200 nStart = (nIndex > 0 ? pData[nIndex-1].nEnd + 1 : 0);
201 return pData[nIndex].aValue;
202 }
203
204
205 template< typename A, typename D >
GetEntryCount() const206 size_t ScCompressedArray<A,D>::GetEntryCount() const
207 {
208 return nCount;
209 }
210
211
212 template< typename A, typename D >
213 const typename ScCompressedArray<A,D>::DataEntry&
GetDataEntry(size_t nIndex) const214 ScCompressedArray<A,D>::GetDataEntry( size_t nIndex ) const
215 {
216 return pData[nIndex];
217 }
218
219
220 // === ScCompressedArrayIterator =============================================
221
222 /** Iterator for ScCompressedArray.
223
224 @ATTENTION: the iterator is not persistant if the underlying
225 ScCompressedArray happens to be changed by any means, for example by
226 setting new values or adding or removing or combining entries. If you do
227 such things inside a loop you MUST resynchronize the iterator by calling
228 <method>Resync()</method> with the row where resynchronization should
229 start. After doing so, <method>GetRangeStart()</method> and
230 <method>GetRangeEnd()</method> may not point to the previous access points
231 anymore. Use with care.
232 */
233
234 template< typename A, typename D > class ScCompressedArrayIterator
235 {
236 public:
237 ScCompressedArrayIterator(
238 const ScCompressedArray<A,D> & rArray,
239 A nStart, A nEnd );
240 /// Set new start and end, position on start.
241 void NewLimits( A nStart, A nEnd );
242 A GetIterStart() const;
243 A GetIterEnd() const;
244 /// Advance by a single access point (e.g. row).
245 bool operator ++();
246 A GetPos() const;
247 operator bool() const;
248 const D& operator *() const;
249 /// Advance an entire range, one entry of the array.
250 bool NextRange();
251 A GetRangeStart() const;
252 A GetRangeEnd() const;
253 /// Resync to underlying array, calling Search().
254 void Resync( A nPos );
255 /** Set position without resyncing, avoid calling Search() if possible.
256 Position obtained from steering coupled iterator is NOT checked for
257 iterator bounds. */
258 template< typename X >
259 void Follow( const ScCompressedArrayIterator<A,X>& );
260
261 private:
262 const ScCompressedArray<A,D> & rArray;
263 size_t nIndex;
264 A nIterStart;
265 A nIterEnd;
266 A nCurrent;
267 bool bEnd;
268 };
269
270
271 template< typename A, typename D >
ScCompressedArrayIterator(const ScCompressedArray<A,D> & rArrayP,A nStart,A nEnd)272 ScCompressedArrayIterator<A,D>::ScCompressedArrayIterator(
273 const ScCompressedArray<A,D> & rArrayP, A nStart, A nEnd )
274 : rArray( rArrayP )
275 // other values set in NewLimits()
276 {
277 NewLimits( nStart, nEnd);
278 }
279
280
281 template< typename A, typename D >
NewLimits(A nStart,A nEnd)282 void ScCompressedArrayIterator<A,D>::NewLimits( A nStart, A nEnd )
283 {
284 nIterStart = nStart;
285 nIterEnd = nEnd;
286 nIndex = rArray.Search( nStart);
287 nCurrent = GetRangeStart();
288 bEnd = (nIterEnd < nIterStart);
289 }
290
291
292 template< typename A, typename D >
GetIterStart() const293 A ScCompressedArrayIterator<A,D>::GetIterStart() const
294 {
295 return nIterStart;
296 }
297
298
299 template< typename A, typename D >
GetIterEnd() const300 A ScCompressedArrayIterator<A,D>::GetIterEnd() const
301 {
302 return nIterEnd;
303 }
304
305
306 template< typename A, typename D >
operator ++()307 bool ScCompressedArrayIterator<A,D>::operator++()
308 {
309 if (nCurrent < GetRangeEnd())
310 {
311 ++nCurrent;
312 return true;
313 }
314 else
315 return NextRange();
316 }
317
318
319 template< typename A, typename D >
GetPos() const320 A ScCompressedArrayIterator<A,D>::GetPos() const
321 {
322 return nCurrent;
323 }
324
325
326 template< typename A, typename D >
NextRange()327 bool ScCompressedArrayIterator<A,D>::NextRange()
328 {
329 if (!operator bool())
330 return false;
331
332 if (rArray.pData[nIndex].nEnd >= nIterEnd)
333 bEnd = true;
334 else if (++nIndex >= rArray.GetEntryCount())
335 {
336 nIndex = rArray.GetEntryCount() - 1;
337 bEnd = true;
338 }
339 nCurrent = bEnd ? nIterEnd : GetRangeStart();
340 return operator bool();
341 }
342
343
344 template< typename A, typename D >
345 ScCompressedArrayIterator<A,D>::operator bool() const
346 {
347 return !bEnd;
348 }
349
350
351 template< typename A, typename D >
operator *() const352 const D& ScCompressedArrayIterator<A,D>::operator*() const
353 {
354 return rArray.pData[nIndex].aValue;
355 }
356
357
358 template< typename A, typename D >
GetRangeStart() const359 A ScCompressedArrayIterator<A,D>::GetRangeStart() const
360 {
361 if (nIndex == 0)
362 return nIterStart > 0 ? nIterStart : 0;
363 else
364 return nIterStart > rArray.pData[nIndex-1].nEnd ? nIterStart :
365 rArray.pData[nIndex-1].nEnd + 1;
366 }
367
368
369 template< typename A, typename D >
GetRangeEnd() const370 A ScCompressedArrayIterator<A,D>::GetRangeEnd() const
371 {
372 return nIterEnd < rArray.pData[nIndex].nEnd ? nIterEnd :
373 rArray.pData[nIndex].nEnd;
374 }
375
376
377 template< typename A, typename D >
Resync(A nPos)378 void ScCompressedArrayIterator<A,D>::Resync( A nPos )
379 {
380 if (nPos < nIterStart)
381 nPos = nIterStart;
382 else if (nPos > nIterEnd)
383 nPos = nIterEnd;
384 nCurrent = nPos;
385 bEnd = (nIterEnd < nIterStart);
386 nIndex = rArray.Search( nPos);
387 }
388
389
390 // === ScSummableCompressedArray =============================================
391
392 /** Data type D must be of a type that is convertable to unsigned long. The
393 advantage is that specialized methods exist to act on a region of values
394 for performance reasons.
395 */
396
397 template< typename A, typename D > class ScSummableCompressedArray : public ScCompressedArray<A,D>
398 {
399 public:
ScSummableCompressedArray(A nMaxAccessP,const D & rValue,size_t nDeltaP=nScCompressedArrayDelta)400 ScSummableCompressedArray( A nMaxAccessP,
401 const D& rValue,
402 size_t nDeltaP = nScCompressedArrayDelta )
403 : ScCompressedArray<A,D>( nMaxAccessP,
404 rValue, nDeltaP)
405 {}
ScSummableCompressedArray(A nMaxAccessP,const D * pDataArray,size_t nDataCount)406 ScSummableCompressedArray( A nMaxAccessP,
407 const D* pDataArray, size_t nDataCount )
408 : ScCompressedArray<A,D>( nMaxAccessP,
409 pDataArray, nDataCount)
410 {}
411
412 /** Returns the sum of all values for a region. If an overflow would occur,
413 ::std::numeric_limits<unsigned long>::max() is returned. */
414 unsigned long SumValues( A nStart, A nEnd ) const;
415
416 /** Returns the sum of all values for a region. If an overflow would occur,
417 ::std::numeric_limits<unsigned long>::max() is returned.
418 The caller has to assure that nIndex matches an entry belonging to
419 nStart, for example, by calling Search(nStart) first! */
420 unsigned long SumValuesContinuation( A nStart, A nEnd,
421 size_t& nIndex ) const;
422
423 /** Returns the sum of all scaled values for a region. If an overflow would
424 occur, ::std::numeric_limits<unsigned long>::max() is returned.
425 Summed values are treated as if for each row the expression
426 (sum += (unsigned long) (scale * value)) had been applied.
427 The caller has to assure that nIndex matches an entry belonging to
428 nStart, for example, by calling Search(nStart) first! */
429 unsigned long SumScaledValuesContinuation( A nStart, A nEnd,
430 size_t& nIndex, double fScale ) const;
431
432 };
433
434
435 // === ScBitMaskCompressedArray ==============================================
436
437 /** The data type represents bits, managable by bitwise operations.
438 */
439
440 template< typename A, typename D > class ScBitMaskCompressedArray : public ScCompressedArray<A,D>
441 {
442 public:
ScBitMaskCompressedArray(A nMaxAccessP,const D & rValue,size_t nDeltaP=nScCompressedArrayDelta)443 ScBitMaskCompressedArray( A nMaxAccessP,
444 const D& rValue,
445 size_t nDeltaP = nScCompressedArrayDelta )
446 : ScCompressedArray<A,D>( nMaxAccessP, rValue, nDeltaP)
447 {}
ScBitMaskCompressedArray(A nMaxAccessP,const D * pDataArray,size_t nDataCount)448 ScBitMaskCompressedArray( A nMaxAccessP,
449 const D* pDataArray, size_t nDataCount )
450 : ScCompressedArray<A,D>( nMaxAccessP,
451 pDataArray, nDataCount)
452 {}
453 void AndValue( A nPos, const D& rValueToAnd );
454 void OrValue( A nPos, const D& rValueToOr );
455 void AndValue( A nStart, A nEnd, const D& rValueToAnd );
456 void OrValue( A nStart, A nEnd, const D& rValueToOr );
457
458 /** Copy values from rArray and bitwise AND them with rValueToAnd. */
459 void CopyFromAnded(
460 const ScBitMaskCompressedArray& rArray,
461 A nStart, A nEnd, const D& rValueToAnd,
462 long nSourceDy = 0 );
463
464 /** Copy values from rArray and bitwise OR them with rValueToOr. */
465 void CopyFromOred(
466 const ScBitMaskCompressedArray& rArray,
467 A nStart, A nEnd, const D& rValueToOr,
468 long nSourceDy = 0 );
469
470 /** Return the start row of a region where all entries meet the condition:
471 ((aValue & rBitMask) == rMaskedCompare). If not even nEnd meets
472 this condition, ::std::numeric_limits<A>::max() is returned. */
473 A GetBitStateStart( A nEnd, const D& rBitMask,
474 const D& rMaskedCompare ) const;
475
476 /** Return the end row of a region where all entries meet the condition:
477 ((aValue & rBitMask) == rMaskedCompare). If not even nStart meets
478 this condition, ::std::numeric_limits<A>::max() is returned. */
479 A GetBitStateEnd( A nStart, const D& rBitMask,
480 const D& rMaskedCompare ) const;
481
482 /** Return the first row where an entry meets the condition:
483 ((aValue & rBitMask) == rMaskedCompare), searching between nStart and
484 nEnd. If no entry meets this condition, ::std::numeric_limits<A>::max()
485 is returned. */
486 SC_DLLPUBLIC A GetFirstForCondition( A nStart, A nEnd,
487 const D& rBitMask,
488 const D& rMaskedCompare ) const;
489
490 /** Return the last row where an entry meets the condition:
491 ((aValue & rBitMask) == rMaskedCompare), searching between nStart and
492 nEnd. If no entry meets this condition, ::std::numeric_limits<A>::max()
493 is returned. */
494 SC_DLLPUBLIC A GetLastForCondition( A nStart, A nEnd,
495 const D& rBitMask,
496 const D& rMaskedCompare ) const;
497
498 /** Count rows between nStart and nEnd where entries meet the condition:
499 ((aValue & rBitMask) == rMaskedCompare) */
500 A CountForCondition( A nStart, A nEnd,
501 const D& rBitMask,
502 const D& rMaskedCompare ) const;
503
504 /** Whether there is any entry between nStart and nEnd where the condition
505 is met: ((aValue & rBitMask) == rMaskedCompare) */
506 SC_DLLPUBLIC bool HasCondition( A nStart, A nEnd,
507 const D& rBitMask,
508 const D& rMaskedCompare ) const;
509
510 /** Fill an array with row numbers between nStart and nEnd where entries
511 meet the condition: ((aValue & rBitMask) == rMaskedCompare).
512 @return the count of used elements in array. */
513 size_t FillArrayForCondition( A nStart, A nEnd,
514 const D& rBitMask,
515 const D& rMaskedCompare,
516 A * pArray, size_t nArraySize ) const;
517
518 /** Count rows between nStart and nEnd where entries meet the condition:
519 ((aValue & rBitMask) != 0) */
520 A CountForAnyBitCondition( A nStart, A nEnd,
521 const D& rBitMask ) const;
522
523 /** Return the last row where an entry meets the condition:
524 ((aValue & rBitMask) != 0), start searching at nStart. If no entry
525 meets this condition, ::std::numeric_limits<A>::max() is returned. */
526 A GetLastAnyBitAccess( A nStart,
527 const D& rBitMask ) const;
528
529 /** Sum values of a ScSummableCompressedArray for each row where in *this*
530 array the condition is met: ((aValue & rBitMask) == rMaskedCompare). */
531 template< typename S >
532 SC_DLLPUBLIC unsigned long SumCoupledArrayForCondition( A nStart, A nEnd,
533 const D& rBitMask, const D& rMaskedCompare,
534 const ScSummableCompressedArray<A,S>& rArray ) const;
535
536 /** Sum scaled values of a ScSummableCompressedArray for each row where in
537 *this* array the condition is met: ((aValue & rBitMask) == rMaskedCompare). */
538 template< typename S >
539 SC_DLLPUBLIC unsigned long SumScaledCoupledArrayForCondition( A nStart, A nEnd,
540 const D& rBitMask, const D& rMaskedCompare,
541 const ScSummableCompressedArray<A,S>& rArray,
542 double fScale ) const;
543 };
544
545
546 template< typename A, typename D >
AndValue(A nPos,const D & rValueToAnd)547 void ScBitMaskCompressedArray<A,D>::AndValue( A nPos, const D& rValueToAnd )
548 {
549 const D& rValue = this->GetValue( nPos);
550 if ((rValue & rValueToAnd) != rValue)
551 this->SetValue( nPos, rValue & rValueToAnd);
552 }
553
554
555 template< typename A, typename D >
OrValue(A nPos,const D & rValueToOr)556 void ScBitMaskCompressedArray<A,D>::OrValue( A nPos, const D& rValueToOr )
557 {
558 const D& rValue = this->GetValue( nPos);
559 if ((rValue | rValueToOr) != rValue)
560 this->SetValue( nPos, rValue | rValueToOr);
561 }
562
563
564 // === ScCoupledCompressedArrayIterator ======================================
565
566 /** Iterate over a ScBitMaskCompressedArray and retrieve values from a coupled
567 array for positions where in the bit mask array the condition ((*aIter1 &
568 rBitMask) == rMaskedCompare) is met.
569 */
570
571 template< typename A, typename D, typename S > class ScCoupledCompressedArrayIterator
572 {
573 public:
574 SC_DLLPUBLIC ScCoupledCompressedArrayIterator(
575 const ScBitMaskCompressedArray<A,D> & rArray1,
576 A nStart, A nEnd,
577 const D& rBitMask,
578 const D& rMaskedCompare,
579 const ScCompressedArray<A,S> & rArray2 );
580 void NewLimits( A nStart, A nEnd );
581 A GetIterStart() const;
582 A GetIterEnd() const;
583 bool operator ++();
584 A GetPos() const;
585 operator bool() const;
586 const S& operator *() const;
587 SC_DLLPUBLIC bool NextRange();
588 A GetRangeStart() const;
589 A GetRangeEnd() const;
590 void Resync( A nPos );
591
592 private:
593 ScCompressedArrayIterator<A,D> aIter1;
594 ScCompressedArrayIterator<A,S> aIter2;
595 const D& rBitMask;
596 const D& rMaskedCompare;
597
598 void InitLimits();
599 };
600
601
602 template< typename A, typename D, typename S >
GetIterStart() const603 A ScCoupledCompressedArrayIterator<A,D,S>::GetIterStart() const
604 {
605 return aIter1.GetIterStart();
606 }
607
608
609 template< typename A, typename D, typename S >
GetIterEnd() const610 A ScCoupledCompressedArrayIterator<A,D,S>::GetIterEnd() const
611 {
612 return aIter1.GetIterEnd();
613 }
614
615
616 template< typename A, typename D, typename S >
617 ScCoupledCompressedArrayIterator<A,D,S>::operator bool() const
618 {
619 return aIter1 && aIter2;
620 }
621
622
623 template< typename A, typename D, typename S >
operator *() const624 const S& ScCoupledCompressedArrayIterator<A,D,S>::operator*() const
625 {
626 return *aIter2;
627 }
628
629
630 template< typename A, typename D, typename S >
operator ++()631 bool ScCoupledCompressedArrayIterator<A,D,S>::operator ++()
632 {
633 if (aIter1.GetPos() < aIter1.GetRangeEnd())
634 {
635 ++aIter1;
636 ++aIter2;
637 return operator bool();
638 }
639 else
640 return NextRange();
641 }
642
643
644 template< typename A, typename D, typename S >
GetPos() const645 A ScCoupledCompressedArrayIterator<A,D,S>::GetPos() const
646 {
647 return aIter2.GetPos();
648 }
649
650
651 template< typename A, typename D, typename S >
GetRangeStart() const652 A ScCoupledCompressedArrayIterator<A,D,S>::GetRangeStart() const
653 {
654 return ::std::max( aIter1.GetRangeStart(), aIter2.GetRangeStart());
655 }
656
657
658 template< typename A, typename D, typename S >
GetRangeEnd() const659 A ScCoupledCompressedArrayIterator<A,D,S>::GetRangeEnd() const
660 {
661 return ::std::min( aIter1.GetRangeEnd(), aIter2.GetRangeEnd());
662 }
663
664
665 #endif // SC_COMPRESSEDARRAY_HXX
666