Version 7.5.1.1, tag libreoffice-7.5.1.1
[LibreOffice.git] / sc / inc / mtvfunctions.hxx
blob9fe394faff57a53817eb64a44201668ebf33e849
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/.
8 */
10 #pragma once
12 #include <cstdlib>
13 #include <mdds/multi_type_vector/types.hpp>
15 namespace sc {
17 template<typename SizeT, typename Ret = bool>
18 struct FuncElseNoOp
20 Ret operator() (mdds::mtv::element_t, SizeT, SizeT) const
22 return Ret();
26 template<typename FuncElem, typename Elem>
27 struct FuncNotElem
29 FuncElem& func;
30 FuncNotElem(FuncElem& f) : func(f) {}
31 bool operator() (size_t s, Elem elem) const
33 return !func(s, elem);
37 /**
38 * Generic algorithm to parse blocks of multi_type_vector either partially
39 * or fully.
41 template<typename StoreT, typename Func>
42 typename StoreT::const_iterator
43 ParseBlock(
44 const typename StoreT::const_iterator& itPos, const StoreT& rStore, Func& rFunc,
45 typename StoreT::size_type nStart, typename StoreT::size_type nEnd)
47 typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType;
49 PositionType aPos = rStore.position(itPos, nStart);
50 typename StoreT::const_iterator it = aPos.first;
51 typename StoreT::size_type nOffset = aPos.second;
52 typename StoreT::size_type nDataSize = 0;
53 typename StoreT::size_type nTopRow = nStart;
55 for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize)
57 bool bLastBlock = false;
58 nDataSize = it->size - nOffset;
59 if (nTopRow + nDataSize - 1 > nEnd)
61 // Truncate the block.
62 nDataSize = nEnd - nTopRow + 1;
63 bLastBlock = true;
66 rFunc(*it, nOffset, nDataSize);
68 if (bLastBlock)
69 break;
72 return it;
75 /**
76 * Non-const variant of the above function. TODO: Find a way to merge these
77 * two in an elegant way.
79 template<typename StoreT, typename Func>
80 typename StoreT::iterator
81 ProcessBlock(const typename StoreT::iterator& itPos, StoreT& rStore, Func& rFunc, typename StoreT::size_type nStart, typename StoreT::size_type nEnd)
83 typedef std::pair<typename StoreT::iterator, typename StoreT::size_type> PositionType;
85 PositionType aPos = rStore.position(itPos, nStart);
86 typename StoreT::iterator it = aPos.first;
87 typename StoreT::size_type nOffset = aPos.second;
88 typename StoreT::size_type nDataSize = 0;
89 typename StoreT::size_type nCurRow = nStart;
91 for (; it != rStore.end() && nCurRow <= nEnd; ++it, nOffset = 0, nCurRow += nDataSize)
93 bool bLastBlock = false;
94 nDataSize = it->size - nOffset;
95 if (nCurRow + nDataSize - 1 > nEnd)
97 // Truncate the block.
98 nDataSize = nEnd - nCurRow + 1;
99 bLastBlock = true;
102 rFunc(*it, nOffset, nDataSize);
104 if (bLastBlock)
105 break;
108 return it;
111 template<typename BlkT, typename ItrT, typename NodeT, typename FuncElem>
112 void EachElem(NodeT& rNode, size_t nOffset, size_t nDataSize, FuncElem& rFuncElem)
114 ItrT it = BlkT::begin(*rNode.data);
115 std::advance(it, nOffset);
116 ItrT itEnd = it;
117 std::advance(itEnd, nDataSize);
118 size_t nRow = rNode.position + nOffset;
119 for (; it != itEnd; ++it, ++nRow)
120 rFuncElem(nRow, *it);
123 template<typename BlkT, typename ItrT, typename NodeT, typename FuncElem>
124 void EachElem(NodeT& rNode, FuncElem& rFuncElem)
126 auto it = BlkT::begin(*rNode.data);
127 auto itEnd = BlkT::end(*rNode.data);
128 size_t nRow = rNode.position;
129 for (; it != itEnd; ++it, ++nRow)
130 rFuncElem(nRow, *it);
133 template<typename BlkT, typename ItrT, typename NodeT, typename FuncElem>
134 void EachElemReverse(NodeT& rNode, FuncElem& rFuncElem)
136 auto it = BlkT::rbegin(*rNode.data);
137 auto itEnd = BlkT::rend(*rNode.data);
138 size_t nRow = rNode.position;
139 for (; it != itEnd; ++it, ++nRow)
140 rFuncElem(nRow, *it);
143 template<typename BlkT, typename StoreT, typename FuncElem>
144 std::pair<typename StoreT::const_iterator, size_t>
145 CheckElem(
146 const StoreT& rStore, const typename StoreT::const_iterator& it, size_t nOffset, size_t nDataSize,
147 FuncElem& rFuncElem)
149 typedef std::pair<typename StoreT::const_iterator, size_t> PositionType;
151 typename BlkT::const_iterator itData = BlkT::begin(*it->data);
152 std::advance(itData, nOffset);
153 typename BlkT::const_iterator itDataEnd = itData;
154 std::advance(itDataEnd, nDataSize);
155 size_t nTopRow = it->position + nOffset;
156 size_t nRow = nTopRow;
157 for (; itData != itDataEnd; ++itData, ++nRow)
159 if (rFuncElem(nRow, *itData))
160 return PositionType(it, nRow - it->position);
163 return PositionType(rStore.end(), 0);
166 template<typename StoreT, typename BlkT, typename FuncElem, typename FuncElse>
167 void ParseElements1(const StoreT& rStore, FuncElem& rFuncElem, FuncElse& rFuncElse)
169 typename StoreT::size_type nTopRow = 0, nDataSize = 0;
170 typename StoreT::const_iterator it = rStore.begin(), itEnd = rStore.end();
171 for (; it != itEnd; ++it, nTopRow += nDataSize)
173 nDataSize = it->size;
174 if (it->type != BlkT::block_type)
176 rFuncElse(it->type, nTopRow, nDataSize);
177 continue;
180 EachElem<BlkT, typename BlkT::const_iterator>(*it, rFuncElem);
184 template<typename StoreT, typename BlkT, typename FuncElem, typename FuncElse>
185 typename StoreT::const_iterator
186 ParseElements1(
187 const typename StoreT::const_iterator& itPos, const StoreT& rStore,
188 typename StoreT::size_type nStart, typename StoreT::size_type nEnd,
189 FuncElem& rFuncElem, FuncElse& rFuncElse)
191 typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType;
193 PositionType aPos = rStore.position(itPos, nStart);
194 typename StoreT::const_iterator it = aPos.first;
195 typename StoreT::size_type nOffset = aPos.second;
196 typename StoreT::size_type nDataSize = 0;
197 typename StoreT::size_type nTopRow = nStart;
199 for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize)
201 bool bLastBlock = false;
202 nDataSize = it->size - nOffset;
203 if (nTopRow + nDataSize - 1 > nEnd)
205 // Truncate the block.
206 nDataSize = nEnd - nTopRow + 1;
207 bLastBlock = true;
210 if (it->type == BlkT::block_type)
211 EachElem<BlkT, typename BlkT::const_iterator>(*it, nOffset, nDataSize, rFuncElem);
212 else
213 rFuncElse(it->type, nTopRow, nDataSize);
215 if (bLastBlock)
216 break;
219 return it;
222 template<typename StoreT, typename Blk1, typename Blk2, typename FuncElem, typename FuncElse>
223 typename StoreT::const_iterator
224 ParseElements2(
225 const typename StoreT::const_iterator& itPos, const StoreT& rStore, typename StoreT::size_type nStart, typename StoreT::size_type nEnd,
226 FuncElem& rFuncElem, FuncElse& rFuncElse)
228 typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType;
230 PositionType aPos = rStore.position(itPos, nStart);
231 typename StoreT::const_iterator it = aPos.first;
232 typename StoreT::size_type nOffset = aPos.second;
233 typename StoreT::size_type nDataSize = 0;
234 typename StoreT::size_type nTopRow = nStart;
236 for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize)
238 bool bLastBlock = false;
239 nDataSize = it->size - nOffset;
240 if (nTopRow + nDataSize - 1 > nEnd)
242 // Truncate the block.
243 nDataSize = nEnd - nTopRow + 1;
244 bLastBlock = true;
247 switch (it->type)
249 case Blk1::block_type:
250 EachElem<Blk1, typename Blk1::const_iterator>(*it, nOffset, nDataSize, rFuncElem);
251 break;
252 case Blk2::block_type:
253 EachElem<Blk2, typename Blk2::const_iterator>(*it, nOffset, nDataSize, rFuncElem);
254 break;
255 default:
256 rFuncElse(it->type, nTopRow, nDataSize);
259 if (bLastBlock)
260 break;
263 return it;
266 template<typename StoreT, typename Blk1, typename Blk2, typename Blk3, typename Blk4, typename FuncElem, typename FuncElse>
267 typename StoreT::const_iterator
268 ParseElements4(
269 const typename StoreT::const_iterator& itPos, const StoreT& rStore, typename StoreT::size_type nStart, typename StoreT::size_type nEnd,
270 FuncElem& rFuncElem, FuncElse& rFuncElse)
272 typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType;
274 PositionType aPos = rStore.position(itPos, nStart);
275 typename StoreT::const_iterator it = aPos.first;
276 typename StoreT::size_type nOffset = aPos.second;
277 typename StoreT::size_type nDataSize = 0;
278 typename StoreT::size_type nTopRow = nStart;
280 for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize)
282 bool bLastBlock = false;
283 nDataSize = it->size - nOffset;
284 if (nTopRow + nDataSize - 1 > nEnd)
286 // Truncate the block.
287 nDataSize = nEnd - nTopRow + 1;
288 bLastBlock = true;
291 switch (it->type)
293 case Blk1::block_type:
294 EachElem<Blk1, typename Blk1::const_iterator>(*it, nOffset, nDataSize, rFuncElem);
295 break;
296 case Blk2::block_type:
297 EachElem<Blk2, typename Blk2::const_iterator>(*it, nOffset, nDataSize, rFuncElem);
298 break;
299 case Blk3::block_type:
300 EachElem<Blk3, typename Blk3::const_iterator>(*it, nOffset, nDataSize, rFuncElem);
301 break;
302 case Blk4::block_type:
303 EachElem<Blk4, typename Blk4::const_iterator>(*it, nOffset, nDataSize, rFuncElem);
304 break;
305 default:
306 rFuncElse(it->type, nTopRow, nDataSize);
309 if (bLastBlock)
310 break;
313 return it;
316 template<typename StoreT, typename BlkT, typename FuncElem, typename FuncElse>
317 void ProcessElements1(StoreT& rStore, FuncElem& rFuncElem, FuncElse& rFuncElse)
319 typename StoreT::size_type nTopRow = 0, nDataSize = 0;
320 typename StoreT::iterator it = rStore.begin(), itEnd = rStore.end();
321 for (; it != itEnd; ++it, nTopRow += nDataSize)
323 nDataSize = it->size;
324 if (it->type != BlkT::block_type)
326 rFuncElse(it->type, nTopRow, nDataSize);
327 continue;
330 EachElem<BlkT, typename BlkT::iterator>(*it, rFuncElem);
335 * This variant specifies start and end positions.
337 template<typename StoreT, typename BlkT, typename FuncElem, typename FuncElse>
338 typename StoreT::iterator
339 ProcessElements1(
340 const typename StoreT::iterator& itPos, StoreT& rStore,
341 typename StoreT::size_type nStart, typename StoreT::size_type nEnd,
342 FuncElem& rFuncElem, FuncElse& rFuncElse)
344 typedef std::pair<typename StoreT::iterator, typename StoreT::size_type> PositionType;
346 PositionType aPos = rStore.position(itPos, nStart);
347 typename StoreT::iterator it = aPos.first;
348 typename StoreT::size_type nOffset = aPos.second;
349 typename StoreT::size_type nDataSize = 0;
350 typename StoreT::size_type nTopRow = nStart;
352 for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize)
354 bool bLastBlock = false;
355 nDataSize = it->size - nOffset;
356 if (nTopRow + nDataSize - 1 > nEnd)
358 // Truncate the block.
359 nDataSize = nEnd - nTopRow + 1;
360 bLastBlock = true;
363 if (it->type == BlkT::block_type)
364 EachElem<BlkT, typename BlkT::iterator>(*it, nOffset, nDataSize, rFuncElem);
365 else
366 rFuncElse(it->type, nTopRow, nDataSize);
368 if (bLastBlock)
369 break;
372 return it;
375 template<typename StoreT, typename Blk1, typename Blk2, typename FuncElem, typename FuncElse>
376 void ProcessElements2(StoreT& rStore, FuncElem& rFuncElem, FuncElse& rFuncElse)
378 typename StoreT::size_type nTopRow = 0, nDataSize = 0;
379 typename StoreT::iterator it = rStore.begin(), itEnd = rStore.end();
380 for (; it != itEnd; ++it, nTopRow += nDataSize)
382 nDataSize = it->size;
383 switch (it->type)
385 case Blk1::block_type:
386 EachElem<Blk1, typename Blk1::iterator>(*it, rFuncElem);
387 break;
388 case Blk2::block_type:
389 EachElem<Blk2, typename Blk2::iterator>(*it, rFuncElem);
390 break;
391 default:
392 rFuncElse(it->type, nTopRow, nDataSize);
397 template<typename StoreT, typename Blk1, typename Blk2, typename FuncElem, typename FuncElse>
398 void ProcessElements2Reverse(StoreT& rStore, FuncElem& rFuncElem, FuncElse& rFuncElse)
400 typename StoreT::size_type nTopRow = 0, nDataSize = 0;
401 typename StoreT::iterator it = rStore.begin(), itEnd = rStore.end();
402 for (; it != itEnd; ++it, nTopRow += nDataSize)
404 nDataSize = it->size;
405 switch (it->type)
407 case Blk1::block_type:
408 EachElemReverse<Blk1, typename Blk1::iterator>(*it, rFuncElem);
409 break;
410 case Blk2::block_type:
411 EachElemReverse<Blk2, typename Blk2::iterator>(*it, rFuncElem);
412 break;
413 default:
414 rFuncElse(it->type, nTopRow, nDataSize);
419 template<typename StoreT, typename Blk1, typename FuncElem, typename FuncElse>
420 std::pair<typename StoreT::const_iterator, typename StoreT::size_type>
421 FindElement1(
422 const StoreT& rStore, typename StoreT::size_type nStart, typename StoreT::size_type nEnd,
423 FuncElem& rFuncElem, FuncElse& rFuncElse)
425 typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType;
426 typedef std::pair<typename StoreT::size_type, bool> ElseRetType;
428 PositionType aPos = rStore.position(nStart);
429 typename StoreT::const_iterator it = aPos.first;
430 typename StoreT::size_type nOffset = aPos.second;
431 typename StoreT::size_type nDataSize = 0;
432 typename StoreT::size_type nTopRow = nStart;
434 for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize)
436 bool bLastBlock = false;
437 nDataSize = it->size - nOffset;
438 if (nTopRow + nDataSize - 1 > nEnd)
440 // Truncate the block.
441 nDataSize = nEnd - nTopRow + 1;
442 bLastBlock = true;
445 switch (it->type)
447 case Blk1::block_type:
449 PositionType aRet = CheckElem<Blk1>(rStore, it, nOffset, nDataSize, rFuncElem);
450 if (aRet.first != rStore.end())
451 return aRet;
453 break;
454 default:
456 ElseRetType aRet = rFuncElse(it->type, nTopRow, nDataSize);
457 if (aRet.second)
458 return PositionType(it, aRet.first);
462 if (bLastBlock)
463 break;
466 return PositionType(rStore.end(), 0);
469 template<typename StoreT, typename Blk1, typename Blk2, typename FuncElem, typename FuncElse>
470 std::pair<typename StoreT::const_iterator, typename StoreT::size_type>
471 FindElement2(
472 const StoreT& rStore, typename StoreT::size_type nStart, typename StoreT::size_type nEnd,
473 FuncElem& rFuncElem, FuncElse& rFuncElse)
475 typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType;
476 typedef std::pair<typename StoreT::size_type, bool> ElseRetType;
478 PositionType aPos = rStore.position(nStart);
479 typename StoreT::const_iterator it = aPos.first;
480 typename StoreT::size_type nOffset = aPos.second;
481 typename StoreT::size_type nDataSize = 0;
482 typename StoreT::size_type nTopRow = nStart;
484 for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize)
486 bool bLastBlock = false;
487 nDataSize = it->size - nOffset;
488 if (nTopRow + nDataSize - 1 > nEnd)
490 // Truncate the block.
491 nDataSize = nEnd - nTopRow + 1;
492 bLastBlock = true;
495 switch (it->type)
497 case Blk1::block_type:
499 PositionType aRet = CheckElem<Blk1>(rStore, it, nOffset, nDataSize, rFuncElem);
500 if (aRet.first != rStore.end())
501 return aRet;
503 break;
504 case Blk2::block_type:
506 PositionType aRet = CheckElem<Blk2>(rStore, it, nOffset, nDataSize, rFuncElem);
507 if (aRet.first != rStore.end())
508 return aRet;
510 break;
511 default:
513 ElseRetType aRet = rFuncElse(*it, nOffset, nDataSize);
514 if (aRet.second)
515 return PositionType(it, aRet.first);
519 if (bLastBlock)
520 break;
523 return PositionType(rStore.end(), 0);
526 // Efficiently set all elements for which the predicate returns true as empty.
527 template<typename Blk1, typename StoreT, typename FuncElem>
528 void SetElementsToEmpty1(
529 StoreT& rStore, FuncElem& rFuncElem)
531 typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType;
533 for (typename StoreT::iterator it = rStore.begin(); it != rStore.end(); ++it)
535 if (it->type == Blk1::block_type)
537 PositionType firstToEmpty = CheckElem<Blk1>(rStore, it, 0, it->size, rFuncElem);
538 if (firstToEmpty.first != rStore.end())
540 typename StoreT::size_type nFirstOffset = firstToEmpty.second;
541 typename StoreT::size_type nRemainingDataSize = it->size - nFirstOffset;
542 FuncNotElem<FuncElem, typename Blk1::value_type> notFuncElem(rFuncElem);
543 PositionType lastToEmpty = CheckElem<Blk1>(rStore, it, nFirstOffset, nRemainingDataSize,
544 notFuncElem);
545 typename StoreT::size_type nLastOffset = lastToEmpty.first != rStore.end()
546 ? lastToEmpty.second - 1 : it->size - 1;
547 it = rStore.set_empty(it, it->position + nFirstOffset, it->position + nLastOffset);
548 // The returned iterator points to the empty elements block.
549 assert(it->type == sc::element_type_empty);
557 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */