bump product version to 5.0.4.1
[LibreOffice.git] / svl / source / items / nranges.cxx
blob35b2e482a0bb39acaa0bffcaa5f6d65d038434d9
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!
23 #include <boost/scoped_array.hpp>
25 #include <osl/diagnose.h>
27 #ifdef DBG_UTIL
29 #define DBG_CHECK_RANGES(sal_uInt16, pArr) \
30 for ( const sal_uInt16 *pRange = pArr; *pRange; pRange += 2 ) \
31 { \
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" ); \
37 #else
39 #define DBG_CHECK_RANGES(sal_uInt16,pArr)
41 #endif
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 /**
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
53 * remainder.
55 * It returns the number of sal_uInt16s which are contained in the described
56 * set of sal_uInt16s.
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;
69 while ( 0 !=
70 ( nIns =
71 sal::static_int_cast< sal_uInt16 >(
72 va_arg( pArgs, int ) ) ) )
74 bEndOfRange = !bEndOfRange;
75 if ( 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;
91 return nSize;
94 /**
95 * Determines the number of sal_uInt16s in a 0-terminated array of pairs of
96 * sal_uInt16s.
97 * The terminating 0 is not included in the count.
99 sal_uInt16 Count_Impl( const sal_uInt16 *pRanges )
101 sal_uInt16 nCount = 0;
102 while ( *pRanges )
104 nCount += 2;
105 pRanges += 2;
107 return nCount;
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;
118 if ( pRanges )
120 while ( *pRanges )
122 nCount += pRanges[1] - pRanges[0] + 1;
123 pRanges += 2;
126 return nCount;
130 * Copy ctor
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 );
140 else
141 _pRanges = 0;
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;
154 _pRanges[2] = 0;
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 )
177 return true;
179 // Ranges pointers equal?
180 if ( _pRanges == rOther._pRanges )
181 return true;
183 // Counts equal?
184 sal_uInt16 nCount = Count();
185 if ( nCount != rOther.Count() )
186 return false;
188 // Check arrays.
189 sal_uInt16 n = 0;
190 while( _pRanges[ n ] != 0 )
192 // Elements at current position equal?
193 if ( _pRanges[ n ] != rOther._pRanges[ n ] )
194 return false;
196 ++n;
199 return true;
203 * Assigns ranges from 'rRanges' to '*this'.
205 SfxUShortRanges& SfxUShortRanges::operator =
207 const SfxUShortRanges &rRanges
210 // special case: assign itself
211 if ( &rRanges == this )
212 return *this;
214 delete[] _pRanges;
216 // special case: 'rRanges' is empty
217 if ( rRanges.IsEmpty() )
218 _pRanges = 0;
219 else
221 // copy ranges
222 sal_uInt16 nCount = Count_Impl( rRanges._pRanges ) + 1;
223 _pRanges = new sal_uInt16[ nCount ];
224 memcpy( _pRanges, rRanges._pRanges, sizeof(sal_uInt16) * nCount );
226 return *this;
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() )
242 return *this;
243 if ( 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;
252 for (;;)
254 // The first pair of pRA has a lower lower bound than the first pair
255 // of pRB:
256 if (pRA[0] > pRB[0])
257 Swap_Impl(pRA, pRB);
259 // We are done with the merging if at least pRA is exhausted:
260 if (!pRA[0])
261 break;
263 for (;;)
265 // Skip those pairs in pRB that completely lie in the first pair
266 // of pRA:
267 while (pRB[1] <= pRA[1])
269 pRB += 2;
271 // Watch out for exhaustion of pRB:
272 if (!pRB[0])
274 Swap_Impl(pRA, pRB);
275 goto count_rest;
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)
282 break;
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
289 // further:
290 pRA += 2;
291 if (!pRA[0])
292 goto count_rest;
293 Swap_Impl(pRA, pRB);
296 // Done with the current new pair:
297 pRA += 2;
298 nCount += 2;
301 // Only pRB has more pairs available, pRA is already exhausted:
302 count_rest:
303 for (; pRB[0]; pRB += 2)
304 nCount += 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
308 // ranges:
309 sal_uInt16 * pNew = new sal_uInt16[nCount + 1];
310 pRA = _pRanges;
311 pRB = rRanges._pRanges;
312 sal_uInt16 * pRN = pNew;
314 for (;;)
316 // The first pair of pRA has a lower lower bound than the first pair
317 // of pRB:
318 if (pRA[0] > pRB[0])
319 Swap_Impl(pRA, pRB);
321 // We are done with the merging if at least pRA is exhausted:
322 if (!pRA[0])
323 break;
325 // Lower bound of current new pair is already known:
326 *pRN++ = pRA[0];
328 for (;;)
330 // Skip those pairs in pRB that completely lie in the first pair
331 // of pRA:
332 while (pRB[1] <= pRA[1])
334 pRB += 2;
336 // Watch out for exhaustion of pRB:
337 if (!pRB[0])
339 Swap_Impl(pRA, pRB);
340 ++pRB;
341 goto copy_rest;
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)
348 break;
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
355 // further:
356 pRA += 2;
357 if (!pRA[0])
359 ++pRB;
360 goto copy_rest;
362 Swap_Impl(pRA, pRB);
365 // Done with the current new pair, now upper bound is also known:
366 *pRN++ = pRA[1];
367 pRA += 2;
370 // Only pRB has more pairs available (which are copied to the new ranges
371 // unchanged), pRA is already exhausted:
372 copy_rest:
373 for (; *pRB;)
374 *pRN++ = *pRB++;
375 *pRN = 0;
377 delete[] _pRanges;
378 _pRanges = pNew;
380 return *this;
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() )
397 return *this;
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
415 // boundary cases
416 // * subtrahend is empty -> copy the minuend
417 if( !l2 )
419 pTarget[ nTargetPos ] = l1;
420 pTarget[ nTargetPos+1 ] = u1;
421 nTargetPos += 2;
422 nPos1 += 2;
423 continue;
425 // * next subtrahend interval is completely higher -> copy the minuend
426 if( u1 < l2 )
428 pTarget[ nTargetPos ] = l1;
429 pTarget[ nTargetPos+1 ] = u1;
430 nTargetPos += 2;
431 nPos1 += 2;
432 continue;
435 // * next subtrahend interval is completely lower -> try next
436 if( u2 < l1 )
438 nPos2 += 2;
439 continue;
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
449 continue;
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;
460 nTargetPos += 2;
461 // do not increment nPos2, might affect next minuend interval, too
463 nPos1 += 2; // nothing left at all
464 continue;
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
472 continue;
475 // * subtrahend divides minuend into two pieces
476 if( l1 <= l2 && u1 >= u2 ) // >= and <= since they may be something left only at one side
478 // left side
479 if( l1 < l2 ) // anything left at all
481 pTarget[ nTargetPos ] = l1;
482 pTarget[ nTargetPos+1 ] = l2 - 1;
483 nTargetPos += 2;
486 // right side
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
494 nPos2 += 2;
495 continue;
498 // we should never be here
499 OSL_FAIL( "SfxUShortRanges::operator-=: internal error" );
500 } // while
502 pTarget[ nTargetPos ] = 0;
504 // assign the differentiated ranges
505 delete[] _pRanges;
507 sal_uInt16 nUShorts = Count_Impl(pTarget.get()) + 1;
508 if ( 1 != nUShorts )
510 _pRanges = new sal_uInt16[ nUShorts ];
511 memcpy( _pRanges, pTarget.get(), nUShorts * sizeof(sal_uInt16) );
513 else
514 _pRanges = 0;
516 return *this;
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
531 // boundary cases
532 // * first set is empty -> nothing to be done
533 // * second set is empty -> delete first set
534 if( rRanges.IsEmpty() )
536 delete[] _pRanges;
538 _pRanges = new sal_uInt16[1];
539 _pRanges[0] = 0;
541 return *this;
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
560 if( u1 < l2 )
562 // current interval in s1 is completely before ci in s2
563 nPos1 += 2;
564 continue;
566 if( u2 < l1 )
568 // ci in s2 is completely before ci in s1
569 nPos2 += 2;
570 continue;
573 // assert: there exists an intersection between ci1 and ci2
575 if( l1 <= l2 )
577 // c1 "is more to the left" than c2
579 if( u1 <= u2 )
581 pTarget[ nTargetPos ] = l2;
582 pTarget[ nTargetPos+1 ] = u1;
583 nTargetPos += 2;
584 nPos1 += 2;
585 continue;
587 else
589 pTarget[ nTargetPos ] = l2;
590 pTarget[ nTargetPos+1 ] = u2;
591 nTargetPos += 2;
592 nPos2 += 2;
595 else
597 // c2 "is more to the left" than c1"
599 if( u1 > u2 )
601 pTarget[ nTargetPos ] = l1;
602 pTarget[ nTargetPos+1 ] = u2;
603 nTargetPos += 2;
604 nPos2 += 2;
606 else
608 pTarget[ nTargetPos ] = l1;
609 pTarget[ nTargetPos+1 ] = u1;
610 nTargetPos += 2;
611 nPos1 += 2;
614 }; // while
615 pTarget[ nTargetPos ] = 0;
617 // assign the intersected ranges
618 delete[] _pRanges;
620 sal_uInt16 nUShorts = Count_Impl(pTarget.get()) + 1;
621 if ( 1 != nUShorts )
623 _pRanges = new sal_uInt16[ nUShorts ];
624 memcpy( _pRanges, pTarget.get(), nUShorts * sizeof(sal_uInt16) );
626 else
627 _pRanges = 0;
629 return *this;
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: */