bump product version to 4.1.6.2
[LibreOffice.git] / svl / source / items / nranges.cxx
blob0b1f74ae7a46984a5a7de5d23ee5701ee8132bc3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <cassert>
21 #include <vector>
22 // compiled via include from itemset.cxx only!
24 //========================================================================
26 #ifdef DBG_UTIL
28 #define DBG_CHECK_RANGES(sal_uInt16, pArr) \
29 for ( const sal_uInt16 *pRange = pArr; *pRange; pRange += 2 ) \
30 { \
31 DBG_ASSERT( pRange[0] <= pRange[1], "ranges must be sorted" ); \
32 DBG_ASSERT( !pRange[2] || ( pRange[2] - pRange[1] ) > 1, \
33 "ranges must be sorted and discrete" ); \
36 #else
38 #define DBG_CHECK_RANGES(sal_uInt16,pArr)
40 #endif
42 //============================================================================
43 inline void Swap_Impl(const sal_uInt16 *& rp1, const sal_uInt16 *& rp2)
45 const sal_uInt16 * pTemp = rp1;
46 rp1 = rp2;
47 rp2 = pTemp;
50 //========================================================================
52 sal_uInt16 InitializeRanges_Impl( sal_uInt16 *&rpRanges, va_list pArgs,
53 sal_uInt16 nWh1, sal_uInt16 nWh2, sal_uInt16 nNull )
55 /** <H3>Description</H3>
57 Creates an sal_uInt16-ranges-array in 'rpRanges' using 'nWh1' and 'nWh2' as
58 first range, 'nNull' as terminator or start of 2nd range and 'pArgs' as
59 remaider.
61 It returns the number of sal_uInt16s which are contained in the described
62 set of sal_uInt16s.
66 sal_uInt16 nSize = 0, nIns = 0;
67 std::vector<sal_uInt16> aNumArr;
68 aNumArr.push_back( nWh1 );
69 aNumArr.push_back( nWh2 );
70 DBG_ASSERT( nWh1 <= nWh2, "Ungueltiger Bereich" );
71 nSize += nWh2 - nWh1 + 1;
72 aNumArr.push_back( nNull );
73 bool bEndOfRange = false;
74 while ( 0 !=
75 ( nIns =
76 sal::static_int_cast< sal_uInt16 >(
77 va_arg( pArgs, int ) ) ) )
79 bEndOfRange = !bEndOfRange;
80 if ( bEndOfRange )
82 const sal_uInt16 nPrev(*aNumArr.rbegin());
83 DBG_ASSERT( nPrev <= nIns, "Ungueltiger Bereich" );
84 nSize += nIns - nPrev + 1;
86 aNumArr.push_back( nIns );
89 assert( bEndOfRange ); // odd number of Which-IDs
91 // so, jetzt sind alle Bereiche vorhanden und
92 rpRanges = new sal_uInt16[ aNumArr.size() + 1 ];
93 std::copy( aNumArr.begin(), aNumArr.end(), rpRanges);
94 *(rpRanges + aNumArr.size()) = 0;
96 return nSize;
99 //------------------------------------------------------------------------
101 sal_uInt16 Count_Impl( const sal_uInt16 *pRanges )
103 /** <H3>Description</H3>
105 Determines the number of sal_uInt16s in an 0-terminated array of pairs of
106 sal_uInt16s. The terminating 0 is not included in the count.
110 sal_uInt16 nCount = 0;
111 while ( *pRanges )
113 nCount += 2;
114 pRanges += 2;
116 return nCount;
119 //------------------------------------------------------------------------
121 sal_uInt16 Capacity_Impl( const sal_uInt16 *pRanges )
123 /** <H3>Description</H3>
125 Determines the total number of sal_uInt16s described in an 0-terminated
126 array of pairs of sal_uInt16s, each representing an range of sal_uInt16s.
130 sal_uInt16 nCount = 0;
132 if ( pRanges )
134 while ( *pRanges )
136 nCount += pRanges[1] - pRanges[0] + 1;
137 pRanges += 2;
140 return nCount;
143 //------------------------------------------------------------------------
145 SfxUShortRanges::SfxUShortRanges( const SfxUShortRanges &rOrig )
147 /** <H3>Description</H3>
149 Copy-Ctor.
153 if ( rOrig._pRanges )
155 sal_uInt16 nCount = Count_Impl( rOrig._pRanges ) + 1;
156 _pRanges = new sal_uInt16[nCount];
157 memcpy( _pRanges, rOrig._pRanges, sizeof(sal_uInt16) * nCount );
159 else
160 _pRanges = 0;
163 //------------------------------------------------------------------------
165 SfxUShortRanges::SfxUShortRanges( sal_uInt16 nWhich1, sal_uInt16 nWhich2 )
167 /** <H3>Description</H3>
169 Constructs an SfxUShortRanges-instance from one range of sal_uInt16s.
171 precondition:
172 nWhich1 <= nWhich2
175 : _pRanges( new sal_uInt16[3] )
177 _pRanges[0] = nWhich1;
178 _pRanges[1] = nWhich2;
179 _pRanges[2] = 0;
182 //------------------------------------------------------------------------
184 SfxUShortRanges::SfxUShortRanges( const sal_uInt16* pArr )
186 /** <H3>Description</H3>
188 Constcurts an SfxUShortRanges-instance from an sorted ranges of sal_uInt16s,
189 terminates with on 0.
191 precondition: for each n >= 0 && n < (sizeof(pArr)-1)
192 pArr[2n] <= pArr[2n+1] && ( pArr[2n+2]-pArr[2n+1] ) > 1
196 DBG_CHECK_RANGES(sal_uInt16, pArr);
197 sal_uInt16 nCount = Count_Impl(pArr) + 1;
198 _pRanges = new sal_uInt16[ nCount ];
199 memcpy( _pRanges, pArr, sizeof(sal_uInt16) * nCount );
202 //------------------------------------------------------------------------
204 bool SfxUShortRanges::operator==( const SfxUShortRanges &rOther ) const
206 // Object pointers equal?
207 if ( this == &rOther )
208 return true;
210 // Ranges pointers equal?
211 if ( _pRanges == rOther._pRanges )
212 return true;
214 // Counts equal?
215 sal_uInt16 nCount = Count();
216 if ( nCount != rOther.Count() )
217 return false;
219 // Check arrays.
220 sal_uInt16 n = 0;
221 while( _pRanges[ n ] != 0 )
223 // Elements at current position equal?
224 if ( _pRanges[ n ] != rOther._pRanges[ n ] )
225 return false;
227 ++n;
230 return true;
233 //------------------------------------------------------------------------
235 SfxUShortRanges& SfxUShortRanges::operator =
237 const SfxUShortRanges &rRanges
240 /** <H3>Description</H3>
242 Assigns ranges from 'rRanges' to '*this'.
246 // special case: assign itself
247 if ( &rRanges == this )
248 return *this;
250 delete[] _pRanges;
252 // special case: 'rRanges' is empty
253 if ( rRanges.IsEmpty() )
254 _pRanges = 0;
255 else
257 // copy ranges
258 sal_uInt16 nCount = Count_Impl( rRanges._pRanges ) + 1;
259 _pRanges = new sal_uInt16[ nCount ];
260 memcpy( _pRanges, rRanges._pRanges, sizeof(sal_uInt16) * nCount );
262 return *this;
265 //------------------------------------------------------------------------
267 SfxUShortRanges& SfxUShortRanges::operator +=
269 const SfxUShortRanges &rRanges
272 /** <H3>Description</H3>
274 Merges *this with 'rRanges'.
276 for each sal_uInt16 n:
277 this->Contains( n ) || rRanges.Contains( n ) => this'->Contains( n )
278 !this->Contains( n ) && !rRanges.Contains( n ) => !this'->Contains( n )
282 // special cases: one is empty
283 if ( rRanges.IsEmpty() )
284 return *this;
285 if ( IsEmpty() )
286 return *this = rRanges;
288 // First, run thru _pRanges and rRanges._pRanges and determine the size of
289 // the new, merged ranges:
290 sal_uInt16 nCount = 0;
291 const sal_uInt16 * pRA = _pRanges;
292 const sal_uInt16 * pRB = rRanges._pRanges;
294 for (;;)
296 // The first pair of pRA has a lower lower bound than the first pair
297 // of pRB:
298 if (pRA[0] > pRB[0])
299 Swap_Impl(pRA, pRB);
301 // We are done with the merging if at least pRA is exhausted:
302 if (!pRA[0])
303 break;
305 for (;;)
307 // Skip those pairs in pRB that completely lie in the first pair
308 // of pRA:
309 while (pRB[1] <= pRA[1])
311 pRB += 2;
313 // Watch out for exhaustion of pRB:
314 if (!pRB[0])
316 Swap_Impl(pRA, pRB);
317 goto count_rest;
321 // If the next pair of pRA does not at least touch the current new
322 // pair, we are done with the current new pair:
323 if (pRB[0] > pRA[1] + 1)
324 break;
326 // The next pair of pRB extends the current new pair; first,
327 // extend the current new pair (we are done if pRB is then
328 // exhausted); second, switch the roles of pRA and pRB in order to
329 // merge in those following pairs of the original pRA that will
330 // lie in the (now larger) current new pair or will even extend it
331 // further:
332 pRA += 2;
333 if (!pRA[0])
334 goto count_rest;
335 Swap_Impl(pRA, pRB);
338 // Done with the current new pair:
339 pRA += 2;
340 nCount += 2;
343 // Only pRB has more pairs available, pRA is already exhausted:
344 count_rest:
345 for (; pRB[0]; pRB += 2)
346 nCount += 2;
348 // Now, create new ranges of the correct size and, on a second run thru
349 // _pRanges and rRanges._pRanges, copy the merged pairs into the new
350 // ranges:
351 sal_uInt16 * pNew = new sal_uInt16[nCount + 1];
352 pRA = _pRanges;
353 pRB = rRanges._pRanges;
354 sal_uInt16 * pRN = pNew;
356 for (;;)
358 // The first pair of pRA has a lower lower bound than the first pair
359 // of pRB:
360 if (pRA[0] > pRB[0])
361 Swap_Impl(pRA, pRB);
363 // We are done with the merging if at least pRA is exhausted:
364 if (!pRA[0])
365 break;
367 // Lower bound of current new pair is already known:
368 *pRN++ = pRA[0];
370 for (;;)
372 // Skip those pairs in pRB that completely lie in the first pair
373 // of pRA:
374 while (pRB[1] <= pRA[1])
376 pRB += 2;
378 // Watch out for exhaustion of pRB:
379 if (!pRB[0])
381 Swap_Impl(pRA, pRB);
382 ++pRB;
383 goto copy_rest;
387 // If the next pair of pRA does not at least touch the current new
388 // pair, we are done with the current new pair:
389 if (pRB[0] > pRA[1] + 1)
390 break;
392 // The next pair of pRB extends the current new pair; first,
393 // extend the current new pair (we are done if pRB is then
394 // exhausted); second, switch the roles of pRA and pRB in order to
395 // merge in those following pairs of the original pRA that will
396 // lie in the (now larger) current new pair or will even extend it
397 // further:
398 pRA += 2;
399 if (!pRA[0])
401 ++pRB;
402 goto copy_rest;
404 Swap_Impl(pRA, pRB);
407 // Done with the current new pair, now upper bound is also known:
408 *pRN++ = pRA[1];
409 pRA += 2;
412 // Only pRB has more pairs available (which are copied to the new ranges
413 // unchanged), pRA is already exhausted:
414 copy_rest:
415 for (; *pRB;)
416 *pRN++ = *pRB++;
417 *pRN = 0;
419 delete[] _pRanges;
420 _pRanges = pNew;
422 return *this;
425 //------------------------------------------------------------------------
427 SfxUShortRanges& SfxUShortRanges::operator -=
429 const SfxUShortRanges &rRanges
432 /** <H3>Description</H3>
434 Removes 'rRanges' from '*this'.
436 for each sal_uInt16 n:
437 this->Contains( n ) && rRanges.Contains( n ) => !this'->Contains( n )
438 this->Contains( n ) && !rRanges.Contains( n ) => this'->Contains( n )
439 !this->Contains( n ) => !this'->Contains( n )
443 // special cases: one is empty
444 if ( rRanges.IsEmpty() || IsEmpty() )
445 return *this;
447 // differentiate 'rRanges' in a temporary copy of '*this'
448 // (size is computed for maximal possibly split-count plus terminating 0)
449 sal_uInt16 nThisSize = Count_Impl(_pRanges);
450 sal_uInt16 nTargetSize = 1 + ( nThisSize + Count_Impl(rRanges._pRanges) );
451 sal_uInt16 *pTarget = new sal_uInt16[ nTargetSize ];
452 memset( pTarget, 0, sizeof(sal_uInt16)*nTargetSize );
453 memcpy( pTarget, _pRanges, sizeof(sal_uInt16)*nThisSize );
455 sal_uInt16 nPos1 = 0, nPos2 = 0, nTargetPos = 0;
456 while( _pRanges[ nPos1 ] )
458 sal_uInt16 l1 = _pRanges[ nPos1 ]; // lower bound of interval 1
459 sal_uInt16 u1 = _pRanges[ nPos1+1 ]; // upper bound of interval 1
460 sal_uInt16 l2 = rRanges._pRanges[ nPos2 ]; // lower bound of interval 2
461 sal_uInt16 u2 = rRanges._pRanges[ nPos2+1 ]; // upper bound of interval 2
463 // boundary cases
464 // * subtrahend is empty -> copy the minuend
465 if( !l2 )
467 pTarget[ nTargetPos ] = l1;
468 pTarget[ nTargetPos+1 ] = u1;
469 nTargetPos += 2;
470 nPos1 += 2;
471 continue;
473 // * next subtrahend interval is completely higher -> copy the minuend
474 if( u1 < l2 )
476 pTarget[ nTargetPos ] = l1;
477 pTarget[ nTargetPos+1 ] = u1;
478 nTargetPos += 2;
479 nPos1 += 2;
480 continue;
483 // * next subtrahend interval is completely lower -> try next
484 if( u2 < l1 )
486 nPos2 += 2;
487 continue;
490 // intersecting cases
491 // * subtrahend cuts out from the beginning of the minuend
492 if( l2 <= l1 && u2 <= u1 )
494 // reduce minuend interval, try again (minuend might be affected by other subtrahend intervals)
495 _pRanges[ nPos1 ] = u2 + 1;
496 nPos2 += 2; // this cannot hurt any longer
497 continue;
500 // * subtrahend cuts out from the end of the minuend
501 if( l1 <= l2 && u1 <= u2 )
503 // copy remaining part of minuend (cannot be affected by other intervals)
504 if( l1 < l2 ) // anything left at all?
506 pTarget[ nTargetPos ] = l1;
507 pTarget[ nTargetPos+1 ] = l2 - 1;
508 nTargetPos += 2;
509 // do not increment nPos2, might affect next minuend interval, too
511 nPos1 += 2; // nothing left at all
512 continue;
515 // * subtrahend completely deletes minuend (larger or same at both ends)
516 if( l1 >= l2 && u1 <= u2 )
518 nPos1 += 2; // minuend deleted
519 // do not increment nPos2, might affect next minuend interval, too
520 continue;
523 // * subtrahend divides minuend into two pieces
524 if( l1 <= l2 && u1 >= u2 ) // >= and <= since they may be something left only at one side
526 // left side
527 if( l1 < l2 ) // anything left at all
529 pTarget[ nTargetPos ] = l1;
530 pTarget[ nTargetPos+1 ] = l2 - 1;
531 nTargetPos += 2;
534 // right side
535 if( u1 > u2 ) // anything left at all
537 // reduce minuend interval, try again (minuend might be affected by other subtrahend itnervals )
538 _pRanges[ nPos1 ] = u2 + 1;
541 // subtrahend is completely used
542 nPos2 += 2;
543 continue;
546 // we should never be here
547 OSL_FAIL( "SfxUShortRanges::operator-=: internal error" );
548 } // while
550 pTarget[ nTargetPos ] = 0;
552 // assign the differentiated ranges
553 delete[] _pRanges;
555 sal_uInt16 nUShorts = Count_Impl(pTarget) + 1;
556 if ( 1 != nUShorts )
558 _pRanges = new sal_uInt16[ nUShorts ];
559 memcpy( _pRanges, pTarget, nUShorts * sizeof(sal_uInt16) );
561 else
562 _pRanges = 0;
564 delete [] pTarget;
565 return *this;
568 //------------------------------------------------------------------------
570 SfxUShortRanges& SfxUShortRanges::operator /=
572 const SfxUShortRanges &rRanges
575 /** <H3>Description</H3>
577 Determines intersection of '*this' with 'rRanges'.
579 for each sal_uInt16 n:
580 this->Contains( n ) && rRanges.Contains( n ) => this'->Contains( n )
581 !this->Contains( n ) => !this'->Contains( n )
582 !rRanges.Contains( n ) => !this'->Contains( n )
586 // boundary cases
587 // * first set is empty -> nothing to be done
588 // * second set is empty -> delete first set
589 if( rRanges.IsEmpty() )
591 delete[] _pRanges;
593 _pRanges = new sal_uInt16[1];
594 _pRanges[0] = 0;
596 return *this;
599 // intersect 'rRanges' in a temporary copy of '*this'
600 // (size is computed for maximal possibly split-count plus terminating 0)
601 sal_uInt16 nThisSize = Count_Impl(_pRanges);
602 sal_uInt16 nTargetSize = 1 + ( nThisSize + Count_Impl(rRanges._pRanges) );
603 sal_uInt16 *pTarget = new sal_uInt16[ nTargetSize ];
604 memset( pTarget, 0, sizeof(sal_uInt16)*nTargetSize );
605 memcpy( pTarget, _pRanges, sizeof(sal_uInt16)*nThisSize );
607 sal_uInt16 nPos1 = 0, nPos2 = 0, nTargetPos = 0;
608 while( _pRanges[ nPos1 ] != 0 && rRanges._pRanges[ nPos2 ] != 0 )
610 sal_uInt16 l1 = _pRanges[ nPos1 ]; // lower bound of interval 1
611 sal_uInt16 u1 = _pRanges[ nPos1+1 ]; // upper bound of interval 1
612 sal_uInt16 l2 = rRanges._pRanges[ nPos2 ]; // lower bound of interval 2
613 sal_uInt16 u2 = rRanges._pRanges[ nPos2+1 ]; // upper bound of interval 2
615 if( u1 < l2 )
617 // current interval in s1 is completely before ci in s2
618 nPos1 += 2;
619 continue;
621 if( u2 < l1 )
623 // ci in s2 is completely before ci in s1
624 nPos2 += 2;
625 continue;
628 // assert: there exists an intersection between ci1 and ci2
630 if( l1 <= l2 )
632 // c1 "is more to the left" than c2
634 if( u1 <= u2 )
636 pTarget[ nTargetPos ] = l2;
637 pTarget[ nTargetPos+1 ] = u1;
638 nTargetPos += 2;
639 nPos1 += 2;
640 continue;
642 else
644 pTarget[ nTargetPos ] = l2;
645 pTarget[ nTargetPos+1 ] = u2;
646 nTargetPos += 2;
647 nPos2 += 2;
650 else
652 // c2 "is more to the left" than c1"
654 if( u1 > u2 )
656 pTarget[ nTargetPos ] = l1;
657 pTarget[ nTargetPos+1 ] = u2;
658 nTargetPos += 2;
659 nPos2 += 2;
661 else
663 pTarget[ nTargetPos ] = l1;
664 pTarget[ nTargetPos+1 ] = u1;
665 nTargetPos += 2;
666 nPos1 += 2;
669 }; // while
670 pTarget[ nTargetPos ] = 0;
672 // assign the intersected ranges
673 delete[] _pRanges;
675 sal_uInt16 nUShorts = Count_Impl(pTarget) + 1;
676 if ( 1 != nUShorts )
678 _pRanges = new sal_uInt16[ nUShorts ];
679 memcpy( _pRanges, pTarget, nUShorts * sizeof(sal_uInt16) );
681 else
682 _pRanges = 0;
684 delete [] pTarget;
685 return *this;
688 //------------------------------------------------------------------------
690 sal_uInt16 SfxUShortRanges::Count() const
692 /** <H3>Description</H3>
694 Determines the number of USHORTs in the set described by the ranges
695 of USHORTs in '*this'.
699 return Capacity_Impl( _pRanges );
702 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */