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!
23 #include <boost/scoped_array.hpp>
25 #include <osl/diagnose.h>
29 #define DBG_CHECK_RANGES(sal_uInt16, pArr) \
30 for ( const sal_uInt16 *pRange = pArr; *pRange; pRange += 2 ) \
32 DBG_ASSERT( pRange[0] <= pRange[1], "ranges must be sorted" ); \
33 DBG_ASSERT( !pRange[2] || ( pRange[2] - pRange[1] ) > 1, \
34 "ranges must be sorted and discrete" ); \
39 #define DBG_CHECK_RANGES(sal_uInt16,pArr)
43 inline void Swap_Impl(const sal_uInt16
*& rp1
, const sal_uInt16
*& rp2
)
45 const sal_uInt16
* pTemp
= rp1
;
51 * Creates a sal_uInt16-ranges-array in 'rpRanges' using 'nWh1' and 'nWh2' as
52 * first range, 'nNull' as terminator or start of 2nd range and 'pArgs' as
55 * It returns the number of sal_uInt16s which are contained in the described
58 sal_uInt16
InitializeRanges_Impl( sal_uInt16
*&rpRanges
, va_list pArgs
,
59 sal_uInt16 nWh1
, sal_uInt16 nWh2
, sal_uInt16 nNull
)
61 sal_uInt16 nSize
= 0, nIns
= 0;
62 std::vector
<sal_uInt16
> aNumArr
;
63 aNumArr
.push_back( nWh1
);
64 aNumArr
.push_back( nWh2
);
65 DBG_ASSERT( nWh1
<= nWh2
, "Invalid range" );
66 nSize
+= nWh2
- nWh1
+ 1;
67 aNumArr
.push_back( nNull
);
68 bool bEndOfRange
= false;
71 sal::static_int_cast
< sal_uInt16
>(
72 va_arg( pArgs
, int ) ) ) )
74 bEndOfRange
= !bEndOfRange
;
77 const sal_uInt16
nPrev(*aNumArr
.rbegin());
78 DBG_ASSERT( nPrev
<= nIns
, "Invalid range" );
79 nSize
+= nIns
- nPrev
+ 1;
81 aNumArr
.push_back( nIns
);
84 assert( bEndOfRange
); // odd number of WhichIds
86 // Now all ranges are present
87 rpRanges
= new sal_uInt16
[ aNumArr
.size() + 1 ];
88 std::copy( aNumArr
.begin(), aNumArr
.end(), rpRanges
);
89 *(rpRanges
+ aNumArr
.size()) = 0;
95 * Determines the number of sal_uInt16s in a 0-terminated array of pairs of
97 * The terminating 0 is not included in the count.
99 sal_uInt16
Count_Impl( const sal_uInt16
*pRanges
)
101 sal_uInt16 nCount
= 0;
111 * Determines the total number of sal_uInt16s described in a 0-terminated
112 * array of pairs of sal_uInt16s, each representing an range of sal_uInt16s.
114 sal_uInt16
Capacity_Impl( const sal_uInt16
*pRanges
)
116 sal_uInt16 nCount
= 0;
122 nCount
+= pRanges
[1] - pRanges
[0] + 1;
132 SfxUShortRanges::SfxUShortRanges( const SfxUShortRanges
&rOrig
)
134 if ( rOrig
._pRanges
)
136 sal_uInt16 nCount
= Count_Impl( rOrig
._pRanges
) + 1;
137 _pRanges
= new sal_uInt16
[nCount
];
138 memcpy( _pRanges
, rOrig
._pRanges
, sizeof(sal_uInt16
) * nCount
);
145 * Constructs a SfxUShortRanges instance from one range of sal_uInt16s.
147 * Precondition: nWhich1 <= nWhich2
149 SfxUShortRanges::SfxUShortRanges( sal_uInt16 nWhich1
, sal_uInt16 nWhich2
)
150 : _pRanges( new sal_uInt16
[3] )
152 _pRanges
[0] = nWhich1
;
153 _pRanges
[1] = nWhich2
;
158 * Constcurts an SfxUShortRanges-instance from an sorted ranges of sal_uInt16s,
159 * terminates with on 0.
161 * Precondition: for each n >= 0 && n < (sizeof(pArr)-1)
162 * pArr[2n] <= pArr[2n+1] && ( pArr[2n+2]-pArr[2n+1] ) > 1
164 SfxUShortRanges::SfxUShortRanges( const sal_uInt16
* pArr
)
166 DBG_CHECK_RANGES(sal_uInt16
, pArr
);
167 sal_uInt16 nCount
= Count_Impl(pArr
) + 1;
168 _pRanges
= new sal_uInt16
[ nCount
];
169 memcpy( _pRanges
, pArr
, sizeof(sal_uInt16
) * nCount
);
173 bool SfxUShortRanges::operator==( const SfxUShortRanges
&rOther
) const
175 // Object pointers equal?
176 if ( this == &rOther
)
179 // Ranges pointers equal?
180 if ( _pRanges
== rOther
._pRanges
)
184 sal_uInt16 nCount
= Count();
185 if ( nCount
!= rOther
.Count() )
190 while( _pRanges
[ n
] != 0 )
192 // Elements at current position equal?
193 if ( _pRanges
[ n
] != rOther
._pRanges
[ n
] )
203 * Assigns ranges from 'rRanges' to '*this'.
205 SfxUShortRanges
& SfxUShortRanges::operator =
207 const SfxUShortRanges
&rRanges
210 // special case: assign itself
211 if ( &rRanges
== this )
216 // special case: 'rRanges' is empty
217 if ( rRanges
.IsEmpty() )
222 sal_uInt16 nCount
= Count_Impl( rRanges
._pRanges
) + 1;
223 _pRanges
= new sal_uInt16
[ nCount
];
224 memcpy( _pRanges
, rRanges
._pRanges
, sizeof(sal_uInt16
) * nCount
);
230 * Merges *this with 'rRanges'.
231 * for each sal_uInt16 n:
232 * this->Contains( n ) || rRanges.Contains( n ) => this'->Contains( n )
233 * !this->Contains( n ) && !rRanges.Contains( n ) => !this'->Contains( n )
235 SfxUShortRanges
& SfxUShortRanges::operator +=
237 const SfxUShortRanges
&rRanges
240 // special cases: one is empty
241 if ( rRanges
.IsEmpty() )
244 return *this = rRanges
;
246 // First, run through _pRanges and rRanges._pRanges and determine the size of
247 // the new, merged ranges:
248 sal_uInt16 nCount
= 0;
249 const sal_uInt16
* pRA
= _pRanges
;
250 const sal_uInt16
* pRB
= rRanges
._pRanges
;
254 // The first pair of pRA has a lower lower bound than the first pair
259 // We are done with the merging if at least pRA is exhausted:
265 // Skip those pairs in pRB that completely lie in the first pair
267 while (pRB
[1] <= pRA
[1])
271 // Watch out for exhaustion of pRB:
279 // If the next pair of pRA does not at least touch the current new
280 // pair, we are done with the current new pair:
281 if (pRB
[0] > pRA
[1] + 1)
284 // The next pair of pRB extends the current new pair; first,
285 // extend the current new pair (we are done if pRB is then
286 // exhausted); second, switch the roles of pRA and pRB in order to
287 // merge in those following pairs of the original pRA that will
288 // lie in the (now larger) current new pair or will even extend it
296 // Done with the current new pair:
301 // Only pRB has more pairs available, pRA is already exhausted:
303 for (; pRB
[0]; pRB
+= 2)
306 // Now, create new ranges of the correct size and, on a second run through
307 // _pRanges and rRanges._pRanges, copy the merged pairs into the new
309 sal_uInt16
* pNew
= new sal_uInt16
[nCount
+ 1];
311 pRB
= rRanges
._pRanges
;
312 sal_uInt16
* pRN
= pNew
;
316 // The first pair of pRA has a lower lower bound than the first pair
321 // We are done with the merging if at least pRA is exhausted:
325 // Lower bound of current new pair is already known:
330 // Skip those pairs in pRB that completely lie in the first pair
332 while (pRB
[1] <= pRA
[1])
336 // Watch out for exhaustion of pRB:
345 // If the next pair of pRA does not at least touch the current new
346 // pair, we are done with the current new pair:
347 if (pRB
[0] > pRA
[1] + 1)
350 // The next pair of pRB extends the current new pair; first,
351 // extend the current new pair (we are done if pRB is then
352 // exhausted); second, switch the roles of pRA and pRB in order to
353 // merge in those following pairs of the original pRA that will
354 // lie in the (now larger) current new pair or will even extend it
365 // Done with the current new pair, now upper bound is also known:
370 // Only pRB has more pairs available (which are copied to the new ranges
371 // unchanged), pRA is already exhausted:
384 * Removes 'rRanges' from '*this'.
385 * for each sal_uInt16 n:
386 * this->Contains( n ) && rRanges.Contains( n ) => !this'->Contains( n )
387 * this->Contains( n ) && !rRanges.Contains( n ) => this'->Contains( n )
388 * !this->Contains( n ) => !this'->Contains( n )
390 SfxUShortRanges
& SfxUShortRanges::operator -=
392 const SfxUShortRanges
&rRanges
395 // special cases: one is empty
396 if ( rRanges
.IsEmpty() || IsEmpty() )
399 // differentiate 'rRanges' in a temporary copy of '*this'
400 // (size is computed for maximal possibly split-count plus terminating 0)
401 sal_uInt16 nThisSize
= Count_Impl(_pRanges
);
402 sal_uInt16 nTargetSize
= 1 + ( nThisSize
+ Count_Impl(rRanges
._pRanges
) );
403 boost::scoped_array
<sal_uInt16
> pTarget(new sal_uInt16
[ nTargetSize
]);
404 memset( pTarget
.get(), 0, sizeof(sal_uInt16
)*nTargetSize
);
405 memcpy( pTarget
.get(), _pRanges
, sizeof(sal_uInt16
)*nThisSize
);
407 sal_uInt16 nPos1
= 0, nPos2
= 0, nTargetPos
= 0;
408 while( _pRanges
[ nPos1
] )
410 sal_uInt16 l1
= _pRanges
[ nPos1
]; // lower bound of interval 1
411 sal_uInt16 u1
= _pRanges
[ nPos1
+1 ]; // upper bound of interval 1
412 sal_uInt16 l2
= rRanges
._pRanges
[ nPos2
]; // lower bound of interval 2
413 sal_uInt16 u2
= rRanges
._pRanges
[ nPos2
+1 ]; // upper bound of interval 2
416 // * subtrahend is empty -> copy the minuend
419 pTarget
[ nTargetPos
] = l1
;
420 pTarget
[ nTargetPos
+1 ] = u1
;
425 // * next subtrahend interval is completely higher -> copy the minuend
428 pTarget
[ nTargetPos
] = l1
;
429 pTarget
[ nTargetPos
+1 ] = u1
;
435 // * next subtrahend interval is completely lower -> try next
442 // intersecting cases
443 // * subtrahend cuts out from the beginning of the minuend
444 if( l2
<= l1
&& u2
<= u1
)
446 // reduce minuend interval, try again (minuend might be affected by other subtrahend intervals)
447 _pRanges
[ nPos1
] = u2
+ 1;
448 nPos2
+= 2; // this cannot hurt any longer
452 // * subtrahend cuts out from the end of the minuend
453 if( l1
<= l2
&& u1
<= u2
)
455 // copy remaining part of minuend (cannot be affected by other intervals)
456 if( l1
< l2
) // anything left at all?
458 pTarget
[ nTargetPos
] = l1
;
459 pTarget
[ nTargetPos
+1 ] = l2
- 1;
461 // do not increment nPos2, might affect next minuend interval, too
463 nPos1
+= 2; // nothing left at all
467 // * subtrahend completely deletes minuend (larger or same at both ends)
468 if( l1
>= l2
&& u1
<= u2
)
470 nPos1
+= 2; // minuend deleted
471 // do not increment nPos2, might affect next minuend interval, too
475 // * subtrahend divides minuend into two pieces
476 if( l1
<= l2
&& u1
>= u2
) // >= and <= since they may be something left only at one side
479 if( l1
< l2
) // anything left at all
481 pTarget
[ nTargetPos
] = l1
;
482 pTarget
[ nTargetPos
+1 ] = l2
- 1;
487 if( u1
> u2
) // anything left at all
489 // reduce minuend interval, try again (minuend might be affected by other subtrahend itnervals )
490 _pRanges
[ nPos1
] = u2
+ 1;
493 // subtrahend is completely used
498 // we should never be here
499 OSL_FAIL( "SfxUShortRanges::operator-=: internal error" );
502 pTarget
[ nTargetPos
] = 0;
504 // assign the differentiated ranges
507 sal_uInt16 nUShorts
= Count_Impl(pTarget
.get()) + 1;
510 _pRanges
= new sal_uInt16
[ nUShorts
];
511 memcpy( _pRanges
, pTarget
.get(), nUShorts
* sizeof(sal_uInt16
) );
520 * Determines intersection of '*this' with 'rRanges'.
521 * for each sal_uInt16 n:
522 * this->Contains( n ) && rRanges.Contains( n ) => this'->Contains( n )
523 * !this->Contains( n ) => !this'->Contains( n )
524 * !rRanges.Contains( n ) => !this'->Contains( n )
526 SfxUShortRanges
& SfxUShortRanges::operator /=
528 const SfxUShortRanges
&rRanges
532 // * first set is empty -> nothing to be done
533 // * second set is empty -> delete first set
534 if( rRanges
.IsEmpty() )
538 _pRanges
= new sal_uInt16
[1];
544 // intersect 'rRanges' in a temporary copy of '*this'
545 // (size is computed for maximal possibly split-count plus terminating 0)
546 sal_uInt16 nThisSize
= Count_Impl(_pRanges
);
547 sal_uInt16 nTargetSize
= 1 + ( nThisSize
+ Count_Impl(rRanges
._pRanges
) );
548 boost::scoped_array
<sal_uInt16
> pTarget(new sal_uInt16
[ nTargetSize
]);
549 memset( pTarget
.get(), 0, sizeof(sal_uInt16
)*nTargetSize
);
550 memcpy( pTarget
.get(), _pRanges
, sizeof(sal_uInt16
)*nThisSize
);
552 sal_uInt16 nPos1
= 0, nPos2
= 0, nTargetPos
= 0;
553 while( _pRanges
[ nPos1
] != 0 && rRanges
._pRanges
[ nPos2
] != 0 )
555 sal_uInt16 l1
= _pRanges
[ nPos1
]; // lower bound of interval 1
556 sal_uInt16 u1
= _pRanges
[ nPos1
+1 ]; // upper bound of interval 1
557 sal_uInt16 l2
= rRanges
._pRanges
[ nPos2
]; // lower bound of interval 2
558 sal_uInt16 u2
= rRanges
._pRanges
[ nPos2
+1 ]; // upper bound of interval 2
562 // current interval in s1 is completely before ci in s2
568 // ci in s2 is completely before ci in s1
573 // assert: there exists an intersection between ci1 and ci2
577 // c1 "is more to the left" than c2
581 pTarget
[ nTargetPos
] = l2
;
582 pTarget
[ nTargetPos
+1 ] = u1
;
589 pTarget
[ nTargetPos
] = l2
;
590 pTarget
[ nTargetPos
+1 ] = u2
;
597 // c2 "is more to the left" than c1"
601 pTarget
[ nTargetPos
] = l1
;
602 pTarget
[ nTargetPos
+1 ] = u2
;
608 pTarget
[ nTargetPos
] = l1
;
609 pTarget
[ nTargetPos
+1 ] = u1
;
615 pTarget
[ nTargetPos
] = 0;
617 // assign the intersected ranges
620 sal_uInt16 nUShorts
= Count_Impl(pTarget
.get()) + 1;
623 _pRanges
= new sal_uInt16
[ nUShorts
];
624 memcpy( _pRanges
, pTarget
.get(), nUShorts
* sizeof(sal_uInt16
) );
633 * Determines the number of USHORTs in the set described by the ranges
634 * of USHORTs in '*this'.
636 sal_uInt16
SfxUShortRanges::Count() const
638 return Capacity_Impl( _pRanges
);
641 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */