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 "markarr.hxx"
21 : #include "global.hxx"
22 : #include "address.hxx"
23 :
24 : #include <osl/diagnose.h>
25 :
26 : // STATIC DATA -----------------------------------------------------------
27 :
28 1164288 : ScMarkArray::ScMarkArray() :
29 : nCount( 0 ),
30 : nLimit( 0 ),
31 1164288 : pData( NULL )
32 : {
33 : // special case "no marks" with pData = NULL
34 1164288 : }
35 :
36 1164288 : ScMarkArray::~ScMarkArray()
37 : {
38 1164288 : delete[] pData;
39 1164288 : }
40 :
41 43207 : void ScMarkArray::Reset( bool bMarked )
42 : {
43 : // always create pData here
44 : // (or have separate method to ensure pData)
45 :
46 43207 : delete[] pData;
47 :
48 43207 : nCount = nLimit = 1;
49 43207 : pData = new ScMarkEntry[1];
50 43207 : pData[0].nRow = MAXROW;
51 43207 : pData[0].bMarked = bMarked;
52 43207 : }
53 :
54 167571 : bool ScMarkArray::Search( SCROW nRow, SCSIZE& nIndex ) const
55 : {
56 167571 : long nHi = static_cast<long>(nCount) - 1;
57 167571 : long i = 0;
58 167571 : bool bFound = (nCount == 1);
59 167571 : if (pData)
60 : {
61 167127 : long nLo = 0;
62 167127 : long nStartRow = 0;
63 632118 : while ( !bFound && nLo <= nHi )
64 : {
65 297864 : i = (nLo + nHi) / 2;
66 297864 : if (i > 0)
67 163191 : nStartRow = (long) pData[i - 1].nRow;
68 : else
69 134673 : nStartRow = -1;
70 297864 : long nEndRow = (long) pData[i].nRow;
71 297864 : if (nEndRow < (long) nRow)
72 150276 : nLo = ++i;
73 : else
74 147588 : if (nStartRow >= (long) nRow)
75 451 : nHi = --i;
76 : else
77 147137 : bFound = true;
78 : }
79 : }
80 : else
81 444 : bFound = false;
82 :
83 167571 : if (bFound)
84 167127 : nIndex=(SCSIZE)i;
85 : else
86 444 : nIndex=0;
87 167571 : return bFound;
88 : }
89 :
90 2710 : bool ScMarkArray::GetMark( SCROW nRow ) const
91 : {
92 : SCSIZE i;
93 2710 : if (Search( nRow, i ))
94 2495 : return pData[i].bMarked;
95 : else
96 215 : return false;
97 :
98 : }
99 :
100 187972 : void ScMarkArray::SetMarkArea( SCROW nStartRow, SCROW nEndRow, bool bMarked )
101 : {
102 187972 : if (ValidRow(nStartRow) && ValidRow(nEndRow))
103 : {
104 187972 : if ((nStartRow == 0) && (nEndRow == MAXROW))
105 : {
106 17636 : Reset(bMarked);
107 : }
108 : else
109 : {
110 170336 : if (!pData)
111 23337 : Reset(false); // create pData for further processing - could use special case handling!
112 :
113 170336 : SCSIZE nNeeded = nCount + 2;
114 170336 : if ( nLimit < nNeeded )
115 : {
116 24476 : nLimit += SC_MARKARRAY_DELTA;
117 24476 : if ( nLimit < nNeeded )
118 0 : nLimit = nNeeded;
119 24476 : ScMarkEntry* pNewData = new ScMarkEntry[nLimit];
120 24476 : memcpy( pNewData, pData, nCount*sizeof(ScMarkEntry) );
121 24476 : delete[] pData;
122 24476 : pData = pNewData;
123 : }
124 :
125 : SCSIZE ni; // number of entries in beginning
126 : SCSIZE nInsert; // insert position (MAXROW+1 := no insert)
127 170336 : bool bCombined = false;
128 170336 : bool bSplit = false;
129 170336 : if ( nStartRow > 0 )
130 : {
131 : // skip beginning
132 : SCSIZE nIndex;
133 162141 : Search( nStartRow, nIndex );
134 162141 : ni = nIndex;
135 :
136 162141 : nInsert = MAXROWCOUNT;
137 162141 : if ( pData[ni].bMarked != bMarked )
138 : {
139 147302 : if ( ni == 0 || (pData[ni-1].nRow < nStartRow - 1) )
140 : { // may be a split or a simple insert or just a shrink,
141 : // row adjustment is done further down
142 5030 : if ( pData[ni].nRow > nEndRow )
143 4887 : bSplit = true;
144 5030 : ni++;
145 5030 : nInsert = ni;
146 : }
147 142272 : else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 )
148 142272 : nInsert = ni;
149 : }
150 162141 : if ( ni > 0 && pData[ni-1].bMarked == bMarked )
151 : { // combine
152 142272 : pData[ni-1].nRow = nEndRow;
153 142272 : nInsert = MAXROWCOUNT;
154 142272 : bCombined = true;
155 : }
156 : }
157 : else
158 : {
159 8195 : nInsert = 0;
160 8195 : ni = 0;
161 : }
162 :
163 170336 : SCSIZE nj = ni; // stop position of range to replace
164 347766 : while ( nj < nCount && pData[nj].nRow <= nEndRow )
165 7094 : nj++;
166 170336 : if ( !bSplit )
167 : {
168 165449 : if ( nj < nCount && pData[nj].bMarked == bMarked )
169 : { // combine
170 15393 : if ( ni > 0 )
171 : {
172 82 : if ( pData[ni-1].bMarked == bMarked )
173 : { // adjacent entries
174 40 : pData[ni-1].nRow = pData[nj].nRow;
175 40 : nj++;
176 : }
177 42 : else if ( ni == nInsert )
178 8 : pData[ni-1].nRow = nStartRow - 1; // shrink
179 : }
180 15393 : nInsert = MAXROWCOUNT;
181 15393 : bCombined = true;
182 : }
183 150056 : else if ( ni > 0 && ni == nInsert )
184 135 : pData[ni-1].nRow = nStartRow - 1; // shrink
185 : }
186 170336 : if ( ni < nj )
187 : { // remove middle entries
188 7094 : if ( !bCombined )
189 : { // replace one entry
190 820 : pData[ni].nRow = nEndRow;
191 820 : pData[ni].bMarked = bMarked;
192 820 : ni++;
193 820 : nInsert = MAXROWCOUNT;
194 : }
195 7094 : if ( ni < nj )
196 : { // remove entries
197 6274 : memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScMarkEntry) );
198 6274 : nCount -= nj - ni;
199 : }
200 : }
201 :
202 170336 : if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
203 : { // insert or append new entry
204 11891 : if ( nInsert <= nCount )
205 : {
206 11891 : if ( !bSplit )
207 7004 : memmove( pData + nInsert + 1, pData + nInsert,
208 14008 : (nCount - nInsert) * sizeof(ScMarkEntry) );
209 : else
210 : {
211 4887 : memmove( pData + nInsert + 2, pData + nInsert,
212 9774 : (nCount - nInsert) * sizeof(ScMarkEntry) );
213 4887 : pData[nInsert+1] = pData[nInsert-1];
214 4887 : nCount++;
215 : }
216 : }
217 11891 : if ( nInsert )
218 5022 : pData[nInsert-1].nRow = nStartRow - 1;
219 11891 : pData[nInsert].nRow = nEndRow;
220 11891 : pData[nInsert].bMarked = bMarked;
221 11891 : nCount++;
222 : }
223 : }
224 : }
225 187972 : }
226 :
227 36 : bool ScMarkArray::IsAllMarked( SCROW nStartRow, SCROW nEndRow ) const
228 : {
229 : SCSIZE nStartIndex;
230 : SCSIZE nEndIndex;
231 :
232 36 : if (Search( nStartRow, nStartIndex ))
233 36 : if (pData[nStartIndex].bMarked)
234 36 : if (Search( nEndRow, nEndIndex ))
235 36 : if (nEndIndex==nStartIndex)
236 36 : return true;
237 :
238 0 : return false;
239 : }
240 :
241 131 : bool ScMarkArray::HasOneMark( SCROW& rStartRow, SCROW& rEndRow ) const
242 : {
243 131 : bool bRet = false;
244 131 : if ( nCount == 1 )
245 : {
246 26 : if ( pData[0].bMarked )
247 : {
248 26 : rStartRow = 0;
249 26 : rEndRow = MAXROW;
250 26 : bRet = true;
251 : }
252 : }
253 105 : else if ( nCount == 2 )
254 : {
255 13 : if ( pData[0].bMarked )
256 : {
257 13 : rStartRow = 0;
258 13 : rEndRow = pData[0].nRow;
259 : }
260 : else
261 : {
262 0 : rStartRow = pData[0].nRow + 1;
263 0 : rEndRow = MAXROW;
264 : }
265 13 : bRet = true;
266 : }
267 92 : else if ( nCount == 3 )
268 : {
269 79 : if ( pData[1].bMarked )
270 : {
271 79 : rStartRow = pData[0].nRow + 1;
272 79 : rEndRow = pData[1].nRow;
273 79 : bRet = true;
274 : }
275 : }
276 131 : return bRet;
277 : }
278 :
279 4712 : bool ScMarkArray::HasEqualRowsMarked( const ScMarkArray& rOther ) const
280 : {
281 4712 : if (nCount != rOther.nCount)
282 403 : return false;
283 :
284 13158 : for (size_t i=0; i < nCount; ++i)
285 : {
286 19460 : if (pData[i].bMarked != rOther.pData[i].bMarked ||
287 9730 : pData[i].nRow != rOther.pData[i].nRow)
288 881 : return false;
289 : }
290 :
291 3428 : return true;
292 : }
293 :
294 234496 : void ScMarkArray::CopyMarksTo( ScMarkArray& rDestMarkArray ) const
295 : {
296 234496 : delete[] rDestMarkArray.pData;
297 :
298 234496 : if (pData)
299 : {
300 1138 : rDestMarkArray.pData = new ScMarkEntry[nCount];
301 1138 : memcpy( rDestMarkArray.pData, pData, nCount * sizeof(ScMarkEntry) );
302 : }
303 : else
304 233358 : rDestMarkArray.pData = NULL;
305 :
306 234496 : rDestMarkArray.nCount = rDestMarkArray.nLimit = nCount;
307 234496 : }
308 :
309 2265 : SCsROW ScMarkArray::GetNextMarked( SCsROW nRow, bool bUp ) const
310 : {
311 2265 : if (!pData)
312 2234 : const_cast<ScMarkArray*>(this)->Reset(false); // create pData for further processing
313 :
314 2265 : SCsROW nRet = nRow;
315 2265 : if (ValidRow(nRow))
316 : {
317 : SCSIZE nIndex;
318 2265 : Search(nRow, nIndex);
319 2265 : if (!pData[nIndex].bMarked)
320 : {
321 2258 : if (bUp)
322 : {
323 0 : if (nIndex>0)
324 0 : nRet = pData[nIndex-1].nRow;
325 : else
326 0 : nRet = -1;
327 : }
328 : else
329 2258 : nRet = pData[nIndex].nRow + 1;
330 : }
331 : }
332 2265 : return nRet;
333 : }
334 :
335 29 : SCROW ScMarkArray::GetMarkEnd( SCROW nRow, bool bUp ) const
336 : {
337 29 : if (!pData)
338 0 : const_cast<ScMarkArray*>(this)->Reset(false); // create pData for further processing
339 :
340 : SCROW nRet;
341 : SCSIZE nIndex;
342 29 : Search(nRow, nIndex);
343 : OSL_ENSURE( pData[nIndex].bMarked, "GetMarkEnd without bMarked" );
344 29 : if (bUp)
345 : {
346 0 : if (nIndex>0)
347 0 : nRet = pData[nIndex-1].nRow + 1;
348 : else
349 0 : nRet = 0;
350 : }
351 : else
352 29 : nRet = pData[nIndex].nRow;
353 :
354 29 : return nRet;
355 : }
356 :
357 : // -------------- Iterator ----------------------------------------------
358 :
359 661370 : ScMarkArrayIter::ScMarkArrayIter( const ScMarkArray* pNewArray ) :
360 : pArray( pNewArray ),
361 661370 : nPos( 0 )
362 : {
363 661370 : }
364 :
365 661370 : ScMarkArrayIter::~ScMarkArrayIter()
366 : {
367 661370 : }
368 :
369 736981 : bool ScMarkArrayIter::Next( SCROW& rTop, SCROW& rBottom )
370 : {
371 736981 : if ( nPos >= pArray->nCount )
372 648324 : return false;
373 187024 : while (!pArray->pData[nPos].bMarked)
374 : {
375 22756 : ++nPos;
376 22756 : if ( nPos >= pArray->nCount )
377 13046 : return false;
378 : }
379 75611 : rBottom = pArray->pData[nPos].nRow;
380 75611 : if (nPos==0)
381 65901 : rTop = 0;
382 : else
383 9710 : rTop = pArray->pData[nPos-1].nRow + 1;
384 75611 : ++nPos;
385 75611 : return true;
386 156 : }
387 :
388 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|