Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <cassert>
21 : #include <vector>
22 : // compiled via include from itemset.cxx only!
23 : #include <boost/scoped_array.hpp>
24 :
25 : #ifdef DBG_UTIL
26 :
27 : #define DBG_CHECK_RANGES(sal_uInt16, pArr) \
28 : for ( const sal_uInt16 *pRange = pArr; *pRange; pRange += 2 ) \
29 : { \
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" ); \
33 : }
34 :
35 : #else
36 :
37 : #define DBG_CHECK_RANGES(sal_uInt16,pArr)
38 :
39 : #endif
40 :
41 76560 : inline void Swap_Impl(const sal_uInt16 *& rp1, const sal_uInt16 *& rp2)
42 : {
43 76560 : const sal_uInt16 * pTemp = rp1;
44 76560 : rp1 = rp2;
45 76560 : rp2 = pTemp;
46 76560 : }
47 :
48 : /**
49 : * Creates a sal_uInt16-ranges-array in 'rpRanges' using 'nWh1' and 'nWh2' as
50 : * first range, 'nNull' as terminator or start of 2nd range and 'pArgs' as
51 : * remainder.
52 : *
53 : * It returns the number of sal_uInt16s which are contained in the described
54 : * set of sal_uInt16s.
55 : */
56 667597 : sal_uInt16 InitializeRanges_Impl( sal_uInt16 *&rpRanges, va_list pArgs,
57 : sal_uInt16 nWh1, sal_uInt16 nWh2, sal_uInt16 nNull )
58 : {
59 667597 : sal_uInt16 nSize = 0, nIns = 0;
60 667597 : std::vector<sal_uInt16> aNumArr;
61 667597 : aNumArr.push_back( nWh1 );
62 667597 : aNumArr.push_back( nWh2 );
63 : DBG_ASSERT( nWh1 <= nWh2, "Invalid range" );
64 667597 : nSize += nWh2 - nWh1 + 1;
65 667597 : aNumArr.push_back( nNull );
66 667597 : bool bEndOfRange = false;
67 7603952 : while ( 0 !=
68 : ( nIns =
69 : sal::static_int_cast< sal_uInt16 >(
70 11869919 : va_arg( pArgs, int ) ) ) )
71 : {
72 5601161 : bEndOfRange = !bEndOfRange;
73 5601161 : if ( bEndOfRange )
74 : {
75 3134379 : const sal_uInt16 nPrev(*aNumArr.rbegin());
76 : DBG_ASSERT( nPrev <= nIns, "Invalid range" );
77 3134379 : nSize += nIns - nPrev + 1;
78 : }
79 5601161 : aNumArr.push_back( nIns );
80 : }
81 :
82 : assert( bEndOfRange ); // odd number of WhichIds
83 :
84 : // Now all ranges are present
85 667597 : rpRanges = new sal_uInt16[ aNumArr.size() + 1 ];
86 667597 : std::copy( aNumArr.begin(), aNumArr.end(), rpRanges);
87 667597 : *(rpRanges + aNumArr.size()) = 0;
88 :
89 667597 : return nSize;
90 : }
91 :
92 : /**
93 : * Determines the number of sal_uInt16s in a 0-terminated array of pairs of
94 : * sal_uInt16s.
95 : * The terminating 0 is not included in the count.
96 : */
97 102080 : sal_uInt16 Count_Impl( const sal_uInt16 *pRanges )
98 : {
99 102080 : sal_uInt16 nCount = 0;
100 510400 : while ( *pRanges )
101 : {
102 306240 : nCount += 2;
103 306240 : pRanges += 2;
104 : }
105 102080 : return nCount;
106 : }
107 :
108 : /**
109 : * Determines the total number of sal_uInt16s described in a 0-terminated
110 : * array of pairs of sal_uInt16s, each representing an range of sal_uInt16s.
111 : */
112 51040 : sal_uInt16 Capacity_Impl( const sal_uInt16 *pRanges )
113 : {
114 51040 : sal_uInt16 nCount = 0;
115 :
116 51040 : if ( pRanges )
117 : {
118 280720 : while ( *pRanges )
119 : {
120 178640 : nCount += pRanges[1] - pRanges[0] + 1;
121 178640 : pRanges += 2;
122 : }
123 : }
124 51040 : return nCount;
125 : }
126 :
127 : /**
128 : * Copy ctor
129 : */
130 0 : SfxUShortRanges::SfxUShortRanges( const SfxUShortRanges &rOrig )
131 : {
132 0 : if ( rOrig._pRanges )
133 : {
134 0 : sal_uInt16 nCount = Count_Impl( rOrig._pRanges ) + 1;
135 0 : _pRanges = new sal_uInt16[nCount];
136 0 : memcpy( _pRanges, rOrig._pRanges, sizeof(sal_uInt16) * nCount );
137 : }
138 : else
139 0 : _pRanges = 0;
140 0 : }
141 :
142 : /**
143 : * Constructs a SfxUShortRanges instance from one range of sal_uInt16s.
144 : *
145 : * Precondition: nWhich1 <= nWhich2
146 : */
147 51040 : SfxUShortRanges::SfxUShortRanges( sal_uInt16 nWhich1, sal_uInt16 nWhich2 )
148 51040 : : _pRanges( new sal_uInt16[3] )
149 : {
150 51040 : _pRanges[0] = nWhich1;
151 51040 : _pRanges[1] = nWhich2;
152 51040 : _pRanges[2] = 0;
153 51040 : }
154 :
155 : /**
156 : * Constcurts an SfxUShortRanges-instance from an sorted ranges of sal_uInt16s,
157 : * terminates with on 0.
158 : *
159 : * Precondition: for each n >= 0 && n < (sizeof(pArr)-1)
160 : * pArr[2n] <= pArr[2n+1] && ( pArr[2n+2]-pArr[2n+1] ) > 1
161 : */
162 51040 : SfxUShortRanges::SfxUShortRanges( const sal_uInt16* pArr )
163 : {
164 : DBG_CHECK_RANGES(sal_uInt16, pArr);
165 51040 : sal_uInt16 nCount = Count_Impl(pArr) + 1;
166 51040 : _pRanges = new sal_uInt16[ nCount ];
167 51040 : memcpy( _pRanges, pArr, sizeof(sal_uInt16) * nCount );
168 51040 : }
169 :
170 :
171 0 : bool SfxUShortRanges::operator==( const SfxUShortRanges &rOther ) const
172 : {
173 : // Object pointers equal?
174 0 : if ( this == &rOther )
175 0 : return true;
176 :
177 : // Ranges pointers equal?
178 0 : if ( _pRanges == rOther._pRanges )
179 0 : return true;
180 :
181 : // Counts equal?
182 0 : sal_uInt16 nCount = Count();
183 0 : if ( nCount != rOther.Count() )
184 0 : return false;
185 :
186 : // Check arrays.
187 0 : sal_uInt16 n = 0;
188 0 : while( _pRanges[ n ] != 0 )
189 : {
190 : // Elements at current position equal?
191 0 : if ( _pRanges[ n ] != rOther._pRanges[ n ] )
192 0 : return false;
193 :
194 0 : ++n;
195 : }
196 :
197 0 : return true;
198 : }
199 :
200 : /**
201 : * Assigns ranges from 'rRanges' to '*this'.
202 : */
203 0 : SfxUShortRanges& SfxUShortRanges::operator =
204 : (
205 : const SfxUShortRanges &rRanges
206 : )
207 : {
208 : // special case: assign itself
209 0 : if ( &rRanges == this )
210 0 : return *this;
211 :
212 0 : delete[] _pRanges;
213 :
214 : // special case: 'rRanges' is empty
215 0 : if ( rRanges.IsEmpty() )
216 0 : _pRanges = 0;
217 : else
218 : {
219 : // copy ranges
220 0 : sal_uInt16 nCount = Count_Impl( rRanges._pRanges ) + 1;
221 0 : _pRanges = new sal_uInt16[ nCount ];
222 0 : memcpy( _pRanges, rRanges._pRanges, sizeof(sal_uInt16) * nCount );
223 : }
224 0 : return *this;
225 : }
226 :
227 : /**
228 : * Merges *this with 'rRanges'.
229 : * for each sal_uInt16 n:
230 : * this->Contains( n ) || rRanges.Contains( n ) => this'->Contains( n )
231 : * !this->Contains( n ) && !rRanges.Contains( n ) => !this'->Contains( n )
232 : */
233 51040 : SfxUShortRanges& SfxUShortRanges::operator +=
234 : (
235 : const SfxUShortRanges &rRanges
236 : )
237 : {
238 : // special cases: one is empty
239 51040 : if ( rRanges.IsEmpty() )
240 0 : return *this;
241 51040 : if ( IsEmpty() )
242 0 : return *this = rRanges;
243 :
244 : // First, run thru _pRanges and rRanges._pRanges and determine the size of
245 : // the new, merged ranges:
246 51040 : sal_uInt16 nCount = 0;
247 51040 : const sal_uInt16 * pRA = _pRanges;
248 51040 : const sal_uInt16 * pRB = rRanges._pRanges;
249 :
250 : for (;;)
251 : {
252 : // The first pair of pRA has a lower lower bound than the first pair
253 : // of pRB:
254 178640 : if (pRA[0] > pRB[0])
255 38280 : Swap_Impl(pRA, pRB);
256 :
257 : // We are done with the merging if at least pRA is exhausted:
258 178640 : if (!pRA[0])
259 51040 : break;
260 :
261 : for (;;)
262 : {
263 : // Skip those pairs in pRB that completely lie in the first pair
264 : // of pRA:
265 255200 : while (pRB[1] <= pRA[1])
266 : {
267 0 : pRB += 2;
268 :
269 : // Watch out for exhaustion of pRB:
270 0 : if (!pRB[0])
271 : {
272 0 : Swap_Impl(pRA, pRB);
273 0 : goto count_rest;
274 : }
275 : }
276 :
277 : // If the next pair of pRA does not at least touch the current new
278 : // pair, we are done with the current new pair:
279 127600 : if (pRB[0] > pRA[1] + 1)
280 127600 : break;
281 :
282 : // The next pair of pRB extends the current new pair; first,
283 : // extend the current new pair (we are done if pRB is then
284 : // exhausted); second, switch the roles of pRA and pRB in order to
285 : // merge in those following pairs of the original pRA that will
286 : // lie in the (now larger) current new pair or will even extend it
287 : // further:
288 0 : pRA += 2;
289 0 : if (!pRA[0])
290 0 : goto count_rest;
291 0 : Swap_Impl(pRA, pRB);
292 : }
293 :
294 : // Done with the current new pair:
295 127600 : pRA += 2;
296 127600 : nCount += 2;
297 : }
298 :
299 : // Only pRB has more pairs available, pRA is already exhausted:
300 : count_rest:
301 102080 : for (; pRB[0]; pRB += 2)
302 51040 : nCount += 2;
303 :
304 : // Now, create new ranges of the correct size and, on a second run thru
305 : // _pRanges and rRanges._pRanges, copy the merged pairs into the new
306 : // ranges:
307 51040 : sal_uInt16 * pNew = new sal_uInt16[nCount + 1];
308 51040 : pRA = _pRanges;
309 51040 : pRB = rRanges._pRanges;
310 51040 : sal_uInt16 * pRN = pNew;
311 :
312 : for (;;)
313 : {
314 : // The first pair of pRA has a lower lower bound than the first pair
315 : // of pRB:
316 178640 : if (pRA[0] > pRB[0])
317 38280 : Swap_Impl(pRA, pRB);
318 :
319 : // We are done with the merging if at least pRA is exhausted:
320 178640 : if (!pRA[0])
321 51040 : break;
322 :
323 : // Lower bound of current new pair is already known:
324 127600 : *pRN++ = pRA[0];
325 :
326 : for (;;)
327 : {
328 : // Skip those pairs in pRB that completely lie in the first pair
329 : // of pRA:
330 255200 : while (pRB[1] <= pRA[1])
331 : {
332 0 : pRB += 2;
333 :
334 : // Watch out for exhaustion of pRB:
335 0 : if (!pRB[0])
336 : {
337 0 : Swap_Impl(pRA, pRB);
338 0 : ++pRB;
339 0 : goto copy_rest;
340 : }
341 : }
342 :
343 : // If the next pair of pRA does not at least touch the current new
344 : // pair, we are done with the current new pair:
345 127600 : if (pRB[0] > pRA[1] + 1)
346 127600 : break;
347 :
348 : // The next pair of pRB extends the current new pair; first,
349 : // extend the current new pair (we are done if pRB is then
350 : // exhausted); second, switch the roles of pRA and pRB in order to
351 : // merge in those following pairs of the original pRA that will
352 : // lie in the (now larger) current new pair or will even extend it
353 : // further:
354 0 : pRA += 2;
355 0 : if (!pRA[0])
356 : {
357 0 : ++pRB;
358 0 : goto copy_rest;
359 : }
360 0 : Swap_Impl(pRA, pRB);
361 : }
362 :
363 : // Done with the current new pair, now upper bound is also known:
364 127600 : *pRN++ = pRA[1];
365 127600 : pRA += 2;
366 : }
367 :
368 : // Only pRB has more pairs available (which are copied to the new ranges
369 : // unchanged), pRA is already exhausted:
370 : copy_rest:
371 204160 : for (; *pRB;)
372 102080 : *pRN++ = *pRB++;
373 51040 : *pRN = 0;
374 :
375 51040 : delete[] _pRanges;
376 51040 : _pRanges = pNew;
377 :
378 306240 : return *this;
379 : }
380 :
381 : /**
382 : * Removes 'rRanges' from '*this'.
383 : * for each sal_uInt16 n:
384 : * this->Contains( n ) && rRanges.Contains( n ) => !this'->Contains( n )
385 : * this->Contains( n ) && !rRanges.Contains( n ) => this'->Contains( n )
386 : * !this->Contains( n ) => !this'->Contains( n )
387 : */
388 0 : SfxUShortRanges& SfxUShortRanges::operator -=
389 : (
390 : const SfxUShortRanges &rRanges
391 : )
392 : {
393 : // special cases: one is empty
394 0 : if ( rRanges.IsEmpty() || IsEmpty() )
395 0 : return *this;
396 :
397 : // differentiate 'rRanges' in a temporary copy of '*this'
398 : // (size is computed for maximal possibly split-count plus terminating 0)
399 0 : sal_uInt16 nThisSize = Count_Impl(_pRanges);
400 0 : sal_uInt16 nTargetSize = 1 + ( nThisSize + Count_Impl(rRanges._pRanges) );
401 0 : boost::scoped_array<sal_uInt16> pTarget(new sal_uInt16[ nTargetSize ]);
402 0 : memset( pTarget.get(), 0, sizeof(sal_uInt16)*nTargetSize );
403 0 : memcpy( pTarget.get(), _pRanges, sizeof(sal_uInt16)*nThisSize );
404 :
405 0 : sal_uInt16 nPos1 = 0, nPos2 = 0, nTargetPos = 0;
406 0 : while( _pRanges[ nPos1 ] )
407 : {
408 0 : sal_uInt16 l1 = _pRanges[ nPos1 ]; // lower bound of interval 1
409 0 : sal_uInt16 u1 = _pRanges[ nPos1+1 ]; // upper bound of interval 1
410 0 : sal_uInt16 l2 = rRanges._pRanges[ nPos2 ]; // lower bound of interval 2
411 0 : sal_uInt16 u2 = rRanges._pRanges[ nPos2+1 ]; // upper bound of interval 2
412 :
413 : // boundary cases
414 : // * subtrahend is empty -> copy the minuend
415 0 : if( !l2 )
416 : {
417 0 : pTarget[ nTargetPos ] = l1;
418 0 : pTarget[ nTargetPos+1 ] = u1;
419 0 : nTargetPos += 2;
420 0 : nPos1 += 2;
421 0 : continue;
422 : }
423 : // * next subtrahend interval is completely higher -> copy the minuend
424 0 : if( u1 < l2 )
425 : {
426 0 : pTarget[ nTargetPos ] = l1;
427 0 : pTarget[ nTargetPos+1 ] = u1;
428 0 : nTargetPos += 2;
429 0 : nPos1 += 2;
430 0 : continue;
431 : }
432 :
433 : // * next subtrahend interval is completely lower -> try next
434 0 : if( u2 < l1 )
435 : {
436 0 : nPos2 += 2;
437 0 : continue;
438 : }
439 :
440 : // intersecting cases
441 : // * subtrahend cuts out from the beginning of the minuend
442 0 : if( l2 <= l1 && u2 <= u1 )
443 : {
444 : // reduce minuend interval, try again (minuend might be affected by other subtrahend intervals)
445 0 : _pRanges[ nPos1 ] = u2 + 1;
446 0 : nPos2 += 2; // this cannot hurt any longer
447 0 : continue;
448 : }
449 :
450 : // * subtrahend cuts out from the end of the minuend
451 0 : if( l1 <= l2 && u1 <= u2 )
452 : {
453 : // copy remaining part of minuend (cannot be affected by other intervals)
454 0 : if( l1 < l2 ) // anything left at all?
455 : {
456 0 : pTarget[ nTargetPos ] = l1;
457 0 : pTarget[ nTargetPos+1 ] = l2 - 1;
458 0 : nTargetPos += 2;
459 : // do not increment nPos2, might affect next minuend interval, too
460 : }
461 0 : nPos1 += 2; // nothing left at all
462 0 : continue;
463 : }
464 :
465 : // * subtrahend completely deletes minuend (larger or same at both ends)
466 0 : if( l1 >= l2 && u1 <= u2 )
467 : {
468 0 : nPos1 += 2; // minuend deleted
469 : // do not increment nPos2, might affect next minuend interval, too
470 0 : continue;
471 : }
472 :
473 : // * subtrahend divides minuend into two pieces
474 0 : if( l1 <= l2 && u1 >= u2 ) // >= and <= since they may be something left only at one side
475 : {
476 : // left side
477 0 : if( l1 < l2 ) // anything left at all
478 : {
479 0 : pTarget[ nTargetPos ] = l1;
480 0 : pTarget[ nTargetPos+1 ] = l2 - 1;
481 0 : nTargetPos += 2;
482 : }
483 :
484 : // right side
485 0 : if( u1 > u2 ) // anything left at all
486 : {
487 : // reduce minuend interval, try again (minuend might be affected by other subtrahend itnervals )
488 0 : _pRanges[ nPos1 ] = u2 + 1;
489 : }
490 :
491 : // subtrahend is completely used
492 0 : nPos2 += 2;
493 0 : continue;
494 : }
495 :
496 : // we should never be here
497 : OSL_FAIL( "SfxUShortRanges::operator-=: internal error" );
498 : } // while
499 :
500 0 : pTarget[ nTargetPos ] = 0;
501 :
502 : // assign the differentiated ranges
503 0 : delete[] _pRanges;
504 :
505 0 : sal_uInt16 nUShorts = Count_Impl(pTarget.get()) + 1;
506 0 : if ( 1 != nUShorts )
507 : {
508 0 : _pRanges = new sal_uInt16[ nUShorts ];
509 0 : memcpy( _pRanges, pTarget.get(), nUShorts * sizeof(sal_uInt16) );
510 : }
511 : else
512 0 : _pRanges = 0;
513 :
514 0 : return *this;
515 : }
516 :
517 : /**
518 : * Determines intersection of '*this' with 'rRanges'.
519 : * for each sal_uInt16 n:
520 : * this->Contains( n ) && rRanges.Contains( n ) => this'->Contains( n )
521 : * !this->Contains( n ) => !this'->Contains( n )
522 : * !rRanges.Contains( n ) => !this'->Contains( n )
523 : */
524 0 : SfxUShortRanges& SfxUShortRanges::operator /=
525 : (
526 : const SfxUShortRanges &rRanges
527 : )
528 : {
529 : // boundary cases
530 : // * first set is empty -> nothing to be done
531 : // * second set is empty -> delete first set
532 0 : if( rRanges.IsEmpty() )
533 : {
534 0 : delete[] _pRanges;
535 :
536 0 : _pRanges = new sal_uInt16[1];
537 0 : _pRanges[0] = 0;
538 :
539 0 : return *this;
540 : }
541 :
542 : // intersect 'rRanges' in a temporary copy of '*this'
543 : // (size is computed for maximal possibly split-count plus terminating 0)
544 0 : sal_uInt16 nThisSize = Count_Impl(_pRanges);
545 0 : sal_uInt16 nTargetSize = 1 + ( nThisSize + Count_Impl(rRanges._pRanges) );
546 0 : boost::scoped_array<sal_uInt16> pTarget(new sal_uInt16[ nTargetSize ]);
547 0 : memset( pTarget.get(), 0, sizeof(sal_uInt16)*nTargetSize );
548 0 : memcpy( pTarget.get(), _pRanges, sizeof(sal_uInt16)*nThisSize );
549 :
550 0 : sal_uInt16 nPos1 = 0, nPos2 = 0, nTargetPos = 0;
551 0 : while( _pRanges[ nPos1 ] != 0 && rRanges._pRanges[ nPos2 ] != 0 )
552 : {
553 0 : sal_uInt16 l1 = _pRanges[ nPos1 ]; // lower bound of interval 1
554 0 : sal_uInt16 u1 = _pRanges[ nPos1+1 ]; // upper bound of interval 1
555 0 : sal_uInt16 l2 = rRanges._pRanges[ nPos2 ]; // lower bound of interval 2
556 0 : sal_uInt16 u2 = rRanges._pRanges[ nPos2+1 ]; // upper bound of interval 2
557 :
558 0 : if( u1 < l2 )
559 : {
560 : // current interval in s1 is completely before ci in s2
561 0 : nPos1 += 2;
562 0 : continue;
563 : }
564 0 : if( u2 < l1 )
565 : {
566 : // ci in s2 is completely before ci in s1
567 0 : nPos2 += 2;
568 0 : continue;
569 : }
570 :
571 : // assert: there exists an intersection between ci1 and ci2
572 :
573 0 : if( l1 <= l2 )
574 : {
575 : // c1 "is more to the left" than c2
576 :
577 0 : if( u1 <= u2 )
578 : {
579 0 : pTarget[ nTargetPos ] = l2;
580 0 : pTarget[ nTargetPos+1 ] = u1;
581 0 : nTargetPos += 2;
582 0 : nPos1 += 2;
583 0 : continue;
584 : }
585 : else
586 : {
587 0 : pTarget[ nTargetPos ] = l2;
588 0 : pTarget[ nTargetPos+1 ] = u2;
589 0 : nTargetPos += 2;
590 0 : nPos2 += 2;
591 : }
592 : }
593 : else
594 : {
595 : // c2 "is more to the left" than c1"
596 :
597 0 : if( u1 > u2 )
598 : {
599 0 : pTarget[ nTargetPos ] = l1;
600 0 : pTarget[ nTargetPos+1 ] = u2;
601 0 : nTargetPos += 2;
602 0 : nPos2 += 2;
603 : }
604 : else
605 : {
606 0 : pTarget[ nTargetPos ] = l1;
607 0 : pTarget[ nTargetPos+1 ] = u1;
608 0 : nTargetPos += 2;
609 0 : nPos1 += 2;
610 : }
611 : }
612 : }; // while
613 0 : pTarget[ nTargetPos ] = 0;
614 :
615 : // assign the intersected ranges
616 0 : delete[] _pRanges;
617 :
618 0 : sal_uInt16 nUShorts = Count_Impl(pTarget.get()) + 1;
619 0 : if ( 1 != nUShorts )
620 : {
621 0 : _pRanges = new sal_uInt16[ nUShorts ];
622 0 : memcpy( _pRanges, pTarget.get(), nUShorts * sizeof(sal_uInt16) );
623 : }
624 : else
625 0 : _pRanges = 0;
626 :
627 0 : return *this;
628 : }
629 :
630 : /**
631 : * Determines the number of USHORTs in the set described by the ranges
632 : * of USHORTs in '*this'.
633 : */
634 0 : sal_uInt16 SfxUShortRanges::Count() const
635 : {
636 0 : return Capacity_Impl( _pRanges );
637 : }
638 :
639 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|