1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "address.hxx"
25 template< typename A
, typename D
>
26 ScCompressedArray
<A
,D
>::ScCompressedArray( A nMaxAccessP
, const D
& rValue
,
30 , nDelta( nDeltaP
> 0 ? nDeltaP
: 1)
31 , pData( new DataEntry
[1])
32 , nMaxAccess( nMaxAccessP
)
34 pData
[0].aValue
= rValue
;
35 pData
[0].nEnd
= nMaxAccess
;
38 template< typename A
, typename D
>
39 ScCompressedArray
<A
,D
>::ScCompressedArray( A nMaxAccessP
, const D
* pDataArray
,
43 , nDelta( nScCompressedArrayDelta
)
44 , pData( new DataEntry
[nDataCount
])
45 , nMaxAccess( nMaxAccessP
)
47 D aValue
= pDataArray
[0];
48 for (size_t j
=0; j
<nDataCount
; ++j
)
50 if (!(aValue
== pDataArray
[j
]))
52 pData
[nCount
].aValue
= aValue
;
53 pData
[nCount
].nEnd
= j
-1;
55 aValue
= pDataArray
[j
];
58 pData
[nCount
].aValue
= aValue
;
59 pData
[nCount
].nEnd
= nMaxAccess
;
64 template< typename A
, typename D
>
65 ScCompressedArray
<A
,D
>::~ScCompressedArray()
70 template< typename A
, typename D
>
71 void ScCompressedArray
<A
,D
>::Resize( size_t nNewLimit
)
73 if ((nCount
<= nNewLimit
&& nNewLimit
< nLimit
) || nLimit
< nNewLimit
)
76 DataEntry
* pNewData
= new DataEntry
[nLimit
];
77 memcpy( pNewData
, pData
, nCount
*sizeof(DataEntry
));
83 template< typename A
, typename D
>
84 size_t ScCompressedArray
<A
,D
>::Search( A nAccess
) const
90 long nHi
= static_cast<long>(nCount
) - 1;
94 bool bFound
= (nCount
== 1);
95 while (!bFound
&& nLo
<= nHi
)
99 nStart
= static_cast<long>(pData
[i
- 1].nEnd
);
102 nEnd
= static_cast<long>(pData
[i
].nEnd
);
103 if (nEnd
< static_cast<long>(nAccess
))
106 if (nStart
>= static_cast<long>(nAccess
))
111 return (bFound
? static_cast<size_t>(i
) : (nAccess
< 0 ? 0 : nCount
-1));
114 template< typename A
, typename D
>
115 void ScCompressedArray
<A
,D
>::SetValue( A nStart
, A nEnd
, const D
& rValue
)
117 if (0 <= nStart
&& nStart
<= nMaxAccess
&& 0 <= nEnd
&& nEnd
<= nMaxAccess
120 if ((nStart
== 0) && (nEnd
== nMaxAccess
))
124 // Create a temporary copy in case we got a reference passed that
125 // points to a part of the array to be reallocated.
127 size_t nNeeded
= nCount
+ 2;
128 if (nLimit
< nNeeded
)
131 if (nLimit
< nNeeded
)
133 DataEntry
* pNewData
= new DataEntry
[nLimit
];
134 memcpy( pNewData
, pData
, nCount
*sizeof(DataEntry
));
139 size_t ni
; // number of leading entries
140 size_t nInsert
; // insert position (nMaxAccess+1 := no insert)
141 bool bCombined
= false;
146 ni
= this->Search( nStart
);
148 nInsert
= nMaxAccess
+1;
149 if (!(pData
[ni
].aValue
== aNewVal
))
151 if (ni
== 0 || (pData
[ni
-1].nEnd
< nStart
- 1))
152 { // may be a split or a simple insert or just a shrink,
153 // row adjustment is done further down
154 if (pData
[ni
].nEnd
> nEnd
)
159 else if (ni
> 0 && pData
[ni
-1].nEnd
== nStart
- 1)
162 if (ni
> 0 && pData
[ni
-1].aValue
== aNewVal
)
164 pData
[ni
-1].nEnd
= nEnd
;
165 nInsert
= nMaxAccess
+1;
175 size_t nj
= ni
; // stop position of range to replace
176 while (nj
< nCount
&& pData
[nj
].nEnd
<= nEnd
)
180 if (nj
< nCount
&& pData
[nj
].aValue
== aNewVal
)
184 if (pData
[ni
-1].aValue
== aNewVal
)
185 { // adjacent entries
186 pData
[ni
-1].nEnd
= pData
[nj
].nEnd
;
189 else if (ni
== nInsert
)
190 pData
[ni
-1].nEnd
= nStart
- 1; // shrink
192 nInsert
= nMaxAccess
+1;
195 else if (ni
> 0 && ni
== nInsert
)
196 pData
[ni
-1].nEnd
= nStart
- 1; // shrink
199 { // remove middle entries
201 { // replace one entry
202 pData
[ni
].nEnd
= nEnd
;
203 pData
[ni
].aValue
= aNewVal
;
205 nInsert
= nMaxAccess
+1;
209 memmove( pData
+ ni
, pData
+ nj
,
210 (nCount
- nj
) * sizeof(DataEntry
));
215 if (nInsert
< static_cast<size_t>(nMaxAccess
+1))
216 { // insert or append new entry
217 if (nInsert
<= nCount
)
220 memmove( pData
+ nInsert
+ 1, pData
+ nInsert
,
221 (nCount
- nInsert
) * sizeof(DataEntry
));
224 memmove( pData
+ nInsert
+ 2, pData
+ nInsert
,
225 (nCount
- nInsert
) * sizeof(DataEntry
));
226 pData
[nInsert
+1] = pData
[nInsert
-1];
231 pData
[nInsert
-1].nEnd
= nStart
- 1;
232 pData
[nInsert
].nEnd
= nEnd
;
233 pData
[nInsert
].aValue
= aNewVal
;
240 template< typename A
, typename D
>
241 void ScCompressedArray
<A
,D
>::CopyFrom( const ScCompressedArray
<A
,D
>& rArray
, A nStart
,
242 A nEnd
, long nSourceDy
)
246 for (A j
=nStart
; j
<=nEnd
; ++j
)
248 const D
& rValue
= (j
==nStart
?
249 rArray
.GetValue( j
+nSourceDy
, nIndex
, nRegionEnd
) :
250 rArray
.GetNextValue( nIndex
, nRegionEnd
));
251 nRegionEnd
-= nSourceDy
;
252 if (nRegionEnd
> nEnd
)
254 this->SetValue( j
, nRegionEnd
, rValue
);
259 template< typename A
, typename D
>
260 const D
& ScCompressedArray
<A
,D
>::Insert( A nStart
, size_t nAccessCount
)
262 size_t nIndex
= this->Search( nStart
);
263 // No real insertion is needed, simply extend the one entry and adapt all
264 // following. In case nStart points to the start row of an entry, extend
265 // the previous entry (inserting before nStart).
266 if (nIndex
> 0 && pData
[nIndex
-1].nEnd
+1 == nStart
)
268 const D
& rValue
= pData
[nIndex
].aValue
; // the value "copied"
271 pData
[nIndex
].nEnd
+= nAccessCount
;
272 if (pData
[nIndex
].nEnd
>= nMaxAccess
)
274 pData
[nIndex
].nEnd
= nMaxAccess
;
275 nCount
= nIndex
+ 1; // discard trailing entries
277 } while (++nIndex
< nCount
);
281 template< typename A
, typename D
>
282 void ScCompressedArray
<A
,D
>::Remove( A nStart
, size_t nAccessCount
)
284 A nEnd
= nStart
+ nAccessCount
- 1;
285 size_t nIndex
= this->Search( nStart
);
286 // equalize/combine/remove all entries in between
287 if (nEnd
> pData
[nIndex
].nEnd
)
288 this->SetValue( nStart
, nEnd
, pData
[nIndex
].aValue
);
289 // remove an exactly matching entry by shifting up all following by one
290 if ((nStart
== 0 || (nIndex
> 0 && nStart
== pData
[nIndex
-1].nEnd
+1)) &&
291 pData
[nIndex
].nEnd
== nEnd
&& nIndex
< nCount
-1)
293 // In case removing an entry results in two adjacent entries with
294 // identical data, combine them into one. This is also necessary to
295 // make the algorithm used in SetValue() work correctly, it relies on
296 // the fact that consecutive values actually differ.
298 if (nIndex
> 0 && pData
[nIndex
-1].aValue
== pData
[nIndex
+1].aValue
)
305 memmove( pData
+ nIndex
, pData
+ nIndex
+ nRemove
, (nCount
- (nIndex
+
306 nRemove
)) * sizeof(DataEntry
));
309 // adjust end rows, nIndex still being valid
312 pData
[nIndex
].nEnd
-= nAccessCount
;
313 } while (++nIndex
< nCount
);
314 pData
[nCount
-1].nEnd
= nMaxAccess
;
317 // === ScBitMaskCompressedArray ==============================================
319 template< typename A
, typename D
>
320 void ScBitMaskCompressedArray
<A
,D
>::AndValue( A nStart
, A nEnd
,
321 const D
& rValueToAnd
)
326 size_t nIndex
= this->Search( nStart
);
329 if ((this->pData
[nIndex
].aValue
& rValueToAnd
) != this->pData
[nIndex
].aValue
)
331 A nS
= ::std::max( (nIndex
>0 ? this->pData
[nIndex
-1].nEnd
+1 : 0), nStart
);
332 A nE
= ::std::min( this->pData
[nIndex
].nEnd
, nEnd
);
333 this->SetValue( nS
, nE
, this->pData
[nIndex
].aValue
& rValueToAnd
);
336 nIndex
= this->Search( nE
+ 1);
338 else if (this->pData
[nIndex
].nEnd
>= nEnd
)
342 } while (nIndex
< this->nCount
);
345 template< typename A
, typename D
>
346 void ScBitMaskCompressedArray
<A
,D
>::OrValue( A nStart
, A nEnd
,
347 const D
& rValueToOr
)
352 size_t nIndex
= this->Search( nStart
);
355 if ((this->pData
[nIndex
].aValue
| rValueToOr
) != this->pData
[nIndex
].aValue
)
357 A nS
= ::std::max( (nIndex
>0 ? this->pData
[nIndex
-1].nEnd
+1 : 0), nStart
);
358 A nE
= ::std::min( this->pData
[nIndex
].nEnd
, nEnd
);
359 this->SetValue( nS
, nE
, this->pData
[nIndex
].aValue
| rValueToOr
);
362 nIndex
= this->Search( nE
+ 1);
364 else if (this->pData
[nIndex
].nEnd
>= nEnd
)
368 } while (nIndex
< this->nCount
);
371 template< typename A
, typename D
>
372 void ScBitMaskCompressedArray
<A
,D
>::CopyFromAnded(
373 const ScBitMaskCompressedArray
<A
,D
>& rArray
, A nStart
, A nEnd
,
374 const D
& rValueToAnd
, long nSourceDy
)
378 for (A j
=nStart
; j
<=nEnd
; ++j
)
380 const D
& rValue
= (j
==nStart
?
381 rArray
.GetValue( j
+nSourceDy
, nIndex
, nRegionEnd
) :
382 rArray
.GetNextValue( nIndex
, nRegionEnd
));
383 nRegionEnd
-= nSourceDy
;
384 if (nRegionEnd
> nEnd
)
386 this->SetValue( j
, nRegionEnd
, rValue
& rValueToAnd
);
391 template< typename A
, typename D
>
392 A ScBitMaskCompressedArray
<A
,D
>::GetLastAnyBitAccess( A nStart
,
393 const D
& rBitMask
) const
395 A nEnd
= ::std::numeric_limits
<A
>::max();
396 size_t nIndex
= this->nCount
-1;
399 if ((this->pData
[nIndex
].aValue
& rBitMask
) != 0)
401 nEnd
= this->pData
[nIndex
].nEnd
;
409 if (this->pData
[nIndex
].nEnd
< nStart
)
419 // === Force instantiation of specializations ================================
421 template class ScCompressedArray
< SCROW
, sal_uInt8
>; // flags, base class
422 template class ScBitMaskCompressedArray
< SCROW
, sal_uInt8
>; // flags
424 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */