xref: /trunk/main/svl/source/items/nranges.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svl.hxx"
30 
31 // compiled via include from itemset.cxx only!
32 
33 //========================================================================
34 
35 #ifdef DBG_UTIL
36 
37 #define DBG_CHECK_RANGES(NUMTYPE, pArr)                                 \
38     for ( const NUMTYPE *pRange = pArr; *pRange; pRange += 2 )          \
39     {                                                                   \
40         DBG_ASSERT( pRange[0] <= pRange[1], "ranges must be sorted" );  \
41         DBG_ASSERT( !pRange[2] || ( pRange[2] - pRange[1] ) > 1,        \
42                     "ranges must be sorted and discrete" );             \
43     }
44 
45 #else
46 
47 #define DBG_CHECK_RANGES(NUMTYPE,pArr)
48 
49 #endif
50 
51 //============================================================================
52 inline void Swap_Impl(const NUMTYPE *& rp1, const NUMTYPE *& rp2)
53 {
54     const NUMTYPE * pTemp = rp1;
55     rp1 = rp2;
56     rp2 = pTemp;
57 }
58 
59 //========================================================================
60 
61 NUMTYPE InitializeRanges_Impl( NUMTYPE *&rpRanges, va_list pArgs,
62                                NUMTYPE nWh1, NUMTYPE nWh2, NUMTYPE nNull )
63 
64 /** <H3>Description</H3>
65 
66     Creates an sal_uInt16-ranges-array in 'rpRanges' using 'nWh1' and 'nWh2' as
67     first range, 'nNull' as terminator or start of 2nd range and 'pArgs' as
68     remaider.
69 
70     It returns the number of NUMTYPEs which are contained in the described
71     set of NUMTYPEs.
72 */
73 
74 {
75     NUMTYPE nSize = 0, nIns = 0;
76     sal_uInt16 nCnt = 0;
77     SvNums aNumArr( 11, 8 );
78     aNumArr.Insert( nWh1, nCnt++ );
79     aNumArr.Insert( nWh2, nCnt++ );
80     DBG_ASSERT( nWh1 <= nWh2, "Ungueltiger Bereich" );
81     nSize += nWh2 - nWh1 + 1;
82     aNumArr.Insert( nNull, nCnt++ );
83     while ( 0 !=
84             ( nIns =
85               sal::static_int_cast< NUMTYPE >(
86                   va_arg( pArgs, NUMTYPE_ARG ) ) ) )
87     {
88         aNumArr.Insert( nIns, nCnt++ );
89         if ( 0 == (nCnt & 1) )       // 4,6,8, usw.
90         {
91             DBG_ASSERT( aNumArr[ nCnt-2 ] <= nIns, "Ungueltiger Bereich" );
92             nSize += nIns - aNumArr[ nCnt-2 ] + 1;
93         }
94     }
95     va_end( pArgs );
96 
97     DBG_ASSERT( 0 == (nCnt & 1), "ungerade Anzahl von Which-Paaren!" );
98 
99     // so, jetzt sind alle Bereiche vorhanden und
100     rpRanges = new NUMTYPE[ nCnt+1 ];
101     memcpy( rpRanges, aNumArr.GetData(), sizeof(NUMTYPE) * nCnt );
102     *(rpRanges+nCnt) = 0;
103 
104     return nSize;
105 }
106 
107 //------------------------------------------------------------------------
108 
109 NUMTYPE Count_Impl( const NUMTYPE *pRanges )
110 
111 /** <H3>Description</H3>
112 
113     Determines the number of NUMTYPEs in an 0-terminated array of pairs of
114     NUMTYPEs. The terminating 0 is not included in the count.
115 */
116 
117 {
118     NUMTYPE nCount = 0;
119     while ( *pRanges )
120     {
121         nCount += 2;
122         pRanges += 2;
123     }
124     return nCount;
125 }
126 
127 //------------------------------------------------------------------------
128 
129 NUMTYPE Capacity_Impl( const NUMTYPE *pRanges )
130 
131 /** <H3>Description</H3>
132 
133     Determines the total number of NUMTYPEs described in an 0-terminated
134     array of pairs of NUMTYPEs, each representing an range of NUMTYPEs.
135 */
136 
137 {
138     NUMTYPE nCount = 0;
139 
140     if ( pRanges )
141     {
142         while ( *pRanges )
143         {
144             nCount += pRanges[1] - pRanges[0] + 1;
145             pRanges += 2;
146         }
147     }
148     return nCount;
149 }
150 
151 //------------------------------------------------------------------------
152 
153 SfxNumRanges::SfxNumRanges( const SfxNumRanges &rOrig )
154 
155 /** <H3>Description</H3>
156 
157     Copy-Ctor.
158 */
159 
160 {
161     if ( rOrig._pRanges )
162     {
163         NUMTYPE nCount = Count_Impl( rOrig._pRanges ) + 1;
164         _pRanges = new NUMTYPE[nCount];
165         memcpy( _pRanges, rOrig._pRanges, sizeof(NUMTYPE) * nCount );
166     }
167     else
168         _pRanges = 0;
169 }
170 
171 //------------------------------------------------------------------------
172 
173 SfxNumRanges::SfxNumRanges( NUMTYPE nWhich1, NUMTYPE nWhich2 )
174 
175 /** <H3>Description</H3>
176 
177     Constructs an SfxNumRanges-instance from one range of NUMTYPEs.
178 
179     precondition:
180         nWhich1 <= nWhich2
181 */
182 
183 :   _pRanges( new NUMTYPE[3] )
184 {
185     _pRanges[0] = nWhich1;
186     _pRanges[1] = nWhich2;
187     _pRanges[2] = 0;
188 }
189 
190 //------------------------------------------------------------------------
191 
192 SfxNumRanges::SfxNumRanges( NUMTYPE_ARG nWh0, NUMTYPE_ARG nWh1, NUMTYPE_ARG nNull, ... )
193 
194 /** <H3>Description</H3>
195 
196     Constructs an SfxNumRanges-instance from more than one sorted ranges of
197     NUMTYPEs terminated with one 0.
198 
199     precondition: for each n >= 0 && n < nArgs
200         nWh(2n) <= nWh(2n+1) && ( nWh(2n+2)-nWh(2n+1) ) > 1
201 */
202 
203 {
204     va_list pArgs;
205     va_start( pArgs, nNull );
206     InitializeRanges_Impl(
207         _pRanges, pArgs, sal::static_int_cast< NUMTYPE >(nWh0),
208         sal::static_int_cast< NUMTYPE >(nWh1),
209         sal::static_int_cast< NUMTYPE >(nNull));
210     DBG_CHECK_RANGES(NUMTYPE, _pRanges);
211 }
212 
213 //------------------------------------------------------------------------
214 
215 SfxNumRanges::SfxNumRanges( const NUMTYPE* pArr )
216 
217 /** <H3>Description</H3>
218 
219     Constcurts an SfxNumRanges-instance from an sorted ranges of NUMTYPEs,
220     terminates with on 0.
221 
222     precondition: for each n >= 0 && n < (sizeof(pArr)-1)
223         pArr[2n] <= pArr[2n+1] && ( pArr[2n+2]-pArr[2n+1] ) > 1
224 */
225 
226 {
227     DBG_CHECK_RANGES(NUMTYPE, pArr);
228     NUMTYPE nCount = Count_Impl(pArr) + 1;
229     _pRanges = new NUMTYPE[ nCount ];
230     memcpy( _pRanges, pArr, sizeof(NUMTYPE) * nCount );
231 }
232 
233 //------------------------------------------------------------------------
234 
235 sal_Bool SfxNumRanges::operator==( const SfxNumRanges &rOther ) const
236 {
237     // Object pointers equal?
238     if ( this == &rOther )
239         return sal_True;
240 
241     // Ranges pointers equal?
242     if ( _pRanges == rOther._pRanges )
243         return sal_True;
244 
245     // Counts equal?
246     NUMTYPE nCount = Count();
247     if ( nCount != rOther.Count() )
248         return sal_False;
249 
250     // Check arrays.
251     NUMTYPE n = 0;
252     while( _pRanges[ n ] != 0 )
253     {
254         // Elements at current position equal?
255         if ( _pRanges[ n ] != rOther._pRanges[ n ] )
256             return sal_False;
257 
258         ++n;
259     }
260 
261     return sal_True;
262 }
263 
264 //------------------------------------------------------------------------
265 
266 SfxNumRanges& SfxNumRanges::operator =
267 (
268     const SfxNumRanges &rRanges
269 )
270 
271 /** <H3>Description</H3>
272 
273     Assigns ranges from 'rRanges' to '*this'.
274 */
275 
276 {
277     // special case: assign itself
278     if ( &rRanges == this )
279         return *this;
280 
281     delete[] _pRanges;
282 
283     // special case: 'rRanges' is empty
284     if ( rRanges.IsEmpty() )
285         _pRanges = 0;
286     else
287     {
288         // copy ranges
289         NUMTYPE nCount = Count_Impl( rRanges._pRanges ) + 1;
290         _pRanges = new NUMTYPE[ nCount ];
291         memcpy( _pRanges, rRanges._pRanges, sizeof(NUMTYPE) * nCount );
292     }
293     return *this;
294 }
295 
296 //------------------------------------------------------------------------
297 
298 SfxNumRanges& SfxNumRanges::operator +=
299 (
300     const SfxNumRanges &rRanges
301 )
302 
303 /** <H3>Description</H3>
304 
305     Merges *this with 'rRanges'.
306 
307     for each NUMTYPE n:
308         this->Contains( n ) || rRanges.Contains( n ) => this'->Contains( n )
309         !this->Contains( n ) && !rRanges.Contains( n ) => !this'->Contains( n )
310 */
311 
312 {
313     // special cases: one is empty
314     if ( rRanges.IsEmpty() )
315         return *this;
316     if ( IsEmpty() )
317         return *this = rRanges;
318 
319     // First, run thru _pRanges and rRanges._pRanges and determine the size of
320     // the new, merged ranges:
321     NUMTYPE nCount = 0;
322     const NUMTYPE * pRA = _pRanges;
323     const NUMTYPE * pRB = rRanges._pRanges;
324 
325     for (;;)
326     {
327         // The first pair of pRA has a lower lower bound than the first pair
328         // of pRB:
329         if (pRA[0] > pRB[0])
330             Swap_Impl(pRA, pRB);
331 
332         // We are done with the merging if at least pRA is exhausted:
333         if (!pRA[0])
334             break;
335 
336         for (;;)
337         {
338             // Skip those pairs in pRB that completely lie in the first pair
339             // of pRA:
340             while (pRB[1] <= pRA[1])
341             {
342                 pRB += 2;
343 
344                 // Watch out for exhaustion of pRB:
345                 if (!pRB[0])
346                 {
347                     Swap_Impl(pRA, pRB);
348                     goto count_rest;
349                 }
350             }
351 
352             // If the next pair of pRA does not at least touch the current new
353             // pair, we are done with the current new pair:
354             if (pRB[0] > pRA[1] + 1)
355                 break;
356 
357             // The next pair of pRB extends the current new pair; first,
358             // extend the current new pair (we are done if pRB is then
359             // exhausted); second, switch the roles of pRA and pRB in order to
360             // merge in those following pairs of the original pRA that will
361             // lie in the (now larger) current new pair or will even extend it
362             // further:
363             pRA += 2;
364             if (!pRA[0])
365                 goto count_rest;
366             Swap_Impl(pRA, pRB);
367         }
368 
369         // Done with the current new pair:
370         pRA += 2;
371         nCount += 2;
372     }
373 
374     // Only pRB has more pairs available, pRA is already exhausted:
375 count_rest:
376     for (; pRB[0]; pRB += 2)
377         nCount += 2;
378 
379     // Now, create new ranges of the correct size and, on a second run thru
380     // _pRanges and rRanges._pRanges, copy the merged pairs into the new
381     // ranges:
382     NUMTYPE * pNew = new NUMTYPE[nCount + 1];
383     pRA = _pRanges;
384     pRB = rRanges._pRanges;
385     NUMTYPE * pRN = pNew;
386 
387     for (;;)
388     {
389         // The first pair of pRA has a lower lower bound than the first pair
390         // of pRB:
391         if (pRA[0] > pRB[0])
392             Swap_Impl(pRA, pRB);
393 
394         // We are done with the merging if at least pRA is exhausted:
395         if (!pRA[0])
396             break;
397 
398         // Lower bound of current new pair is already known:
399         *pRN++ = pRA[0];
400 
401         for (;;)
402         {
403             // Skip those pairs in pRB that completely lie in the first pair
404             // of pRA:
405             while (pRB[1] <= pRA[1])
406             {
407                 pRB += 2;
408 
409                 // Watch out for exhaustion of pRB:
410                 if (!pRB[0])
411                 {
412                     Swap_Impl(pRA, pRB);
413                     ++pRB;
414                     goto copy_rest;
415                 }
416             }
417 
418             // If the next pair of pRA does not at least touch the current new
419             // pair, we are done with the current new pair:
420             if (pRB[0] > pRA[1] + 1)
421                 break;
422 
423             // The next pair of pRB extends the current new pair; first,
424             // extend the current new pair (we are done if pRB is then
425             // exhausted); second, switch the roles of pRA and pRB in order to
426             // merge in those following pairs of the original pRA that will
427             // lie in the (now larger) current new pair or will even extend it
428             // further:
429             pRA += 2;
430             if (!pRA[0])
431             {
432                 ++pRB;
433                 goto copy_rest;
434             }
435             Swap_Impl(pRA, pRB);
436         }
437 
438         // Done with the current new pair, now upper bound is also known:
439         *pRN++ = pRA[1];
440         pRA += 2;
441     }
442 
443     // Only pRB has more pairs available (which are copied to the new ranges
444     // unchanged), pRA is already exhausted:
445 copy_rest:
446     for (; *pRB;)
447         *pRN++ = *pRB++;
448     *pRN = 0;
449 
450     delete[] _pRanges;
451     _pRanges = pNew;
452 
453     return *this;
454 }
455 
456 //------------------------------------------------------------------------
457 
458 SfxNumRanges& SfxNumRanges::operator -=
459 (
460     const SfxNumRanges &rRanges
461 )
462 
463 /** <H3>Description</H3>
464 
465     Removes 'rRanges' from '*this'.
466 
467     for each NUMTYPE n:
468         this->Contains( n ) && rRanges.Contains( n ) => !this'->Contains( n )
469         this->Contains( n ) && !rRanges.Contains( n ) => this'->Contains( n )
470         !this->Contains( n ) => !this'->Contains( n )
471 */
472 
473 {
474     // special cases: one is empty
475     if ( rRanges.IsEmpty() || IsEmpty() )
476         return *this;
477 
478     // differentiate 'rRanges' in a temporary copy of '*this'
479     // (size is computed for maximal possibly split-count plus terminating 0)
480     NUMTYPE nThisSize = Count_Impl(_pRanges);
481     NUMTYPE nTargetSize = 1 + (  nThisSize + Count_Impl(rRanges._pRanges) );
482     NUMTYPE *pTarget = new NUMTYPE[ nTargetSize ];
483     memset( pTarget, 0, sizeof(NUMTYPE)*nTargetSize );
484     memcpy( pTarget, _pRanges, sizeof(NUMTYPE)*nThisSize );
485 
486     NUMTYPE nPos1 = 0, nPos2 = 0, nTargetPos = 0;
487     while( _pRanges[ nPos1 ] )
488     {
489         NUMTYPE l1 = _pRanges[ nPos1 ];      // lower bound of interval 1
490         NUMTYPE u1 = _pRanges[ nPos1+1 ];    // upper bound of interval 1
491         NUMTYPE l2 = rRanges._pRanges[ nPos2 ];      // lower bound of interval 2
492         NUMTYPE u2 = rRanges._pRanges[ nPos2+1 ];    // upper bound of interval 2
493 
494         // boundary cases
495         // * subtrahend is empty -> copy the minuend
496         if( !l2 )
497         {
498             pTarget[ nTargetPos ] = l1;
499             pTarget[ nTargetPos+1 ] = u1;
500             nTargetPos += 2;
501             nPos1 += 2;
502             continue;
503         }
504         // * next subtrahend interval is completely higher -> copy the minuend
505         if( u1 < l2 )
506         {
507             pTarget[ nTargetPos ] = l1;
508             pTarget[ nTargetPos+1 ] = u1;
509             nTargetPos += 2;
510             nPos1 += 2;
511             continue;
512         }
513 
514         // * next subtrahend interval is completely lower -> try next
515         if( u2 < l1 )
516         {
517             nPos2 += 2;
518             continue;
519         }
520 
521         // intersecting cases
522         // * subtrahend cuts out from the beginning of the minuend
523         if( l2 <= l1 && u2 <= u1 )
524         {
525             // reduce minuend interval, try again (minuend might be affected by other subtrahend intervals)
526             _pRanges[ nPos1 ] = u2 + 1;
527             nPos2 += 2; // this cannot hurt any longer
528             continue;
529         }
530 
531         // * subtrahend cuts out from the end of the minuend
532         if( l1 <= l2 && u1 <= u2 )
533         {
534             // copy remaining part of minuend (cannot be affected by other intervals)
535             if( l1 < l2 ) // anything left at all?
536             {
537                 pTarget[ nTargetPos ] = l1;
538                 pTarget[ nTargetPos+1 ] = l2 - 1;
539                 nTargetPos += 2;
540                 // do not increment nPos2, might affect next minuend interval, too
541             }
542             nPos1 += 2; // nothing left at all
543             continue;
544         }
545 
546         // * subtrahend completely deletes minuend (larger or same at both ends)
547         if( l1 >= l2 && u1 <= u2 )
548         {
549             nPos1 += 2; // minuend deleted
550             // do not increment nPos2, might affect next minuend interval, too
551             continue;
552         }
553 
554         // * subtrahend divides minuend into two pieces
555         if( l1 <= l2 && u1 >= u2 ) // >= and <= since they may be something left only at one side
556         {
557             // left side
558             if( l1 < l2 ) // anything left at all
559             {
560                 pTarget[ nTargetPos ] = l1;
561                 pTarget[ nTargetPos+1 ] = l2 - 1;
562                 nTargetPos += 2;
563             }
564 
565             // right side
566             if( u1 > u2 ) // anything left at all
567             {
568                 // reduce minuend interval, try again (minuend might be affected by other subtrahend itnervals )
569                 _pRanges[ nPos1 ] = u2 + 1;
570             }
571 
572             // subtrahend is completely used
573             nPos2 += 2;
574             continue;
575         }
576 
577         // we should never be here
578         DBG_ERROR( "SfxNumRanges::operator-=: internal error" );
579     } // while
580 
581     pTarget[ nTargetPos ] = 0;
582 
583     // assign the differentiated ranges
584     delete[] _pRanges;
585 
586     NUMTYPE nUShorts = Count_Impl(pTarget) + 1;
587     if ( 1 != nUShorts )
588     {
589         _pRanges = new NUMTYPE[ nUShorts ];
590         memcpy( _pRanges, pTarget, nUShorts * sizeof(NUMTYPE) );
591     }
592     else
593         _pRanges = 0;
594 
595     delete [] pTarget;
596     return *this;
597 
598     /* untested code from MI commented out (MDA, 28.01.97)
599     do
600     {
601         // 1st range is smaller than 2nd range?
602         if ( pRange1[1] < pRange2[0] )
603             // => keep 1st range
604             pRange1 += 2;
605 
606         // 2nd range is smaller than 1st range?
607         else if ( pRange2[1] < pRange1[0] )
608             // => skip 2nd range
609             pRange2 += 2;
610 
611         // 2nd range totally overlaps the 1st range?
612         else if ( pRange2[0] <= pRange1[0] && pRange2[1] >= pRange1[1] )
613             // => remove 1st range
614             memmove( pRange1, pRange1+2, sizeof(NUMTYPE) * (pEndOfTarget-pRange1+2) );
615 
616         // 2nd range overlaps only the beginning of 1st range?
617         else if ( pRange2[0] <= pRange1[0] && pRange2[1] < pRange1[1] )
618         {
619             // => cut the beginning of 1st range and goto next 2nd range
620             pRange1[0] = pRange2[1] + 1;
621             pRange2 += 2;
622         }
623 
624         // 2nd range overlaps only the end of 1st range?
625         else if ( pRange2[0] > pRange1[0] && pRange2[1] >= pRange1[0] )
626             // => cut the beginning of 1st range
627             pRange1[0] = pRange2[1]+1;
628 
629         // 2nd range is a real subset of 1st range
630         else
631         {
632             // => split 1st range and goto next 2nd range
633             memmove( pRange1+3, pRange1+1, sizeof(NUMTYPE) * (pEndOfTarget-pRange1-1) );
634             pRange1[1] = pRange2[0] - 1;
635             pRange1[2] = pRange2[1] + 1;
636             pRange1 += 2;
637             pRange2 += 2;
638         }
639     }
640     while ( *pRange1 && *pRange2 );
641 
642     // assign the differentiated ranges
643     delete[] _pRanges;
644     NUMTYPE nUShorts = Count_Impl(pTarget) + 1;
645     if ( 1 != nUShorts )
646     {
647         _pRanges = new NUMTYPE[ nUShorts ];
648         memcpy( _pRanges, pTarget, nUShorts * sizeof(NUMTYPE) );
649         _pRanges[ nUShorts-1 ] = 0;
650     }
651     else
652         _pRanges = 0;
653     return *this;
654     */
655 }
656 
657 //------------------------------------------------------------------------
658 
659 SfxNumRanges& SfxNumRanges::operator /=
660 (
661     const SfxNumRanges &rRanges
662 )
663 
664 /** <H3>Description</H3>
665 
666     Determines intersection of '*this' with 'rRanges'.
667 
668     for each NUMTYPE n:
669         this->Contains( n ) && rRanges.Contains( n ) => this'->Contains( n )
670         !this->Contains( n ) => !this'->Contains( n )
671         !rRanges.Contains( n ) => !this'->Contains( n )
672 */
673 
674 {
675     // boundary cases
676     // * first set is empty -> nothing to be done
677     // * second set is empty -> delete first set
678     if( rRanges.IsEmpty() )
679     {
680         delete[] _pRanges;
681 
682         _pRanges = new NUMTYPE[1];
683         _pRanges[0] = 0;
684 
685         return *this;
686     }
687 
688     // intersect 'rRanges' in a temporary copy of '*this'
689     // (size is computed for maximal possibly split-count plus terminating 0)
690     NUMTYPE nThisSize = Count_Impl(_pRanges);
691     NUMTYPE nTargetSize = 1 + (  nThisSize + Count_Impl(rRanges._pRanges) );
692     NUMTYPE *pTarget = new NUMTYPE[ nTargetSize ];
693     memset( pTarget, 0, sizeof(NUMTYPE)*nTargetSize );
694     memcpy( pTarget, _pRanges, sizeof(NUMTYPE)*nThisSize );
695 
696     NUMTYPE nPos1 = 0, nPos2 = 0, nTargetPos = 0;
697     while( _pRanges[ nPos1 ] != 0 && rRanges._pRanges[ nPos2 ] != 0 )
698     {
699         NUMTYPE l1 = _pRanges[ nPos1 ];      // lower bound of interval 1
700         NUMTYPE u1 = _pRanges[ nPos1+1 ];    // upper bound of interval 1
701         NUMTYPE l2 = rRanges._pRanges[ nPos2 ];      // lower bound of interval 2
702         NUMTYPE u2 = rRanges._pRanges[ nPos2+1 ];    // upper bound of interval 2
703 
704         if( u1 < l2 )
705         {
706             // current interval in s1 is completely before ci in s2
707             nPos1 += 2;
708             continue;
709         }
710         if( u2 < l1 )
711         {
712             // ci in s2 is completely before ci in s1
713             nPos2 += 2;
714             continue;
715         }
716 
717         // assert: there exists an intersection between ci1 and ci2
718 
719         if( l1 <= l2 )
720         {
721             // c1 "is more to the left" than c2
722 
723             if( u1 <= u2 )
724             {
725                 pTarget[ nTargetPos ] = l2;
726                 pTarget[ nTargetPos+1 ] = u1;
727                 nTargetPos += 2;
728                 nPos1 += 2;
729                 continue;
730             }
731             else
732             {
733                 pTarget[ nTargetPos ] = l2;
734                 pTarget[ nTargetPos+1 ] = u2;
735                 nTargetPos += 2;
736                 nPos2 += 2;
737             }
738         }
739         else
740         {
741             // c2 "is more to the left" than c1"
742 
743             if( u1 > u2 )
744             {
745                 pTarget[ nTargetPos ] = l1;
746                 pTarget[ nTargetPos+1 ] = u2;
747                 nTargetPos += 2;
748                 nPos2 += 2;
749             }
750             else
751             {
752                 pTarget[ nTargetPos ] = l1;
753                 pTarget[ nTargetPos+1 ] = u1;
754                 nTargetPos += 2;
755                 nPos1 += 2;
756             }
757         }
758     }; // while
759     pTarget[ nTargetPos ] = 0;
760 
761     // assign the intersected ranges
762     delete[] _pRanges;
763 
764     NUMTYPE nUShorts = Count_Impl(pTarget) + 1;
765     if ( 1 != nUShorts )
766     {
767         _pRanges = new NUMTYPE[ nUShorts ];
768         memcpy( _pRanges, pTarget, nUShorts * sizeof(NUMTYPE) );
769     }
770     else
771         _pRanges = 0;
772 
773     delete [] pTarget;
774     return *this;
775 }
776 
777 //------------------------------------------------------------------------
778 
779 sal_Bool SfxNumRanges::Intersects( const SfxNumRanges &rRanges ) const
780 
781 /** <H3>Description</H3>
782 
783     Determines if at least one range in 'rRanges' intersects with one
784     range in '*this'.
785 
786     sal_True, if there is at least one with:
787         this->Contains( n ) && rRanges.Contains( n )
788 */
789 
790 {
791     // special cases: one is empty
792     if ( rRanges.IsEmpty() || IsEmpty() )
793         return sal_False;
794 
795     // find at least one intersecting range
796     const NUMTYPE *pRange1 = _pRanges;
797     const NUMTYPE *pRange2 = rRanges._pRanges;
798 
799     do
800     {
801         // 1st range is smaller than 2nd range?
802         if ( pRange1[1] < pRange2[0] )
803             // => keep 1st range
804             pRange1 += 2;
805 
806         // 2nd range is smaller than 1st range?
807         else if ( pRange2[1] < pRange1[0] )
808             // => skip 2nd range
809             pRange2 += 2;
810 
811         // the ranges are overlappung
812         else
813             return sal_True;
814     }
815     while ( *pRange2 );
816 
817     // no intersection found
818     return sal_False;
819 }
820 
821 //------------------------------------------------------------------------
822 
823 NUMTYPE SfxNumRanges::Count() const
824 
825 /** <H3>Description</H3>
826 
827     Determines the number of USHORTs in the set described by the ranges
828     of USHORTs in '*this'.
829 */
830 
831 {
832     return Capacity_Impl( _pRanges );
833 }
834 
835 //------------------------------------------------------------------------
836 
837 sal_Bool SfxNumRanges::Contains( NUMTYPE n ) const
838 
839 /** <H3>Description</H3>
840 
841     Determines if '*this' contains 'n'.
842 */
843 
844 {
845     for ( NUMTYPE *pRange = _pRanges; *pRange && *pRange <= n; pRange += 2 )
846         if ( pRange[0] <= n && n <= pRange[1] )
847             return sal_True;
848     return sal_False;
849 
850 }
851