1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: nranges.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svtools.hxx"
34 // compiled via include from itemset.cxx only!
36 //========================================================================
40 #define DBG_CHECK_RANGES(NUMTYPE, pArr) \
41 for ( const NUMTYPE *pRange = pArr; *pRange; pRange += 2 ) \
43 DBG_ASSERT( pRange[0] <= pRange[1], "ranges must be sorted" ); \
44 DBG_ASSERT( !pRange[2] || ( pRange[2] - pRange[1] ) > 1, \
45 "ranges must be sorted and discrete" ); \
50 #define DBG_CHECK_RANGES(NUMTYPE,pArr)
54 //============================================================================
55 inline void Swap_Impl(const NUMTYPE
*& rp1
, const NUMTYPE
*& rp2
)
57 const NUMTYPE
* pTemp
= rp1
;
62 //========================================================================
64 NUMTYPE
InitializeRanges_Impl( NUMTYPE
*&rpRanges
, va_list pArgs
,
65 NUMTYPE nWh1
, NUMTYPE nWh2
, NUMTYPE nNull
)
67 /** <H3>Description</H3>
69 Creates an USHORT-ranges-array in 'rpRanges' using 'nWh1' and 'nWh2' as
70 first range, 'nNull' as terminator or start of 2nd range and 'pArgs' as
73 It returns the number of NUMTYPEs which are contained in the described
78 NUMTYPE nSize
= 0, nIns
= 0;
80 SvNums
aNumArr( 11, 8 );
81 aNumArr
.Insert( nWh1
, nCnt
++ );
82 aNumArr
.Insert( nWh2
, nCnt
++ );
83 DBG_ASSERT( nWh1
<= nWh2
, "Ungueltiger Bereich" );
84 nSize
+= nWh2
- nWh1
+ 1;
85 aNumArr
.Insert( nNull
, nCnt
++ );
88 sal::static_int_cast
< NUMTYPE
>(
89 va_arg( pArgs
, NUMTYPE_ARG
) ) ) )
91 aNumArr
.Insert( nIns
, nCnt
++ );
92 if ( 0 == (nCnt
& 1) ) // 4,6,8, usw.
94 DBG_ASSERT( aNumArr
[ nCnt
-2 ] <= nIns
, "Ungueltiger Bereich" );
95 nSize
+= nIns
- aNumArr
[ nCnt
-2 ] + 1;
100 DBG_ASSERT( 0 == (nCnt
& 1), "ungerade Anzahl von Which-Paaren!" );
102 // so, jetzt sind alle Bereiche vorhanden und
103 rpRanges
= new NUMTYPE
[ nCnt
+1 ];
104 memcpy( rpRanges
, aNumArr
.GetData(), sizeof(NUMTYPE
) * nCnt
);
105 *(rpRanges
+nCnt
) = 0;
110 //------------------------------------------------------------------------
112 NUMTYPE
Count_Impl( const NUMTYPE
*pRanges
)
114 /** <H3>Description</H3>
116 Determines the number of NUMTYPEs in an 0-terminated array of pairs of
117 NUMTYPEs. The terminating 0 is not included in the count.
130 //------------------------------------------------------------------------
132 NUMTYPE
Capacity_Impl( const NUMTYPE
*pRanges
)
134 /** <H3>Description</H3>
136 Determines the total number of NUMTYPEs described in an 0-terminated
137 array of pairs of NUMTYPEs, each representing an range of NUMTYPEs.
147 nCount
+= pRanges
[1] - pRanges
[0] + 1;
154 //------------------------------------------------------------------------
156 SfxNumRanges::SfxNumRanges( const SfxNumRanges
&rOrig
)
158 /** <H3>Description</H3>
164 if ( rOrig
._pRanges
)
166 NUMTYPE nCount
= Count_Impl( rOrig
._pRanges
) + 1;
167 _pRanges
= new NUMTYPE
[nCount
];
168 memcpy( _pRanges
, rOrig
._pRanges
, sizeof(NUMTYPE
) * nCount
);
174 //------------------------------------------------------------------------
176 SfxNumRanges::SfxNumRanges( NUMTYPE nWhich1
, NUMTYPE nWhich2
)
178 /** <H3>Description</H3>
180 Constructs an SfxNumRanges-instance from one range of NUMTYPEs.
186 : _pRanges( new NUMTYPE
[3] )
188 _pRanges
[0] = nWhich1
;
189 _pRanges
[1] = nWhich2
;
193 //------------------------------------------------------------------------
195 SfxNumRanges::SfxNumRanges( NUMTYPE_ARG nWh0
, NUMTYPE_ARG nWh1
, NUMTYPE_ARG nNull
, ... )
197 /** <H3>Description</H3>
199 Constructs an SfxNumRanges-instance from more than one sorted ranges of
200 NUMTYPEs terminated with one 0.
202 precondition: for each n >= 0 && n < nArgs
203 nWh(2n) <= nWh(2n+1) && ( nWh(2n+2)-nWh(2n+1) ) > 1
208 va_start( pArgs
, nNull
);
209 InitializeRanges_Impl(
210 _pRanges
, pArgs
, sal::static_int_cast
< NUMTYPE
>(nWh0
),
211 sal::static_int_cast
< NUMTYPE
>(nWh1
),
212 sal::static_int_cast
< NUMTYPE
>(nNull
));
213 DBG_CHECK_RANGES(NUMTYPE
, _pRanges
);
216 //------------------------------------------------------------------------
218 SfxNumRanges::SfxNumRanges( const NUMTYPE
* pArr
)
220 /** <H3>Description</H3>
222 Constcurts an SfxNumRanges-instance from an sorted ranges of NUMTYPEs,
223 terminates with on 0.
225 precondition: for each n >= 0 && n < (sizeof(pArr)-1)
226 pArr[2n] <= pArr[2n+1] && ( pArr[2n+2]-pArr[2n+1] ) > 1
230 DBG_CHECK_RANGES(NUMTYPE
, pArr
);
231 NUMTYPE nCount
= Count_Impl(pArr
) + 1;
232 _pRanges
= new NUMTYPE
[ nCount
];
233 memcpy( _pRanges
, pArr
, sizeof(NUMTYPE
) * nCount
);
236 //------------------------------------------------------------------------
238 BOOL
SfxNumRanges::operator==( const SfxNumRanges
&rOther
) const
240 // Object pointers equal?
241 if ( this == &rOther
)
244 // Ranges pointers equal?
245 if ( _pRanges
== rOther
._pRanges
)
249 NUMTYPE nCount
= Count();
250 if ( nCount
!= rOther
.Count() )
255 while( _pRanges
[ n
] != 0 )
257 // Elements at current position equal?
258 if ( _pRanges
[ n
] != rOther
._pRanges
[ n
] )
267 //------------------------------------------------------------------------
269 SfxNumRanges
& SfxNumRanges::operator =
271 const SfxNumRanges
&rRanges
274 /** <H3>Description</H3>
276 Assigns ranges from 'rRanges' to '*this'.
280 // special case: assign itself
281 if ( &rRanges
== this )
286 // special case: 'rRanges' is empty
287 if ( rRanges
.IsEmpty() )
292 NUMTYPE nCount
= Count_Impl( rRanges
._pRanges
) + 1;
293 _pRanges
= new NUMTYPE
[ nCount
];
294 memcpy( _pRanges
, rRanges
._pRanges
, sizeof(NUMTYPE
) * nCount
);
299 //------------------------------------------------------------------------
301 SfxNumRanges
& SfxNumRanges::operator +=
303 const SfxNumRanges
&rRanges
306 /** <H3>Description</H3>
308 Merges *this with 'rRanges'.
311 this->Contains( n ) || rRanges.Contains( n ) => this'->Contains( n )
312 !this->Contains( n ) && !rRanges.Contains( n ) => !this'->Contains( n )
316 // special cases: one is empty
317 if ( rRanges
.IsEmpty() )
320 return *this = rRanges
;
322 // First, run thru _pRanges and rRanges._pRanges and determine the size of
323 // the new, merged ranges:
325 const NUMTYPE
* pRA
= _pRanges
;
326 const NUMTYPE
* pRB
= rRanges
._pRanges
;
330 // The first pair of pRA has a lower lower bound than the first pair
335 // We are done with the merging if at least pRA is exhausted:
341 // Skip those pairs in pRB that completely lie in the first pair
343 while (pRB
[1] <= pRA
[1])
347 // Watch out for exhaustion of pRB:
355 // If the next pair of pRA does not at least touch the current new
356 // pair, we are done with the current new pair:
357 if (pRB
[0] > pRA
[1] + 1)
360 // The next pair of pRB extends the current new pair; first,
361 // extend the current new pair (we are done if pRB is then
362 // exhausted); second, switch the roles of pRA and pRB in order to
363 // merge in those following pairs of the original pRA that will
364 // lie in the (now larger) current new pair or will even extend it
372 // Done with the current new pair:
377 // Only pRB has more pairs available, pRA is already exhausted:
379 for (; pRB
[0]; pRB
+= 2)
382 // Now, create new ranges of the correct size and, on a second run thru
383 // _pRanges and rRanges._pRanges, copy the merged pairs into the new
385 NUMTYPE
* pNew
= new NUMTYPE
[nCount
+ 1];
387 pRB
= rRanges
._pRanges
;
388 NUMTYPE
* pRN
= pNew
;
392 // The first pair of pRA has a lower lower bound than the first pair
397 // We are done with the merging if at least pRA is exhausted:
401 // Lower bound of current new pair is already known:
406 // Skip those pairs in pRB that completely lie in the first pair
408 while (pRB
[1] <= pRA
[1])
412 // Watch out for exhaustion of pRB:
421 // If the next pair of pRA does not at least touch the current new
422 // pair, we are done with the current new pair:
423 if (pRB
[0] > pRA
[1] + 1)
426 // The next pair of pRB extends the current new pair; first,
427 // extend the current new pair (we are done if pRB is then
428 // exhausted); second, switch the roles of pRA and pRB in order to
429 // merge in those following pairs of the original pRA that will
430 // lie in the (now larger) current new pair or will even extend it
441 // Done with the current new pair, now upper bound is also known:
446 // Only pRB has more pairs available (which are copied to the new ranges
447 // unchanged), pRA is already exhausted:
459 //------------------------------------------------------------------------
461 SfxNumRanges
& SfxNumRanges::operator -=
463 const SfxNumRanges
&rRanges
466 /** <H3>Description</H3>
468 Removes 'rRanges' from '*this'.
471 this->Contains( n ) && rRanges.Contains( n ) => !this'->Contains( n )
472 this->Contains( n ) && !rRanges.Contains( n ) => this'->Contains( n )
473 !this->Contains( n ) => !this'->Contains( n )
477 // special cases: one is empty
478 if ( rRanges
.IsEmpty() || IsEmpty() )
481 // differentiate 'rRanges' in a temporary copy of '*this'
482 // (size is computed for maximal possibly split-count plus terminating 0)
483 NUMTYPE nThisSize
= Count_Impl(_pRanges
);
484 NUMTYPE nTargetSize
= 1 + ( nThisSize
+ Count_Impl(rRanges
._pRanges
) );
485 NUMTYPE
*pTarget
= new NUMTYPE
[ nTargetSize
];
486 memset( pTarget
, sizeof(NUMTYPE
)*nTargetSize
, 0 );
487 memcpy( pTarget
, _pRanges
, sizeof(NUMTYPE
)*nThisSize
);
489 NUMTYPE nPos1
= 0, nPos2
= 0, nTargetPos
= 0;
490 while( _pRanges
[ nPos1
] )
492 NUMTYPE l1
= _pRanges
[ nPos1
]; // lower bound of interval 1
493 NUMTYPE u1
= _pRanges
[ nPos1
+1 ]; // upper bound of interval 1
494 NUMTYPE l2
= rRanges
._pRanges
[ nPos2
]; // lower bound of interval 2
495 NUMTYPE u2
= rRanges
._pRanges
[ nPos2
+1 ]; // upper bound of interval 2
498 // * subtrahend is empty -> copy the minuend
501 pTarget
[ nTargetPos
] = l1
;
502 pTarget
[ nTargetPos
+1 ] = u1
;
507 // * next subtrahend interval is completely higher -> copy the minuend
510 pTarget
[ nTargetPos
] = l1
;
511 pTarget
[ nTargetPos
+1 ] = u1
;
517 // * next subtrahend interval is completely lower -> try next
524 // intersecting cases
525 // * subtrahend cuts out from the beginning of the minuend
526 if( l2
<= l1
&& u2
<= u1
)
528 // reduce minuend interval, try again (minuend might be affected by other subtrahend intervals)
529 _pRanges
[ nPos1
] = u2
+ 1;
530 nPos2
+= 2; // this cannot hurt any longer
534 // * subtrahend cuts out from the end of the minuend
535 if( l1
<= l2
&& u1
<= u2
)
537 // copy remaining part of minuend (cannot be affected by other intervals)
538 if( l1
< l2
) // anything left at all?
540 pTarget
[ nTargetPos
] = l1
;
541 pTarget
[ nTargetPos
+1 ] = l2
- 1;
543 // do not increment nPos2, might affect next minuend interval, too
545 nPos1
+= 2; // nothing left at all
549 // * subtrahend completely deletes minuend (larger or same at both ends)
550 if( l1
>= l2
&& u1
<= u2
)
552 nPos1
+= 2; // minuend deleted
553 // do not increment nPos2, might affect next minuend interval, too
557 // * subtrahend divides minuend into two pieces
558 if( l1
<= l2
&& u1
>= u2
) // >= and <= since they may be something left only at one side
561 if( l1
< l2
) // anything left at all
563 pTarget
[ nTargetPos
] = l1
;
564 pTarget
[ nTargetPos
+1 ] = l2
- 1;
569 if( u1
> u2
) // anything left at all
571 // reduce minuend interval, try again (minuend might be affected by other subtrahend itnervals )
572 _pRanges
[ nPos1
] = u2
+ 1;
575 // subtrahend is completely used
580 // we should never be here
581 DBG_ERROR( "SfxNumRanges::operator-=: internal error" );
584 pTarget
[ nTargetPos
] = 0;
586 // assign the differentiated ranges
589 NUMTYPE nUShorts
= Count_Impl(pTarget
) + 1;
592 _pRanges
= new NUMTYPE
[ nUShorts
];
593 memcpy( _pRanges
, pTarget
, nUShorts
* sizeof(NUMTYPE
) );
601 /* untested code from MI commented out (MDA, 28.01.97)
604 // 1st range is smaller than 2nd range?
605 if ( pRange1[1] < pRange2[0] )
609 // 2nd range is smaller than 1st range?
610 else if ( pRange2[1] < pRange1[0] )
614 // 2nd range totally overlaps the 1st range?
615 else if ( pRange2[0] <= pRange1[0] && pRange2[1] >= pRange1[1] )
616 // => remove 1st range
617 memmove( pRange1, pRange1+2, sizeof(NUMTYPE) * (pEndOfTarget-pRange1+2) );
619 // 2nd range overlaps only the beginning of 1st range?
620 else if ( pRange2[0] <= pRange1[0] && pRange2[1] < pRange1[1] )
622 // => cut the beginning of 1st range and goto next 2nd range
623 pRange1[0] = pRange2[1] + 1;
627 // 2nd range overlaps only the end of 1st range?
628 else if ( pRange2[0] > pRange1[0] && pRange2[1] >= pRange1[0] )
629 // => cut the beginning of 1st range
630 pRange1[0] = pRange2[1]+1;
632 // 2nd range is a real subset of 1st range
635 // => split 1st range and goto next 2nd range
636 memmove( pRange1+3, pRange1+1, sizeof(NUMTYPE) * (pEndOfTarget-pRange1-1) );
637 pRange1[1] = pRange2[0] - 1;
638 pRange1[2] = pRange2[1] + 1;
643 while ( *pRange1 && *pRange2 );
645 // assign the differentiated ranges
647 NUMTYPE nUShorts = Count_Impl(pTarget) + 1;
650 _pRanges = new NUMTYPE[ nUShorts ];
651 memcpy( _pRanges, pTarget, nUShorts * sizeof(NUMTYPE) );
652 _pRanges[ nUShorts-1 ] = 0;
660 //------------------------------------------------------------------------
662 SfxNumRanges
& SfxNumRanges::operator /=
664 const SfxNumRanges
&rRanges
667 /** <H3>Description</H3>
669 Determines intersection of '*this' with 'rRanges'.
672 this->Contains( n ) && rRanges.Contains( n ) => this'->Contains( n )
673 !this->Contains( n ) => !this'->Contains( n )
674 !rRanges.Contains( n ) => !this'->Contains( n )
679 // * first set is empty -> nothing to be done
680 // * second set is empty -> delete first set
681 if( rRanges
.IsEmpty() )
685 _pRanges
= new NUMTYPE
[1];
691 // intersect 'rRanges' in a temporary copy of '*this'
692 // (size is computed for maximal possibly split-count plus terminating 0)
693 NUMTYPE nThisSize
= Count_Impl(_pRanges
);
694 NUMTYPE nTargetSize
= 1 + ( nThisSize
+ Count_Impl(rRanges
._pRanges
) );
695 NUMTYPE
*pTarget
= new NUMTYPE
[ nTargetSize
];
696 memset( pTarget
, sizeof(NUMTYPE
)*nTargetSize
, 0 );
697 memcpy( pTarget
, _pRanges
, sizeof(NUMTYPE
)*nThisSize
);
699 NUMTYPE nPos1
= 0, nPos2
= 0, nTargetPos
= 0;
700 while( _pRanges
[ nPos1
] != 0 && rRanges
._pRanges
[ nPos2
] != 0 )
702 NUMTYPE l1
= _pRanges
[ nPos1
]; // lower bound of interval 1
703 NUMTYPE u1
= _pRanges
[ nPos1
+1 ]; // upper bound of interval 1
704 NUMTYPE l2
= rRanges
._pRanges
[ nPos2
]; // lower bound of interval 2
705 NUMTYPE u2
= rRanges
._pRanges
[ nPos2
+1 ]; // upper bound of interval 2
709 // current interval in s1 is completely before ci in s2
715 // ci in s2 is completely before ci in s1
720 // assert: there exists an intersection between ci1 and ci2
724 // c1 "is more to the left" than c2
728 pTarget
[ nTargetPos
] = l2
;
729 pTarget
[ nTargetPos
+1 ] = u1
;
736 pTarget
[ nTargetPos
] = l2
;
737 pTarget
[ nTargetPos
+1 ] = u2
;
744 // c2 "is more to the left" than c1"
748 pTarget
[ nTargetPos
] = l1
;
749 pTarget
[ nTargetPos
+1 ] = u2
;
755 pTarget
[ nTargetPos
] = l1
;
756 pTarget
[ nTargetPos
+1 ] = u1
;
762 pTarget
[ nTargetPos
] = 0;
764 // assign the intersected ranges
767 NUMTYPE nUShorts
= Count_Impl(pTarget
) + 1;
770 _pRanges
= new NUMTYPE
[ nUShorts
];
771 memcpy( _pRanges
, pTarget
, nUShorts
* sizeof(NUMTYPE
) );
780 //------------------------------------------------------------------------
782 BOOL
SfxNumRanges::Intersects( const SfxNumRanges
&rRanges
) const
784 /** <H3>Description</H3>
786 Determines if at least one range in 'rRanges' intersects with one
789 TRUE, if there is at least one with:
790 this->Contains( n ) && rRanges.Contains( n )
794 // special cases: one is empty
795 if ( rRanges
.IsEmpty() || IsEmpty() )
798 // find at least one intersecting range
799 const NUMTYPE
*pRange1
= _pRanges
;
800 const NUMTYPE
*pRange2
= rRanges
._pRanges
;
804 // 1st range is smaller than 2nd range?
805 if ( pRange1
[1] < pRange2
[0] )
809 // 2nd range is smaller than 1st range?
810 else if ( pRange2
[1] < pRange1
[0] )
814 // the ranges are overlappung
820 // no intersection found
824 //------------------------------------------------------------------------
826 NUMTYPE
SfxNumRanges::Count() const
828 /** <H3>Description</H3>
830 Determines the number of USHORTs in the set described by the ranges
831 of USHORTs in '*this'.
835 return Capacity_Impl( _pRanges
);
838 //------------------------------------------------------------------------
840 BOOL
SfxNumRanges::Contains( NUMTYPE n
) const
842 /** <H3>Description</H3>
844 Determines if '*this' contains 'n'.
848 for ( NUMTYPE
*pRange
= _pRanges
; *pRange
&& *pRange
<= n
; pRange
+= 2 )
849 if ( pRange
[0] <= n
&& n
<= pRange
[1] )