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!
24 //========================================================================
28 #define DBG_CHECK_RANGES(sal_uInt16, pArr) \
29 for ( const sal_uInt16 *pRange = pArr; *pRange; pRange += 2 ) \
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" ); \
38 #define DBG_CHECK_RANGES(sal_uInt16,pArr)
42 //============================================================================
43 inline void Swap_Impl(const sal_uInt16
*& rp1
, const sal_uInt16
*& rp2
)
45 const sal_uInt16
* pTemp
= rp1
;
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
61 It returns the number of sal_uInt16s which are contained in the described
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;
76 sal::static_int_cast
< sal_uInt16
>(
77 va_arg( pArgs
, int ) ) ) )
79 bEndOfRange
= !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;
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;
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;
136 nCount
+= pRanges
[1] - pRanges
[0] + 1;
143 //------------------------------------------------------------------------
145 SfxUShortRanges::SfxUShortRanges( const SfxUShortRanges
&rOrig
)
147 /** <H3>Description</H3>
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
);
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.
175 : _pRanges( new sal_uInt16
[3] )
177 _pRanges
[0] = nWhich1
;
178 _pRanges
[1] = nWhich2
;
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
)
210 // Ranges pointers equal?
211 if ( _pRanges
== rOther
._pRanges
)
215 sal_uInt16 nCount
= Count();
216 if ( nCount
!= rOther
.Count() )
221 while( _pRanges
[ n
] != 0 )
223 // Elements at current position equal?
224 if ( _pRanges
[ n
] != rOther
._pRanges
[ n
] )
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 )
252 // special case: 'rRanges' is empty
253 if ( rRanges
.IsEmpty() )
258 sal_uInt16 nCount
= Count_Impl( rRanges
._pRanges
) + 1;
259 _pRanges
= new sal_uInt16
[ nCount
];
260 memcpy( _pRanges
, rRanges
._pRanges
, sizeof(sal_uInt16
) * nCount
);
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() )
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
;
296 // The first pair of pRA has a lower lower bound than the first pair
301 // We are done with the merging if at least pRA is exhausted:
307 // Skip those pairs in pRB that completely lie in the first pair
309 while (pRB
[1] <= pRA
[1])
313 // Watch out for exhaustion of pRB:
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)
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
338 // Done with the current new pair:
343 // Only pRB has more pairs available, pRA is already exhausted:
345 for (; pRB
[0]; pRB
+= 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
351 sal_uInt16
* pNew
= new sal_uInt16
[nCount
+ 1];
353 pRB
= rRanges
._pRanges
;
354 sal_uInt16
* pRN
= pNew
;
358 // The first pair of pRA has a lower lower bound than the first pair
363 // We are done with the merging if at least pRA is exhausted:
367 // Lower bound of current new pair is already known:
372 // Skip those pairs in pRB that completely lie in the first pair
374 while (pRB
[1] <= pRA
[1])
378 // Watch out for exhaustion of pRB:
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)
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
407 // Done with the current new pair, now upper bound is also known:
412 // Only pRB has more pairs available (which are copied to the new ranges
413 // unchanged), pRA is already exhausted:
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() )
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
464 // * subtrahend is empty -> copy the minuend
467 pTarget
[ nTargetPos
] = l1
;
468 pTarget
[ nTargetPos
+1 ] = u1
;
473 // * next subtrahend interval is completely higher -> copy the minuend
476 pTarget
[ nTargetPos
] = l1
;
477 pTarget
[ nTargetPos
+1 ] = u1
;
483 // * next subtrahend interval is completely lower -> try next
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
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;
509 // do not increment nPos2, might affect next minuend interval, too
511 nPos1
+= 2; // nothing left at all
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
523 // * subtrahend divides minuend into two pieces
524 if( l1
<= l2
&& u1
>= u2
) // >= and <= since they may be something left only at one side
527 if( l1
< l2
) // anything left at all
529 pTarget
[ nTargetPos
] = l1
;
530 pTarget
[ nTargetPos
+1 ] = l2
- 1;
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
546 // we should never be here
547 OSL_FAIL( "SfxUShortRanges::operator-=: internal error" );
550 pTarget
[ nTargetPos
] = 0;
552 // assign the differentiated ranges
555 sal_uInt16 nUShorts
= Count_Impl(pTarget
) + 1;
558 _pRanges
= new sal_uInt16
[ nUShorts
];
559 memcpy( _pRanges
, pTarget
, nUShorts
* sizeof(sal_uInt16
) );
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 )
587 // * first set is empty -> nothing to be done
588 // * second set is empty -> delete first set
589 if( rRanges
.IsEmpty() )
593 _pRanges
= new sal_uInt16
[1];
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
617 // current interval in s1 is completely before ci in s2
623 // ci in s2 is completely before ci in s1
628 // assert: there exists an intersection between ci1 and ci2
632 // c1 "is more to the left" than c2
636 pTarget
[ nTargetPos
] = l2
;
637 pTarget
[ nTargetPos
+1 ] = u1
;
644 pTarget
[ nTargetPos
] = l2
;
645 pTarget
[ nTargetPos
+1 ] = u2
;
652 // c2 "is more to the left" than c1"
656 pTarget
[ nTargetPos
] = l1
;
657 pTarget
[ nTargetPos
+1 ] = u2
;
663 pTarget
[ nTargetPos
] = l1
;
664 pTarget
[ nTargetPos
+1 ] = u1
;
670 pTarget
[ nTargetPos
] = 0;
672 // assign the intersected ranges
675 sal_uInt16 nUShorts
= Count_Impl(pTarget
) + 1;
678 _pRanges
= new sal_uInt16
[ nUShorts
];
679 memcpy( _pRanges
, pTarget
, nUShorts
* sizeof(sal_uInt16
) );
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: */