Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "bparr.hxx"
30 : :
31 : : #include <limits.h>
32 : : #include <string.h>
33 : :
34 : : /** Resize block management by this constant.
35 : : As a result there are approx. 20 * MAXENTRY == 20000 entries available */
36 : : const sal_uInt16 nBlockGrowSize = 20;
37 : :
38 : : #if OSL_DEBUG_LEVEL > 2
39 : : #define CHECKIDX( p, n, i, c ) CheckIdx( p, n, i, c );
40 : : void CheckIdx( BlockInfo** ppInf, sal_uInt16 nBlock, sal_uLong nSize, sal_uInt16 nCur )
41 : : {
42 : : assert( !nSize || nCur < nBlock ); // BigPtrArray: CurIndex invalid
43 : :
44 : : sal_uLong nIdx = 0;
45 : : for( sal_uInt16 nCnt = 0; nCnt < nBlock; ++nCnt, ++ppInf )
46 : : {
47 : : nIdx += (*ppInf)->nElem;
48 : : // Array with holes is not allowed
49 : : assert( !nCnt || (*(ppInf-1))->nEnd + 1 == (*ppInf)->nStart );
50 : : }
51 : : assert(nIdx == nSize); // invalid count in nSize
52 : : }
53 : : #else
54 : : #define CHECKIDX( p, n, i, c )
55 : : #endif
56 : :
57 : 3927 : BigPtrArray::BigPtrArray()
58 : : {
59 : 3927 : nBlock = nCur = 0;
60 : 3927 : nSize = 0;
61 : 3927 : nMaxBlock = nBlockGrowSize;
62 : 3927 : ppInf = new BlockInfo* [ nMaxBlock ];
63 : 3927 : }
64 : :
65 : 3629 : BigPtrArray::~BigPtrArray()
66 : : {
67 [ + + ]: 3629 : if( nBlock )
68 : : {
69 : 3599 : BlockInfo** pp = ppInf;
70 [ + + ]: 7198 : for( sal_uInt16 n = 0; n < nBlock; ++n, ++pp )
71 : : {
72 [ + - ]: 3599 : delete[] (*pp)->pData;
73 : 3599 : delete *pp;
74 : : }
75 : : }
76 [ + - ]: 3629 : delete[] ppInf;
77 : 3629 : }
78 : :
79 : : // Also moving is done simply here. Optimization is useless because of the
80 : : // division of this field into multiple parts.
81 : 198 : void BigPtrArray::Move( sal_uLong from, sal_uLong to )
82 : : {
83 [ + - ]: 198 : sal_uInt16 cur = Index2Block( from );
84 : 198 : BlockInfo* p = ppInf[ cur ];
85 : 198 : ElementPtr pElem = p->pData[ from - p->nStart ];
86 [ + - ]: 198 : Insert( pElem, to ); // insert first, then delete!
87 [ + + ][ + - ]: 198 : Remove( ( to < from ) ? ( from + 1 ) : from );
88 : 198 : }
89 : :
90 : : /** Apply function to every element.
91 : :
92 : : @param nStart First element to start with
93 : : @param nEnd Last element (exclusive!)
94 : : @param fn Function
95 : : @param pArgs Additional arguments for <fn>
96 : : */
97 : 41475 : void BigPtrArray::ForEach( sal_uLong nStart, sal_uLong nEnd,
98 : : FnForEach fn, void* pArgs )
99 : : {
100 [ - + ]: 41475 : if( nEnd > nSize )
101 : 0 : nEnd = nSize;
102 : :
103 [ + + ]: 41475 : if( nStart < nEnd )
104 : : {
105 : 41470 : sal_uInt16 cur = Index2Block( nStart );
106 : 41470 : BlockInfo** pp = ppInf + cur;
107 : 41470 : BlockInfo* p = *pp;
108 : 41470 : sal_uInt16 nElem = sal_uInt16( nStart - p->nStart );
109 : 41470 : ElementPtr* pElem = p->pData + nElem;
110 : 41470 : nElem = p->nElem - nElem;
111 : 48801 : for(;;)
112 : : {
113 [ + - ][ + + ]: 48801 : if( !(*fn)( *pElem++, pArgs ) || ++nStart >= nEnd )
[ + + ]
114 : 41470 : break;
115 : :
116 : : // next element
117 [ - + ]: 7331 : if( !--nElem )
118 : : {
119 : : // new block
120 : 0 : p = *++pp;
121 : 0 : pElem = p->pData;
122 : 0 : nElem = p->nElem;
123 : : }
124 : : }
125 : : }
126 : 41475 : }
127 : :
128 : 1441246 : ElementPtr BigPtrArray::operator[]( sal_uLong idx ) const
129 : : {
130 : : assert(idx < nSize); // operator[]: Index out of bounds
131 : : // because this function is not <const>:
132 : 1441246 : BigPtrArray* pThis = (BigPtrArray*) this;
133 : 1441246 : sal_uInt16 cur = Index2Block( idx );
134 : 1441246 : BlockInfo* p = ppInf[ cur ];
135 : 1441246 : pThis->nCur = cur;
136 : 1441246 : return p->pData[ idx - p->nStart ];
137 : : }
138 : :
139 : : /** Search a block at a given position */
140 : 1555565 : sal_uInt16 BigPtrArray::Index2Block( sal_uLong pos ) const
141 : : {
142 : : // last used block?
143 : 1555565 : BlockInfo* p = ppInf[ nCur ];
144 [ + - ][ + - ]: 1555565 : if( p->nStart <= pos && p->nEnd >= pos )
145 : 1555565 : return nCur;
146 : : // Index = 0?
147 [ # # ]: 0 : if( !pos )
148 : 0 : return 0;
149 : :
150 : : // following one?
151 [ # # ]: 0 : if( nCur < ( nBlock - 1 ) )
152 : : {
153 : 0 : p = ppInf[ nCur+1 ];
154 [ # # ][ # # ]: 0 : if( p->nStart <= pos && p->nEnd >= pos )
155 : 0 : return nCur+1;
156 : : }
157 : : // previous one?
158 [ # # ][ # # ]: 0 : else if( pos < p->nStart && nCur > 0 )
159 : : {
160 : 0 : p = ppInf[ nCur-1 ];
161 [ # # ][ # # ]: 0 : if( p->nStart <= pos && p->nEnd >= pos )
162 : 0 : return nCur-1;
163 : : }
164 : :
165 : : // binary search: always successful
166 : 0 : sal_uInt16 lower = 0, upper = nBlock - 1;
167 : 0 : sal_uInt16 cur = 0;
168 : 1555565 : for(;;)
169 : : {
170 : 0 : sal_uInt16 n = lower + ( upper - lower ) / 2;
171 [ # # ]: 0 : cur = ( n == cur ) ? n+1 : n;
172 : 0 : p = ppInf[ cur ];
173 [ # # ][ # # ]: 0 : if( p->nStart <= pos && p->nEnd >= pos )
174 : 0 : return cur;
175 : :
176 [ # # ]: 0 : if( p->nStart > pos )
177 : 0 : upper = cur;
178 : : else
179 : 0 : lower = cur;
180 : : }
181 : : }
182 : :
183 : : /** Update all index areas
184 : :
185 : : @param pos last correct block (starting point)
186 : : */
187 : 7335 : void BigPtrArray::UpdIndex( sal_uInt16 pos )
188 : : {
189 : 7335 : BlockInfo** pp = ppInf + pos;
190 : 7335 : sal_uLong idx = (*pp)->nEnd + 1;
191 : : BlockInfo* p;
192 [ - + ]: 7335 : while( ++pos < nBlock )
193 : : {
194 : 0 : p = *++pp;
195 : 0 : p->nStart = idx;
196 : 0 : idx += p->nElem;
197 : 0 : p->nEnd = idx - 1;
198 : : }
199 : 7335 : }
200 : :
201 : : /** Create and insert new block
202 : :
203 : : Existing blocks will be moved rearward.
204 : :
205 : : @param pos Position at which the new block should be created.
206 : : */
207 : 3922 : BlockInfo* BigPtrArray::InsBlock( sal_uInt16 pos )
208 : : {
209 [ - + ]: 3922 : if( nBlock == nMaxBlock )
210 : : {
211 : : // than extend the array first
212 : 0 : BlockInfo** ppNew = new BlockInfo* [ nMaxBlock + nBlockGrowSize ];
213 : 0 : memcpy( ppNew, ppInf, nMaxBlock * sizeof( BlockInfo* ));
214 [ # # ]: 0 : delete[] ppInf;
215 : 0 : nMaxBlock += nBlockGrowSize;
216 : 0 : ppInf = ppNew;
217 : : }
218 [ - + ]: 3922 : if( pos != nBlock )
219 : : {
220 : 0 : memmove( ppInf + pos+1, ppInf + pos,
221 : 0 : ( nBlock - pos ) * sizeof( BlockInfo* ));
222 : : }
223 : 3922 : ++nBlock;
224 : 3922 : BlockInfo* p = new BlockInfo;
225 : 3922 : ppInf[ pos ] = p;
226 : :
227 [ - + ]: 3922 : if( pos )
228 : 0 : p->nStart = p->nEnd = ppInf[ pos-1 ]->nEnd + 1;
229 : : else
230 : 3922 : p->nStart = p->nEnd = 0;
231 : :
232 : 3922 : p->nEnd--; // no elements
233 : 3922 : p->nElem = 0;
234 : 3922 : p->pData = new ElementPtr [ MAXENTRY ];
235 : 3922 : p->pBigArr = this;
236 : 3922 : return p;
237 : : }
238 : :
239 : 25 : void BigPtrArray::BlockDel( sal_uInt16 nDel )
240 : : {
241 : 25 : nBlock = nBlock - nDel;
242 [ - + ]: 25 : if( nMaxBlock - nBlock > nBlockGrowSize )
243 : : {
244 : : // than shrink array
245 : 0 : nDel = (( nBlock / nBlockGrowSize ) + 1 ) * nBlockGrowSize;
246 : 0 : BlockInfo** ppNew = new BlockInfo* [ nDel ];
247 : 0 : memcpy( ppNew, ppInf, nBlock * sizeof( BlockInfo* ));
248 [ # # ]: 0 : delete[] ppInf;
249 : 0 : ppInf = ppNew;
250 : 0 : nMaxBlock = nDel;
251 : : }
252 : 25 : }
253 : :
254 : 72734 : void BigPtrArray::Insert( const ElementPtr& rElem, sal_uLong pos )
255 : : {
256 : : CHECKIDX( ppInf, nBlock, nSize, nCur );
257 : :
258 : : BlockInfo* p;
259 : : sal_uInt16 cur;
260 [ + + ]: 72734 : if( !nSize )
261 : : {
262 : : // special case: insert first element
263 : 3922 : p = InsBlock( cur = 0 );
264 : : }
265 [ + + ]: 68812 : else if( pos == nSize )
266 : : {
267 : : // special case: insert at end
268 : 35263 : cur = nBlock - 1;
269 : 35263 : p = ppInf[ cur ];
270 [ - + ]: 35263 : if( p->nElem == MAXENTRY )
271 : : // the last block is full, create a new one
272 : 0 : p = InsBlock( ++cur );
273 : : }
274 : : else
275 : : {
276 : : // standard case:
277 : 33549 : cur = Index2Block( pos );
278 : 33549 : p = ppInf[ cur ];
279 : : }
280 : :
281 [ - + ]: 72734 : if( p->nElem == MAXENTRY )
282 : : {
283 : : // does the last entry fit into the next block?
284 : : BlockInfo* q;
285 [ # # ][ # # ]: 0 : if( cur < ( nBlock - 1 ) && ppInf[ cur+1 ]->nElem < MAXENTRY )
286 : : {
287 : 0 : q = ppInf[ cur+1 ];
288 [ # # ]: 0 : if( q->nElem )
289 : : {
290 : 0 : int nCount = q->nElem;
291 : 0 : ElementPtr *pFrom = q->pData + nCount,
292 : 0 : *pTo = pFrom+1;
293 [ # # ]: 0 : while( nCount-- )
294 : 0 : ++( *--pTo = *--pFrom )->nOffset;
295 : : }
296 : 0 : q->nStart--;
297 : 0 : q->nEnd--;
298 : : }
299 : : else
300 : : {
301 : : // If it does not fit, then insert a new block. But if there is more
302 : : // than 50% space in the array then compress first.
303 [ # # # # ]: 0 : if( /*nBlock == nMaxBlock &&*/
[ # # ]
304 : : nBlock > ( nSize / ( MAXENTRY / 2 ) ) &&
305 : 0 : cur >= Compress() )
306 : : {
307 : : // Something was moved before the current position and all
308 : : // pointer might be invalid. Thus restart Insert.
309 : 0 : Insert( rElem, pos );
310 : 72734 : return ;
311 : : }
312 : :
313 : 0 : q = InsBlock( cur+1 );
314 : : }
315 : :
316 : : // entry does not fit anymore - clear space
317 : 0 : ElementPtr pLast = p->pData[ MAXENTRY-1 ];
318 : 0 : pLast->nOffset = 0;
319 : 0 : pLast->pBlock = q;
320 : :
321 : 0 : q->pData[ 0 ] = pLast;
322 : 0 : q->nElem++;
323 : 0 : q->nEnd++;
324 : :
325 : 0 : p->nEnd--;
326 : 0 : p->nElem--;
327 : : }
328 : : // now we have free space - insert
329 : 72734 : pos -= p->nStart;
330 : : assert(pos < MAXENTRY);
331 [ + + ]: 72734 : if( pos != p->nElem )
332 : : {
333 : 33549 : int nCount = p->nElem - sal_uInt16(pos);
334 : 33549 : ElementPtr *pFrom = p->pData + p->nElem;
335 : 33549 : ElementPtr *pTo = pFrom + 1;
336 [ + + ]: 267287 : while( nCount-- )
337 : 233738 : ++( *--pTo = *--pFrom )->nOffset;
338 : : }
339 : : // insert element and update indices
340 : 72734 : ((ElementPtr&)rElem)->nOffset = sal_uInt16(pos);
341 : 72734 : ((ElementPtr&)rElem)->pBlock = p;
342 : 72734 : p->pData[ pos ] = rElem;
343 : 72734 : p->nEnd++;
344 : 72734 : p->nElem++;
345 : 72734 : nSize++;
346 [ - + ]: 72734 : if( cur != ( nBlock - 1 ) ) UpdIndex( cur );
347 : 72734 : nCur = cur;
348 : :
349 : : CHECKIDX( ppInf, nBlock, nSize, nCur );
350 : : }
351 : :
352 : 7360 : void BigPtrArray::Remove( sal_uLong pos, sal_uLong n )
353 : : {
354 : : CHECKIDX( ppInf, nBlock, nSize, nCur );
355 : :
356 : 7360 : sal_uInt16 nBlkdel = 0; // deleted blocks
357 : 7360 : sal_uInt16 cur = Index2Block( pos ); // current block number
358 : 7360 : sal_uInt16 nBlk1 = cur; // 1st treated block
359 : 7360 : sal_uInt16 nBlk1del = USHRT_MAX; // 1st deleted block
360 : 7360 : BlockInfo* p = ppInf[ cur ];
361 : 7360 : pos -= p->nStart;
362 : :
363 : 7360 : sal_uLong nElem = n;
364 [ + - ]: 7360 : while( nElem )
365 : : {
366 : 7360 : sal_uInt16 nel = p->nElem - sal_uInt16(pos);
367 [ + + ]: 7360 : if( sal_uLong(nel) > nElem )
368 : 7280 : nel = sal_uInt16(nElem);
369 : : // move elements if needed
370 [ + + ]: 7360 : if( ( pos + nel ) < sal_uLong(p->nElem) )
371 : : {
372 : 7280 : ElementPtr *pTo = p->pData + pos;
373 : 7280 : ElementPtr *pFrom = pTo + nel;
374 : 7280 : int nCount = p->nElem - nel - sal_uInt16(pos);
375 [ + + ]: 60244 : while( nCount-- )
376 : : {
377 : 52964 : *pTo = *pFrom++;
378 : 52964 : (*pTo)->nOffset = (*pTo)->nOffset - nel;
379 : 52964 : ++pTo;
380 : : }
381 : : }
382 : 7360 : p->nEnd -= nel;
383 : 7360 : p->nElem = p->nElem - nel;
384 : : // possibly delete block completely
385 [ + + ]: 7360 : if( !p->nElem )
386 : : {
387 [ + - ]: 25 : delete[] p->pData;
388 : 25 : nBlkdel++;
389 [ + - ]: 25 : if( USHRT_MAX == nBlk1del )
390 : 25 : nBlk1del = cur;
391 : : }
392 : 7360 : nElem -= nel;
393 [ + - ]: 7360 : if( !nElem )
394 : 7360 : break;
395 : 0 : p = ppInf[ ++cur ];
396 : 0 : pos = 0;
397 : : }
398 : :
399 : : // update table if blocks were removed
400 [ + + ]: 7360 : if( nBlkdel )
401 : : {
402 [ + + ]: 50 : for( sal_uInt16 i = nBlk1del; i < ( nBlk1del + nBlkdel ); i++ )
403 : 25 : delete ppInf[ i ];
404 : :
405 [ - + ]: 25 : if( ( nBlk1del + nBlkdel ) < nBlock )
406 : : {
407 : 0 : memmove( ppInf + nBlk1del, ppInf + nBlk1del + nBlkdel,
408 : 0 : ( nBlock - nBlkdel - nBlk1del ) * sizeof( BlockInfo* ) );
409 : :
410 : : // UpdateIdx updates the successor thus start before first elem
411 [ # # ]: 0 : if( !nBlk1 )
412 : : {
413 : 0 : p = ppInf[ 0 ];
414 : 0 : p->nStart = 0;
415 : 0 : p->nEnd = p->nElem-1;
416 : : }
417 : : else
418 : : {
419 : 0 : --nBlk1;
420 : : }
421 : : }
422 : 25 : BlockDel( nBlkdel ); // blocks were deleted
423 : : }
424 : :
425 : 7360 : nSize -= n;
426 [ + + ][ - + ]: 7360 : if( nBlk1 != ( nBlock - 1 ) && nSize )
427 : 0 : UpdIndex( nBlk1 );
428 : 7360 : nCur = nBlk1;
429 : :
430 : : // call Compress() if there is more than 50% space in the array
431 [ + + ]: 7360 : if( nBlock > ( nSize / ( MAXENTRY / 2 ) ) )
432 : 7335 : Compress();
433 : :
434 : : CHECKIDX( ppInf, nBlock, nSize, nCur );
435 : 7360 : }
436 : :
437 : 31742 : void BigPtrArray::Replace( sal_uLong idx, const ElementPtr& rElem)
438 : : {
439 : : assert(idx < nSize); // Index out of bounds
440 : : // because this function ist not <const>:
441 : 31742 : BigPtrArray* pThis = (BigPtrArray*) this;
442 : 31742 : sal_uInt16 cur = Index2Block( idx );
443 : 31742 : BlockInfo* p = ppInf[ cur ];
444 : 31742 : pThis->nCur = cur;
445 : 31742 : ((ElementPtr&)rElem)->nOffset = sal_uInt16(idx - p->nStart);
446 : 31742 : ((ElementPtr&)rElem)->pBlock = p;
447 : 31742 : p->pData[ idx - p->nStart ] = rElem;
448 : 31742 : }
449 : :
450 : : /** Compress the array */
451 : 7335 : sal_uInt16 BigPtrArray::Compress( short nMax )
452 : : {
453 : : CHECKIDX( ppInf, nBlock, nSize, nCur );
454 : :
455 : : // Iterate over InfoBlock array from beginning to end. If there is a deleted
456 : : // block in between so move all following ones accordingly. The pointer <pp>
457 : : // represents the "old" and <qq> the "new" array.
458 : 7335 : BlockInfo** pp = ppInf, **qq = pp;
459 : : BlockInfo* p;
460 : 7335 : BlockInfo* pLast(0); // last empty block
461 : 7335 : sal_uInt16 nLast = 0; // missing elements
462 : 7335 : sal_uInt16 nBlkdel = 0; // number of deleted blocks
463 : 7335 : sal_uInt16 nFirstChgPos = USHRT_MAX; // at which position was the 1st change?
464 : :
465 : : // convert fill percentage into number of remaining elements
466 : 7335 : nMax = MAXENTRY - (long) MAXENTRY * nMax / 100;
467 : :
468 [ + + ]: 14670 : for( sal_uInt16 cur = 0; cur < nBlock; ++cur )
469 : : {
470 : 7335 : p = *pp++;
471 : 7335 : sal_uInt16 n = p->nElem;
472 : : // Check if a not completely full block will be ignored. This happens if
473 : : // the current block would have to be split but the filling of the
474 : : // inspected block is already over its threshold value. In this case we
475 : : // do not fill more (it's expensive because of a double memmove() call)
476 [ - + ][ # # ]: 7335 : if( nLast && ( n > nLast ) && ( nLast < nMax ) )
[ # # ]
477 : 0 : nLast = 0;
478 [ - + ]: 7335 : if( nLast )
479 : : {
480 [ # # ]: 0 : if( USHRT_MAX == nFirstChgPos )
481 : 0 : nFirstChgPos = cur;
482 : :
483 : : // Not full yet? Than fill up.
484 [ # # ]: 0 : if( n > nLast )
485 : 0 : n = nLast;
486 : :
487 : : // move elements from current to last block
488 : 0 : ElementPtr* pElem = pLast->pData + pLast->nElem;
489 : 0 : ElementPtr* pFrom = p->pData;
490 [ # # ]: 0 : for( sal_uInt16 nCount = n, nOff = pLast->nElem;
491 : : nCount; --nCount, ++pElem )
492 : : {
493 : : *pElem = *pFrom++,
494 : : (*pElem)->pBlock = pLast,
495 : 0 : (*pElem)->nOffset = nOff++;
496 : : }
497 : :
498 : : // adjustment
499 : 0 : pLast->nElem = pLast->nElem + n;
500 : 0 : nLast = nLast - n;
501 : 0 : p->nElem = p->nElem - n;
502 : :
503 : : // Is the current block now empty as a result?
504 [ # # ]: 0 : if( !p->nElem )
505 : : {
506 : : // than remove
507 [ # # ]: 0 : delete[] p->pData;
508 : 0 : delete p, p = 0;
509 : 0 : ++nBlkdel;
510 : : }
511 : : else
512 : : {
513 : 0 : pElem = p->pData, pFrom = pElem + n;
514 : 0 : int nCount = p->nElem;
515 [ # # ]: 0 : while( nCount-- )
516 : : {
517 : 0 : *pElem = *pFrom++;
518 : 0 : (*pElem)->nOffset = (*pElem)->nOffset - n;
519 : 0 : ++pElem;
520 : : }
521 : : }
522 : : }
523 : :
524 [ + - ]: 7335 : if( p ) // BlockInfo was not deleted
525 : : {
526 : 7335 : *qq++ = p; // adjust to correct position
527 : :
528 : : // keep the potentially existing last half-full block
529 [ + - ][ + - ]: 7335 : if( !nLast && p->nElem < MAXENTRY )
530 : : {
531 : 7335 : pLast = p;
532 : 7335 : nLast = MAXENTRY - p->nElem;
533 : : }
534 : : }
535 : : }
536 : :
537 : : // if blocks were deleted shrink BlockInfo array if needed
538 [ - + ]: 7335 : if( nBlkdel )
539 : 0 : BlockDel( nBlkdel );
540 : :
541 : : // and re-index
542 : 7335 : p = ppInf[ 0 ];
543 : 7335 : p->nEnd = p->nElem - 1;
544 : 7335 : UpdIndex( 0 );
545 : :
546 [ - + ]: 7335 : if( nCur >= nFirstChgPos )
547 : 0 : nCur = 0;
548 : :
549 : : CHECKIDX( ppInf, nBlock, nSize, nCur );
550 : :
551 : 7335 : return nFirstChgPos;
552 : : }
553 : :
554 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|