Gtk-WARNING gtktreestore.c:1047: Invalid column number 1 added to iter
[LibreOffice.git] / sc / source / core / data / compressedarray.cxx
blob793b43b43a3bb0e5b04a7076a1e840f2e42496b2
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 <compressedarray.hxx>
21 #include <global.hxx>
23 template< typename A, typename D >
24 ScCompressedArray<A,D>::ScCompressedArray( A nMaxAccessP, const D& rValue )
25 : nCount(1)
26 , nLimit(1)
27 , pData( new DataEntry[1])
28 , nMaxAccess( nMaxAccessP)
30 pData[0].aValue = rValue;
31 pData[0].nEnd = nMaxAccess;
34 template< typename A, typename D >
35 size_t ScCompressedArray<A,D>::Search( A nAccess ) const
37 if (nAccess == 0)
38 return 0;
40 tools::Long nLo = 0;
41 tools::Long nHi = static_cast<tools::Long>(nCount) - 1;
42 tools::Long nStart = 0;
43 tools::Long i = 0;
44 bool bFound = (nCount == 1);
45 while (!bFound && nLo <= nHi)
47 i = (nLo + nHi) / 2;
48 if (i > 0)
49 nStart = static_cast<tools::Long>(pData[i - 1].nEnd);
50 else
51 nStart = -1;
52 tools::Long nEnd = static_cast<tools::Long>(pData[i].nEnd);
53 if (nEnd < static_cast<tools::Long>(nAccess))
54 nLo = ++i;
55 else
56 if (nStart >= static_cast<tools::Long>(nAccess))
57 nHi = --i;
58 else
59 bFound = true;
61 return (bFound ? static_cast<size_t>(i) : (nAccess < 0 ? 0 : nCount-1));
64 template< typename A, typename D >
65 void ScCompressedArray<A,D>::SetValue( A nStart, A nEnd, const D& rValue )
67 if (!(0 <= nStart && nStart <= nMaxAccess && 0 <= nEnd && nEnd <= nMaxAccess
68 && nStart <= nEnd))
69 return;
71 if ((nStart == 0) && (nEnd == nMaxAccess))
72 Reset( rValue);
73 else
75 // Create a temporary copy in case we got a reference passed that
76 // points to a part of the array to be reallocated.
77 D aNewVal( rValue);
78 size_t nNeeded = nCount + 2;
79 if (nLimit < nNeeded)
81 nLimit *= 1.5;
82 if (nLimit < nNeeded)
83 nLimit = nNeeded;
84 std::unique_ptr<DataEntry[]> pNewData(new DataEntry[nLimit]);
85 memcpy( pNewData.get(), pData.get(), nCount*sizeof(DataEntry));
86 pData = std::move(pNewData);
89 size_t ni; // number of leading entries
90 size_t nInsert; // insert position (nMaxAccess+1 := no insert)
91 bool bCombined = false;
92 bool bSplit = false;
93 if (nStart > 0)
95 // skip leading
96 ni = this->Search( nStart);
98 nInsert = nMaxAccess+1;
99 if (!(pData[ni].aValue == aNewVal))
101 if (ni == 0 || (pData[ni-1].nEnd < nStart - 1))
102 { // may be a split or a simple insert or just a shrink,
103 // row adjustment is done further down
104 if (pData[ni].nEnd > nEnd)
105 bSplit = true;
106 ni++;
107 nInsert = ni;
109 else if (ni > 0 && pData[ni-1].nEnd == nStart - 1)
110 nInsert = ni;
112 if (ni > 0 && pData[ni-1].aValue == aNewVal)
113 { // combine
114 pData[ni-1].nEnd = nEnd;
115 nInsert = nMaxAccess+1;
116 bCombined = true;
119 else
121 nInsert = 0;
122 ni = 0;
125 size_t nj = ni; // stop position of range to replace
126 while (nj < nCount && pData[nj].nEnd <= nEnd)
127 nj++;
128 if (!bSplit)
130 if (nj < nCount && pData[nj].aValue == aNewVal)
131 { // combine
132 if (ni > 0)
134 if (pData[ni-1].aValue == aNewVal)
135 { // adjacent entries
136 pData[ni-1].nEnd = pData[nj].nEnd;
137 nj++;
139 else if (ni == nInsert)
140 pData[ni-1].nEnd = nStart - 1; // shrink
142 nInsert = nMaxAccess+1;
143 bCombined = true;
145 else if (ni > 0 && ni == nInsert)
146 pData[ni-1].nEnd = nStart - 1; // shrink
148 if (ni < nj)
149 { // remove middle entries
150 if (!bCombined)
151 { // replace one entry
152 pData[ni].nEnd = nEnd;
153 pData[ni].aValue = aNewVal;
154 ni++;
155 nInsert = nMaxAccess+1;
157 if (ni < nj)
158 { // remove entries
159 memmove( pData.get() + ni, pData.get() + nj,
160 (nCount - nj) * sizeof(DataEntry));
161 nCount -= nj - ni;
165 if (nInsert < static_cast<size_t>(nMaxAccess+1))
166 { // insert or append new entry
167 if (nInsert <= nCount)
169 if (!bSplit)
170 memmove( pData.get() + nInsert + 1, pData.get() + nInsert,
171 (nCount - nInsert) * sizeof(DataEntry));
172 else
174 memmove( pData.get() + nInsert + 2, pData.get() + nInsert,
175 (nCount - nInsert) * sizeof(DataEntry));
176 pData[nInsert+1] = pData[nInsert-1];
177 nCount++;
180 if (nInsert)
181 pData[nInsert-1].nEnd = nStart - 1;
182 pData[nInsert].nEnd = nEnd;
183 pData[nInsert].aValue = aNewVal;
184 nCount++;
189 template< typename A, typename D >
190 void ScCompressedArray<A,D>::CopyFrom( const ScCompressedArray<A,D>& rArray, A nDestStart,
191 A nDestEnd, A nSrcStart )
193 assert( this != &rArray && "cannot copy self->self" );
194 size_t nIndex = 0;
195 A nRegionEnd;
196 for (A j=nDestStart; j<=nDestEnd; ++j)
198 const D& rValue = (j==nDestStart ?
199 rArray.GetValue( j - nDestStart + nSrcStart, nIndex, nRegionEnd) :
200 rArray.GetNextValue( nIndex, nRegionEnd));
201 nRegionEnd = nRegionEnd - nSrcStart + nDestStart;
202 if (nRegionEnd > nDestEnd)
203 nRegionEnd = nDestEnd;
204 this->SetValue( j, nRegionEnd, rValue);
205 j = nRegionEnd;
209 template< typename A, typename D >
210 const D& ScCompressedArray<A,D>::Insert( A nStart, size_t nAccessCount )
212 size_t nIndex = this->Search( nStart);
213 // No real insertion is needed, simply extend the one entry and adapt all
214 // following. In case nStart points to the start row of an entry, extend
215 // the previous entry (inserting before nStart).
216 if (nIndex > 0 && pData[nIndex-1].nEnd+1 == nStart)
217 --nIndex;
218 const D& rValue = pData[nIndex].aValue; // the value "copied"
221 pData[nIndex].nEnd += nAccessCount;
222 if (pData[nIndex].nEnd >= nMaxAccess)
224 pData[nIndex].nEnd = nMaxAccess;
225 nCount = nIndex + 1; // discard trailing entries
227 } while (++nIndex < nCount);
228 return rValue;
231 template< typename A, typename D >
232 void ScCompressedArray<A,D>::InsertPreservingSize( A nStart, size_t nAccessCount, const D& rFillValue )
234 const A nPrevLastPos = GetLastPos();
236 Insert(nStart, nAccessCount);
237 for (A i = nStart; i < A(nStart + nAccessCount); ++i)
238 SetValue(i, rFillValue);
240 const A nNewLastPos = GetLastPos();
241 Remove(nPrevLastPos, nNewLastPos - nPrevLastPos);
244 template< typename A, typename D >
245 void ScCompressedArray<A,D>::Remove( A nStart, size_t nAccessCount )
247 A nEnd = nStart + nAccessCount - 1;
248 size_t nIndex = this->Search( nStart);
249 // equalize/combine/remove all entries in between
250 if (nEnd > pData[nIndex].nEnd)
251 this->SetValue( nStart, nEnd, pData[nIndex].aValue);
252 // remove an exactly matching entry by shifting up all following by one
253 if ((nStart == 0 || (nIndex > 0 && nStart == pData[nIndex-1].nEnd+1)) &&
254 pData[nIndex].nEnd == nEnd && nIndex < nCount-1)
256 // In case removing an entry results in two adjacent entries with
257 // identical data, combine them into one. This is also necessary to
258 // make the algorithm used in SetValue() work correctly, it relies on
259 // the fact that consecutive values actually differ.
260 size_t nRemove;
261 if (nIndex > 0 && pData[nIndex-1].aValue == pData[nIndex+1].aValue)
263 nRemove = 2;
264 --nIndex;
266 else
267 nRemove = 1;
268 memmove( pData.get() + nIndex, pData.get() + nIndex + nRemove, (nCount - (nIndex +
269 nRemove)) * sizeof(DataEntry));
270 nCount -= nRemove;
272 // adjust end rows, nIndex still being valid
275 pData[nIndex].nEnd -= nAccessCount;
276 } while (++nIndex < nCount);
277 pData[nCount-1].nEnd = nMaxAccess;
280 template< typename A, typename D >
281 void ScCompressedArray<A,D>::RemovePreservingSize( A nStart, size_t nAccessCount, const D& rFillValue )
283 const A nPrevLastPos = GetLastPos();
285 Remove(nStart, nAccessCount);
287 const A nNewLastPos = GetLastPos();
288 InsertPreservingSize(nNewLastPos, nNewLastPos - nPrevLastPos, rFillValue);
291 template< typename A, typename D >
292 void ScCompressedArray<A,D>::Iterator::operator++()
294 ++mnRegion;
295 if (mnRegion > mrArray.pData[mnIndex].nEnd)
296 ++mnIndex;
299 template< typename A, typename D >
300 typename ScCompressedArray<A,D>::Iterator ScCompressedArray<A,D>::Iterator::operator+(size_t nAccessCount) const
302 A nRegion = mnRegion + nAccessCount;
303 auto nIndex = mnIndex;
304 while (nRegion > mrArray.pData[nIndex].nEnd)
305 ++nIndex;
306 return Iterator(mrArray, nIndex, nRegion);
309 // === ScBitMaskCompressedArray ==============================================
311 template< typename A, typename D >
312 void ScBitMaskCompressedArray<A,D>::AndValue( A nStart, A nEnd,
313 const D& rValueToAnd )
315 if (nStart > nEnd)
316 return;
318 size_t nIndex = this->Search( nStart);
321 if ((this->pData[nIndex].aValue & rValueToAnd) != this->pData[nIndex].aValue)
323 A nS = ::std::max<A>( (nIndex>0 ? this->pData[nIndex-1].nEnd+1 : 0), nStart);
324 A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
325 this->SetValue( nS, nE, this->pData[nIndex].aValue & rValueToAnd);
326 if (nE >= nEnd)
327 break; // while
328 nIndex = this->Search( nE + 1);
330 else if (this->pData[nIndex].nEnd >= nEnd)
331 break; // while
332 else
333 ++nIndex;
334 } while (nIndex < this->nCount);
337 template< typename A, typename D >
338 void ScBitMaskCompressedArray<A,D>::OrValue( A nStart, A nEnd,
339 const D& rValueToOr )
341 if (nStart > nEnd)
342 return;
344 size_t nIndex = this->Search( nStart);
347 if ((this->pData[nIndex].aValue | rValueToOr) != this->pData[nIndex].aValue)
349 A nS = ::std::max<A>( (nIndex>0 ? this->pData[nIndex-1].nEnd+1 : 0), nStart);
350 A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
351 this->SetValue( nS, nE, this->pData[nIndex].aValue | rValueToOr);
352 if (nE >= nEnd)
353 break; // while
354 nIndex = this->Search( nE + 1);
356 else if (this->pData[nIndex].nEnd >= nEnd)
357 break; // while
358 else
359 ++nIndex;
360 } while (nIndex < this->nCount);
363 template< typename A, typename D >
364 void ScBitMaskCompressedArray<A,D>::CopyFromAnded(
365 const ScBitMaskCompressedArray<A,D>& rArray, A nStart, A nEnd,
366 const D& rValueToAnd )
368 size_t nIndex = 0;
369 A nRegionEnd;
370 for (A j=nStart; j<=nEnd; ++j)
372 const D& rValue = (j==nStart ?
373 rArray.GetValue( j, nIndex, nRegionEnd) :
374 rArray.GetNextValue( nIndex, nRegionEnd));
375 if (nRegionEnd > nEnd)
376 nRegionEnd = nEnd;
377 this->SetValue( j, nRegionEnd, rValue & rValueToAnd);
378 j = nRegionEnd;
382 template< typename A, typename D >
383 A ScBitMaskCompressedArray<A,D>::GetLastAnyBitAccess( const D& rBitMask ) const
385 A nEnd = ::std::numeric_limits<A>::max();
386 size_t nIndex = this->nCount-1;
387 while (true)
389 if (this->pData[nIndex].aValue & rBitMask)
391 nEnd = this->pData[nIndex].nEnd;
392 break; // while
394 else
396 if (nIndex > 0)
398 --nIndex;
399 if (this->pData[nIndex].nEnd < 0)
400 break; // while
402 else
403 break; // while
406 return nEnd;
409 // === Force instantiation of specializations ================================
411 template class ScCompressedArray< SCROW, CRFlags>; // flags, base class
412 template class ScBitMaskCompressedArray< SCROW, CRFlags>; // flags
413 template class ScCompressedArray< SCCOL, sal_uInt16>;
414 template class ScCompressedArray< SCCOL, CRFlags>;
415 template class ScCompressedArray< SCROW, sal_uInt16>;
416 template class ScBitMaskCompressedArray< SCCOL, CRFlags>;
418 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */