1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
22 // compiled via include from itemset.cxx only!
27 #define DBG_CHECK_RANGES(sal_uInt16, pArr) \
28 for ( const sal_uInt16 *pRange = pArr; *pRange; pRange += 2 ) \
30 DBG_ASSERT( pRange[0] <= pRange[1], "ranges must be sorted" ); \
31 DBG_ASSERT( !pRange[2] || ( pRange[2] - pRange[1] ) > 1, \
32 "ranges must be sorted and discrete" ); \
37 #define DBG_CHECK_RANGES(sal_uInt16,pArr)
41 inline void Swap_Impl(const sal_uInt16
*& rp1
, const sal_uInt16
*& rp2
)
43 const sal_uInt16
* pTemp
= rp1
;
49 sal_uInt16
InitializeRanges_Impl( sal_uInt16
*&rpRanges
, va_list pArgs
,
50 sal_uInt16 nWh1
, sal_uInt16 nWh2
, sal_uInt16 nNull
)
52 /** <H3>Description</H3>
54 Creates an sal_uInt16-ranges-array in 'rpRanges' using 'nWh1' and 'nWh2' as
55 first range, 'nNull' as terminator or start of 2nd range and 'pArgs' as
58 It returns the number of sal_uInt16s which are contained in the described
63 sal_uInt16 nSize
= 0, nIns
= 0;
64 std::vector
<sal_uInt16
> aNumArr
;
65 aNumArr
.push_back( nWh1
);
66 aNumArr
.push_back( nWh2
);
67 DBG_ASSERT( nWh1
<= nWh2
, "Ungueltiger Bereich" );
68 nSize
+= nWh2
- nWh1
+ 1;
69 aNumArr
.push_back( nNull
);
70 bool bEndOfRange
= false;
73 sal::static_int_cast
< sal_uInt16
>(
74 va_arg( pArgs
, int ) ) ) )
76 bEndOfRange
= !bEndOfRange
;
79 const sal_uInt16
nPrev(*aNumArr
.rbegin());
80 DBG_ASSERT( nPrev
<= nIns
, "Ungueltiger Bereich" );
81 nSize
+= nIns
- nPrev
+ 1;
83 aNumArr
.push_back( nIns
);
86 assert( bEndOfRange
); // odd number of Which-IDs
88 // so, jetzt sind alle Bereiche vorhanden und
89 rpRanges
= new sal_uInt16
[ aNumArr
.size() + 1 ];
90 std::copy( aNumArr
.begin(), aNumArr
.end(), rpRanges
);
91 *(rpRanges
+ aNumArr
.size()) = 0;
97 sal_uInt16
Count_Impl( const sal_uInt16
*pRanges
)
99 /** <H3>Description</H3>
101 Determines the number of sal_uInt16s in an 0-terminated array of pairs of
102 sal_uInt16s. The terminating 0 is not included in the count.
106 sal_uInt16 nCount
= 0;
116 sal_uInt16
Capacity_Impl( const sal_uInt16
*pRanges
)
118 /** <H3>Description</H3>
120 Determines the total number of sal_uInt16s described in an 0-terminated
121 array of pairs of sal_uInt16s, each representing an range of sal_uInt16s.
125 sal_uInt16 nCount
= 0;
131 nCount
+= pRanges
[1] - pRanges
[0] + 1;
139 SfxUShortRanges::SfxUShortRanges( const SfxUShortRanges
&rOrig
)
141 /** <H3>Description</H3>
147 if ( rOrig
._pRanges
)
149 sal_uInt16 nCount
= Count_Impl( rOrig
._pRanges
) + 1;
150 _pRanges
= new sal_uInt16
[nCount
];
151 memcpy( _pRanges
, rOrig
._pRanges
, sizeof(sal_uInt16
) * nCount
);
158 SfxUShortRanges::SfxUShortRanges( sal_uInt16 nWhich1
, sal_uInt16 nWhich2
)
160 /** <H3>Description</H3>
162 Constructs an SfxUShortRanges-instance from one range of sal_uInt16s.
168 : _pRanges( new sal_uInt16
[3] )
170 _pRanges
[0] = nWhich1
;
171 _pRanges
[1] = nWhich2
;
176 SfxUShortRanges::SfxUShortRanges( const sal_uInt16
* pArr
)
178 /** <H3>Description</H3>
180 Constcurts an SfxUShortRanges-instance from an sorted ranges of sal_uInt16s,
181 terminates with on 0.
183 precondition: for each n >= 0 && n < (sizeof(pArr)-1)
184 pArr[2n] <= pArr[2n+1] && ( pArr[2n+2]-pArr[2n+1] ) > 1
188 DBG_CHECK_RANGES(sal_uInt16
, pArr
);
189 sal_uInt16 nCount
= Count_Impl(pArr
) + 1;
190 _pRanges
= new sal_uInt16
[ nCount
];
191 memcpy( _pRanges
, pArr
, sizeof(sal_uInt16
) * nCount
);
195 bool SfxUShortRanges::operator==( const SfxUShortRanges
&rOther
) const
197 // Object pointers equal?
198 if ( this == &rOther
)
201 // Ranges pointers equal?
202 if ( _pRanges
== rOther
._pRanges
)
206 sal_uInt16 nCount
= Count();
207 if ( nCount
!= rOther
.Count() )
212 while( _pRanges
[ n
] != 0 )
214 // Elements at current position equal?
215 if ( _pRanges
[ n
] != rOther
._pRanges
[ n
] )
225 SfxUShortRanges
& SfxUShortRanges::operator =
227 const SfxUShortRanges
&rRanges
230 /** <H3>Description</H3>
232 Assigns ranges from 'rRanges' to '*this'.
236 // special case: assign itself
237 if ( &rRanges
== this )
242 // special case: 'rRanges' is empty
243 if ( rRanges
.IsEmpty() )
248 sal_uInt16 nCount
= Count_Impl( rRanges
._pRanges
) + 1;
249 _pRanges
= new sal_uInt16
[ nCount
];
250 memcpy( _pRanges
, rRanges
._pRanges
, sizeof(sal_uInt16
) * nCount
);
256 SfxUShortRanges
& SfxUShortRanges::operator +=
258 const SfxUShortRanges
&rRanges
261 /** <H3>Description</H3>
263 Merges *this with 'rRanges'.
265 for each sal_uInt16 n:
266 this->Contains( n ) || rRanges.Contains( n ) => this'->Contains( n )
267 !this->Contains( n ) && !rRanges.Contains( n ) => !this'->Contains( n )
271 // special cases: one is empty
272 if ( rRanges
.IsEmpty() )
275 return *this = rRanges
;
277 // First, run thru _pRanges and rRanges._pRanges and determine the size of
278 // the new, merged ranges:
279 sal_uInt16 nCount
= 0;
280 const sal_uInt16
* pRA
= _pRanges
;
281 const sal_uInt16
* pRB
= rRanges
._pRanges
;
285 // The first pair of pRA has a lower lower bound than the first pair
290 // We are done with the merging if at least pRA is exhausted:
296 // Skip those pairs in pRB that completely lie in the first pair
298 while (pRB
[1] <= pRA
[1])
302 // Watch out for exhaustion of pRB:
310 // If the next pair of pRA does not at least touch the current new
311 // pair, we are done with the current new pair:
312 if (pRB
[0] > pRA
[1] + 1)
315 // The next pair of pRB extends the current new pair; first,
316 // extend the current new pair (we are done if pRB is then
317 // exhausted); second, switch the roles of pRA and pRB in order to
318 // merge in those following pairs of the original pRA that will
319 // lie in the (now larger) current new pair or will even extend it
327 // Done with the current new pair:
332 // Only pRB has more pairs available, pRA is already exhausted:
334 for (; pRB
[0]; pRB
+= 2)
337 // Now, create new ranges of the correct size and, on a second run thru
338 // _pRanges and rRanges._pRanges, copy the merged pairs into the new
340 sal_uInt16
* pNew
= new sal_uInt16
[nCount
+ 1];
342 pRB
= rRanges
._pRanges
;
343 sal_uInt16
* pRN
= pNew
;
347 // The first pair of pRA has a lower lower bound than the first pair
352 // We are done with the merging if at least pRA is exhausted:
356 // Lower bound of current new pair is already known:
361 // Skip those pairs in pRB that completely lie in the first pair
363 while (pRB
[1] <= pRA
[1])
367 // Watch out for exhaustion of pRB:
376 // If the next pair of pRA does not at least touch the current new
377 // pair, we are done with the current new pair:
378 if (pRB
[0] > pRA
[1] + 1)
381 // The next pair of pRB extends the current new pair; first,
382 // extend the current new pair (we are done if pRB is then
383 // exhausted); second, switch the roles of pRA and pRB in order to
384 // merge in those following pairs of the original pRA that will
385 // lie in the (now larger) current new pair or will even extend it
396 // Done with the current new pair, now upper bound is also known:
401 // Only pRB has more pairs available (which are copied to the new ranges
402 // unchanged), pRA is already exhausted:
415 SfxUShortRanges
& SfxUShortRanges::operator -=
417 const SfxUShortRanges
&rRanges
420 /** <H3>Description</H3>
422 Removes 'rRanges' from '*this'.
424 for each sal_uInt16 n:
425 this->Contains( n ) && rRanges.Contains( n ) => !this'->Contains( n )
426 this->Contains( n ) && !rRanges.Contains( n ) => this'->Contains( n )
427 !this->Contains( n ) => !this'->Contains( n )
431 // special cases: one is empty
432 if ( rRanges
.IsEmpty() || IsEmpty() )
435 // differentiate 'rRanges' in a temporary copy of '*this'
436 // (size is computed for maximal possibly split-count plus terminating 0)
437 sal_uInt16 nThisSize
= Count_Impl(_pRanges
);
438 sal_uInt16 nTargetSize
= 1 + ( nThisSize
+ Count_Impl(rRanges
._pRanges
) );
439 sal_uInt16
*pTarget
= new sal_uInt16
[ nTargetSize
];
440 memset( pTarget
, 0, sizeof(sal_uInt16
)*nTargetSize
);
441 memcpy( pTarget
, _pRanges
, sizeof(sal_uInt16
)*nThisSize
);
443 sal_uInt16 nPos1
= 0, nPos2
= 0, nTargetPos
= 0;
444 while( _pRanges
[ nPos1
] )
446 sal_uInt16 l1
= _pRanges
[ nPos1
]; // lower bound of interval 1
447 sal_uInt16 u1
= _pRanges
[ nPos1
+1 ]; // upper bound of interval 1
448 sal_uInt16 l2
= rRanges
._pRanges
[ nPos2
]; // lower bound of interval 2
449 sal_uInt16 u2
= rRanges
._pRanges
[ nPos2
+1 ]; // upper bound of interval 2
452 // * subtrahend is empty -> copy the minuend
455 pTarget
[ nTargetPos
] = l1
;
456 pTarget
[ nTargetPos
+1 ] = u1
;
461 // * next subtrahend interval is completely higher -> copy the minuend
464 pTarget
[ nTargetPos
] = l1
;
465 pTarget
[ nTargetPos
+1 ] = u1
;
471 // * next subtrahend interval is completely lower -> try next
478 // intersecting cases
479 // * subtrahend cuts out from the beginning of the minuend
480 if( l2
<= l1
&& u2
<= u1
)
482 // reduce minuend interval, try again (minuend might be affected by other subtrahend intervals)
483 _pRanges
[ nPos1
] = u2
+ 1;
484 nPos2
+= 2; // this cannot hurt any longer
488 // * subtrahend cuts out from the end of the minuend
489 if( l1
<= l2
&& u1
<= u2
)
491 // copy remaining part of minuend (cannot be affected by other intervals)
492 if( l1
< l2
) // anything left at all?
494 pTarget
[ nTargetPos
] = l1
;
495 pTarget
[ nTargetPos
+1 ] = l2
- 1;
497 // do not increment nPos2, might affect next minuend interval, too
499 nPos1
+= 2; // nothing left at all
503 // * subtrahend completely deletes minuend (larger or same at both ends)
504 if( l1
>= l2
&& u1
<= u2
)
506 nPos1
+= 2; // minuend deleted
507 // do not increment nPos2, might affect next minuend interval, too
511 // * subtrahend divides minuend into two pieces
512 if( l1
<= l2
&& u1
>= u2
) // >= and <= since they may be something left only at one side
515 if( l1
< l2
) // anything left at all
517 pTarget
[ nTargetPos
] = l1
;
518 pTarget
[ nTargetPos
+1 ] = l2
- 1;
523 if( u1
> u2
) // anything left at all
525 // reduce minuend interval, try again (minuend might be affected by other subtrahend itnervals )
526 _pRanges
[ nPos1
] = u2
+ 1;
529 // subtrahend is completely used
534 // we should never be here
535 OSL_FAIL( "SfxUShortRanges::operator-=: internal error" );
538 pTarget
[ nTargetPos
] = 0;
540 // assign the differentiated ranges
543 sal_uInt16 nUShorts
= Count_Impl(pTarget
) + 1;
546 _pRanges
= new sal_uInt16
[ nUShorts
];
547 memcpy( _pRanges
, pTarget
, nUShorts
* sizeof(sal_uInt16
) );
557 SfxUShortRanges
& SfxUShortRanges::operator /=
559 const SfxUShortRanges
&rRanges
562 /** <H3>Description</H3>
564 Determines intersection of '*this' with 'rRanges'.
566 for each sal_uInt16 n:
567 this->Contains( n ) && rRanges.Contains( n ) => this'->Contains( n )
568 !this->Contains( n ) => !this'->Contains( n )
569 !rRanges.Contains( n ) => !this'->Contains( n )
574 // * first set is empty -> nothing to be done
575 // * second set is empty -> delete first set
576 if( rRanges
.IsEmpty() )
580 _pRanges
= new sal_uInt16
[1];
586 // intersect 'rRanges' in a temporary copy of '*this'
587 // (size is computed for maximal possibly split-count plus terminating 0)
588 sal_uInt16 nThisSize
= Count_Impl(_pRanges
);
589 sal_uInt16 nTargetSize
= 1 + ( nThisSize
+ Count_Impl(rRanges
._pRanges
) );
590 sal_uInt16
*pTarget
= new sal_uInt16
[ nTargetSize
];
591 memset( pTarget
, 0, sizeof(sal_uInt16
)*nTargetSize
);
592 memcpy( pTarget
, _pRanges
, sizeof(sal_uInt16
)*nThisSize
);
594 sal_uInt16 nPos1
= 0, nPos2
= 0, nTargetPos
= 0;
595 while( _pRanges
[ nPos1
] != 0 && rRanges
._pRanges
[ nPos2
] != 0 )
597 sal_uInt16 l1
= _pRanges
[ nPos1
]; // lower bound of interval 1
598 sal_uInt16 u1
= _pRanges
[ nPos1
+1 ]; // upper bound of interval 1
599 sal_uInt16 l2
= rRanges
._pRanges
[ nPos2
]; // lower bound of interval 2
600 sal_uInt16 u2
= rRanges
._pRanges
[ nPos2
+1 ]; // upper bound of interval 2
604 // current interval in s1 is completely before ci in s2
610 // ci in s2 is completely before ci in s1
615 // assert: there exists an intersection between ci1 and ci2
619 // c1 "is more to the left" than c2
623 pTarget
[ nTargetPos
] = l2
;
624 pTarget
[ nTargetPos
+1 ] = u1
;
631 pTarget
[ nTargetPos
] = l2
;
632 pTarget
[ nTargetPos
+1 ] = u2
;
639 // c2 "is more to the left" than c1"
643 pTarget
[ nTargetPos
] = l1
;
644 pTarget
[ nTargetPos
+1 ] = u2
;
650 pTarget
[ nTargetPos
] = l1
;
651 pTarget
[ nTargetPos
+1 ] = u1
;
657 pTarget
[ nTargetPos
] = 0;
659 // assign the intersected ranges
662 sal_uInt16 nUShorts
= Count_Impl(pTarget
) + 1;
665 _pRanges
= new sal_uInt16
[ nUShorts
];
666 memcpy( _pRanges
, pTarget
, nUShorts
* sizeof(sal_uInt16
) );
676 sal_uInt16
SfxUShortRanges::Count() const
678 /** <H3>Description</H3>
680 Determines the number of USHORTs in the set described by the ranges
681 of USHORTs in '*this'.
685 return Capacity_Impl( _pRanges
);
688 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */