clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name interpr6.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SC_DLLIMPLEMENTATION -D SC_INFO_OSVERSION="LINUX" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/liborcus/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/clew/source/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sc/source/core/inc -I /home/maarten/src/libreoffice/core/sc/source/filter/inc -I /home/maarten/src/libreoffice/core/sc/source/ui/inc -I /home/maarten/src/libreoffice/core/sc/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sc/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sc/source/core/tool/interpr6.cxx
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | #include <interpre.hxx> |
21 | #include <columnspanset.hxx> |
22 | #include <column.hxx> |
23 | #include <document.hxx> |
24 | #include <cellvalue.hxx> |
25 | #include <dociter.hxx> |
26 | #include <mtvcellfunc.hxx> |
27 | #include <scmatrix.hxx> |
28 | |
29 | #include <arraysumfunctor.hxx> |
30 | |
31 | #include <formula/token.hxx> |
32 | |
33 | using namespace formula; |
34 | |
35 | double const fHalfMachEps = 0.5 * ::std::numeric_limits<double>::epsilon(); |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | double ScInterpreter::GetGammaContFraction( double fA, double fX ) |
45 | { |
46 | |
47 | double const fBigInv = ::std::numeric_limits<double>::epsilon(); |
48 | double const fBig = 1.0/fBigInv; |
49 | double fCount = 0.0; |
50 | double fY = 1.0 - fA; |
51 | double fDenom = fX + 2.0-fA; |
52 | double fPkm1 = fX + 1.0; |
53 | double fPkm2 = 1.0; |
54 | double fQkm1 = fDenom * fX; |
55 | double fQkm2 = fX; |
56 | double fApprox = fPkm1/fQkm1; |
57 | bool bFinished = false; |
58 | do |
59 | { |
60 | fCount = fCount +1.0; |
61 | fY = fY+ 1.0; |
62 | const double fNum = fY * fCount; |
63 | fDenom = fDenom +2.0; |
64 | double fPk = fPkm1 * fDenom - fPkm2 * fNum; |
65 | const double fQk = fQkm1 * fDenom - fQkm2 * fNum; |
66 | if (fQk != 0.0) |
67 | { |
68 | const double fR = fPk/fQk; |
69 | bFinished = (fabs( (fApprox - fR)/fR ) <= fHalfMachEps); |
70 | fApprox = fR; |
71 | } |
72 | fPkm2 = fPkm1; |
73 | fPkm1 = fPk; |
74 | fQkm2 = fQkm1; |
75 | fQkm1 = fQk; |
76 | if (fabs(fPk) > fBig) |
77 | { |
78 | |
79 | fPkm2 = fPkm2 * fBigInv; |
80 | fPkm1 = fPkm1 * fBigInv; |
81 | fQkm2 = fQkm2 * fBigInv; |
82 | fQkm1 = fQkm1 * fBigInv; |
83 | } |
84 | } while (!bFinished && fCount<10000); |
85 | |
86 | if (!bFinished) |
87 | { |
88 | SetError(FormulaError::NoConvergence); |
89 | } |
90 | return fApprox; |
91 | } |
92 | |
93 | |
94 | |
95 | |
96 | double ScInterpreter::GetGammaSeries( double fA, double fX ) |
97 | { |
98 | double fDenomfactor = fA; |
99 | double fSummand = 1.0/fA; |
100 | double fSum = fSummand; |
101 | int nCount=1; |
102 | do |
103 | { |
104 | fDenomfactor = fDenomfactor + 1.0; |
105 | fSummand = fSummand * fX/fDenomfactor; |
106 | fSum = fSum + fSummand; |
107 | nCount = nCount+1; |
108 | } while ( fSummand/fSum > fHalfMachEps && nCount<=10000); |
109 | |
110 | |
111 | if (nCount>10000) |
112 | { |
113 | SetError(FormulaError::NoConvergence); |
114 | } |
115 | return fSum; |
116 | } |
117 | |
118 | |
119 | double ScInterpreter::GetLowRegIGamma( double fA, double fX ) |
120 | { |
121 | double fLnFactor = fA * log(fX) - fX - GetLogGamma(fA); |
122 | double fFactor = exp(fLnFactor); |
123 | if (fX>fA+1.0) |
124 | return 1.0 - fFactor * GetGammaContFraction(fA,fX); |
125 | else |
126 | return fFactor * GetGammaSeries(fA,fX); |
127 | } |
128 | |
129 | |
130 | double ScInterpreter::GetUpRegIGamma( double fA, double fX ) |
131 | { |
132 | |
133 | double fLnFactor= fA*log(fX)-fX-GetLogGamma(fA); |
134 | double fFactor = exp(fLnFactor); |
135 | if (fX>fA+1.0) |
136 | return fFactor * GetGammaContFraction(fA,fX); |
137 | else |
138 | return 1.0 -fFactor * GetGammaSeries(fA,fX); |
139 | } |
140 | |
141 | |
142 | |
143 | |
144 | double ScInterpreter::GetGammaDistPDF( double fX, double fAlpha, double fLambda ) |
145 | { |
146 | if (fX < 0.0) |
147 | return 0.0; |
148 | else if (fX == 0) |
149 | |
150 | { |
151 | if (fAlpha < 1.0) |
152 | { |
153 | SetError(FormulaError::DivisionByZero); |
154 | return HUGE_VAL; |
155 | } |
156 | else if (fAlpha == 1) |
157 | { |
158 | return (1.0 / fLambda); |
159 | } |
160 | else |
161 | { |
162 | return 0.0; |
163 | } |
164 | } |
165 | else |
166 | { |
167 | double fXr = fX / fLambda; |
168 | |
169 | if (fXr > 1.0) |
170 | { |
171 | const double fLogDblMax = log( ::std::numeric_limits<double>::max()); |
172 | if (log(fXr) * (fAlpha-1.0) < fLogDblMax && fAlpha < fMaxGammaArgument) |
173 | { |
174 | return pow( fXr, fAlpha-1.0) * exp(-fXr) / fLambda / GetGamma(fAlpha); |
175 | } |
176 | else |
177 | { |
178 | return exp( (fAlpha-1.0) * log(fXr) - fXr - log(fLambda) - GetLogGamma(fAlpha)); |
179 | } |
180 | } |
181 | else |
182 | { |
183 | if (fAlpha<fMaxGammaArgument) |
184 | { |
185 | return pow( fXr, fAlpha-1.0) * exp(-fXr) / fLambda / GetGamma(fAlpha); |
186 | } |
187 | else |
188 | { |
189 | return pow( fXr, fAlpha-1.0) * exp(-fXr) / fLambda / exp( GetLogGamma(fAlpha)); |
190 | } |
191 | } |
192 | } |
193 | } |
194 | |
195 | |
196 | |
197 | |
198 | double ScInterpreter::GetGammaDist( double fX, double fAlpha, double fLambda ) |
199 | { |
200 | if (fX <= 0.0) |
201 | return 0.0; |
202 | else |
203 | return GetLowRegIGamma( fAlpha, fX / fLambda); |
204 | } |
205 | |
206 | namespace { |
207 | |
208 | class NumericCellAccumulator |
209 | { |
210 | double mfFirst; |
211 | double mfRest; |
212 | FormulaError mnError; |
213 | |
214 | public: |
215 | NumericCellAccumulator() : mfFirst(0.0), mfRest(0.0), mnError(FormulaError::NONE) {} |
216 | |
217 | void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize) |
218 | { |
219 | switch (rNode.type) |
| 12 | | Control jumps to 'case 10:' at line 221 | |
|
220 | { |
221 | case sc::element_type_numeric: |
222 | { |
223 | const double *p = &sc::numeric_block::at(*rNode.data, nOffset); |
224 | size_t i = 0; |
225 | |
226 | |
227 | if (!mfFirst) |
| 13 | | Assuming the condition is false | |
|
| |
228 | { |
229 | for (i = 0; i < nDataSize; ++i) |
230 | { |
231 | if (!mfFirst) |
232 | mfFirst = p[i]; |
233 | else |
234 | break; |
235 | } |
236 | } |
237 | p += i; |
238 | nDataSize -= i; |
239 | if (nDataSize == 0) |
| 15 | | Assuming 'nDataSize' is not equal to 0 | |
|
| |
240 | return; |
241 | |
242 | sc::ArraySumFunctor functor(p, nDataSize); |
243 | |
244 | mfRest += functor(); |
| 17 | | Calling 'ArraySumFunctor::operator()' | |
|
245 | break; |
246 | } |
247 | |
248 | case sc::element_type_formula: |
249 | { |
250 | sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data); |
251 | std::advance(it, nOffset); |
252 | sc::formula_block::const_iterator itEnd = it; |
253 | std::advance(itEnd, nDataSize); |
254 | for (; it != itEnd; ++it) |
255 | { |
256 | double fVal = 0.0; |
257 | FormulaError nErr = FormulaError::NONE; |
258 | ScFormulaCell& rCell = *(*it); |
259 | if (!rCell.GetErrorOrValue(nErr, fVal)) |
260 | |
261 | continue; |
262 | |
263 | if (nErr != FormulaError::NONE) |
264 | { |
265 | |
266 | mnError = nErr; |
267 | return; |
268 | } |
269 | |
270 | if ( !mfFirst ) |
271 | mfFirst = fVal; |
272 | else |
273 | mfRest += fVal; |
274 | } |
275 | } |
276 | break; |
277 | default: |
278 | ; |
279 | } |
280 | } |
281 | |
282 | FormulaError getError() const { return mnError; } |
283 | double getFirst() const { return mfFirst; } |
284 | double getRest() const { return mfRest; } |
285 | }; |
286 | |
287 | class NumericCellCounter |
288 | { |
289 | size_t mnCount; |
290 | public: |
291 | NumericCellCounter() : mnCount(0) {} |
292 | |
293 | void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize) |
294 | { |
295 | switch (rNode.type) |
296 | { |
297 | case sc::element_type_numeric: |
298 | mnCount += nDataSize; |
299 | break; |
300 | case sc::element_type_formula: |
301 | { |
302 | sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data); |
303 | std::advance(it, nOffset); |
304 | sc::formula_block::const_iterator itEnd = it; |
305 | std::advance(itEnd, nDataSize); |
306 | for (; it != itEnd; ++it) |
307 | { |
308 | ScFormulaCell& rCell = **it; |
309 | if (rCell.IsValueNoError()) |
310 | ++mnCount; |
311 | } |
312 | } |
313 | break; |
314 | default: |
315 | ; |
316 | } |
317 | } |
318 | |
319 | size_t getCount() const { return mnCount; } |
320 | }; |
321 | |
322 | class FuncCount : public sc::ColumnSpanSet::ColumnAction |
323 | { |
324 | const ScInterpreterContext& mrContext; |
325 | sc::ColumnBlockConstPosition maPos; |
326 | ScColumn* mpCol; |
327 | size_t mnCount; |
328 | sal_uInt32 mnNumFmt; |
329 | |
330 | public: |
331 | FuncCount(const ScInterpreterContext& rContext) : mrContext(rContext), mpCol(nullptr), mnCount(0), mnNumFmt(0) {} |
332 | |
333 | virtual void startColumn(ScColumn* pCol) override |
334 | { |
335 | mpCol = pCol; |
336 | mpCol->InitBlockPosition(maPos); |
337 | } |
338 | |
339 | virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal) override |
340 | { |
341 | if (!bVal) |
342 | return; |
343 | |
344 | NumericCellCounter aFunc; |
345 | maPos.miCellPos = sc::ParseBlock(maPos.miCellPos, mpCol->GetCellStore(), aFunc, nRow1, nRow2); |
346 | mnCount += aFunc.getCount(); |
347 | mnNumFmt = mpCol->GetNumberFormat(mrContext, nRow2); |
348 | }; |
349 | |
350 | size_t getCount() const { return mnCount; } |
351 | sal_uInt32 getNumberFormat() const { return mnNumFmt; } |
352 | }; |
353 | |
354 | class FuncSum : public sc::ColumnSpanSet::ColumnAction |
355 | { |
356 | const ScInterpreterContext& mrContext; |
357 | sc::ColumnBlockConstPosition maPos; |
358 | ScColumn* mpCol; |
359 | double mfSum; |
360 | FormulaError mnError; |
361 | sal_uInt32 mnNumFmt; |
362 | |
363 | public: |
364 | FuncSum(const ScInterpreterContext& rContext) : mrContext(rContext), mpCol(nullptr), mfSum(0.0), mnError(FormulaError::NONE), mnNumFmt(0) {} |
365 | |
366 | virtual void startColumn(ScColumn* pCol) override |
367 | { |
368 | mpCol = pCol; |
369 | mpCol->InitBlockPosition(maPos); |
370 | } |
371 | |
372 | virtual void execute(SCROW, SCROW, bool) override {} |
373 | |
374 | virtual void executeSum(SCROW nRow1, SCROW nRow2, bool bVal, double& fMem ) override |
375 | { |
376 | if (!bVal) |
| |
| |
377 | return; |
378 | |
379 | if (mnError != FormulaError::NONE) |
| 3 | | Assuming field 'mnError' is equal to NONE | |
|
| |
380 | return; |
381 | |
382 | NumericCellAccumulator aFunc; |
383 | maPos.miCellPos = sc::ParseBlock(maPos.miCellPos, mpCol->GetCellStore(), aFunc, nRow1, nRow2); |
| 5 | | Calling 'ParseBlock<mdds::multi_type_vector<mdds::mtv::custom_block_func3<mdds::mtv::default_element_block<52, svl::SharedString>, mdds::mtv::noncopyable_managed_element_block<53, EditTextObject>, mdds::mtv::noncopyable_managed_element_block<54, ScFormulaCell>>, sc::CellStoreEvent>, (anonymous namespace)::NumericCellAccumulator>' | |
|
384 | mnError = aFunc.getError(); |
385 | if (mnError != FormulaError::NONE) |
386 | return; |
387 | |
388 | if ( fMem ) |
389 | mfSum += aFunc.getFirst() + aFunc.getRest(); |
390 | else |
391 | { |
392 | fMem = aFunc.getFirst(); |
393 | mfSum += aFunc.getRest(); |
394 | } |
395 | |
396 | mnNumFmt = mpCol->GetNumberFormat(mrContext, nRow2); |
397 | }; |
398 | |
399 | FormulaError getError() const { return mnError; } |
400 | double getSum() const { return mfSum; } |
401 | sal_uInt32 getNumberFormat() const { return mnNumFmt; } |
402 | }; |
403 | |
404 | } |
405 | |
406 | static void IterateMatrix( |
407 | const ScMatrixRef& pMat, ScIterFunc eFunc, bool bTextAsZero, SubtotalFlags nSubTotalFlags, |
408 | sal_uLong& rCount, SvNumFormatType& rFuncFmtType, double& fRes, double& fMem ) |
409 | { |
410 | if (!pMat) |
411 | return; |
412 | |
413 | const bool bIgnoreErrVal = bool(nSubTotalFlags & SubtotalFlags::IgnoreErrVal); |
414 | rFuncFmtType = SvNumFormatType::NUMBER; |
415 | switch (eFunc) |
416 | { |
417 | case ifAVERAGE: |
418 | case ifSUM: |
419 | { |
420 | ScMatrix::IterateResult aRes = pMat->Sum(bTextAsZero, bIgnoreErrVal); |
421 | |
422 | |
423 | if ( !std::isfinite(aRes.mfFirst) ) |
424 | { |
425 | sal_uInt32 nErr = reinterpret_cast< sal_math_Double * >(&aRes.mfFirst)->nan_parts.fraction_lo; |
426 | if (nErr & 0xffff0000) |
427 | { |
428 | aRes.mfFirst = 0; |
429 | } |
430 | } |
431 | if ( fMem ) |
432 | fRes += aRes.mfFirst + aRes.mfRest; |
433 | else |
434 | { |
435 | fMem = aRes.mfFirst; |
436 | fRes += aRes.mfRest; |
437 | } |
438 | rCount += aRes.mnCount; |
439 | } |
440 | break; |
441 | case ifCOUNT: |
442 | rCount += pMat->Count(bTextAsZero, false); |
443 | break; |
444 | case ifCOUNT2: |
445 | |
446 | rCount += pMat->Count(true, true); |
447 | break; |
448 | case ifPRODUCT: |
449 | { |
450 | ScMatrix::IterateResult aRes = pMat->Product(bTextAsZero, bIgnoreErrVal); |
451 | fRes *= aRes.mfFirst; |
452 | fRes *= aRes.mfRest; |
453 | rCount += aRes.mnCount; |
454 | } |
455 | break; |
456 | case ifSUMSQ: |
457 | { |
458 | ScMatrix::IterateResult aRes = pMat->SumSquare(bTextAsZero, bIgnoreErrVal); |
459 | fRes += aRes.mfFirst; |
460 | fRes += aRes.mfRest; |
461 | rCount += aRes.mnCount; |
462 | } |
463 | break; |
464 | default: |
465 | ; |
466 | } |
467 | } |
468 | |
469 | size_t ScInterpreter::GetRefListArrayMaxSize( short nParamCount ) |
470 | { |
471 | size_t nSize = 0; |
472 | if (IsInArrayContext()) |
473 | { |
474 | for (short i=1; i <= nParamCount; ++i) |
475 | { |
476 | if (GetStackType(i) == svRefList) |
477 | { |
478 | const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp - i]); |
479 | if (p && p->IsArrayResult() && p->GetRefList()->size() > nSize) |
480 | nSize = p->GetRefList()->size(); |
481 | } |
482 | } |
483 | } |
484 | return nSize; |
485 | } |
486 | |
487 | static double lcl_IterResult( ScIterFunc eFunc, double fRes, double fMem, sal_uLong nCount ) |
488 | { |
489 | switch( eFunc ) |
490 | { |
491 | case ifSUM: |
492 | fRes = ::rtl::math::approxAdd( fRes, fMem ); |
493 | break; |
494 | case ifAVERAGE: |
495 | fRes = sc::div( ::rtl::math::approxAdd( fRes, fMem ), nCount); |
496 | break; |
497 | case ifCOUNT2: |
498 | case ifCOUNT: |
499 | fRes = nCount; |
500 | break; |
501 | case ifPRODUCT: |
502 | if ( !nCount ) |
503 | fRes = 0.0; |
504 | break; |
505 | default: |
506 | ; |
507 | } |
508 | return fRes; |
509 | } |
510 | |
511 | void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero ) |
512 | { |
513 | short nParamCount = GetByte(); |
514 | const SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount); |
515 | ScMatrixRef xResMat, xResCount; |
516 | auto ResInitVal = [eFunc]() |
517 | { |
518 | return (eFunc == ifPRODUCT) ? 1.0 : 0.0; |
519 | }; |
520 | double fRes = ResInitVal(); |
521 | double fVal = 0.0; |
522 | double fMem = 0.0; |
523 | sal_uLong nCount = 0; |
524 | ScAddress aAdr; |
525 | ScRange aRange; |
526 | size_t nRefInList = 0; |
527 | size_t nRefArrayPos = std::numeric_limits<size_t>::max(); |
528 | if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT || |
529 | ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) ) |
530 | nGlobalError = FormulaError::NONE; |
531 | while (nParamCount-- > 0) |
532 | { |
533 | switch (GetStackType()) |
534 | { |
535 | case svString: |
536 | { |
537 | if( eFunc == ifCOUNT ) |
538 | { |
539 | OUString aStr = PopString().getString(); |
540 | if ( bTextAsZero ) |
541 | nCount++; |
542 | else |
543 | { |
544 | |
545 | |
546 | FormulaError nErr = nGlobalError; |
547 | nGlobalError = FormulaError::NONE; |
548 | ConvertStringToValue( aStr ); |
549 | if (nGlobalError == FormulaError::NONE) |
550 | ++nCount; |
551 | nGlobalError = nErr; |
552 | } |
553 | } |
554 | else |
555 | { |
556 | Pop(); |
557 | switch ( eFunc ) |
558 | { |
559 | case ifAVERAGE: |
560 | case ifSUM: |
561 | case ifSUMSQ: |
562 | case ifPRODUCT: |
563 | { |
564 | if ( bTextAsZero ) |
565 | { |
566 | nCount++; |
567 | if ( eFunc == ifPRODUCT ) |
568 | fRes = 0.0; |
569 | } |
570 | else |
571 | { |
572 | while (nParamCount-- > 0) |
573 | Pop(); |
574 | SetError( FormulaError::NoValue ); |
575 | } |
576 | } |
577 | break; |
578 | default: |
579 | nCount++; |
580 | } |
581 | } |
582 | } |
583 | break; |
584 | case svDouble : |
585 | fVal = GetDouble(); |
586 | nCount++; |
587 | switch( eFunc ) |
588 | { |
589 | case ifAVERAGE: |
590 | case ifSUM: |
591 | if ( fMem ) |
592 | fRes += fVal; |
593 | else |
594 | fMem = fVal; |
595 | break; |
596 | case ifSUMSQ: fRes += fVal * fVal; break; |
597 | case ifPRODUCT: fRes *= fVal; break; |
598 | default: ; |
599 | } |
600 | nFuncFmtType = SvNumFormatType::NUMBER; |
601 | break; |
602 | case svExternalSingleRef: |
603 | { |
604 | ScExternalRefCache::TokenRef pToken; |
605 | ScExternalRefCache::CellFormat aFmt; |
606 | PopExternalSingleRef(pToken, &aFmt); |
607 | if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT || |
608 | ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) ) |
609 | { |
610 | nGlobalError = FormulaError::NONE; |
611 | if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) |
612 | ++nCount; |
613 | break; |
614 | } |
615 | |
616 | if (!pToken) |
617 | break; |
618 | |
619 | StackVar eType = pToken->GetType(); |
620 | if (eFunc == ifCOUNT2) |
621 | { |
622 | if ( eType != svEmptyCell && |
623 | ( ( pToken->GetOpCode() != ocSubTotal && |
624 | pToken->GetOpCode() != ocAggregate ) || |
625 | ( mnSubTotalFlags & SubtotalFlags::IgnoreNestedStAg ) ) ) |
626 | nCount++; |
627 | if (nGlobalError != FormulaError::NONE) |
628 | nGlobalError = FormulaError::NONE; |
629 | } |
630 | else if (eType == svDouble) |
631 | { |
632 | nCount++; |
633 | fVal = pToken->GetDouble(); |
634 | if (aFmt.mbIsSet) |
635 | { |
636 | nFuncFmtType = aFmt.mnType; |
637 | nFuncFmtIndex = aFmt.mnIndex; |
638 | } |
639 | switch( eFunc ) |
640 | { |
641 | case ifAVERAGE: |
642 | case ifSUM: |
643 | if ( fMem ) |
644 | fRes += fVal; |
645 | else |
646 | fMem = fVal; |
647 | break; |
648 | case ifSUMSQ: fRes += fVal * fVal; break; |
649 | case ifPRODUCT: fRes *= fVal; break; |
650 | case ifCOUNT: |
651 | if ( nGlobalError != FormulaError::NONE ) |
652 | { |
653 | nGlobalError = FormulaError::NONE; |
654 | nCount--; |
655 | } |
656 | break; |
657 | default: ; |
658 | } |
659 | } |
660 | else if (bTextAsZero && eType == svString) |
661 | { |
662 | nCount++; |
663 | if ( eFunc == ifPRODUCT ) |
664 | fRes = 0.0; |
665 | } |
666 | } |
667 | break; |
668 | case svSingleRef : |
669 | { |
670 | PopSingleRef( aAdr ); |
671 | if (nGlobalError == FormulaError::NoRef) |
672 | { |
673 | PushError( FormulaError::NoRef); |
674 | return; |
675 | } |
676 | |
677 | if ( ( ( mnSubTotalFlags & SubtotalFlags::IgnoreFiltered ) && |
678 | mrDoc.RowFiltered( aAdr.Row(), aAdr.Tab() ) ) || |
679 | ( ( mnSubTotalFlags & SubtotalFlags::IgnoreHidden ) && |
680 | mrDoc.RowHidden( aAdr.Row(), aAdr.Tab() ) ) ) |
681 | { |
682 | break; |
683 | } |
684 | if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT || |
685 | ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) ) |
686 | { |
687 | nGlobalError = FormulaError::NONE; |
688 | if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) |
689 | ++nCount; |
690 | break; |
691 | } |
692 | ScRefCellValue aCell(mrDoc, aAdr); |
693 | if (!aCell.isEmpty()) |
694 | { |
695 | if( eFunc == ifCOUNT2 ) |
696 | { |
697 | CellType eCellType = aCell.meType; |
698 | if ( eCellType != CELLTYPE_NONE ) |
699 | nCount++; |
700 | if ( nGlobalError != FormulaError::NONE ) |
701 | nGlobalError = FormulaError::NONE; |
702 | } |
703 | else if (aCell.hasNumeric()) |
704 | { |
705 | nCount++; |
706 | fVal = GetCellValue(aAdr, aCell); |
707 | CurFmtToFuncFmt(); |
708 | switch( eFunc ) |
709 | { |
710 | case ifAVERAGE: |
711 | case ifSUM: |
712 | if ( fMem ) |
713 | fRes += fVal; |
714 | else |
715 | fMem = fVal; |
716 | break; |
717 | case ifSUMSQ: fRes += fVal * fVal; break; |
718 | case ifPRODUCT: fRes *= fVal; break; |
719 | case ifCOUNT: |
720 | if ( nGlobalError != FormulaError::NONE ) |
721 | { |
722 | nGlobalError = FormulaError::NONE; |
723 | nCount--; |
724 | } |
725 | break; |
726 | default: ; |
727 | } |
728 | } |
729 | else if (bTextAsZero && aCell.hasString()) |
730 | { |
731 | nCount++; |
732 | if ( eFunc == ifPRODUCT ) |
733 | fRes = 0.0; |
734 | } |
735 | } |
736 | } |
737 | break; |
738 | case svRefList : |
739 | { |
740 | const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]); |
741 | if (p && p->IsArrayResult()) |
742 | { |
743 | nRefArrayPos = nRefInList; |
744 | if ((eFunc == ifSUM || eFunc == ifAVERAGE) && fMem != 0.0) |
745 | { |
746 | fRes = rtl::math::approxAdd( fRes, fMem); |
747 | fMem = 0.0; |
748 | } |
749 | |
750 | |
751 | |
752 | if (!xResMat) |
753 | { |
754 | |
755 | assert(nMatRows > 0); |
756 | xResMat = GetNewMat( 1, nMatRows, true); |
757 | xResMat->FillDouble( fRes, 0,0, 0,nMatRows-1); |
758 | if (eFunc != ifSUM) |
759 | { |
760 | xResCount = GetNewMat( 1, nMatRows, true); |
761 | xResCount->FillDouble( nCount, 0,0, 0,nMatRows-1); |
762 | } |
763 | } |
764 | else |
765 | { |
766 | |
767 | |
768 | if (nCount && xResCount) |
769 | { |
770 | for (SCSIZE i=0; i < nMatRows; ++i) |
771 | { |
772 | xResCount->PutDouble( xResCount->GetDouble(0,i) + nCount, 0,i); |
773 | } |
774 | } |
775 | if (fRes != ResInitVal()) |
776 | { |
777 | for (SCSIZE i=0; i < nMatRows; ++i) |
778 | { |
779 | double fVecRes = xResMat->GetDouble(0,i); |
780 | if (eFunc == ifPRODUCT) |
781 | fVecRes *= fRes; |
782 | else |
783 | fVecRes += fRes; |
784 | xResMat->PutDouble( fVecRes, 0,i); |
785 | } |
786 | } |
787 | } |
788 | fRes = ResInitVal(); |
789 | nCount = 0; |
790 | } |
791 | } |
792 | [[fallthrough]]; |
793 | case svDoubleRef : |
794 | { |
795 | PopDoubleRef( aRange, nParamCount, nRefInList); |
796 | if (nGlobalError == FormulaError::NoRef) |
797 | { |
798 | PushError( FormulaError::NoRef); |
799 | return; |
800 | } |
801 | |
802 | if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT || |
803 | ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) ) |
804 | { |
805 | nGlobalError = FormulaError::NONE; |
806 | if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) |
807 | ++nCount; |
808 | if ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) |
809 | break; |
810 | } |
811 | if( eFunc == ifCOUNT2 ) |
812 | { |
813 | ScCellIterator aIter( mrDoc, aRange, mnSubTotalFlags ); |
814 | for (bool bHas = aIter.first(); bHas; bHas = aIter.next()) |
815 | { |
816 | if ( !aIter.isEmpty() ) |
817 | { |
818 | ++nCount; |
819 | } |
820 | } |
821 | |
822 | if ( nGlobalError != FormulaError::NONE ) |
823 | nGlobalError = FormulaError::NONE; |
824 | } |
825 | else if (((eFunc == ifSUM && !bCalcAsShown) || eFunc == ifCOUNT ) |
826 | && mnSubTotalFlags == SubtotalFlags::NONE) |
827 | { |
828 | |
829 | |
830 | |
831 | sc::RangeColumnSpanSet aSet( aRange ); |
832 | |
833 | if ( eFunc == ifSUM ) |
834 | { |
835 | FuncSum aAction(mrContext); |
836 | aSet.executeColumnAction( mrDoc, aAction, fMem ); |
837 | FormulaError nErr = aAction.getError(); |
838 | if ( nErr != FormulaError::NONE ) |
839 | { |
840 | PushError( nErr ); |
841 | return; |
842 | } |
843 | fRes += aAction.getSum(); |
844 | |
845 | |
846 | nFuncFmtIndex = aAction.getNumberFormat(); |
847 | } |
848 | else |
849 | { |
850 | FuncCount aAction(mrContext); |
851 | aSet.executeColumnAction(mrDoc, aAction); |
852 | nCount += aAction.getCount(); |
853 | |
854 | |
855 | nFuncFmtIndex = aAction.getNumberFormat(); |
856 | } |
857 | |
858 | nFuncFmtType = mrContext.GetNumberFormatType( nFuncFmtIndex ); |
859 | } |
860 | else |
861 | { |
862 | ScValueIterator aValIter( mrDoc, aRange, mnSubTotalFlags, bTextAsZero ); |
863 | aValIter.SetInterpreterContext( &mrContext ); |
864 | FormulaError nErr = FormulaError::NONE; |
865 | if (aValIter.GetFirst(fVal, nErr)) |
866 | { |
867 | |
868 | aValIter.GetCurNumFmtInfo( mrContext, nFuncFmtType, nFuncFmtIndex ); |
869 | switch( eFunc ) |
870 | { |
871 | case ifAVERAGE: |
872 | case ifSUM: |
873 | if ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) |
874 | { |
875 | do |
876 | { |
877 | if ( nErr == FormulaError::NONE ) |
878 | { |
879 | SetError(nErr); |
880 | if ( fMem ) |
881 | fRes += fVal; |
882 | else |
883 | fMem = fVal; |
884 | nCount++; |
885 | } |
886 | } |
887 | while (aValIter.GetNext(fVal, nErr)); |
888 | } |
889 | else |
890 | { |
891 | do |
892 | { |
893 | SetError(nErr); |
894 | if ( fMem ) |
895 | fRes += fVal; |
896 | else |
897 | fMem = fVal; |
898 | nCount++; |
899 | } |
900 | while (aValIter.GetNext(fVal, nErr)); |
901 | } |
902 | break; |
903 | case ifSUMSQ: |
904 | if ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) |
905 | { |
906 | do |
907 | { |
908 | if ( nErr == FormulaError::NONE ) |
909 | { |
910 | SetError(nErr); |
911 | fRes += fVal * fVal; |
912 | nCount++; |
913 | } |
914 | } |
915 | while (aValIter.GetNext(fVal, nErr)); |
916 | } |
917 | else |
918 | { |
919 | do |
920 | { |
921 | SetError(nErr); |
922 | fRes += fVal * fVal; |
923 | nCount++; |
924 | } |
925 | while (aValIter.GetNext(fVal, nErr)); |
926 | } |
927 | break; |
928 | case ifPRODUCT: |
929 | do |
930 | { |
931 | if ( !( nErr != FormulaError::NONE && ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) ) |
932 | { |
933 | SetError(nErr); |
934 | fRes *= fVal; |
935 | nCount++; |
936 | } |
937 | } |
938 | while (aValIter.GetNext(fVal, nErr)); |
939 | break; |
940 | case ifCOUNT: |
941 | do |
942 | { |
943 | if ( nErr == FormulaError::NONE ) |
944 | nCount++; |
945 | } |
946 | while (aValIter.GetNext(fVal, nErr)); |
947 | break; |
948 | default: ; |
949 | } |
950 | SetError( nErr ); |
951 | } |
952 | } |
953 | if (nRefArrayPos != std::numeric_limits<size_t>::max()) |
954 | { |
955 | |
956 | if ((eFunc == ifSUM || eFunc == ifAVERAGE) && fMem != 0.0) |
957 | { |
958 | fRes = rtl::math::approxAdd( fRes, fMem); |
959 | fMem = 0.0; |
960 | } |
961 | if (xResCount) |
962 | xResCount->PutDouble( xResCount->GetDouble(0,nRefArrayPos) + nCount, 0,nRefArrayPos); |
963 | double fVecRes = xResMat->GetDouble(0,nRefArrayPos); |
964 | if (eFunc == ifPRODUCT) |
965 | fVecRes *= fRes; |
966 | else |
967 | fVecRes += fRes; |
968 | xResMat->PutDouble( fVecRes, 0,nRefArrayPos); |
969 | |
970 | fRes = ResInitVal(); |
971 | nCount = 0; |
972 | nRefArrayPos = std::numeric_limits<size_t>::max(); |
973 | } |
974 | } |
975 | break; |
976 | case svExternalDoubleRef: |
977 | { |
978 | ScMatrixRef pMat; |
979 | PopExternalDoubleRef(pMat); |
980 | if ( nGlobalError != FormulaError::NONE && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) |
981 | break; |
982 | |
983 | IterateMatrix( pMat, eFunc, bTextAsZero, mnSubTotalFlags, nCount, nFuncFmtType, fRes, fMem ); |
984 | } |
985 | break; |
986 | case svMatrix : |
987 | { |
988 | ScMatrixRef pMat = PopMatrix(); |
989 | |
990 | IterateMatrix( pMat, eFunc, bTextAsZero, mnSubTotalFlags, nCount, nFuncFmtType, fRes, fMem ); |
991 | } |
992 | break; |
993 | case svError: |
994 | { |
995 | PopError(); |
996 | if ( eFunc == ifCOUNT || ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) |
997 | { |
998 | nGlobalError = FormulaError::NONE; |
999 | } |
1000 | else if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) |
1001 | { |
1002 | nCount++; |
1003 | nGlobalError = FormulaError::NONE; |
1004 | } |
1005 | } |
1006 | break; |
1007 | default : |
1008 | while (nParamCount-- > 0) |
1009 | PopError(); |
1010 | SetError(FormulaError::IllegalParameter); |
1011 | } |
1012 | } |
1013 | |
1014 | |
1015 | |
1016 | if( nFuncFmtType == SvNumFormatType::LOGICAL || eFunc == ifCOUNT || eFunc == ifCOUNT2 ) |
1017 | nFuncFmtType = SvNumFormatType::NUMBER; |
1018 | |
1019 | if (xResMat) |
1020 | { |
1021 | |
1022 | for (SCSIZE i=0; i < nMatRows; ++i) |
1023 | { |
1024 | sal_uLong nVecCount = (xResCount ? nCount + xResCount->GetDouble(0,i) : nCount); |
1025 | double fVecRes = xResMat->GetDouble(0,i); |
1026 | if (eFunc == ifPRODUCT) |
1027 | fVecRes *= fRes; |
1028 | else |
1029 | fVecRes += fRes; |
1030 | fVecRes = lcl_IterResult( eFunc, fVecRes, fMem, nVecCount); |
1031 | xResMat->PutDouble( fVecRes, 0,i); |
1032 | } |
1033 | PushMatrix( xResMat); |
1034 | } |
1035 | else |
1036 | { |
1037 | PushDouble( lcl_IterResult( eFunc, fRes, fMem, nCount)); |
1038 | } |
1039 | } |
1040 | |
1041 | void ScInterpreter::ScSumSQ() |
1042 | { |
1043 | IterateParameters( ifSUMSQ ); |
1044 | } |
1045 | |
1046 | void ScInterpreter::ScSum() |
1047 | { |
1048 | IterateParameters( ifSUM ); |
1049 | } |
1050 | |
1051 | void ScInterpreter::ScProduct() |
1052 | { |
1053 | IterateParameters( ifPRODUCT ); |
1054 | } |
1055 | |
1056 | void ScInterpreter::ScAverage( bool bTextAsZero ) |
1057 | { |
1058 | IterateParameters( ifAVERAGE, bTextAsZero ); |
1059 | } |
1060 | |
1061 | void ScInterpreter::ScCount() |
1062 | { |
1063 | IterateParameters( ifCOUNT ); |
1064 | } |
1065 | |
1066 | void ScInterpreter::ScCount2() |
1067 | { |
1068 | IterateParameters( ifCOUNT2 ); |
1069 | } |
1070 | |
1071 | void ScInterpreter::ScRawSubtract() |
1072 | { |
1073 | short nParamCount = GetByte(); |
1074 | if (!MustHaveParamCountMin( nParamCount, 2)) |
1075 | return; |
1076 | |
1077 | |
1078 | const FormulaToken* p = pStack[ sp - nParamCount ]; |
1079 | PushWithoutError( *p ); |
1080 | |
1081 | double fRes = GetDouble(); |
1082 | |
1083 | while (nGlobalError == FormulaError::NONE && nParamCount > 1) |
1084 | { |
1085 | |
1086 | fRes -= GetDouble(); |
1087 | --nParamCount; |
1088 | } |
1089 | while (nParamCount-- > 0) |
1090 | PopError(); |
1091 | |
1092 | PushDouble( fRes); |
1093 | } |
1094 | |
1095 | |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | #ifndef INCLUDED_SC_INC_MTVFUNCTIONS_HXX |
11 | #define INCLUDED_SC_INC_MTVFUNCTIONS_HXX |
12 | |
13 | #include <cstdlib> |
14 | #include <mdds/multi_type_vector_types.hpp> |
15 | |
16 | namespace sc { |
17 | |
18 | template<typename SizeT, typename Ret = bool> |
19 | struct FuncElseNoOp |
20 | { |
21 | Ret operator() (mdds::mtv::element_t, SizeT, SizeT) const |
22 | { |
23 | return Ret(); |
24 | } |
25 | }; |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | template<typename StoreT, typename Func> |
32 | typename StoreT::const_iterator |
33 | ParseBlock( |
34 | const typename StoreT::const_iterator& itPos, const StoreT& rStore, Func& rFunc, |
35 | typename StoreT::size_type nStart, typename StoreT::size_type nEnd) |
36 | { |
37 | typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType; |
38 | |
39 | PositionType aPos = rStore.position(itPos, nStart); |
40 | typename StoreT::const_iterator it = aPos.first; |
41 | typename StoreT::size_type nOffset = aPos.second; |
42 | typename StoreT::size_type nDataSize = 0; |
43 | typename StoreT::size_type nTopRow = nStart; |
44 | |
45 | for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize) |
| 6 | | Assuming the condition is true | |
|
| 7 | | Assuming 'nTopRow' is <= 'nEnd' | |
|
| 8 | | Loop condition is true. Entering loop body | |
|
46 | { |
47 | bool bLastBlock = false; |
48 | nDataSize = it->size - nOffset; |
49 | if (nTopRow + nDataSize - 1 > nEnd) |
| 9 | | Assuming the condition is false | |
|
| |
50 | { |
51 | |
52 | nDataSize = nEnd - nTopRow + 1; |
53 | bLastBlock = true; |
54 | } |
55 | |
56 | rFunc(*it, nOffset, nDataSize); |
| 11 | | Calling 'NumericCellAccumulator::operator()' | |
|
57 | |
58 | if (bLastBlock) |
59 | break; |
60 | } |
61 | |
62 | return it; |
63 | } |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | template<typename StoreT, typename Func> |
70 | typename StoreT::iterator |
71 | ProcessBlock(const typename StoreT::iterator& itPos, StoreT& rStore, Func& rFunc, typename StoreT::size_type nStart, typename StoreT::size_type nEnd) |
72 | { |
73 | typedef std::pair<typename StoreT::iterator, typename StoreT::size_type> PositionType; |
74 | |
75 | PositionType aPos = rStore.position(itPos, nStart); |
76 | typename StoreT::iterator it = aPos.first; |
77 | typename StoreT::size_type nOffset = aPos.second; |
78 | typename StoreT::size_type nDataSize = 0; |
79 | typename StoreT::size_type nCurRow = nStart; |
80 | |
81 | for (; it != rStore.end() && nCurRow <= nEnd; ++it, nOffset = 0, nCurRow += nDataSize) |
82 | { |
83 | bool bLastBlock = false; |
84 | nDataSize = it->size - nOffset; |
85 | if (nCurRow + nDataSize - 1 > nEnd) |
86 | { |
87 | |
88 | nDataSize = nEnd - nCurRow + 1; |
89 | bLastBlock = true; |
90 | } |
91 | |
92 | rFunc(*it, nOffset, nDataSize); |
93 | |
94 | if (bLastBlock) |
95 | break; |
96 | } |
97 | |
98 | return it; |
99 | } |
100 | |
101 | template<typename BlkT, typename ItrT, typename NodeT, typename FuncElem> |
102 | void EachElem(NodeT& rNode, size_t nOffset, size_t nDataSize, FuncElem& rFuncElem) |
103 | { |
104 | ItrT it = BlkT::begin(*rNode.data); |
105 | std::advance(it, nOffset); |
106 | ItrT itEnd = it; |
107 | std::advance(itEnd, nDataSize); |
108 | size_t nRow = rNode.position + nOffset; |
109 | for (; it != itEnd; ++it, ++nRow) |
110 | rFuncElem(nRow, *it); |
111 | } |
112 | |
113 | template<typename BlkT, typename ItrT, typename NodeT, typename FuncElem> |
114 | void EachElem(NodeT& rNode, FuncElem& rFuncElem) |
115 | { |
116 | auto it = BlkT::begin(*rNode.data); |
117 | auto itEnd = BlkT::end(*rNode.data); |
118 | size_t nRow = rNode.position; |
119 | for (; it != itEnd; ++it, ++nRow) |
120 | rFuncElem(nRow, *it); |
121 | } |
122 | |
123 | template<typename BlkT, typename ItrT, typename NodeT, typename FuncElem> |
124 | void EachElemReverse(NodeT& rNode, FuncElem& rFuncElem) |
125 | { |
126 | auto it = BlkT::rbegin(*rNode.data); |
127 | auto itEnd = BlkT::rend(*rNode.data); |
128 | size_t nRow = rNode.position; |
129 | for (; it != itEnd; ++it, ++nRow) |
130 | rFuncElem(nRow, *it); |
131 | } |
132 | |
133 | template<typename BlkT, typename StoreT, typename FuncElem> |
134 | std::pair<typename StoreT::const_iterator, size_t> |
135 | CheckElem( |
136 | const StoreT& rStore, const typename StoreT::const_iterator& it, size_t nOffset, size_t nDataSize, |
137 | FuncElem& rFuncElem) |
138 | { |
139 | typedef std::pair<typename StoreT::const_iterator, size_t> PositionType; |
140 | |
141 | typename BlkT::const_iterator itData = BlkT::begin(*it->data); |
142 | std::advance(itData, nOffset); |
143 | typename BlkT::const_iterator itDataEnd = itData; |
144 | std::advance(itDataEnd, nDataSize); |
145 | size_t nTopRow = it->position + nOffset; |
146 | size_t nRow = nTopRow; |
147 | for (; itData != itDataEnd; ++itData, ++nRow) |
148 | { |
149 | if (rFuncElem(nRow, *itData)) |
150 | return PositionType(it, nRow - it->position); |
151 | } |
152 | |
153 | return PositionType(rStore.end(), 0); |
154 | } |
155 | |
156 | template<typename StoreT, typename BlkT, typename FuncElem, typename FuncElse> |
157 | void ParseElements1(const StoreT& rStore, FuncElem& rFuncElem, FuncElse& rFuncElse) |
158 | { |
159 | typename StoreT::size_type nTopRow = 0, nDataSize = 0; |
160 | typename StoreT::const_iterator it = rStore.begin(), itEnd = rStore.end(); |
161 | for (; it != itEnd; ++it, nTopRow += nDataSize) |
162 | { |
163 | nDataSize = it->size; |
164 | if (it->type != BlkT::block_type) |
165 | { |
166 | rFuncElse(it->type, nTopRow, nDataSize); |
167 | continue; |
168 | } |
169 | |
170 | EachElem<BlkT, typename BlkT::const_iterator>(*it, rFuncElem); |
171 | } |
172 | } |
173 | |
174 | template<typename StoreT, typename BlkT, typename FuncElem, typename FuncElse> |
175 | typename StoreT::const_iterator |
176 | ParseElements1( |
177 | const typename StoreT::const_iterator& itPos, const StoreT& rStore, |
178 | typename StoreT::size_type nStart, typename StoreT::size_type nEnd, |
179 | FuncElem& rFuncElem, FuncElse& rFuncElse) |
180 | { |
181 | typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType; |
182 | |
183 | PositionType aPos = rStore.position(itPos, nStart); |
184 | typename StoreT::const_iterator it = aPos.first; |
185 | typename StoreT::size_type nOffset = aPos.second; |
186 | typename StoreT::size_type nDataSize = 0; |
187 | typename StoreT::size_type nTopRow = nStart; |
188 | |
189 | for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize) |
190 | { |
191 | bool bLastBlock = false; |
192 | nDataSize = it->size - nOffset; |
193 | if (nTopRow + nDataSize - 1 > nEnd) |
194 | { |
195 | |
196 | nDataSize = nEnd - nTopRow + 1; |
197 | bLastBlock = true; |
198 | } |
199 | |
200 | if (it->type == BlkT::block_type) |
201 | EachElem<BlkT, typename BlkT::const_iterator>(*it, nOffset, nDataSize, rFuncElem); |
202 | else |
203 | rFuncElse(it->type, nTopRow, nDataSize); |
204 | |
205 | if (bLastBlock) |
206 | break; |
207 | } |
208 | |
209 | return it; |
210 | }; |
211 | |
212 | template<typename StoreT, typename Blk1, typename Blk2, typename FuncElem, typename FuncElse> |
213 | typename StoreT::const_iterator |
214 | ParseElements2( |
215 | const typename StoreT::const_iterator& itPos, const StoreT& rStore, typename StoreT::size_type nStart, typename StoreT::size_type nEnd, |
216 | FuncElem& rFuncElem, FuncElse& rFuncElse) |
217 | { |
218 | typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType; |
219 | |
220 | PositionType aPos = rStore.position(itPos, nStart); |
221 | typename StoreT::const_iterator it = aPos.first; |
222 | typename StoreT::size_type nOffset = aPos.second; |
223 | typename StoreT::size_type nDataSize = 0; |
224 | typename StoreT::size_type nTopRow = nStart; |
225 | |
226 | for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize) |
227 | { |
228 | bool bLastBlock = false; |
229 | nDataSize = it->size - nOffset; |
230 | if (nTopRow + nDataSize - 1 > nEnd) |
231 | { |
232 | |
233 | nDataSize = nEnd - nTopRow + 1; |
234 | bLastBlock = true; |
235 | } |
236 | |
237 | switch (it->type) |
238 | { |
239 | case Blk1::block_type: |
240 | EachElem<Blk1, typename Blk1::const_iterator>(*it, nOffset, nDataSize, rFuncElem); |
241 | break; |
242 | case Blk2::block_type: |
243 | EachElem<Blk2, typename Blk2::const_iterator>(*it, nOffset, nDataSize, rFuncElem); |
244 | break; |
245 | default: |
246 | rFuncElse(it->type, nTopRow, nDataSize); |
247 | } |
248 | |
249 | if (bLastBlock) |
250 | break; |
251 | } |
252 | |
253 | return it; |
254 | } |
255 | |
256 | template<typename StoreT, typename Blk1, typename Blk2, typename Blk3, typename Blk4, typename FuncElem, typename FuncElse> |
257 | typename StoreT::const_iterator |
258 | ParseElements4( |
259 | const typename StoreT::const_iterator& itPos, const StoreT& rStore, typename StoreT::size_type nStart, typename StoreT::size_type nEnd, |
260 | FuncElem& rFuncElem, FuncElse& rFuncElse) |
261 | { |
262 | typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType; |
263 | |
264 | PositionType aPos = rStore.position(itPos, nStart); |
265 | typename StoreT::const_iterator it = aPos.first; |
266 | typename StoreT::size_type nOffset = aPos.second; |
267 | typename StoreT::size_type nDataSize = 0; |
268 | typename StoreT::size_type nTopRow = nStart; |
269 | |
270 | for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize) |
271 | { |
272 | bool bLastBlock = false; |
273 | nDataSize = it->size - nOffset; |
274 | if (nTopRow + nDataSize - 1 > nEnd) |
275 | { |
276 | |
277 | nDataSize = nEnd - nTopRow + 1; |
278 | bLastBlock = true; |
279 | } |
280 | |
281 | switch (it->type) |
282 | { |
283 | case Blk1::block_type: |
284 | EachElem<Blk1, typename Blk1::const_iterator>(*it, nOffset, nDataSize, rFuncElem); |
285 | break; |
286 | case Blk2::block_type: |
287 | EachElem<Blk2, typename Blk2::const_iterator>(*it, nOffset, nDataSize, rFuncElem); |
288 | break; |
289 | case Blk3::block_type: |
290 | EachElem<Blk3, typename Blk3::const_iterator>(*it, nOffset, nDataSize, rFuncElem); |
291 | break; |
292 | case Blk4::block_type: |
293 | EachElem<Blk4, typename Blk4::const_iterator>(*it, nOffset, nDataSize, rFuncElem); |
294 | break; |
295 | default: |
296 | rFuncElse(it->type, nTopRow, nDataSize); |
297 | } |
298 | |
299 | if (bLastBlock) |
300 | break; |
301 | } |
302 | |
303 | return it; |
304 | } |
305 | |
306 | template<typename StoreT, typename BlkT, typename FuncElem, typename FuncElse> |
307 | void ProcessElements1(StoreT& rStore, FuncElem& rFuncElem, FuncElse& rFuncElse) |
308 | { |
309 | typename StoreT::size_type nTopRow = 0, nDataSize = 0; |
310 | typename StoreT::iterator it = rStore.begin(), itEnd = rStore.end(); |
311 | for (; it != itEnd; ++it, nTopRow += nDataSize) |
312 | { |
313 | nDataSize = it->size; |
314 | if (it->type != BlkT::block_type) |
315 | { |
316 | rFuncElse(it->type, nTopRow, nDataSize); |
317 | continue; |
318 | } |
319 | |
320 | EachElem<BlkT, typename BlkT::iterator>(*it, rFuncElem); |
321 | } |
322 | } |
323 | |
324 | |
325 | |
326 | |
327 | template<typename StoreT, typename BlkT, typename FuncElem, typename FuncElse> |
328 | typename StoreT::iterator |
329 | ProcessElements1( |
330 | const typename StoreT::iterator& itPos, StoreT& rStore, |
331 | typename StoreT::size_type nStart, typename StoreT::size_type nEnd, |
332 | FuncElem& rFuncElem, FuncElse& rFuncElse) |
333 | { |
334 | typedef std::pair<typename StoreT::iterator, typename StoreT::size_type> PositionType; |
335 | |
336 | PositionType aPos = rStore.position(itPos, nStart); |
337 | typename StoreT::iterator it = aPos.first; |
338 | typename StoreT::size_type nOffset = aPos.second; |
339 | typename StoreT::size_type nDataSize = 0; |
340 | typename StoreT::size_type nTopRow = nStart; |
341 | |
342 | for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize) |
343 | { |
344 | bool bLastBlock = false; |
345 | nDataSize = it->size - nOffset; |
346 | if (nTopRow + nDataSize - 1 > nEnd) |
347 | { |
348 | |
349 | nDataSize = nEnd - nTopRow + 1; |
350 | bLastBlock = true; |
351 | } |
352 | |
353 | if (it->type == BlkT::block_type) |
354 | EachElem<BlkT, typename BlkT::iterator>(*it, nOffset, nDataSize, rFuncElem); |
355 | else |
356 | rFuncElse(it->type, nTopRow, nDataSize); |
357 | |
358 | if (bLastBlock) |
359 | break; |
360 | } |
361 | |
362 | return it; |
363 | }; |
364 | |
365 | template<typename StoreT, typename Blk1, typename Blk2, typename FuncElem, typename FuncElse> |
366 | void ProcessElements2(StoreT& rStore, FuncElem& rFuncElem, FuncElse& rFuncElse) |
367 | { |
368 | typename StoreT::size_type nTopRow = 0, nDataSize = 0; |
369 | typename StoreT::iterator it = rStore.begin(), itEnd = rStore.end(); |
370 | for (; it != itEnd; ++it, nTopRow += nDataSize) |
371 | { |
372 | nDataSize = it->size; |
373 | switch (it->type) |
374 | { |
375 | case Blk1::block_type: |
376 | EachElem<Blk1, typename Blk1::iterator>(*it, rFuncElem); |
377 | break; |
378 | case Blk2::block_type: |
379 | EachElem<Blk2, typename Blk2::iterator>(*it, rFuncElem); |
380 | break; |
381 | default: |
382 | rFuncElse(it->type, nTopRow, nDataSize); |
383 | } |
384 | } |
385 | } |
386 | |
387 | template<typename StoreT, typename Blk1, typename Blk2, typename FuncElem, typename FuncElse> |
388 | void ProcessElements2Reverse(StoreT& rStore, FuncElem& rFuncElem, FuncElse& rFuncElse) |
389 | { |
390 | typename StoreT::size_type nTopRow = 0, nDataSize = 0; |
391 | typename StoreT::iterator it = rStore.begin(), itEnd = rStore.end(); |
392 | for (; it != itEnd; ++it, nTopRow += nDataSize) |
393 | { |
394 | nDataSize = it->size; |
395 | switch (it->type) |
396 | { |
397 | case Blk1::block_type: |
398 | EachElemReverse<Blk1, typename Blk1::iterator>(*it, rFuncElem); |
399 | break; |
400 | case Blk2::block_type: |
401 | EachElemReverse<Blk2, typename Blk2::iterator>(*it, rFuncElem); |
402 | break; |
403 | default: |
404 | rFuncElse(it->type, nTopRow, nDataSize); |
405 | } |
406 | } |
407 | } |
408 | |
409 | template<typename StoreT, typename Blk1, typename FuncElem, typename FuncElse> |
410 | std::pair<typename StoreT::const_iterator, typename StoreT::size_type> |
411 | FindElement1( |
412 | const StoreT& rStore, typename StoreT::size_type nStart, typename StoreT::size_type nEnd, |
413 | FuncElem& rFuncElem, FuncElse& rFuncElse) |
414 | { |
415 | typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType; |
416 | typedef std::pair<typename StoreT::size_type, bool> ElseRetType; |
417 | |
418 | PositionType aPos = rStore.position(nStart); |
419 | typename StoreT::const_iterator it = aPos.first; |
420 | typename StoreT::size_type nOffset = aPos.second; |
421 | typename StoreT::size_type nDataSize = 0; |
422 | typename StoreT::size_type nTopRow = nStart; |
423 | |
424 | for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize) |
425 | { |
426 | bool bLastBlock = false; |
427 | nDataSize = it->size - nOffset; |
428 | if (nTopRow + nDataSize - 1 > nEnd) |
429 | { |
430 | |
431 | nDataSize = nEnd - nTopRow + 1; |
432 | bLastBlock = true; |
433 | } |
434 | |
435 | switch (it->type) |
436 | { |
437 | case Blk1::block_type: |
438 | { |
439 | PositionType aRet = CheckElem<Blk1>(rStore, it, nOffset, nDataSize, rFuncElem); |
440 | if (aRet.first != rStore.end()) |
441 | return aRet; |
442 | } |
443 | break; |
444 | default: |
445 | { |
446 | ElseRetType aRet = rFuncElse(it->type, nTopRow, nDataSize); |
447 | if (aRet.second) |
448 | return PositionType(it, aRet.first); |
449 | } |
450 | } |
451 | |
452 | if (bLastBlock) |
453 | break; |
454 | } |
455 | |
456 | return PositionType(rStore.end(), 0); |
457 | } |
458 | |
459 | template<typename StoreT, typename Blk1, typename Blk2, typename FuncElem, typename FuncElse> |
460 | std::pair<typename StoreT::const_iterator, typename StoreT::size_type> |
461 | FindElement2( |
462 | const StoreT& rStore, typename StoreT::size_type nStart, typename StoreT::size_type nEnd, |
463 | FuncElem& rFuncElem, FuncElse& rFuncElse) |
464 | { |
465 | typedef std::pair<typename StoreT::const_iterator, typename StoreT::size_type> PositionType; |
466 | typedef std::pair<typename StoreT::size_type, bool> ElseRetType; |
467 | |
468 | PositionType aPos = rStore.position(nStart); |
469 | typename StoreT::const_iterator it = aPos.first; |
470 | typename StoreT::size_type nOffset = aPos.second; |
471 | typename StoreT::size_type nDataSize = 0; |
472 | typename StoreT::size_type nTopRow = nStart; |
473 | |
474 | for (; it != rStore.end() && nTopRow <= nEnd; ++it, nOffset = 0, nTopRow += nDataSize) |
475 | { |
476 | bool bLastBlock = false; |
477 | nDataSize = it->size - nOffset; |
478 | if (nTopRow + nDataSize - 1 > nEnd) |
479 | { |
480 | |
481 | nDataSize = nEnd - nTopRow + 1; |
482 | bLastBlock = true; |
483 | } |
484 | |
485 | switch (it->type) |
486 | { |
487 | case Blk1::block_type: |
488 | { |
489 | PositionType aRet = CheckElem<Blk1>(rStore, it, nOffset, nDataSize, rFuncElem); |
490 | if (aRet.first != rStore.end()) |
491 | return aRet; |
492 | } |
493 | break; |
494 | case Blk2::block_type: |
495 | { |
496 | PositionType aRet = CheckElem<Blk2>(rStore, it, nOffset, nDataSize, rFuncElem); |
497 | if (aRet.first != rStore.end()) |
498 | return aRet; |
499 | } |
500 | break; |
501 | default: |
502 | { |
503 | ElseRetType aRet = rFuncElse(*it, nOffset, nDataSize); |
504 | if (aRet.second) |
505 | return PositionType(it, aRet.first); |
506 | } |
507 | } |
508 | |
509 | if (bLastBlock) |
510 | break; |
511 | } |
512 | |
513 | return PositionType(rStore.end(), 0); |
514 | } |
515 | |
516 | } |
517 | |
518 | #endif |
519 | |
520 | |