Resolves: tdf#162093 TableRef item specifier may occur standalone
[LibreOffice.git] / sc / source / core / tool / token.cxx
blob9881f33e2f6a70bdb72a97ccde54bbd246083812
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 <functional>
22 #include <string.h>
23 #include <osl/diagnose.h>
24 #include <sal/log.hxx>
26 #include <token.hxx>
27 #include <tokenarray.hxx>
28 #include <reftokenhelper.hxx>
29 #include <clipparam.hxx>
30 #include <compiler.hxx>
31 #include <interpre.hxx>
32 #include <formula/FormulaCompiler.hxx>
33 #include <formula/compiler.hxx>
34 #include <formula/opcode.hxx>
35 #include <jumpmatrix.hxx>
36 #include <rangeseq.hxx>
37 #include <rangeutl.hxx>
38 #include <externalrefmgr.hxx>
39 #include <document.hxx>
40 #include <refupdatecontext.hxx>
41 #include <tokenstringcontext.hxx>
42 #include <types.hxx>
43 #include <addincol.hxx>
44 #include <dbdata.hxx>
45 #include <reordermap.hxx>
46 #include <svl/sharedstring.hxx>
47 #include <scmatrix.hxx>
49 #include <com/sun/star/sheet/ComplexReference.hpp>
50 #include <com/sun/star/sheet/ExternalReference.hpp>
51 #include <com/sun/star/sheet/FormulaToken.hpp>
52 #include <com/sun/star/sheet/ReferenceFlags.hpp>
53 #include <com/sun/star/sheet/NameToken.hpp>
54 #include <utility>
55 #include <o3tl/safeint.hxx>
56 #include <o3tl/sorted_vector.hxx>
58 using ::std::vector;
59 using namespace formula;
60 using namespace com::sun::star;
62 namespace
64 void lcl_SingleRefToCalc( ScSingleRefData& rRef, const sheet::SingleReference& rAPI )
66 rRef.InitFlags();
68 rRef.SetColRel( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_RELATIVE ) != 0 );
69 rRef.SetRowRel( ( rAPI.Flags & sheet::ReferenceFlags::ROW_RELATIVE ) != 0 );
70 rRef.SetTabRel( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_RELATIVE ) != 0 );
71 rRef.SetColDeleted( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_DELETED ) != 0 );
72 rRef.SetRowDeleted( ( rAPI.Flags & sheet::ReferenceFlags::ROW_DELETED ) != 0 );
73 rRef.SetTabDeleted( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_DELETED ) != 0 );
74 rRef.SetFlag3D( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_3D ) != 0 );
75 rRef.SetRelName( ( rAPI.Flags & sheet::ReferenceFlags::RELATIVE_NAME ) != 0 );
77 if (rRef.IsColRel())
78 rRef.SetRelCol(static_cast<SCCOL>(rAPI.RelativeColumn));
79 else
80 rRef.SetAbsCol(static_cast<SCCOL>(rAPI.Column));
82 if (rRef.IsRowRel())
83 rRef.SetRelRow(static_cast<SCROW>(rAPI.RelativeRow));
84 else
85 rRef.SetAbsRow(static_cast<SCROW>(rAPI.Row));
87 if (rRef.IsTabRel())
88 rRef.SetRelTab(static_cast<SCTAB>(rAPI.RelativeSheet));
89 else
90 rRef.SetAbsTab(static_cast<SCTAB>(rAPI.Sheet));
93 void lcl_ExternalRefToCalc( ScSingleRefData& rRef, const sheet::SingleReference& rAPI )
95 rRef.InitFlags();
97 rRef.SetColRel( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_RELATIVE ) != 0 );
98 rRef.SetRowRel( ( rAPI.Flags & sheet::ReferenceFlags::ROW_RELATIVE ) != 0 );
99 rRef.SetColDeleted( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_DELETED ) != 0 );
100 rRef.SetRowDeleted( ( rAPI.Flags & sheet::ReferenceFlags::ROW_DELETED ) != 0 );
101 rRef.SetTabDeleted( false ); // sheet must not be deleted for external refs
102 rRef.SetFlag3D( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_3D ) != 0 );
103 rRef.SetRelName( false );
105 if (rRef.IsColRel())
106 rRef.SetRelCol(static_cast<SCCOL>(rAPI.RelativeColumn));
107 else
108 rRef.SetAbsCol(static_cast<SCCOL>(rAPI.Column));
110 if (rRef.IsRowRel())
111 rRef.SetRelRow(static_cast<SCROW>(rAPI.RelativeRow));
112 else
113 rRef.SetAbsRow(static_cast<SCROW>(rAPI.Row));
115 // sheet index must be absolute for external refs
116 rRef.SetAbsTab(0);
119 struct TokenPointerRange
121 FormulaToken** mpStart;
122 FormulaToken** mpStop;
124 TokenPointerRange() : mpStart(nullptr), mpStop(nullptr) {}
125 TokenPointerRange( FormulaToken** p, sal_uInt16 n ) :
126 mpStart(p), mpStop( p + static_cast<size_t>(n)) {}
128 struct TokenPointers
130 TokenPointerRange maPointerRange[2];
131 bool mbSkipRelName;
133 TokenPointers( FormulaToken** pCode, sal_uInt16 nLen, FormulaToken** pRPN, sal_uInt16 nRPN,
134 bool bSkipRelName = true ) :
135 mbSkipRelName(bSkipRelName)
137 maPointerRange[0] = TokenPointerRange( pCode, nLen);
138 maPointerRange[1] = TokenPointerRange( pRPN, nRPN);
141 bool skipToken( size_t i, const FormulaToken* const * pp )
143 // Handle all code tokens, and tokens in RPN only if they have a
144 // reference count of 1, which means they are not referenced in the
145 // code array. Doing it the other way would skip code tokens that
146 // are held by flat copied token arrays and thus are shared. For
147 // flat copy arrays the caller has to know what it does and should
148 // discard all RPN, update only one array and regenerate all RPN.
149 if (i == 1)
151 if ((*pp)->GetRef() > 1)
152 return true;
154 if (mbSkipRelName)
156 // Skip (do not adjust) relative references resulting from
157 // named expressions. Resolved expressions are only in RPN.
158 switch ((*pp)->GetType())
160 case svSingleRef:
161 return (*pp)->GetSingleRef()->IsRelName();
162 case svDoubleRef:
164 const ScComplexRefData& rRef = *(*pp)->GetDoubleRef();
165 return rRef.Ref1.IsRelName() || rRef.Ref2.IsRelName();
167 default:
168 ; // nothing
173 return false;
176 FormulaToken* getHandledToken( size_t i, FormulaToken* const * pp )
178 if (skipToken( i, pp))
179 return nullptr;
181 FormulaToken* p = *pp;
182 if (p->GetOpCode() == ocTableRef)
184 // Return the inner reference token if it is not in RPN.
185 ScTableRefToken* pTR = dynamic_cast<ScTableRefToken*>(p);
186 if (!pTR)
187 return p;
188 p = pTR->GetAreaRefRPN();
189 if (!p)
190 return pTR;
191 if (p->GetRef() > 1)
192 // Reference handled in RPN, but do not return nullptr so
193 // loops will process ocTableRef via pp instead of issuing
194 // a continue.
195 return pTR;
197 return p;
201 } // namespace
204 // --- class ScRawToken -----------------------------------------------------
206 void ScRawToken::SetOpCode( OpCode e )
208 eOp = e;
209 switch (eOp)
211 case ocIf:
212 eType = svJump;
213 nJump[ 0 ] = 3; // If, Else, Behind
214 break;
215 case ocIfError:
216 case ocIfNA:
217 eType = svJump;
218 nJump[ 0 ] = 2; // If, Behind
219 break;
220 case ocChoose:
221 eType = svJump;
222 nJump[ 0 ] = FORMULA_MAXJUMPCOUNT + 1;
223 break;
224 case ocLet:
225 eType = svJump;
226 nJump[ 0 ] = FORMULA_MAXPARAMS + 1;
227 break;
228 case ocMissing:
229 eType = svMissing;
230 break;
231 case ocSep:
232 case ocOpen:
233 case ocClose:
234 case ocArrayRowSep:
235 case ocArrayColSep:
236 case ocArrayOpen:
237 case ocArrayClose:
238 case ocTableRefOpen:
239 case ocTableRefClose:
240 eType = svSep;
241 break;
242 case ocWhitespace:
243 eType = svByte;
244 whitespace.nCount = 1;
245 whitespace.cChar = 0x20;
246 break;
247 default:
248 eType = svByte;
249 sbyte.cByte = 0;
250 sbyte.eInForceArray = ParamClass::Unknown;
254 void ScRawToken::SetString( rtl_uString* pData, rtl_uString* pDataIgnoreCase )
256 eOp = ocPush;
257 eType = svString;
259 sharedstring.mpData = pData;
260 sharedstring.mpDataIgnoreCase = pDataIgnoreCase;
263 void ScRawToken::SetStringName( rtl_uString* pData, rtl_uString* pDataIgnoreCase )
265 eOp = ocStringName;
266 eType = svString;
268 sharedstring.mpData = pData;
269 sharedstring.mpDataIgnoreCase = pDataIgnoreCase;
272 void ScRawToken::SetSingleReference( const ScSingleRefData& rRef )
274 eOp = ocPush;
275 eType = svSingleRef;
276 aRef.Ref1 =
277 aRef.Ref2 = rRef;
280 void ScRawToken::SetDoubleReference( const ScComplexRefData& rRef )
282 eOp = ocPush;
283 eType = svDoubleRef;
284 aRef = rRef;
287 void ScRawToken::SetDouble(double rVal)
289 eOp = ocPush;
290 eType = svDouble;
291 nValue = rVal;
294 void ScRawToken::SetErrorConstant( FormulaError nErr )
296 eOp = ocPush;
297 eType = svError;
298 nError = nErr;
301 void ScRawToken::SetName(sal_Int16 nSheet, sal_uInt16 nIndex)
303 eOp = ocName;
304 eType = svIndex;
306 name.nSheet = nSheet;
307 name.nIndex = nIndex;
310 void ScRawToken::SetExternalSingleRef( sal_uInt16 nFileId, const OUString& rTabName, const ScSingleRefData& rRef )
312 eOp = ocPush;
313 eType = svExternalSingleRef;
315 extref.nFileId = nFileId;
316 extref.aRef.Ref1 =
317 extref.aRef.Ref2 = rRef;
318 maExternalName = rTabName;
321 void ScRawToken::SetExternalDoubleRef( sal_uInt16 nFileId, const OUString& rTabName, const ScComplexRefData& rRef )
323 eOp = ocPush;
324 eType = svExternalDoubleRef;
326 extref.nFileId = nFileId;
327 extref.aRef = rRef;
328 maExternalName = rTabName;
331 void ScRawToken::SetExternalName( sal_uInt16 nFileId, const OUString& rName )
333 eOp = ocPush;
334 eType = svExternalName;
336 extname.nFileId = nFileId;
337 maExternalName = rName;
340 void ScRawToken::SetExternal( const OUString& rStr )
342 eOp = ocExternal;
343 eType = svExternal;
344 maExternalName = rStr;
347 bool ScRawToken::IsValidReference(const ScDocument& rDoc) const
349 switch (eType)
351 case svSingleRef:
352 return aRef.Ref1.Valid(rDoc);
353 case svDoubleRef:
354 return aRef.Valid(rDoc);
355 case svExternalSingleRef:
356 case svExternalDoubleRef:
357 return true;
358 default:
359 ; // nothing
361 return false;
364 FormulaToken* ScRawToken::CreateToken(ScSheetLimits& rLimits) const
366 #define IF_NOT_OPCODE_ERROR(o,c) SAL_WARN_IF((eOp!=o), "sc.core", #c "::ctor: OpCode " << static_cast<int>(eOp) << " lost, converted to " #o "; maybe inherit from FormulaToken instead!")
367 switch ( GetType() )
369 case svByte :
370 if (eOp == ocWhitespace)
371 return new FormulaSpaceToken( whitespace.nCount, whitespace.cChar );
372 else
373 return new FormulaByteToken( eOp, sbyte.cByte, sbyte.eInForceArray );
374 case svDouble :
375 IF_NOT_OPCODE_ERROR( ocPush, FormulaDoubleToken);
376 return new FormulaDoubleToken( nValue );
377 case svString :
379 svl::SharedString aSS(sharedstring.mpData, sharedstring.mpDataIgnoreCase);
380 if (eOp == ocPush)
381 return new FormulaStringToken(std::move(aSS));
382 else
383 return new FormulaStringOpToken(eOp, std::move(aSS));
385 case svSingleRef :
386 return new ScSingleRefToken(rLimits, aRef.Ref1, eOp);
387 case svDoubleRef :
388 return new ScDoubleRefToken(rLimits, aRef, eOp);
389 case svMatrix :
390 IF_NOT_OPCODE_ERROR( ocPush, ScMatrixToken);
391 return new ScMatrixToken( pMat );
392 case svIndex :
393 if (eOp == ocTableRef)
394 return new ScTableRefToken( table.nIndex, table.eItem);
395 else
396 return new FormulaIndexToken( eOp, name.nIndex, name.nSheet);
397 case svExternalSingleRef:
399 svl::SharedString aTabName(maExternalName); // string not interned
400 return new ScExternalSingleRefToken(extref.nFileId, std::move(aTabName), extref.aRef.Ref1);
402 case svExternalDoubleRef:
404 svl::SharedString aTabName(maExternalName); // string not interned
405 return new ScExternalDoubleRefToken(extref.nFileId, std::move(aTabName), extref.aRef);
407 case svExternalName:
409 svl::SharedString aName(maExternalName); // string not interned
410 return new ScExternalNameToken( extname.nFileId, std::move(aName) );
412 case svJump :
413 return new FormulaJumpToken( eOp, nJump );
414 case svExternal :
415 return new FormulaExternalToken( eOp, sbyte.cByte, maExternalName );
416 case svFAP :
417 return new FormulaFAPToken( eOp, sbyte.cByte, nullptr );
418 case svMissing :
419 IF_NOT_OPCODE_ERROR( ocMissing, FormulaMissingToken);
420 return new FormulaMissingToken;
421 case svSep :
422 return new FormulaToken( svSep,eOp );
423 case svError :
424 return new FormulaErrorToken( nError );
425 case svUnknown :
426 return new FormulaUnknownToken( eOp );
427 default:
429 SAL_WARN("sc.core", "unknown ScRawToken::CreateToken() type " << int(GetType()));
430 return new FormulaUnknownToken( ocBad );
433 #undef IF_NOT_OPCODE_ERROR
436 namespace {
438 // TextEqual: if same formula entered (for optimization in sort)
439 bool checkTextEqual( const ScSheetLimits& rLimits, const FormulaToken& _rToken1, const FormulaToken& _rToken2 )
441 assert(
442 (_rToken1.GetType() == svSingleRef || _rToken1.GetType() == svDoubleRef)
443 && _rToken1.FormulaToken::operator ==(_rToken2));
445 // in relative Refs only compare relative parts
447 ScComplexRefData aTemp1;
448 if ( _rToken1.GetType() == svSingleRef )
450 aTemp1.Ref1 = *_rToken1.GetSingleRef();
451 aTemp1.Ref2 = aTemp1.Ref1;
453 else
454 aTemp1 = *_rToken1.GetDoubleRef();
456 ScComplexRefData aTemp2;
457 if ( _rToken2.GetType() == svSingleRef )
459 aTemp2.Ref1 = *_rToken2.GetSingleRef();
460 aTemp2.Ref2 = aTemp2.Ref1;
462 else
463 aTemp2 = *_rToken2.GetDoubleRef();
465 ScAddress aPos;
466 ScRange aRange1 = aTemp1.toAbs(rLimits, aPos), aRange2 = aTemp2.toAbs(rLimits, aPos);
468 // memcmp doesn't work because of the alignment byte after bFlags.
469 // After SmartRelAbs only absolute parts have to be compared.
470 return aRange1 == aRange2 && aTemp1.Ref1.FlagValue() == aTemp2.Ref1.FlagValue() && aTemp1.Ref2.FlagValue() == aTemp2.Ref2.FlagValue();
475 #if DEBUG_FORMULA_COMPILER
476 void DumpToken(formula::FormulaToken const & rToken)
478 switch (rToken.GetType()) {
479 case svSingleRef:
480 cout << "-- ScSingleRefToken" << endl;
481 rToken.GetSingleRef()->Dump(1);
482 break;
483 case svDoubleRef:
484 cout << "-- ScDoubleRefToken" << endl;
485 rToken.GetDoubleRef()->Dump(1);
486 break;
487 default:
488 cout << "-- FormulaToken" << endl;
489 cout << " opcode: " << int(rToken.GetOpCode()) << " " <<
490 formula::FormulaCompiler::GetNativeSymbol( rToken.GetOpCode()).toUtf8().getStr() << endl;
491 cout << " type: " << static_cast<int>(rToken.GetType()) << endl;
492 switch (rToken.GetType())
494 case svDouble:
495 cout << " value: " << rToken.GetDouble() << endl;
496 break;
497 case svString:
498 cout << " string: "
499 << OUStringToOString(rToken.GetString().getString(), RTL_TEXTENCODING_UTF8).getStr()
500 << endl;
501 break;
502 default:
505 break;
508 #endif
510 FormulaTokenRef extendRangeReference( ScSheetLimits& rLimits, FormulaToken & rTok1, FormulaToken & rTok2,
511 const ScAddress & rPos, bool bReuseDoubleRef )
514 StackVar sv1 = rTok1.GetType();
515 // Doing a RangeOp with RefList is probably utter nonsense, but Xcl
516 // supports it, so do we.
517 if (sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList
518 && sv1 != svExternalSingleRef && sv1 != svExternalDoubleRef)
519 return nullptr;
520 StackVar sv2 = rTok2.GetType();
521 if (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList)
522 return nullptr;
524 ScTokenRef xRes;
525 bool bExternal = (sv1 == svExternalSingleRef);
526 if ((sv1 == svSingleRef || bExternal) && sv2 == svSingleRef)
528 // Range references like Sheet1.A1:A2 are generalized and built by
529 // first creating a DoubleRef from the first SingleRef, effectively
530 // generating Sheet1.A1:A1, and then extending that with A2 as if
531 // Sheet1.A1:A1:A2 was encountered, so the mechanisms to adjust the
532 // references apply as well.
534 /* Given the current structure of external references an external
535 * reference can only be extended if the second reference does not
536 * point to a different sheet. 'file'#Sheet1.A1:A2 is ok,
537 * 'file'#Sheet1.A1:Sheet2.A2 is not. Since we can't determine from a
538 * svSingleRef whether the sheet would be different from the one given
539 * in the external reference, we have to bail out if there is any sheet
540 * specified. NOTE: Xcl does handle external 3D references as in
541 * '[file]Sheet1:Sheet2'!A1:A2
543 * FIXME: For OOo syntax be smart and remember an external singleref
544 * encountered and if followed by ocRange and singleref, create an
545 * external singleref for the second singleref. Both could then be
546 * merged here. For Xcl syntax already parse an external range
547 * reference entirely, cumbersome. */
549 const ScSingleRefData& rRef2 = *rTok2.GetSingleRef();
550 if (bExternal && rRef2.IsFlag3D())
551 return nullptr;
553 ScComplexRefData aRef;
554 aRef.Ref1 = aRef.Ref2 = *rTok1.GetSingleRef();
555 aRef.Ref2.SetFlag3D( false);
556 aRef.Extend(rLimits, rRef2, rPos);
557 if (bExternal)
558 xRes = new ScExternalDoubleRefToken( rTok1.GetIndex(), rTok1.GetString(), aRef);
559 else
560 xRes = new ScDoubleRefToken(rLimits, aRef);
562 else
564 bExternal |= (sv1 == svExternalDoubleRef);
565 const ScRefList* pRefList = nullptr;
566 if (sv1 == svDoubleRef)
568 xRes = (bReuseDoubleRef && rTok1.GetRef() == 1 ? &rTok1 : rTok1.Clone());
569 sv1 = svUnknown; // mark as handled
571 else if (sv2 == svDoubleRef)
573 xRes = (bReuseDoubleRef && rTok2.GetRef() == 1 ? &rTok2 : rTok2.Clone());
574 sv2 = svUnknown; // mark as handled
576 else if (sv1 == svRefList)
577 pRefList = rTok1.GetRefList();
578 else if (sv2 == svRefList)
579 pRefList = rTok2.GetRefList();
580 if (pRefList)
582 if (pRefList->empty())
583 return nullptr;
584 if (bExternal)
585 return nullptr; // external reference list not possible
586 xRes = new ScDoubleRefToken(rLimits, (*pRefList)[0] );
588 if (!xRes)
589 return nullptr; // shouldn't happen...
590 StackVar sv[2] = { sv1, sv2 };
591 formula::FormulaToken* pt[2] = { &rTok1, &rTok2 };
592 ScComplexRefData& rRef = *xRes->GetDoubleRef();
593 for (size_t i=0; i<2; ++i)
595 switch (sv[i])
597 case svSingleRef:
598 rRef.Extend(rLimits, *pt[i]->GetSingleRef(), rPos);
599 break;
600 case svDoubleRef:
601 rRef.Extend(rLimits, *pt[i]->GetDoubleRef(), rPos);
602 break;
603 case svRefList:
605 const ScRefList* p = pt[i]->GetRefList();
606 if (p->empty())
607 return nullptr;
608 for (const auto& rRefData : *p)
610 rRef.Extend(rLimits, rRefData, rPos);
613 break;
614 case svExternalSingleRef:
615 if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D())
616 return nullptr; // no other sheets with external refs
617 else
618 rRef.Extend(rLimits, *pt[i]->GetSingleRef(), rPos);
619 break;
620 case svExternalDoubleRef:
621 if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D())
622 return nullptr; // no other sheets with external refs
623 else
624 rRef.Extend(rLimits, *pt[i]->GetDoubleRef(), rPos);
625 break;
626 default:
627 ; // nothing, prevent compiler warning
631 return FormulaTokenRef(xRes.get());
634 // real implementations of virtual functions
636 const ScSingleRefData* ScSingleRefToken::GetSingleRef() const { return &aSingleRef; }
637 ScSingleRefData* ScSingleRefToken::GetSingleRef() { return &aSingleRef; }
638 bool ScSingleRefToken::TextEqual( const FormulaToken& _rToken ) const
640 return FormulaToken::operator ==(_rToken) && checkTextEqual(mrSheetLimits, *this, _rToken);
642 bool ScSingleRefToken::operator==( const FormulaToken& r ) const
644 return FormulaToken::operator==( r ) && aSingleRef == *r.GetSingleRef();
647 const ScSingleRefData* ScDoubleRefToken::GetSingleRef() const { return &aDoubleRef.Ref1; }
648 ScSingleRefData* ScDoubleRefToken::GetSingleRef() { return &aDoubleRef.Ref1; }
649 const ScComplexRefData* ScDoubleRefToken::GetDoubleRef() const { return &aDoubleRef; }
650 ScComplexRefData* ScDoubleRefToken::GetDoubleRef() { return &aDoubleRef; }
651 const ScSingleRefData* ScDoubleRefToken::GetSingleRef2() const { return &aDoubleRef.Ref2; }
652 ScSingleRefData* ScDoubleRefToken::GetSingleRef2() { return &aDoubleRef.Ref2; }
653 bool ScDoubleRefToken::TextEqual( const FormulaToken& _rToken ) const
655 return FormulaToken::operator ==(_rToken) && checkTextEqual(mrSheetLimits, *this, _rToken);
657 bool ScDoubleRefToken::operator==( const FormulaToken& r ) const
659 return FormulaToken::operator==( r ) && aDoubleRef == *r.GetDoubleRef();
662 const ScRefList* ScRefListToken::GetRefList() const { return &aRefList; }
663 ScRefList* ScRefListToken::GetRefList() { return &aRefList; }
664 bool ScRefListToken::IsArrayResult() const { return mbArrayResult; }
665 bool ScRefListToken::operator==( const FormulaToken& r ) const
667 if (!FormulaToken::operator==( r ) || &aRefList != r.GetRefList())
668 return false;
669 const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(&r);
670 return p && mbArrayResult == p->IsArrayResult();
673 ScMatrixToken::ScMatrixToken( ScMatrixRef p ) :
674 FormulaToken(formula::svMatrix), pMatrix(std::move(p)) {}
676 ScMatrixToken::ScMatrixToken( const ScMatrixToken& ) = default;
678 const ScMatrix* ScMatrixToken::GetMatrix() const { return pMatrix.get(); }
679 ScMatrix* ScMatrixToken::GetMatrix() { return pMatrix.get(); }
680 bool ScMatrixToken::operator==( const FormulaToken& r ) const
682 return FormulaToken::operator==( r ) && pMatrix == r.GetMatrix();
685 ScMatrixRangeToken::ScMatrixRangeToken( const sc::RangeMatrix& rMat ) :
686 FormulaToken(formula::svMatrix), mpMatrix(rMat.mpMat)
688 maRef.InitRange(rMat.mnCol1, rMat.mnRow1, rMat.mnTab1, rMat.mnCol2, rMat.mnRow2, rMat.mnTab2);
691 ScMatrixRangeToken::ScMatrixRangeToken( const ScMatrixRangeToken& ) = default;
693 sal_uInt8 ScMatrixRangeToken::GetByte() const
695 return MATRIX_TOKEN_HAS_RANGE;
698 const ScMatrix* ScMatrixRangeToken::GetMatrix() const
700 return mpMatrix.get();
703 ScMatrix* ScMatrixRangeToken::GetMatrix()
705 return mpMatrix.get();
708 const ScComplexRefData* ScMatrixRangeToken::GetDoubleRef() const
710 return &maRef;
713 ScComplexRefData* ScMatrixRangeToken::GetDoubleRef()
715 return &maRef;
718 bool ScMatrixRangeToken::operator==( const FormulaToken& r ) const
720 return FormulaToken::operator==(r) && mpMatrix == r.GetMatrix();
723 FormulaToken* ScMatrixRangeToken::Clone() const
725 return new ScMatrixRangeToken(*this);
728 ScExternalSingleRefToken::ScExternalSingleRefToken( sal_uInt16 nFileId, svl::SharedString aTabName, const ScSingleRefData& r ) :
729 FormulaToken( svExternalSingleRef, ocPush),
730 mnFileId(nFileId),
731 maTabName(std::move(aTabName)),
732 maSingleRef(r)
736 ScExternalSingleRefToken::~ScExternalSingleRefToken()
740 sal_uInt16 ScExternalSingleRefToken::GetIndex() const
742 return mnFileId;
745 const svl::SharedString & ScExternalSingleRefToken::GetString() const
747 return maTabName;
750 const ScSingleRefData* ScExternalSingleRefToken::GetSingleRef() const
752 return &maSingleRef;
755 ScSingleRefData* ScExternalSingleRefToken::GetSingleRef()
757 return &maSingleRef;
760 bool ScExternalSingleRefToken::operator ==( const FormulaToken& r ) const
762 if (!FormulaToken::operator==(r))
763 return false;
765 if (mnFileId != r.GetIndex())
766 return false;
768 if (maTabName != r.GetString())
769 return false;
771 return maSingleRef == *r.GetSingleRef();
774 ScExternalDoubleRefToken::ScExternalDoubleRefToken( sal_uInt16 nFileId, svl::SharedString aTabName, const ScComplexRefData& r ) :
775 FormulaToken( svExternalDoubleRef, ocPush),
776 mnFileId(nFileId),
777 maTabName(std::move(aTabName)),
778 maDoubleRef(r)
782 ScExternalDoubleRefToken::~ScExternalDoubleRefToken()
786 sal_uInt16 ScExternalDoubleRefToken::GetIndex() const
788 return mnFileId;
791 const svl::SharedString & ScExternalDoubleRefToken::GetString() const
793 return maTabName;
796 const ScSingleRefData* ScExternalDoubleRefToken::GetSingleRef() const
798 return &maDoubleRef.Ref1;
801 ScSingleRefData* ScExternalDoubleRefToken::GetSingleRef()
803 return &maDoubleRef.Ref1;
806 const ScSingleRefData* ScExternalDoubleRefToken::GetSingleRef2() const
808 return &maDoubleRef.Ref2;
811 ScSingleRefData* ScExternalDoubleRefToken::GetSingleRef2()
813 return &maDoubleRef.Ref2;
816 const ScComplexRefData* ScExternalDoubleRefToken::GetDoubleRef() const
818 return &maDoubleRef;
821 ScComplexRefData* ScExternalDoubleRefToken::GetDoubleRef()
823 return &maDoubleRef;
826 bool ScExternalDoubleRefToken::operator ==( const FormulaToken& r ) const
828 if (!FormulaToken::operator==(r))
829 return false;
831 if (mnFileId != r.GetIndex())
832 return false;
834 if (maTabName != r.GetString())
835 return false;
837 return maDoubleRef == *r.GetDoubleRef();
840 ScExternalNameToken::ScExternalNameToken( sal_uInt16 nFileId, svl::SharedString aName ) :
841 FormulaToken( svExternalName, ocPush),
842 mnFileId(nFileId),
843 maName(std::move(aName))
847 ScExternalNameToken::~ScExternalNameToken() {}
849 sal_uInt16 ScExternalNameToken::GetIndex() const
851 return mnFileId;
854 const svl::SharedString & ScExternalNameToken::GetString() const
856 return maName;
859 bool ScExternalNameToken::operator==( const FormulaToken& r ) const
861 if ( !FormulaToken::operator==(r) )
862 return false;
864 if (mnFileId != r.GetIndex())
865 return false;
867 return maName.getData() == r.GetString().getData();
870 ScTableRefToken::ScTableRefToken( sal_uInt16 nIndex, ScTableRefToken::Item eItem ) :
871 FormulaToken( svIndex, ocTableRef),
872 mnIndex(nIndex),
873 meItem(eItem)
877 ScTableRefToken::ScTableRefToken( const ScTableRefToken& r ) :
878 FormulaToken(r),
879 mxAreaRefRPN( r.mxAreaRefRPN ? r.mxAreaRefRPN->Clone() : nullptr),
880 mnIndex(r.mnIndex),
881 meItem(r.meItem)
885 ScTableRefToken::~ScTableRefToken() {}
887 sal_uInt16 ScTableRefToken::GetIndex() const
889 return mnIndex;
892 void ScTableRefToken::SetIndex( sal_uInt16 n )
894 mnIndex = n;
897 sal_Int16 ScTableRefToken::GetSheet() const
899 // Code asking for this may have to be adapted as it might assume an
900 // svIndex token would always be ocName or ocDBArea.
901 SAL_WARN("sc.core","ScTableRefToken::GetSheet - maybe adapt caller to know about TableRef?");
902 // Database range is always global.
903 return -1;
906 ScTableRefToken::Item ScTableRefToken::GetItem() const
908 return meItem;
911 void ScTableRefToken::AddItem( ScTableRefToken::Item eItem )
913 meItem = static_cast<ScTableRefToken::Item>(meItem | eItem);
916 void ScTableRefToken::SetAreaRefRPN( formula::FormulaToken* pToken )
918 mxAreaRefRPN = pToken;
921 formula::FormulaToken* ScTableRefToken::GetAreaRefRPN() const
923 return mxAreaRefRPN.get();
926 bool ScTableRefToken::operator==( const FormulaToken& r ) const
928 if ( !FormulaToken::operator==(r) )
929 return false;
931 if (mnIndex != r.GetIndex())
932 return false;
934 const ScTableRefToken* p = dynamic_cast<const ScTableRefToken*>(&r);
935 if (!p)
936 return false;
938 if (meItem != p->GetItem())
939 return false;
941 if (!mxAreaRefRPN && !p->mxAreaRefRPN)
942 ; // nothing
943 else if (!mxAreaRefRPN || !p->mxAreaRefRPN)
944 return false;
945 else if (!(*mxAreaRefRPN == *(p->mxAreaRefRPN)))
946 return false;
948 return true;
951 ScJumpMatrixToken::ScJumpMatrixToken(std::shared_ptr<ScJumpMatrix> p)
952 : FormulaToken(formula::svJumpMatrix)
953 , mpJumpMatrix(std::move(p))
956 ScJumpMatrixToken::ScJumpMatrixToken( const ScJumpMatrixToken & ) = default;
958 ScJumpMatrix* ScJumpMatrixToken::GetJumpMatrix() const
960 return mpJumpMatrix.get();
963 bool ScJumpMatrixToken::operator==( const FormulaToken& r ) const
965 return FormulaToken::operator==( r ) && mpJumpMatrix.get() == r.GetJumpMatrix();
968 ScJumpMatrixToken::~ScJumpMatrixToken()
972 double ScEmptyCellToken::GetDouble() const { return 0.0; }
974 const svl::SharedString & ScEmptyCellToken::GetString() const
976 return svl::SharedString::getEmptyString();
979 bool ScEmptyCellToken::operator==( const FormulaToken& r ) const
981 return FormulaToken::operator==( r ) &&
982 bInherited == static_cast< const ScEmptyCellToken & >(r).IsInherited() &&
983 bDisplayedAsString == static_cast< const ScEmptyCellToken & >(r).IsDisplayedAsString();
986 ScMatrixCellResultToken::ScMatrixCellResultToken( ScConstMatrixRef pMat, const formula::FormulaToken* pUL ) :
987 FormulaToken(formula::svMatrixCell), xMatrix(std::move(pMat)), xUpperLeft(pUL) {}
989 ScMatrixCellResultToken::ScMatrixCellResultToken( const ScMatrixCellResultToken& ) = default;
991 double ScMatrixCellResultToken::GetDouble() const { return xUpperLeft->GetDouble(); }
993 ScMatrixCellResultToken::~ScMatrixCellResultToken() {}
995 const svl::SharedString & ScMatrixCellResultToken::GetString() const
997 return xUpperLeft->GetString();
1000 const ScMatrix* ScMatrixCellResultToken::GetMatrix() const { return xMatrix.get(); }
1001 // Non-const GetMatrix() is private and unused but must be implemented to
1002 // satisfy vtable linkage.
1003 ScMatrix* ScMatrixCellResultToken::GetMatrix()
1005 return const_cast<ScMatrix*>(xMatrix.get());
1008 bool ScMatrixCellResultToken::operator==( const FormulaToken& r ) const
1010 return FormulaToken::operator==( r ) &&
1011 xUpperLeft == static_cast<const ScMatrixCellResultToken &>(r).xUpperLeft &&
1012 xMatrix == static_cast<const ScMatrixCellResultToken &>(r).xMatrix;
1015 FormulaToken* ScMatrixCellResultToken::Clone() const
1017 return new ScMatrixCellResultToken(*this);
1020 void ScMatrixCellResultToken::Assign( const ScMatrixCellResultToken & r )
1022 xMatrix = r.xMatrix;
1023 xUpperLeft = r.xUpperLeft;
1026 ScMatrixFormulaCellToken::ScMatrixFormulaCellToken(
1027 SCCOL nC, SCROW nR, const ScConstMatrixRef& pMat, const formula::FormulaToken* pUL ) :
1028 ScMatrixCellResultToken(pMat, pUL), nRows(nR), nCols(nC)
1030 CloneUpperLeftIfNecessary();
1033 ScMatrixFormulaCellToken::ScMatrixFormulaCellToken( SCCOL nC, SCROW nR ) :
1034 ScMatrixCellResultToken(nullptr, nullptr), nRows(nR), nCols(nC) {}
1036 ScMatrixFormulaCellToken::ScMatrixFormulaCellToken( const ScMatrixFormulaCellToken& r ) :
1037 ScMatrixCellResultToken(r), nRows(r.nRows), nCols(r.nCols)
1039 CloneUpperLeftIfNecessary();
1042 ScMatrixFormulaCellToken::~ScMatrixFormulaCellToken() {}
1044 bool ScMatrixFormulaCellToken::operator==( const FormulaToken& r ) const
1046 const ScMatrixFormulaCellToken* p = dynamic_cast<const ScMatrixFormulaCellToken*>(&r);
1047 return p && ScMatrixCellResultToken::operator==( r ) &&
1048 nCols == p->nCols && nRows == p->nRows;
1051 void ScMatrixFormulaCellToken::CloneUpperLeftIfNecessary()
1053 if (xUpperLeft && xUpperLeft->GetType() == svDouble)
1054 xUpperLeft = xUpperLeft->Clone();
1057 void ScMatrixFormulaCellToken::Assign( const ScMatrixCellResultToken & r )
1059 ScMatrixCellResultToken::Assign( r);
1061 CloneUpperLeftIfNecessary();
1064 void ScMatrixFormulaCellToken::Assign( const formula::FormulaToken& r )
1066 if (this == &r)
1067 return;
1068 const ScMatrixCellResultToken* p = dynamic_cast<const ScMatrixCellResultToken*>(&r);
1069 if (p)
1070 ScMatrixCellResultToken::Assign( *p);
1071 else
1073 OSL_ENSURE( r.GetType() != svMatrix, "ScMatrixFormulaCellToken::operator=: assigning ScMatrixToken to ScMatrixFormulaCellToken is not proper, use ScMatrixCellResultToken instead");
1074 if (r.GetType() == svMatrix)
1076 xUpperLeft = nullptr;
1077 xMatrix = r.GetMatrix();
1079 else
1081 xUpperLeft = &r;
1082 xMatrix = nullptr;
1083 CloneUpperLeftIfNecessary();
1088 void ScMatrixFormulaCellToken::SetUpperLeftDouble( double f )
1090 switch (GetUpperLeftType())
1092 case svDouble:
1093 const_cast<FormulaToken*>(xUpperLeft.get())->SetDouble(f);
1094 break;
1095 case svString:
1096 xUpperLeft = new FormulaDoubleToken( f);
1097 break;
1098 case svUnknown:
1099 if (!xUpperLeft)
1101 xUpperLeft = new FormulaDoubleToken( f);
1102 break;
1104 [[fallthrough]];
1105 default:
1107 OSL_FAIL("ScMatrixFormulaCellToken::SetUpperLeftDouble: not modifying unhandled token type");
1112 void ScMatrixFormulaCellToken::ResetResult()
1114 xMatrix = nullptr;
1115 xUpperLeft = nullptr;
1118 ScHybridCellToken::ScHybridCellToken(
1119 double f, const svl::SharedString & rStr, OUString aFormula, bool bEmptyDisplayedAsString ) :
1120 FormulaToken( formula::svHybridCell ),
1121 mfDouble( f ), maString( rStr ),
1122 maFormula(std::move( aFormula )),
1123 mbEmptyDisplayedAsString( bEmptyDisplayedAsString)
1125 // caller, make up your mind...
1126 assert( !bEmptyDisplayedAsString || (f == 0.0 && rStr.getString().isEmpty()));
1129 double ScHybridCellToken::GetDouble() const { return mfDouble; }
1131 const svl::SharedString & ScHybridCellToken::GetString() const
1133 return maString;
1136 bool ScHybridCellToken::operator==( const FormulaToken& r ) const
1138 return FormulaToken::operator==( r ) &&
1139 mfDouble == r.GetDouble() && maString == r.GetString() &&
1140 maFormula == static_cast<const ScHybridCellToken &>(r).GetFormula();
1143 bool ScTokenArray::AddFormulaToken(
1144 const css::sheet::FormulaToken& rToken, svl::SharedStringPool& rSPool, formula::ExternalReferenceHelper* pExtRef)
1146 bool bError = FormulaTokenArray::AddFormulaToken(rToken, rSPool, pExtRef);
1147 if ( bError )
1149 bError = false;
1150 const OpCode eOpCode = static_cast<OpCode>(rToken.OpCode); // assuming equal values for the moment
1152 const uno::TypeClass eClass = rToken.Data.getValueTypeClass();
1153 switch ( eClass )
1155 case uno::TypeClass_STRUCT:
1157 uno::Type aType = rToken.Data.getValueType();
1158 if ( aType.equals( cppu::UnoType<sheet::SingleReference>::get() ) )
1160 ScSingleRefData aSingleRef;
1161 sheet::SingleReference aApiRef;
1162 rToken.Data >>= aApiRef;
1163 lcl_SingleRefToCalc( aSingleRef, aApiRef );
1164 if ( eOpCode == ocPush )
1165 AddSingleReference( aSingleRef );
1166 else if ( eOpCode == ocColRowName )
1167 AddColRowName( aSingleRef );
1168 else
1169 bError = true;
1171 else if ( aType.equals( cppu::UnoType<sheet::ComplexReference>::get() ) )
1173 ScComplexRefData aComplRef;
1174 sheet::ComplexReference aApiRef;
1175 rToken.Data >>= aApiRef;
1176 lcl_SingleRefToCalc( aComplRef.Ref1, aApiRef.Reference1 );
1177 lcl_SingleRefToCalc( aComplRef.Ref2, aApiRef.Reference2 );
1179 if ( eOpCode == ocPush )
1180 AddDoubleReference( aComplRef );
1181 else
1182 bError = true;
1184 else if ( aType.equals( cppu::UnoType<sheet::NameToken>::get() ) )
1186 sheet::NameToken aTokenData;
1187 rToken.Data >>= aTokenData;
1188 if ( eOpCode == ocName )
1190 SAL_WARN_IF( aTokenData.Sheet < -1 || std::numeric_limits<sal_Int16>::max() < aTokenData.Sheet,
1191 "sc.core",
1192 "ScTokenArray::AddFormulaToken - NameToken.Sheet out of limits: " << aTokenData.Sheet);
1193 sal_Int16 nSheet = static_cast<sal_Int16>(aTokenData.Sheet);
1194 AddRangeName(aTokenData.Index, nSheet);
1196 else if (eOpCode == ocDBArea)
1197 AddDBRange(aTokenData.Index);
1198 else if (eOpCode == ocTableRef)
1199 bError = true; /* TODO: implementation */
1200 else
1201 bError = true;
1203 else if ( aType.equals( cppu::UnoType<sheet::ExternalReference>::get() ) )
1205 sheet::ExternalReference aApiExtRef;
1206 if( (eOpCode == ocPush) && (rToken.Data >>= aApiExtRef) && (0 <= aApiExtRef.Index) && (aApiExtRef.Index <= SAL_MAX_UINT16) )
1208 sal_uInt16 nFileId = static_cast< sal_uInt16 >( aApiExtRef.Index );
1209 sheet::SingleReference aApiSRef;
1210 sheet::ComplexReference aApiCRef;
1211 OUString aName;
1212 if( aApiExtRef.Reference >>= aApiSRef )
1214 // try to resolve cache index to sheet name
1215 size_t nCacheId = static_cast< size_t >( aApiSRef.Sheet );
1216 OUString aTabName = pExtRef->getCacheTableName( nFileId, nCacheId );
1217 if( !aTabName.isEmpty() )
1219 ScSingleRefData aSingleRef;
1220 // convert column/row settings, set sheet index to absolute
1221 lcl_ExternalRefToCalc( aSingleRef, aApiSRef );
1222 AddExternalSingleReference( nFileId, rSPool.intern( aTabName), aSingleRef );
1224 else
1225 bError = true;
1227 else if( aApiExtRef.Reference >>= aApiCRef )
1229 // try to resolve cache index to sheet name.
1230 size_t nCacheId = static_cast< size_t >( aApiCRef.Reference1.Sheet );
1231 OUString aTabName = pExtRef->getCacheTableName( nFileId, nCacheId );
1232 if( !aTabName.isEmpty() )
1234 ScComplexRefData aComplRef;
1235 // convert column/row settings, set sheet index to absolute
1236 lcl_ExternalRefToCalc( aComplRef.Ref1, aApiCRef.Reference1 );
1237 lcl_ExternalRefToCalc( aComplRef.Ref2, aApiCRef.Reference2 );
1238 // NOTE: This assumes that cached sheets are in consecutive order!
1239 aComplRef.Ref2.SetAbsTab(
1240 aComplRef.Ref1.Tab() + static_cast<SCTAB>(aApiCRef.Reference2.Sheet - aApiCRef.Reference1.Sheet));
1241 AddExternalDoubleReference( nFileId, rSPool.intern( aTabName), aComplRef );
1243 else
1244 bError = true;
1246 else if( aApiExtRef.Reference >>= aName )
1248 if( !aName.isEmpty() )
1249 AddExternalName( nFileId, rSPool.intern( aName) );
1250 else
1251 bError = true;
1253 else
1254 bError = true;
1256 else
1257 bError = true;
1259 else
1260 bError = true; // unknown struct
1262 break;
1263 case uno::TypeClass_SEQUENCE:
1265 if ( eOpCode != ocPush )
1266 bError = true; // not an inline array
1267 else if (!rToken.Data.getValueType().equals( cppu::UnoType<
1268 uno::Sequence< uno::Sequence< uno::Any >>>::get()))
1269 bError = true; // unexpected sequence type
1270 else
1272 ScMatrixRef xMat = ScSequenceToMatrix::CreateMixedMatrix( rToken.Data);
1273 if (xMat)
1274 AddMatrix( xMat);
1275 else
1276 bError = true;
1279 break;
1280 default:
1281 bError = true;
1284 return bError;
1287 void ScTokenArray::CheckForThreading( const FormulaToken& r )
1289 #if HAVE_CPP_CONSTINIT_SORTED_VECTOR
1290 constinit
1291 #endif
1292 static const o3tl::sorted_vector<OpCode> aThreadedCalcDenyList({
1293 ocIndirect,
1294 ocMacro,
1295 ocOffset,
1296 ocTableOp,
1297 ocCell,
1298 ocMatch,
1299 ocInfo,
1300 ocStyle,
1301 ocDBAverage,
1302 ocDBCount,
1303 ocDBCount2,
1304 ocDBGet,
1305 ocDBMax,
1306 ocDBMin,
1307 ocDBProduct,
1308 ocDBStdDev,
1309 ocDBStdDevP,
1310 ocDBSum,
1311 ocDBVar,
1312 ocDBVarP,
1313 ocText,
1314 ocSheet,
1315 ocExternal,
1316 ocDde,
1317 ocWebservice,
1318 ocGetPivotData
1321 // Don't enable threading once we decided to disable it.
1322 if (!mbThreadingEnabled)
1323 return;
1325 static const bool bThreadingProhibited = std::getenv("SC_NO_THREADED_CALCULATION");
1327 if (bThreadingProhibited)
1329 mbThreadingEnabled = false;
1330 return;
1333 OpCode eOp = r.GetOpCode();
1335 if (aThreadedCalcDenyList.find(eOp) != aThreadedCalcDenyList.end())
1337 SAL_INFO("sc.core.formulagroup", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp)
1338 << "(" << int(eOp) << ") disables threaded calculation of formula group");
1339 mbThreadingEnabled = false;
1340 return;
1343 if (eOp != ocPush)
1344 return;
1346 switch (r.GetType())
1348 case svExternalDoubleRef:
1349 case svExternalSingleRef:
1350 case svExternalName:
1351 case svMatrix:
1352 SAL_INFO("sc.core.formulagroup", "opcode ocPush: variable type " << StackVarEnumToString(r.GetType())
1353 << " disables threaded calculation of formula group");
1354 mbThreadingEnabled = false;
1355 return;
1356 default:
1357 break;
1361 void ScTokenArray::CheckToken( const FormulaToken& r )
1363 if (mbThreadingEnabled)
1364 CheckForThreading(r);
1366 if (IsFormulaVectorDisabled())
1367 return; // It's already disabled. No more checking needed.
1369 OpCode eOp = r.GetOpCode();
1371 if (SC_OPCODE_START_FUNCTION <= eOp && eOp < SC_OPCODE_STOP_FUNCTION)
1373 if (ScInterpreter::GetGlobalConfig().mbOpenCLSubsetOnly &&
1374 ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes->find(eOp) == ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes->end())
1376 SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp)
1377 << "(" << int(eOp) << ") disables vectorisation for formula group");
1378 meVectorState = FormulaVectorDisabledNotInSubSet;
1379 mbOpenCLEnabled = false;
1380 return;
1383 // We support vectorization for the following opcodes.
1384 switch (eOp)
1386 case ocAverage:
1387 case ocMin:
1388 case ocMinA:
1389 case ocMax:
1390 case ocMaxA:
1391 case ocSum:
1392 case ocSumIfs:
1393 case ocSumProduct:
1394 case ocCount:
1395 case ocCount2:
1396 case ocVLookup:
1397 case ocXLookup:
1398 case ocXMatch:
1399 case ocFilter:
1400 case ocSort:
1401 case ocSortBy:
1402 case ocSLN:
1403 case ocIRR:
1404 case ocMIRR:
1405 case ocPMT:
1406 case ocRate:
1407 case ocRRI:
1408 case ocPpmt:
1409 case ocFisher:
1410 case ocFisherInv:
1411 case ocGamma:
1412 case ocGammaLn:
1413 case ocNotAvail:
1414 case ocGauss:
1415 case ocGeoMean:
1416 case ocHarMean:
1417 case ocSYD:
1418 case ocCorrel:
1419 case ocNegBinomVert:
1420 case ocPearson:
1421 case ocRSQ:
1422 case ocCos:
1423 case ocCosecant:
1424 case ocCosecantHyp:
1425 case ocISPMT:
1426 case ocPDuration:
1427 case ocSinHyp:
1428 case ocAbs:
1429 case ocPV:
1430 case ocSin:
1431 case ocTan:
1432 case ocTanHyp:
1433 case ocStandard:
1434 case ocWeibull:
1435 case ocMedian:
1436 case ocDDB:
1437 case ocFV:
1438 case ocVBD:
1439 case ocKurt:
1440 case ocNper:
1441 case ocNormDist:
1442 case ocArcCos:
1443 case ocSqrt:
1444 case ocArcCosHyp:
1445 case ocNPV:
1446 case ocStdNormDist:
1447 case ocNormInv:
1448 case ocSNormInv:
1449 case ocPermut:
1450 case ocPermutationA:
1451 case ocPhi:
1452 case ocIpmt:
1453 case ocConfidence:
1454 case ocIntercept:
1455 case ocDB:
1456 case ocLogInv:
1457 case ocArcCot:
1458 case ocCosHyp:
1459 case ocCritBinom:
1460 case ocArcCotHyp:
1461 case ocArcSin:
1462 case ocArcSinHyp:
1463 case ocArcTan:
1464 case ocArcTanHyp:
1465 case ocBitAnd:
1466 case ocForecast:
1467 case ocLogNormDist:
1468 case ocGammaDist:
1469 case ocLn:
1470 case ocRound:
1471 case ocCot:
1472 case ocCotHyp:
1473 case ocFDist:
1474 case ocVar:
1475 case ocChiDist:
1476 case ocPower:
1477 case ocOdd:
1478 case ocChiSqDist:
1479 case ocChiSqInv:
1480 case ocGammaInv:
1481 case ocFloor:
1482 case ocFInv:
1483 case ocFTest:
1484 case ocB:
1485 case ocBetaDist:
1486 case ocExp:
1487 case ocLog10:
1488 case ocExpDist:
1489 case ocAverageIfs:
1490 case ocCountIfs:
1491 case ocCombinA:
1492 case ocEven:
1493 case ocLog:
1494 case ocMod:
1495 case ocTrunc:
1496 case ocSkew:
1497 case ocArcTan2:
1498 case ocBitOr:
1499 case ocBitLshift:
1500 case ocBitRshift:
1501 case ocBitXor:
1502 case ocChiInv:
1503 case ocPoissonDist:
1504 case ocSumSQ:
1505 case ocSkewp:
1506 case ocBinomDist:
1507 case ocVarP:
1508 case ocCeil:
1509 case ocCombin:
1510 case ocDevSq:
1511 case ocStDev:
1512 case ocSlope:
1513 case ocSTEYX:
1514 case ocZTest:
1515 case ocPi:
1516 case ocRandom:
1517 case ocProduct:
1518 case ocHypGeomDist:
1519 case ocSumX2MY2:
1520 case ocSumX2DY2:
1521 case ocBetaInv:
1522 case ocTTest:
1523 case ocTDist:
1524 case ocTInv:
1525 case ocSumXMY2:
1526 case ocStDevP:
1527 case ocCovar:
1528 case ocAnd:
1529 case ocOr:
1530 case ocNot:
1531 case ocXor:
1532 case ocDBMax:
1533 case ocDBMin:
1534 case ocDBProduct:
1535 case ocDBAverage:
1536 case ocDBStdDev:
1537 case ocDBStdDevP:
1538 case ocDBSum:
1539 case ocDBVar:
1540 case ocDBVarP:
1541 case ocAverageIf:
1542 case ocDBCount:
1543 case ocDBCount2:
1544 case ocDeg:
1545 case ocRoundUp:
1546 case ocRoundDown:
1547 case ocInt:
1548 case ocRad:
1549 case ocCountIf:
1550 case ocIsEven:
1551 case ocIsOdd:
1552 case ocFact:
1553 case ocAverageA:
1554 case ocVarA:
1555 case ocVarPA:
1556 case ocStDevA:
1557 case ocStDevPA:
1558 case ocSecant:
1559 case ocSecantHyp:
1560 case ocSumIf:
1561 case ocNegSub:
1562 case ocAveDev:
1563 case ocMatSequence:
1564 case ocRandArray:
1565 case ocUnique:
1566 // Don't change the state.
1567 break;
1568 default:
1569 SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp)
1570 << "(" << int(eOp) << ") disables vectorisation for formula group");
1571 meVectorState = FormulaVectorDisabledByOpCode;
1572 mbOpenCLEnabled = false;
1573 return;
1576 else if (eOp == ocPush)
1578 // This is a stack variable. See if this is a reference.
1580 switch (r.GetType())
1582 case svByte:
1583 case svDouble:
1584 case svString:
1585 // Don't change the state.
1586 break;
1587 case svSingleRef:
1588 case svDoubleRef:
1589 // Depends on the reference state.
1590 meVectorState = FormulaVectorCheckReference;
1591 break;
1592 case svError:
1593 case svEmptyCell:
1594 case svExternal:
1595 case svExternalDoubleRef:
1596 case svExternalName:
1597 case svExternalSingleRef:
1598 case svFAP:
1599 case svHybridCell:
1600 case svIndex:
1601 case svJump:
1602 case svJumpMatrix:
1603 case svMatrix:
1604 case svMatrixCell:
1605 case svMissing:
1606 case svRefList:
1607 case svSep:
1608 case svUnknown:
1609 // We don't support vectorization on these.
1610 SAL_INFO("sc.opencl", "opcode ocPush: variable type " << StackVarEnumToString(r.GetType()) << " disables vectorisation for formula group");
1611 meVectorState = FormulaVectorDisabledByStackVariable;
1612 mbOpenCLEnabled = false;
1613 return;
1614 default:
1618 else if (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP)
1620 if (ScInterpreter::GetGlobalConfig().mbOpenCLSubsetOnly &&
1621 ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes->find(eOp) == ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes->end())
1623 SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp)
1624 << "(" << int(eOp) << ") disables vectorisation for formula group");
1625 meVectorState = FormulaVectorDisabledNotInSubSet;
1626 mbOpenCLEnabled = false;
1627 return;
1630 else
1632 // All the rest, special commands, separators, error codes, ...
1633 switch (eOp)
1635 default:
1636 // Default is off, no vectorization.
1637 // Mentioning some specific values below to indicate why.
1639 case ocName:
1640 // Named expression would need "recursive" handling of its
1641 // token array for vector state in
1642 // ScFormulaCell::InterpretFormulaGroup() and below.
1644 case ocDBArea:
1645 // Certainly not a vectorization of the entire area...
1647 case ocTableRef:
1648 // May result in a single cell or range reference, depending on
1649 // context.
1651 case ocColRowName:
1652 // The associated reference is the name cell with which to
1653 // create the implicit intersection.
1655 case ocColRowNameAuto:
1656 // Auto column/row names lead to references computed in
1657 // interpreter.
1659 SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp)
1660 << "(" << int(eOp) << ") disables vectorisation for formula group");
1661 meVectorState = FormulaVectorDisabledByOpCode;
1662 mbOpenCLEnabled = false;
1663 return;
1665 // Known good, don't change state.
1666 case ocStop:
1667 case ocExternal:
1668 case ocOpen:
1669 case ocClose:
1670 case ocSep:
1671 case ocArrayOpen:
1672 case ocArrayRowSep:
1673 case ocArrayColSep:
1674 case ocArrayClose:
1675 case ocMissing:
1676 case ocBad:
1677 case ocSpaces:
1678 case ocWhitespace:
1679 case ocSkip:
1680 case ocPercentSign:
1681 case ocErrNull:
1682 case ocErrDivZero:
1683 case ocErrValue:
1684 case ocErrRef:
1685 case ocErrName:
1686 case ocErrNum:
1687 case ocErrNA:
1688 break;
1689 case ocIf:
1690 case ocIfError:
1691 case ocIfNA:
1692 case ocChoose:
1693 case ocLet:
1694 // Jump commands are now supported.
1695 break;
1700 bool ScTokenArray::ImplGetReference( ScRange& rRange, const ScAddress& rPos, bool bValidOnly ) const
1702 bool bIs = false;
1703 if ( pCode && nLen == 1 )
1705 const FormulaToken* pToken = pCode[0];
1706 if ( pToken )
1708 if ( pToken->GetType() == svSingleRef )
1710 const ScSingleRefData& rRef = *static_cast<const ScSingleRefToken*>(pToken)->GetSingleRef();
1711 rRange.aStart = rRange.aEnd = rRef.toAbs(*mxSheetLimits, rPos);
1712 bIs = !bValidOnly || mxSheetLimits->ValidAddress(rRange.aStart);
1714 else if ( pToken->GetType() == svDoubleRef )
1716 const ScComplexRefData& rCompl = *static_cast<const ScDoubleRefToken*>(pToken)->GetDoubleRef();
1717 const ScSingleRefData& rRef1 = rCompl.Ref1;
1718 const ScSingleRefData& rRef2 = rCompl.Ref2;
1719 rRange.aStart = rRef1.toAbs(*mxSheetLimits, rPos);
1720 rRange.aEnd = rRef2.toAbs(*mxSheetLimits, rPos);
1721 bIs = !bValidOnly || mxSheetLimits->ValidRange(rRange);
1725 return bIs;
1728 namespace {
1730 // we want to compare for similar not identical formulae
1731 // so we can't use actual row & column indices.
1732 size_t HashSingleRef( const ScSingleRefData& rRef )
1734 size_t nVal = 0;
1736 nVal += size_t(rRef.IsColRel());
1737 nVal += (size_t(rRef.IsRowRel()) << 1);
1738 nVal += (size_t(rRef.IsTabRel()) << 2);
1740 return nVal;
1745 void ScTokenArray::GenHash()
1747 static const OUStringHash aHasher;
1749 size_t nHash = 1;
1750 OpCode eOp;
1751 StackVar eType;
1752 const formula::FormulaToken* p;
1753 sal_uInt16 n = std::min<sal_uInt16>(nLen, 20);
1754 for (sal_uInt16 i = 0; i < n; ++i)
1756 p = pCode[i];
1757 eOp = p->GetOpCode();
1758 if (eOp == ocPush)
1760 // This is stack variable. Do additional differentiation.
1761 eType = p->GetType();
1762 switch (eType)
1764 case svByte:
1766 // Constant value.
1767 sal_uInt8 nVal = p->GetByte();
1768 nHash += static_cast<size_t>(nVal);
1770 break;
1771 case svDouble:
1773 // Constant value.
1774 double fVal = p->GetDouble();
1775 nHash += std::hash<double>()(fVal);
1777 break;
1778 case svString:
1780 // Constant string.
1781 OUString aStr = p->GetString().getString();
1782 nHash += aHasher(aStr);
1784 break;
1785 case svSingleRef:
1787 size_t nVal = HashSingleRef(*p->GetSingleRef());
1788 nHash += nVal;
1790 break;
1791 case svDoubleRef:
1793 const ScComplexRefData& rRef = *p->GetDoubleRef();
1794 size_t nVal1 = HashSingleRef(rRef.Ref1);
1795 size_t nVal2 = HashSingleRef(rRef.Ref2);
1796 nHash += nVal1;
1797 nHash += nVal2;
1799 break;
1800 default:
1801 // Use the opcode value in all the other cases.
1802 nHash += static_cast<size_t>(eOp);
1805 else
1806 // Use the opcode value in all the other cases.
1807 nHash += static_cast<size_t>(eOp);
1809 nHash = (nHash << 4) - nHash;
1812 mnHashValue = nHash;
1815 void ScTokenArray::ResetVectorState()
1817 mbOpenCLEnabled = ScCalcConfig::isOpenCLEnabled();
1818 meVectorState = mbOpenCLEnabled ? FormulaVectorEnabled : FormulaVectorDisabled;
1819 mbThreadingEnabled = ScCalcConfig::isThreadingEnabled();
1822 bool ScTokenArray::IsFormulaVectorDisabled() const
1824 switch (meVectorState)
1826 case FormulaVectorDisabled:
1827 case FormulaVectorDisabledByOpCode:
1828 case FormulaVectorDisabledByStackVariable:
1829 case FormulaVectorDisabledNotInSubSet:
1830 return true;
1831 default:
1835 return false;
1838 bool ScTokenArray::IsInvariant() const
1840 FormulaToken** p = pCode.get();
1841 FormulaToken** pEnd = p + static_cast<size_t>(nLen);
1842 for (; p != pEnd; ++p)
1844 switch ((*p)->GetType())
1846 case svSingleRef:
1847 case svExternalSingleRef:
1849 const ScSingleRefData& rRef = *(*p)->GetSingleRef();
1850 if (rRef.IsRowRel())
1851 return false;
1853 break;
1854 case svDoubleRef:
1855 case svExternalDoubleRef:
1857 const ScComplexRefData& rRef = *(*p)->GetDoubleRef();
1858 if (rRef.Ref1.IsRowRel() || rRef.Ref2.IsRowRel())
1859 return false;
1861 break;
1862 case svIndex:
1863 return false;
1864 default:
1869 return true;
1872 bool ScTokenArray::IsReference( ScRange& rRange, const ScAddress& rPos ) const
1874 return ImplGetReference(rRange, rPos, false);
1877 bool ScTokenArray::IsValidReference( ScRange& rRange, const ScAddress& rPos ) const
1879 return ImplGetReference(rRange, rPos, true);
1882 ScTokenArray::ScTokenArray(const ScDocument& rDoc) :
1883 mxSheetLimits(&rDoc.GetSheetLimits()),
1884 mnHashValue(0)
1886 ResetVectorState();
1889 ScTokenArray::ScTokenArray(ScSheetLimits& rLimits) :
1890 mxSheetLimits(&rLimits),
1891 mnHashValue(0)
1893 ResetVectorState();
1896 ScTokenArray::~ScTokenArray()
1900 ScTokenArray& ScTokenArray::operator=( const ScTokenArray& rArr )
1902 Clear();
1903 Assign( rArr );
1904 mnHashValue = rArr.mnHashValue;
1905 meVectorState = rArr.meVectorState;
1906 mbOpenCLEnabled = rArr.mbOpenCLEnabled;
1907 mbThreadingEnabled = rArr.mbThreadingEnabled;
1908 return *this;
1911 ScTokenArray& ScTokenArray::operator=( ScTokenArray&& rArr )
1913 mxSheetLimits = std::move(rArr.mxSheetLimits);
1914 mnHashValue = rArr.mnHashValue;
1915 meVectorState = rArr.meVectorState;
1916 mbOpenCLEnabled = rArr.mbOpenCLEnabled;
1917 mbThreadingEnabled = rArr.mbThreadingEnabled;
1918 Move(std::move(rArr));
1919 return *this;
1922 bool ScTokenArray::EqualTokens( const ScTokenArray* pArr2) const
1924 // We only compare the non-RPN array
1925 if ( pArr2->nLen != nLen )
1926 return false;
1928 FormulaToken** ppToken1 = GetArray();
1929 FormulaToken** ppToken2 = pArr2->GetArray();
1930 for (sal_uInt16 i=0; i<nLen; i++)
1932 if ( ppToken1[i] != ppToken2[i] &&
1933 !(*ppToken1[i] == *ppToken2[i]) )
1934 return false; // Difference
1936 return true; // All entries are the same
1939 void ScTokenArray::Clear()
1941 mnHashValue = 0;
1942 ResetVectorState();
1943 FormulaTokenArray::Clear();
1946 std::unique_ptr<ScTokenArray> ScTokenArray::Clone() const
1948 std::unique_ptr<ScTokenArray> p(new ScTokenArray(*mxSheetLimits));
1949 p->nLen = nLen;
1950 p->nRPN = nRPN;
1951 p->nMode = nMode;
1952 p->nError = nError;
1953 p->bHyperLink = bHyperLink;
1954 p->mnHashValue = mnHashValue;
1955 p->meVectorState = meVectorState;
1956 p->mbOpenCLEnabled = mbOpenCLEnabled;
1957 p->mbThreadingEnabled = mbThreadingEnabled;
1958 p->mbFromRangeName = mbFromRangeName;
1959 p->mbShareable = mbShareable;
1961 FormulaToken** pp;
1962 if( nLen )
1964 p->pCode.reset(new FormulaToken*[ nLen ]);
1965 pp = p->pCode.get();
1966 memcpy( pp, pCode.get(), nLen * sizeof( formula::FormulaToken* ) );
1967 for( sal_uInt16 i = 0; i < nLen; i++, pp++ )
1969 *pp = (*pp)->Clone();
1970 (*pp)->IncRef();
1973 if( nRPN )
1975 pp = p->pRPN = new FormulaToken*[ nRPN ];
1976 memcpy( pp, pRPN, nRPN * sizeof( formula::FormulaToken* ) );
1977 for( sal_uInt16 i = 0; i < nRPN; i++, pp++ )
1979 FormulaToken* t = *pp;
1980 if( t->GetRef() > 1 )
1982 FormulaToken** p2 = pCode.get();
1983 sal_uInt16 nIdx = 0xFFFF;
1984 for( sal_uInt16 j = 0; j < nLen; j++, p2++ )
1986 if( *p2 == t )
1988 nIdx = j; break;
1991 if( nIdx == 0xFFFF )
1992 *pp = t->Clone();
1993 else
1994 *pp = p->pCode[ nIdx ];
1996 else
1997 *pp = t->Clone();
1998 (*pp)->IncRef();
2001 return p;
2004 ScTokenArray ScTokenArray::CloneValue() const
2006 ScTokenArray aNew(*mxSheetLimits);
2007 aNew.nLen = nLen;
2008 aNew.nRPN = nRPN;
2009 aNew.nMode = nMode;
2010 aNew.nError = nError;
2011 aNew.bHyperLink = bHyperLink;
2012 aNew.mnHashValue = mnHashValue;
2013 aNew.meVectorState = meVectorState;
2014 aNew.mbOpenCLEnabled = mbOpenCLEnabled;
2015 aNew.mbThreadingEnabled = mbThreadingEnabled;
2016 aNew.mbFromRangeName = mbFromRangeName;
2017 aNew.mbShareable = mbShareable;
2019 FormulaToken** pp;
2020 if( nLen )
2022 aNew.pCode.reset(new FormulaToken*[ nLen ]);
2023 pp = aNew.pCode.get();
2024 memcpy( pp, pCode.get(), nLen * sizeof( formula::FormulaToken* ) );
2025 for( sal_uInt16 i = 0; i < nLen; i++, pp++ )
2027 *pp = (*pp)->Clone();
2028 (*pp)->IncRef();
2031 if( nRPN )
2033 pp = aNew.pRPN = new FormulaToken*[ nRPN ];
2034 memcpy( pp, pRPN, nRPN * sizeof( formula::FormulaToken* ) );
2035 for( sal_uInt16 i = 0; i < nRPN; i++, pp++ )
2037 FormulaToken* t = *pp;
2038 if( t->GetRef() > 1 )
2040 FormulaToken** p2 = pCode.get();
2041 sal_uInt16 nIdx = 0xFFFF;
2042 for( sal_uInt16 j = 0; j < nLen; j++, p2++ )
2044 if( *p2 == t )
2046 nIdx = j; break;
2049 if( nIdx == 0xFFFF )
2050 *pp = t->Clone();
2051 else
2052 *pp = aNew.pCode[ nIdx ];
2054 else
2055 *pp = t->Clone();
2056 (*pp)->IncRef();
2059 return aNew;
2062 FormulaToken* ScTokenArray::AddRawToken( const ScRawToken& r )
2064 return Add( r.CreateToken(*mxSheetLimits) );
2067 // Utility function to ensure that there is strict alternation of values and
2068 // separators.
2069 static bool
2070 checkArraySep( bool & bPrevWasSep, bool bNewVal )
2072 bool bResult = (bPrevWasSep == bNewVal);
2073 bPrevWasSep = bNewVal;
2074 return bResult;
2077 FormulaToken* ScTokenArray::MergeArray( )
2079 int nCol = -1, nRow = 0;
2080 int i, nPrevRowSep = -1, nStart = 0;
2081 bool bPrevWasSep = false; // top of stack is ocArrayClose
2082 FormulaToken* t;
2083 bool bNumeric = false; // numeric value encountered in current element
2085 // (1) Iterate from the end to the start to find matrix dims
2086 // and do basic validation.
2087 for ( i = nLen ; i-- > nStart ; )
2089 t = pCode[i];
2090 switch ( t->GetOpCode() )
2092 case ocPush :
2093 if( checkArraySep( bPrevWasSep, false ) )
2095 return nullptr;
2098 // no references or nested arrays
2099 if ( t->GetType() != svDouble && t->GetType() != svString )
2101 return nullptr;
2103 bNumeric = (t->GetType() == svDouble);
2104 break;
2106 case ocMissing :
2107 case ocTrue :
2108 case ocFalse :
2109 if( checkArraySep( bPrevWasSep, false ) )
2111 return nullptr;
2113 bNumeric = false;
2114 break;
2116 case ocArrayColSep :
2117 case ocSep :
2118 if( checkArraySep( bPrevWasSep, true ) )
2120 return nullptr;
2122 bNumeric = false;
2123 break;
2125 case ocArrayClose :
2126 // not possible with the , but check just in case
2127 // something changes in the future
2128 if( i != (nLen-1))
2130 return nullptr;
2133 if( checkArraySep( bPrevWasSep, true ) )
2135 return nullptr;
2138 nPrevRowSep = i;
2139 bNumeric = false;
2140 break;
2142 case ocArrayOpen :
2143 nStart = i; // stop iteration
2144 [[fallthrough]]; // to ArrayRowSep
2146 case ocArrayRowSep :
2147 if( checkArraySep( bPrevWasSep, true ) )
2149 return nullptr;
2152 if( nPrevRowSep < 0 || // missing ocArrayClose
2153 ((nPrevRowSep - i) % 2) == 1) // no complex elements
2155 return nullptr;
2158 if( nCol < 0 )
2160 nCol = (nPrevRowSep - i) / 2;
2162 else if( (nPrevRowSep - i)/2 != nCol) // irregular array
2164 return nullptr;
2167 nPrevRowSep = i;
2168 nRow++;
2169 bNumeric = false;
2170 break;
2172 case ocNegSub :
2173 case ocAdd :
2174 // negation or unary plus must precede numeric value
2175 if( !bNumeric )
2177 return nullptr;
2179 --nPrevRowSep; // shorten this row by 1
2180 bNumeric = false; // one level only, no --42
2181 break;
2183 case ocSpaces :
2184 case ocWhitespace :
2185 // ignore spaces
2186 --nPrevRowSep; // shorten this row by 1
2187 break;
2189 default :
2190 // no functions or operators
2191 return nullptr;
2194 if( nCol <= 0 || nRow <= 0 )
2195 return nullptr;
2197 int nSign = 1;
2198 ScMatrix* pArray = new ScMatrix(nCol, nRow, 0.0);
2199 for ( i = nStart, nCol = 0, nRow = 0 ; i < nLen ; i++ )
2201 t = pCode[i];
2203 switch ( t->GetOpCode() )
2205 case ocPush :
2206 if ( t->GetType() == svDouble )
2208 pArray->PutDouble( t->GetDouble() * nSign, nCol, nRow );
2209 nSign = 1;
2211 else if ( t->GetType() == svString )
2213 pArray->PutString(t->GetString(), nCol, nRow);
2215 break;
2217 case ocMissing :
2218 pArray->PutEmpty( nCol, nRow );
2219 break;
2221 case ocTrue :
2222 pArray->PutBoolean( true, nCol, nRow );
2223 break;
2225 case ocFalse :
2226 pArray->PutBoolean( false, nCol, nRow );
2227 break;
2229 case ocArrayColSep :
2230 case ocSep :
2231 nCol++;
2232 break;
2234 case ocArrayRowSep :
2235 nRow++; nCol = 0;
2236 break;
2238 case ocNegSub :
2239 nSign = -nSign;
2240 break;
2242 default :
2243 break;
2245 pCode[i] = nullptr;
2246 t->DecRef();
2248 nLen = sal_uInt16( nStart );
2249 return AddMatrix( pArray );
2252 void ScTokenArray::MergeRangeReference( const ScAddress & rPos )
2254 if (!pCode || !nLen)
2255 return;
2256 sal_uInt16 nIdx = nLen;
2258 // The actual types are checked in extendRangeReference().
2259 FormulaToken *p3 = PeekPrev(nIdx); // ref
2260 if (!p3)
2261 return;
2262 FormulaToken *p2 = PeekPrev(nIdx); // ocRange
2263 if (!p2 || p2->GetOpCode() != ocRange)
2264 return;
2265 FormulaToken *p1 = PeekPrev(nIdx); // ref
2266 if (!p1)
2267 return;
2268 FormulaTokenRef p = extendRangeReference( *mxSheetLimits, *p1, *p3, rPos, true);
2269 if (p)
2271 p->IncRef();
2272 p1->DecRef();
2273 p2->DecRef();
2274 p3->DecRef();
2275 nLen -= 2;
2276 pCode[ nLen-1 ] = p.get();
2280 FormulaToken* ScTokenArray::AddOpCode( OpCode e )
2282 ScRawToken t;
2283 t.SetOpCode( e );
2284 return AddRawToken( t );
2287 FormulaToken* ScTokenArray::AddSingleReference( const ScSingleRefData& rRef )
2289 return Add( new ScSingleRefToken( *mxSheetLimits, rRef ) );
2292 FormulaToken* ScTokenArray::AddMatrixSingleReference( const ScSingleRefData& rRef )
2294 return Add( new ScSingleRefToken(*mxSheetLimits, rRef, ocMatRef ) );
2297 FormulaToken* ScTokenArray::AddDoubleReference( const ScComplexRefData& rRef )
2299 return Add( new ScDoubleRefToken(*mxSheetLimits, rRef ) );
2302 FormulaToken* ScTokenArray::AddMatrix( const ScMatrixRef& p )
2304 return Add( new ScMatrixToken( p ) );
2307 void ScTokenArray::AddRangeName( sal_uInt16 n, sal_Int16 nSheet )
2309 Add( new FormulaIndexToken( ocName, n, nSheet));
2312 FormulaToken* ScTokenArray::AddDBRange( sal_uInt16 n )
2314 return Add( new FormulaIndexToken( ocDBArea, n));
2317 FormulaToken* ScTokenArray::AddExternalName( sal_uInt16 nFileId, const svl::SharedString& rName )
2319 return Add( new ScExternalNameToken(nFileId, rName) );
2322 void ScTokenArray::AddExternalSingleReference( sal_uInt16 nFileId, const svl::SharedString& rTabName,
2323 const ScSingleRefData& rRef )
2325 Add( new ScExternalSingleRefToken(nFileId, rTabName, rRef) );
2328 FormulaToken* ScTokenArray::AddExternalDoubleReference( sal_uInt16 nFileId, const svl::SharedString& rTabName,
2329 const ScComplexRefData& rRef )
2331 return Add( new ScExternalDoubleRefToken(nFileId, rTabName, rRef) );
2334 FormulaToken* ScTokenArray::AddColRowName( const ScSingleRefData& rRef )
2336 return Add( new ScSingleRefToken(*mxSheetLimits, rRef, ocColRowName ) );
2339 void ScTokenArray::AssignXMLString( const OUString &rText, const OUString &rFormulaNmsp )
2341 sal_uInt16 nTokens = 1;
2342 FormulaToken *aTokens[2];
2344 aTokens[0] = new FormulaStringOpToken( ocStringXML, svl::SharedString( rText) ); // string not interned
2345 if( !rFormulaNmsp.isEmpty() )
2346 aTokens[ nTokens++ ] = new FormulaStringOpToken( ocStringXML,
2347 svl::SharedString( rFormulaNmsp) ); // string not interned
2349 Assign( nTokens, aTokens );
2352 bool ScTokenArray::GetAdjacentExtendOfOuterFuncRefs( SCCOLROW& nExtend,
2353 const ScAddress& rPos, ScDirection eDir )
2355 SCCOL nCol = 0;
2356 SCROW nRow = 0;
2357 switch ( eDir )
2359 case DIR_BOTTOM :
2360 if ( rPos.Row() >= mxSheetLimits->mnMaxRow )
2361 return false;
2362 nExtend = rPos.Row();
2363 nRow = nExtend + 1;
2364 break;
2365 case DIR_RIGHT :
2366 if ( rPos.Col() >= mxSheetLimits->mnMaxCol )
2367 return false;
2368 nExtend = rPos.Col();
2369 nCol = static_cast<SCCOL>(nExtend) + 1;
2370 break;
2371 case DIR_TOP :
2372 if ( rPos.Row() <= 0 )
2373 return false;
2374 nExtend = rPos.Row();
2375 nRow = nExtend - 1;
2376 break;
2377 case DIR_LEFT :
2378 if ( rPos.Col() <= 0 )
2379 return false;
2380 nExtend = rPos.Col();
2381 nCol = static_cast<SCCOL>(nExtend) - 1;
2382 break;
2383 default:
2384 OSL_FAIL( "unknown Direction" );
2385 return false;
2387 if ( pRPN && nRPN )
2389 FormulaToken* t = pRPN[nRPN-1];
2390 if ( t->GetType() == svByte )
2392 sal_uInt8 nParamCount = t->GetByte();
2393 if ( nParamCount && nRPN > nParamCount )
2395 bool bRet = false;
2396 sal_uInt16 nParam = nRPN - nParamCount - 1;
2397 for ( ; nParam < nRPN-1; nParam++ )
2399 FormulaToken* p = pRPN[nParam];
2400 switch ( p->GetType() )
2402 case svSingleRef :
2404 ScSingleRefData& rRef = *p->GetSingleRef();
2405 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rPos);
2406 switch ( eDir )
2408 case DIR_BOTTOM :
2409 if (aAbs.Row() == nRow && aAbs.Row() > nExtend)
2411 nExtend = aAbs.Row();
2412 bRet = true;
2414 break;
2415 case DIR_RIGHT :
2416 if (aAbs.Col() == nCol && static_cast<SCCOLROW>(aAbs.Col()) > nExtend)
2418 nExtend = aAbs.Col();
2419 bRet = true;
2421 break;
2422 case DIR_TOP :
2423 if (aAbs.Row() == nRow && aAbs.Row() < nExtend)
2425 nExtend = aAbs.Row();
2426 bRet = true;
2428 break;
2429 case DIR_LEFT :
2430 if (aAbs.Col() == nCol && static_cast<SCCOLROW>(aAbs.Col()) < nExtend)
2432 nExtend = aAbs.Col();
2433 bRet = true;
2435 break;
2438 break;
2439 case svDoubleRef :
2441 ScComplexRefData& rRef = *p->GetDoubleRef();
2442 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rPos);
2443 switch ( eDir )
2445 case DIR_BOTTOM :
2446 if (aAbs.aStart.Row() == nRow && aAbs.aEnd.Row() > nExtend)
2448 nExtend = aAbs.aEnd.Row();
2449 bRet = true;
2451 break;
2452 case DIR_RIGHT :
2453 if (aAbs.aStart.Col() == nCol && static_cast<SCCOLROW>(aAbs.aEnd.Col()) > nExtend)
2455 nExtend = aAbs.aEnd.Col();
2456 bRet = true;
2458 break;
2459 case DIR_TOP :
2460 if (aAbs.aEnd.Row() == nRow && aAbs.aStart.Row() < nExtend)
2462 nExtend = aAbs.aStart.Row();
2463 bRet = true;
2465 break;
2466 case DIR_LEFT :
2467 if (aAbs.aEnd.Col() == nCol && static_cast<SCCOLROW>(aAbs.aStart.Col()) < nExtend)
2469 nExtend = aAbs.aStart.Col();
2470 bRet = true;
2472 break;
2475 break;
2476 default:
2478 // added to avoid warnings
2480 } // switch
2481 } // for
2482 return bRet;
2486 return false;
2489 namespace {
2491 void GetExternalTableData(const ScDocument* pOldDoc, const ScDocument* pNewDoc, const SCTAB nTab, OUString& rTabName, sal_uInt16& rFileId)
2493 const OUString& aFileName = pOldDoc->GetFileURL();
2494 rFileId = pNewDoc->GetExternalRefManager()->getExternalFileId(aFileName);
2495 rTabName = pOldDoc->GetCopyTabName(nTab);
2496 if (rTabName.isEmpty())
2497 pOldDoc->GetName(nTab, rTabName);
2500 bool IsInCopyRange( const ScRange& rRange, const ScDocument* pClipDoc )
2502 ScClipParam& rClipParam = const_cast<ScDocument*>(pClipDoc)->GetClipParam();
2503 return rClipParam.maRanges.Contains(rRange);
2506 bool SkipReference(formula::FormulaToken* pToken, const ScAddress& rPos, const ScDocument& rOldDoc, bool bRangeName, bool bCheckCopyArea)
2508 ScRange aRange;
2510 if (!ScRefTokenHelper::getRangeFromToken(&rOldDoc, aRange, pToken, rPos))
2511 return true;
2513 if (bRangeName && aRange.aStart.Tab() == rPos.Tab())
2515 switch (pToken->GetType())
2517 case svDoubleRef:
2519 ScSingleRefData& rRef = *pToken->GetSingleRef2();
2520 if (rRef.IsColRel() || rRef.IsRowRel())
2521 return true;
2523 [[fallthrough]];
2524 case svSingleRef:
2526 ScSingleRefData& rRef = *pToken->GetSingleRef();
2527 if (rRef.IsColRel() || rRef.IsRowRel())
2528 return true;
2530 break;
2531 default:
2532 break;
2536 if (bCheckCopyArea && IsInCopyRange(aRange, &rOldDoc))
2537 return true;
2539 return false;
2542 void AdjustSingleRefData( ScSingleRefData& rRef, const ScAddress& rOldPos, const ScAddress& rNewPos)
2544 SCCOL nCols = rNewPos.Col() - rOldPos.Col();
2545 SCROW nRows = rNewPos.Row() - rOldPos.Row();
2546 SCTAB nTabs = rNewPos.Tab() - rOldPos.Tab();
2548 if (!rRef.IsColRel())
2549 rRef.IncCol(nCols);
2551 if (!rRef.IsRowRel())
2552 rRef.IncRow(nRows);
2554 if (!rRef.IsTabRel())
2555 rRef.IncTab(nTabs);
2560 void ScTokenArray::ReadjustAbsolute3DReferences( const ScDocument& rOldDoc, ScDocument& rNewDoc, const ScAddress& rPos, bool bRangeName )
2562 for ( sal_uInt16 j=0; j<nLen; ++j )
2564 switch ( pCode[j]->GetType() )
2566 case svDoubleRef :
2568 if (SkipReference(pCode[j], rPos, rOldDoc, bRangeName, true))
2569 continue;
2571 ScComplexRefData& rRef = *pCode[j]->GetDoubleRef();
2572 ScSingleRefData& rRef2 = rRef.Ref2;
2573 ScSingleRefData& rRef1 = rRef.Ref1;
2575 if ( (rRef2.IsFlag3D() && !rRef2.IsTabRel()) || (rRef1.IsFlag3D() && !rRef1.IsTabRel()) )
2577 OUString aTabName;
2578 sal_uInt16 nFileId;
2579 GetExternalTableData(&rOldDoc, &rNewDoc, rRef1.Tab(), aTabName, nFileId);
2580 ReplaceToken( j, new ScExternalDoubleRefToken( nFileId,
2581 rNewDoc.GetSharedStringPool().intern( aTabName), rRef), CODE_AND_RPN);
2582 // ATTENTION: rRef can't be used after this point
2585 break;
2586 case svSingleRef :
2588 if (SkipReference(pCode[j], rPos, rOldDoc, bRangeName, true))
2589 continue;
2591 ScSingleRefData& rRef = *pCode[j]->GetSingleRef();
2593 if ( rRef.IsFlag3D() && !rRef.IsTabRel() )
2595 OUString aTabName;
2596 sal_uInt16 nFileId;
2597 GetExternalTableData(&rOldDoc, &rNewDoc, rRef.Tab(), aTabName, nFileId);
2598 ReplaceToken( j, new ScExternalSingleRefToken( nFileId,
2599 rNewDoc.GetSharedStringPool().intern( aTabName), rRef), CODE_AND_RPN);
2600 // ATTENTION: rRef can't be used after this point
2603 break;
2604 default:
2606 // added to avoid warnings
2612 void ScTokenArray::AdjustAbsoluteRefs( const ScDocument& rOldDoc, const ScAddress& rOldPos, const ScAddress& rNewPos,
2613 bool bCheckCopyRange)
2615 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN, true);
2616 for (size_t j=0; j<2; ++j)
2618 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
2619 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
2620 for (; pp != pEnd; ++pp)
2622 FormulaToken* p = aPtrs.getHandledToken(j,pp);
2623 if (!p)
2624 continue;
2626 switch ( p->GetType() )
2628 case svDoubleRef :
2630 if (!SkipReference(p, rOldPos, rOldDoc, false, bCheckCopyRange))
2631 continue;
2633 ScComplexRefData& rRef = *p->GetDoubleRef();
2634 ScSingleRefData& rRef2 = rRef.Ref2;
2635 ScSingleRefData& rRef1 = rRef.Ref1;
2637 AdjustSingleRefData( rRef1, rOldPos, rNewPos );
2638 AdjustSingleRefData( rRef2, rOldPos, rNewPos );
2640 break;
2641 case svSingleRef :
2643 if (!SkipReference(p, rOldPos, rOldDoc, false, bCheckCopyRange))
2644 continue;
2646 ScSingleRefData& rRef = *p->GetSingleRef();
2648 AdjustSingleRefData( rRef, rOldPos, rNewPos );
2650 break;
2651 default:
2653 // added to avoid warnings
2660 void ScTokenArray::AdjustSheetLocalNameReferences( SCTAB nOldTab, SCTAB nNewTab )
2662 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN, false);
2663 for (size_t j=0; j<2; ++j)
2665 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
2666 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
2667 for (; pp != pEnd; ++pp)
2669 FormulaToken* p = aPtrs.getHandledToken(j,pp);
2670 if (!p)
2671 continue;
2673 switch ( p->GetType() )
2675 case svDoubleRef :
2677 ScComplexRefData& rRef = *p->GetDoubleRef();
2678 ScSingleRefData& rRef2 = rRef.Ref2;
2679 ScSingleRefData& rRef1 = rRef.Ref1;
2681 if (!rRef1.IsTabRel() && rRef1.Tab() == nOldTab)
2682 rRef1.SetAbsTab( nNewTab);
2683 if (!rRef2.IsTabRel() && rRef2.Tab() == nOldTab)
2684 rRef2.SetAbsTab( nNewTab);
2685 if (!rRef1.IsTabRel() && !rRef2.IsTabRel() && rRef1.Tab() > rRef2.Tab())
2687 SCTAB nTab = rRef1.Tab();
2688 rRef1.SetAbsTab( rRef2.Tab());
2689 rRef2.SetAbsTab( nTab);
2692 break;
2693 case svSingleRef :
2695 ScSingleRefData& rRef = *p->GetSingleRef();
2697 if (!rRef.IsTabRel() && rRef.Tab() == nOldTab)
2698 rRef.SetAbsTab( nNewTab);
2700 break;
2701 default:
2708 bool ScTokenArray::ReferencesSheet( SCTAB nTab, SCTAB nPosTab ) const
2710 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN, false);
2711 for (size_t j=0; j<2; ++j)
2713 FormulaToken* const * pp = aPtrs.maPointerRange[j].mpStart;
2714 FormulaToken* const * const pEnd = aPtrs.maPointerRange[j].mpStop;
2715 for (; pp != pEnd; ++pp)
2717 const FormulaToken* p = aPtrs.getHandledToken(j,pp);
2718 if (!p)
2719 continue;
2721 switch ( p->GetType() )
2723 case svDoubleRef :
2725 const ScComplexRefData& rRef = *p->GetDoubleRef();
2726 const ScSingleRefData& rRef2 = rRef.Ref2;
2727 const ScSingleRefData& rRef1 = rRef.Ref1;
2729 SCTAB nTab1 = (rRef1.IsTabRel() ? rRef1.Tab() + nPosTab : rRef1.Tab());
2730 SCTAB nTab2 = (rRef2.IsTabRel() ? rRef2.Tab() + nPosTab : rRef2.Tab());
2731 if (nTab1 <= nTab && nTab <= nTab2)
2732 return true;
2734 break;
2735 case svSingleRef :
2737 const ScSingleRefData& rRef = *p->GetSingleRef();
2738 if (rRef.IsTabRel())
2740 if (rRef.Tab() + nPosTab == nTab)
2741 return true;
2743 else
2745 if (rRef.Tab() == nTab)
2746 return true;
2749 break;
2750 default:
2755 return false;
2758 namespace {
2760 ScRange getSelectedRange( const sc::RefUpdateContext& rCxt )
2762 ScRange aSelectedRange(ScAddress::INITIALIZE_INVALID);
2763 if (rCxt.mnColDelta < 0)
2765 // Delete and shift to left.
2766 aSelectedRange.aStart = ScAddress(rCxt.maRange.aStart.Col()+rCxt.mnColDelta, rCxt.maRange.aStart.Row(), rCxt.maRange.aStart.Tab());
2767 aSelectedRange.aEnd = ScAddress(rCxt.maRange.aStart.Col()-1, rCxt.maRange.aEnd.Row(), rCxt.maRange.aEnd.Tab());
2769 else if (rCxt.mnRowDelta < 0)
2771 // Delete and shift up.
2772 aSelectedRange.aStart = ScAddress(rCxt.maRange.aStart.Col(), rCxt.maRange.aStart.Row()+rCxt.mnRowDelta, rCxt.maRange.aStart.Tab());
2773 aSelectedRange.aEnd = ScAddress(rCxt.maRange.aEnd.Col(), rCxt.maRange.aStart.Row()-1, rCxt.maRange.aEnd.Tab());
2775 else if (rCxt.mnTabDelta < 0)
2777 // Deleting sheets.
2778 // TODO : Figure out what to do here.
2780 else if (rCxt.mnColDelta > 0)
2782 // Insert and shift to the right.
2783 aSelectedRange.aStart = rCxt.maRange.aStart;
2784 aSelectedRange.aEnd = ScAddress(rCxt.maRange.aStart.Col()+rCxt.mnColDelta-1, rCxt.maRange.aEnd.Row(), rCxt.maRange.aEnd.Tab());
2786 else if (rCxt.mnRowDelta > 0)
2788 // Insert and shift down.
2789 aSelectedRange.aStart = rCxt.maRange.aStart;
2790 aSelectedRange.aEnd = ScAddress(rCxt.maRange.aEnd.Col(), rCxt.maRange.aStart.Row()+rCxt.mnRowDelta-1, rCxt.maRange.aEnd.Tab());
2792 else if (rCxt.mnTabDelta > 0)
2794 // Inserting sheets.
2795 // TODO : Figure out what to do here.
2798 return aSelectedRange;
2801 void setRefDeleted( ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt )
2803 if (rCxt.mnColDelta < 0)
2804 rRef.SetColDeleted(true);
2805 else if (rCxt.mnRowDelta < 0)
2806 rRef.SetRowDeleted(true);
2807 else if (rCxt.mnTabDelta < 0)
2808 rRef.SetTabDeleted(true);
2811 void restoreDeletedRef( ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt )
2813 if (rCxt.mnColDelta)
2815 if (rRef.IsColDeleted())
2816 rRef.SetColDeleted(false);
2818 else if (rCxt.mnRowDelta)
2820 if (rRef.IsRowDeleted())
2821 rRef.SetRowDeleted(false);
2823 else if (rCxt.mnTabDelta)
2825 if (rRef.IsTabDeleted())
2826 rRef.SetTabDeleted(false);
2830 void setRefDeleted( ScComplexRefData& rRef, const sc::RefUpdateContext& rCxt )
2832 if (rCxt.mnColDelta < 0)
2834 rRef.Ref1.SetColDeleted(true);
2835 rRef.Ref2.SetColDeleted(true);
2837 else if (rCxt.mnRowDelta < 0)
2839 rRef.Ref1.SetRowDeleted(true);
2840 rRef.Ref2.SetRowDeleted(true);
2842 else if (rCxt.mnTabDelta < 0)
2844 rRef.Ref1.SetTabDeleted(true);
2845 rRef.Ref2.SetTabDeleted(true);
2849 void restoreDeletedRef( ScComplexRefData& rRef, const sc::RefUpdateContext& rCxt )
2851 restoreDeletedRef(rRef.Ref1, rCxt);
2852 restoreDeletedRef(rRef.Ref2, rCxt);
2855 enum ShrinkResult
2857 UNMODIFIED,
2858 SHRUNK,
2859 STICKY
2862 ShrinkResult shrinkRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const ScRange& rDeletedRange,
2863 const ScComplexRefData& rRef )
2865 if (!rDeletedRange.Intersects(rRefRange))
2866 return UNMODIFIED;
2868 if (rCxt.mnColDelta < 0)
2870 if (rRef.IsEntireRow(rCxt.mrDoc.GetSheetLimits()))
2871 // Entire rows are not affected, columns are anchored.
2872 return STICKY;
2874 // Shifting left.
2875 if (rRefRange.aStart.Row() < rDeletedRange.aStart.Row() || rDeletedRange.aEnd.Row() < rRefRange.aEnd.Row())
2876 // Deleted range is only partially overlapping in vertical direction. Bail out.
2877 return UNMODIFIED;
2879 if (rDeletedRange.aStart.Col() <= rRefRange.aStart.Col())
2881 if (rRefRange.aEnd.Col() <= rDeletedRange.aEnd.Col())
2883 // Reference is entirely deleted.
2884 rRefRange.SetInvalid();
2886 else
2888 // The reference range is truncated on the left.
2889 SCCOL nOffset = rDeletedRange.aStart.Col() - rRefRange.aStart.Col();
2890 SCCOL nDelta = rRefRange.aStart.Col() - rDeletedRange.aEnd.Col() - 1;
2891 rRefRange.IncEndColSticky(rCxt.mrDoc, nDelta+nOffset);
2892 rRefRange.aStart.IncCol(nOffset);
2895 else if (rDeletedRange.aEnd.Col() < rRefRange.aEnd.Col())
2897 if (rRefRange.IsEndColSticky(rCxt.mrDoc))
2898 // Sticky end not affected.
2899 return STICKY;
2901 // Reference is deleted in the middle. Move the last column
2902 // position to the left.
2903 SCCOL nDelta = rDeletedRange.aStart.Col() - rDeletedRange.aEnd.Col() - 1;
2904 rRefRange.IncEndColSticky(rCxt.mrDoc, nDelta);
2906 else
2908 if (rRefRange.IsEndColSticky(rCxt.mrDoc))
2909 // Sticky end not affected.
2910 return STICKY;
2912 // The reference range is truncated on the right.
2913 SCCOL nDelta = rDeletedRange.aStart.Col() - rRefRange.aEnd.Col() - 1;
2914 rRefRange.IncEndColSticky(rCxt.mrDoc, nDelta);
2916 return SHRUNK;
2918 else if (rCxt.mnRowDelta < 0)
2920 if (rRef.IsEntireCol(rCxt.mrDoc.GetSheetLimits()))
2921 // Entire columns are not affected, rows are anchored.
2922 return STICKY;
2924 // Shifting up.
2926 if (rRefRange.aStart.Col() < rDeletedRange.aStart.Col() || rDeletedRange.aEnd.Col() < rRefRange.aEnd.Col())
2927 // Deleted range is only partially overlapping in horizontal direction. Bail out.
2928 return UNMODIFIED;
2930 if (rDeletedRange.aStart.Row() <= rRefRange.aStart.Row())
2932 if (rRefRange.aEnd.Row() <= rDeletedRange.aEnd.Row())
2934 // Reference is entirely deleted.
2935 rRefRange.SetInvalid();
2937 else
2939 // The reference range is truncated on the top.
2940 SCROW nOffset = rDeletedRange.aStart.Row() - rRefRange.aStart.Row();
2941 SCROW nDelta = rRefRange.aStart.Row() - rDeletedRange.aEnd.Row() - 1;
2942 rRefRange.IncEndRowSticky(rCxt.mrDoc, nDelta+nOffset);
2943 rRefRange.aStart.IncRow(nOffset);
2946 else if (rDeletedRange.aEnd.Row() < rRefRange.aEnd.Row())
2948 if (rRefRange.IsEndRowSticky(rCxt.mrDoc))
2949 // Sticky end not affected.
2950 return STICKY;
2952 // Reference is deleted in the middle. Move the last row
2953 // position upward.
2954 SCROW nDelta = rDeletedRange.aStart.Row() - rDeletedRange.aEnd.Row() - 1;
2955 rRefRange.IncEndRowSticky(rCxt.mrDoc, nDelta);
2957 else
2959 if (rRefRange.IsEndRowSticky(rCxt.mrDoc))
2960 // Sticky end not affected.
2961 return STICKY;
2963 // The reference range is truncated on the bottom.
2964 SCROW nDelta = rDeletedRange.aStart.Row() - rRefRange.aEnd.Row() - 1;
2965 rRefRange.IncEndRowSticky(rCxt.mrDoc, nDelta);
2967 return SHRUNK;
2970 return UNMODIFIED;
2973 bool expandRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const ScRange& rSelectedRange,
2974 const ScComplexRefData& rRef )
2976 if (!rSelectedRange.Intersects(rRefRange))
2977 return false;
2979 if (rCxt.mnColDelta > 0)
2981 if (rRef.IsEntireRow(rCxt.mrDoc.GetSheetLimits()))
2982 // Entire rows are not affected, columns are anchored.
2983 return false;
2985 // Insert and shifting right.
2986 if (rRefRange.aStart.Row() < rSelectedRange.aStart.Row() || rSelectedRange.aEnd.Row() < rRefRange.aEnd.Row())
2987 // Selected range is only partially overlapping in vertical direction. Bail out.
2988 return false;
2990 if (rCxt.mrDoc.IsExpandRefs())
2992 if (rRefRange.aEnd.Col() - rRefRange.aStart.Col() < 1)
2993 // Reference must be at least two columns wide.
2994 return false;
2996 else
2998 if (rSelectedRange.aStart.Col() <= rRefRange.aStart.Col())
2999 // Selected range is at the left end and the edge expansion is turned off. No expansion.
3000 return false;
3003 if (rRefRange.IsEndColSticky(rCxt.mrDoc))
3004 // Sticky end not affected.
3005 return false;
3007 // Move the last column position to the right.
3008 SCCOL nDelta = rSelectedRange.aEnd.Col() - rSelectedRange.aStart.Col() + 1;
3009 rRefRange.IncEndColSticky(rCxt.mrDoc, nDelta);
3010 return true;
3012 else if (rCxt.mnRowDelta > 0)
3014 if (rRef.IsEntireCol(rCxt.mrDoc.GetSheetLimits()))
3015 // Entire columns are not affected, rows are anchored.
3016 return false;
3018 // Insert and shifting down.
3019 if (rRefRange.aStart.Col() < rSelectedRange.aStart.Col() || rSelectedRange.aEnd.Col() < rRefRange.aEnd.Col())
3020 // Selected range is only partially overlapping in horizontal direction. Bail out.
3021 return false;
3023 if (rCxt.mrDoc.IsExpandRefs())
3025 if (rRefRange.aEnd.Row() - rRefRange.aStart.Row() < 1)
3026 // Reference must be at least two rows tall.
3027 return false;
3029 else
3031 if (rSelectedRange.aStart.Row() <= rRefRange.aStart.Row())
3032 // Selected range is at the top end and the edge expansion is turned off. No expansion.
3033 return false;
3036 if (rRefRange.IsEndRowSticky(rCxt.mrDoc))
3037 // Sticky end not affected.
3038 return false;
3040 // Move the last row position down.
3041 SCROW nDelta = rSelectedRange.aEnd.Row() - rSelectedRange.aStart.Row() + 1;
3042 rRefRange.IncEndRowSticky(rCxt.mrDoc, nDelta);
3043 return true;
3045 return false;
3049 * Check if the referenced range is expandable when the selected range is
3050 * not overlapping the referenced range.
3052 bool expandRangeByEdge( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const ScRange& rSelectedRange,
3053 const ScComplexRefData& rRef )
3055 if (!rCxt.mrDoc.IsExpandRefs())
3056 // Edge-expansion is turned off.
3057 return false;
3059 if (rSelectedRange.aStart.Tab() > rRefRange.aStart.Tab() || rRefRange.aEnd.Tab() > rSelectedRange.aEnd.Tab())
3060 // Sheet references not within selected range.
3061 return false;
3063 if (rCxt.mnColDelta > 0)
3065 if (rRef.IsEntireRow(rCxt.mrDoc.GetSheetLimits()))
3066 // Entire rows are not affected, columns are anchored.
3067 return false;
3069 // Insert and shift right.
3071 if (rRefRange.aEnd.Col() - rRefRange.aStart.Col() < 1)
3072 // Reference must be at least two columns wide.
3073 return false;
3075 if (rRefRange.aStart.Row() < rSelectedRange.aStart.Row() || rSelectedRange.aEnd.Row() < rRefRange.aEnd.Row())
3076 // Selected range is only partially overlapping in vertical direction. Bail out.
3077 return false;
3079 if (rSelectedRange.aStart.Col() - rRefRange.aEnd.Col() != 1)
3080 // Selected range is not immediately adjacent. Bail out.
3081 return false;
3083 if (rRefRange.IsEndColSticky(rCxt.mrDoc))
3084 // Sticky end not affected.
3085 return false;
3087 // Move the last column position to the right.
3088 SCCOL nDelta = rSelectedRange.aEnd.Col() - rSelectedRange.aStart.Col() + 1;
3089 rRefRange.IncEndColSticky(rCxt.mrDoc, nDelta);
3090 return true;
3092 else if (rCxt.mnRowDelta > 0)
3094 if (rRef.IsEntireCol(rCxt.mrDoc.GetSheetLimits()))
3095 // Entire columns are not affected, rows are anchored.
3096 return false;
3098 if (rRefRange.aEnd.Row() - rRefRange.aStart.Row() < 1)
3099 // Reference must be at least two rows tall.
3100 return false;
3102 if (rRefRange.aStart.Col() < rSelectedRange.aStart.Col() || rSelectedRange.aEnd.Col() < rRefRange.aEnd.Col())
3103 // Selected range is only partially overlapping in horizontal direction. Bail out.
3104 return false;
3106 if (rSelectedRange.aStart.Row() - rRefRange.aEnd.Row() != 1)
3107 // Selected range is not immediately adjacent. Bail out.
3108 return false;
3110 if (rRefRange.IsEndRowSticky(rCxt.mrDoc))
3111 // Sticky end not affected.
3112 return false;
3114 // Move the last row position down.
3115 SCROW nDelta = rSelectedRange.aEnd.Row() - rSelectedRange.aStart.Row() + 1;
3116 rRefRange.IncEndRowSticky(rCxt.mrDoc, nDelta);
3117 return true;
3120 return false;
3123 bool isNameModified( const sc::UpdatedRangeNames& rUpdatedNames, SCTAB nOldTab, const formula::FormulaToken& rToken )
3125 SCTAB nTab = -1;
3126 if (rToken.GetSheet() >= 0)
3127 nTab = nOldTab;
3129 // Check if this named expression has been modified.
3130 return rUpdatedNames.isNameUpdated(nTab, rToken.GetIndex());
3133 bool isDBDataModified( const ScDocument& rDoc, const formula::FormulaToken& rToken )
3135 // Check if this DBData has been modified.
3136 const ScDBData* pDBData = rDoc.GetDBCollection()->getNamedDBs().findByIndex( rToken.GetIndex());
3137 if (!pDBData)
3138 return true;
3140 return pDBData->IsModified();
3145 sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos )
3147 ScRange aSelectedRange = getSelectedRange(rCxt);
3149 sc::RefUpdateResult aRes;
3150 ScAddress aNewPos = rOldPos;
3151 bool bCellShifted = rCxt.maRange.Contains(rOldPos);
3152 if (bCellShifted)
3154 ScAddress aErrorPos( ScAddress::UNINITIALIZED );
3155 if (!aNewPos.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos, rCxt.mrDoc))
3157 assert(!"can't move");
3161 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
3162 for (size_t j=0; j<2; ++j)
3164 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
3165 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
3166 for (; pp != pEnd; ++pp)
3168 FormulaToken* p = aPtrs.getHandledToken(j,pp);
3169 if (!p)
3170 continue;
3172 switch (p->GetType())
3174 case svSingleRef:
3176 ScSingleRefData& rRef = *p->GetSingleRef();
3177 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3179 if (rCxt.isDeleted() && aSelectedRange.Contains(aAbs))
3181 // This reference is in the deleted region.
3182 setRefDeleted(rRef, rCxt);
3183 aRes.mbValueChanged = true;
3184 break;
3187 if (!rCxt.isDeleted() && rRef.IsDeleted())
3189 // Check if the token has reference to previously deleted region.
3190 ScAddress aCheckPos = rRef.toAbs(*mxSheetLimits, aNewPos);
3191 if (rCxt.maRange.Contains(aCheckPos))
3193 restoreDeletedRef(rRef, rCxt);
3194 aRes.mbValueChanged = true;
3195 break;
3199 if (rCxt.maRange.Contains(aAbs))
3201 ScAddress aErrorPos( ScAddress::UNINITIALIZED );
3202 if (!aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos, rCxt.mrDoc))
3203 aAbs = aErrorPos;
3204 aRes.mbReferenceModified = true;
3207 rRef.SetAddress(*mxSheetLimits, aAbs, aNewPos);
3209 break;
3210 case svDoubleRef:
3212 ScComplexRefData& rRef = *p->GetDoubleRef();
3213 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3215 if (rCxt.isDeleted())
3217 if (aSelectedRange.Contains(aAbs))
3219 // This reference is in the deleted region.
3220 setRefDeleted(rRef, rCxt);
3221 aRes.mbValueChanged = true;
3222 break;
3224 else if (aSelectedRange.Intersects(aAbs))
3226 const ShrinkResult eSR = shrinkRange(rCxt, aAbs, aSelectedRange, rRef);
3227 if (eSR == SHRUNK)
3229 // The reference range has been shrunk.
3230 rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
3231 aRes.mbValueChanged = true;
3232 aRes.mbReferenceModified = true;
3233 break;
3235 else if (eSR == STICKY)
3237 // The reference range stays the same but a
3238 // new (empty) cell range is shifted in and
3239 // may change the calculation result.
3240 aRes.mbValueChanged = true;
3241 // Sticky when intersecting the selected
3242 // range means also that the other
3243 // conditions below are not met,
3244 // specifically not the
3245 // if (rCxt.maRange.Contains(aAbs))
3246 // that is able to update the reference,
3247 // but aSelectedRange does not intersect
3248 // with rCxt.maRange so that can't happen
3249 // and we can bail out early without
3250 // updating the reference.
3251 break;
3256 if (!rCxt.isDeleted() && rRef.IsDeleted())
3258 // Check if the token has reference to previously deleted region.
3259 ScRange aCheckRange = rRef.toAbs(*mxSheetLimits, aNewPos);
3260 if (aSelectedRange.Contains(aCheckRange))
3262 // This reference was previously in the deleted region. Restore it.
3263 restoreDeletedRef(rRef, rCxt);
3264 aRes.mbValueChanged = true;
3265 break;
3269 if (rCxt.isInserted())
3271 if (expandRange(rCxt, aAbs, aSelectedRange, rRef))
3273 // The reference range has been expanded.
3274 rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
3275 aRes.mbValueChanged = true;
3276 aRes.mbReferenceModified = true;
3277 break;
3280 if (expandRangeByEdge(rCxt, aAbs, aSelectedRange, rRef))
3282 // The reference range has been expanded on the edge.
3283 rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
3284 aRes.mbValueChanged = true;
3285 aRes.mbReferenceModified = true;
3286 break;
3290 if (rCxt.maRange.Contains(aAbs))
3292 // We shift either by column or by row, not both,
3293 // so moving the reference has only to be done in
3294 // the non-sticky case.
3295 if ((rCxt.mnRowDelta && rRef.IsEntireCol(rCxt.mrDoc.GetSheetLimits()))
3296 || (rCxt.mnColDelta && rRef.IsEntireRow(rCxt.mrDoc.GetSheetLimits())))
3298 // In entire col/row, values are shifted within
3299 // the reference, which affects all positional
3300 // results like in MATCH or matrix positions.
3301 aRes.mbValueChanged = true;
3303 else
3305 ScRange aErrorRange( ScAddress::UNINITIALIZED );
3306 if (!aAbs.MoveSticky(rCxt.mrDoc, rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorRange))
3307 aAbs = aErrorRange;
3308 aRes.mbReferenceModified = true;
3311 else if (rCxt.maRange.Intersects(aAbs))
3313 // Part of the referenced range is being shifted. This
3314 // will change the values of the range.
3315 aRes.mbValueChanged = true;
3318 rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
3320 break;
3321 case svExternalSingleRef:
3323 // For external reference, just reset the reference with
3324 // respect to the new cell position.
3325 ScSingleRefData& rRef = *p->GetSingleRef();
3326 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3327 rRef.SetAddress(*mxSheetLimits, aAbs, aNewPos);
3329 break;
3330 case svExternalDoubleRef:
3332 // Same as above.
3333 ScComplexRefData& rRef = *p->GetDoubleRef();
3334 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3335 rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
3337 break;
3338 default:
3342 // For ocTableRef p is the inner token of *pp, so have a separate
3343 // condition here.
3344 if ((*pp)->GetType() == svIndex)
3346 switch ((*pp)->GetOpCode())
3348 case ocName:
3350 SCTAB nOldTab = (*pp)->GetSheet();
3351 if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
3352 aRes.mbNameModified = true;
3353 if (rCxt.mnTabDelta &&
3354 rCxt.maRange.aStart.Tab() <= nOldTab && nOldTab <= rCxt.maRange.aEnd.Tab())
3356 aRes.mbNameModified = true;
3357 (*pp)->SetSheet( nOldTab + rCxt.mnTabDelta);
3360 break;
3361 case ocDBArea:
3362 case ocTableRef:
3363 if (isDBDataModified(rCxt.mrDoc, **pp))
3364 aRes.mbNameModified = true;
3365 break;
3366 default:
3367 ; // nothing
3373 return aRes;
3376 sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMove(
3377 const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos, const ScAddress& rNewPos )
3379 sc::RefUpdateResult aRes;
3381 if (!rCxt.mnColDelta && !rCxt.mnRowDelta && !rCxt.mnTabDelta)
3382 // The cell hasn't moved at all.
3383 return aRes;
3385 // When moving, the range in the context is the destination range. We need
3386 // to use the old range prior to the move for hit analysis.
3387 ScRange aOldRange = rCxt.maRange;
3388 ScRange aErrorMoveRange( ScAddress::UNINITIALIZED );
3389 if (!aOldRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta, aErrorMoveRange, rCxt.mrDoc))
3391 assert(!"can't move");
3394 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
3395 for (size_t j=0; j<2; ++j)
3397 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
3398 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
3399 for (; pp != pEnd; ++pp)
3401 FormulaToken* p = aPtrs.getHandledToken(j,pp);
3402 if (!p)
3403 continue;
3405 switch (p->GetType())
3407 case svSingleRef:
3409 ScSingleRefData& rRef = *p->GetSingleRef();
3410 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3412 // Do not update the reference in transposed case (cut paste transposed).
3413 // The reference will be updated in UpdateTranspose().
3414 // Additionally, do not update the references from cells within the moved
3415 // range as they lead to #REF! errors here. These #REF! cannot by fixed
3416 // later in UpdateTranspose().
3417 if (rCxt.mbTransposed && (aOldRange.Contains(rOldPos) || aOldRange.Contains(aAbs)))
3418 break;
3420 if (aOldRange.Contains(aAbs))
3422 ScAddress aErrorPos( ScAddress::UNINITIALIZED );
3423 if (!aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos, rCxt.mrDoc))
3424 aAbs = aErrorPos;
3425 aRes.mbReferenceModified = true;
3427 else if (rCxt.maRange.Contains(aAbs))
3429 // Referenced cell has been overwritten.
3430 aRes.mbValueChanged = true;
3433 rRef.SetAddress(*mxSheetLimits, aAbs, rNewPos);
3434 rRef.SetFlag3D(rRef.IsFlag3D() || !rRef.IsTabRel() || aAbs.Tab() != rNewPos.Tab());
3436 break;
3437 case svDoubleRef:
3439 ScComplexRefData& rRef = *p->GetDoubleRef();
3440 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3442 // Do not update the reference in transposed case (cut paste transposed).
3443 // The reference will be updated in UpdateTranspose().
3444 // Additionally, do not update the references from cells within the moved
3445 // range as they lead to #REF! errors here. These #REF! cannot by fixed
3446 // later in UpdateTranspose().
3447 if (rCxt.mbTransposed && (aOldRange.Contains(rOldPos) || aOldRange.Contains(aAbs)))
3448 break;
3450 if (aOldRange.Contains(aAbs))
3452 ScRange aErrorRange( ScAddress::UNINITIALIZED );
3453 if (!aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorRange, rCxt.mrDoc))
3454 aAbs = aErrorRange;
3455 aRes.mbReferenceModified = true;
3457 else if (rCxt.maRange.Contains(aAbs))
3459 // Referenced range has been entirely overwritten.
3460 aRes.mbValueChanged = true;
3463 rRef.SetRange(*mxSheetLimits, aAbs, rNewPos);
3464 bool b1, b2;
3465 if (aAbs.aStart.Tab() != aAbs.aEnd.Tab())
3467 // More than one sheet referenced => has to have
3468 // both 3D flags.
3469 b1 = b2 = true;
3471 else
3473 // Keep given 3D flag even for relative sheet
3474 // reference to same sheet.
3475 // Absolute sheet reference => set 3D flag.
3476 // Reference to another sheet => set 3D flag.
3477 b1 = rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel() || rNewPos.Tab() != aAbs.aStart.Tab();
3478 b2 = rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel() || rNewPos.Tab() != aAbs.aEnd.Tab();
3479 // End part has 3D flag => start part must have it too.
3480 if (b2)
3481 b1 = true;
3482 // End part sheet reference is identical to start
3483 // part sheet reference and end part sheet
3484 // reference was not explicitly given => clear end
3485 // part 3D flag.
3486 if (b1 && b2 && rRef.Ref1.IsTabRel() == rRef.Ref2.IsTabRel() && !rRef.Ref2.IsFlag3D())
3487 b2 = false;
3489 rRef.Ref1.SetFlag3D(b1);
3490 rRef.Ref2.SetFlag3D(b2);
3492 break;
3493 case svExternalSingleRef:
3495 ScSingleRefData& rRef = *p->GetSingleRef();
3496 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3497 rRef.SetAddress(*mxSheetLimits, aAbs, rNewPos);
3499 break;
3500 case svExternalDoubleRef:
3502 ScComplexRefData& rRef = *p->GetDoubleRef();
3503 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3504 rRef.SetRange(*mxSheetLimits, aAbs, rNewPos);
3506 break;
3507 default:
3511 // For ocTableRef p is the inner token of *pp, so have a separate
3512 // condition here.
3513 if ((*pp)->GetType() == svIndex)
3515 switch ((*pp)->GetOpCode())
3517 case ocName:
3519 SCTAB nOldTab = (*pp)->GetSheet();
3520 if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
3521 aRes.mbNameModified = true;
3523 break;
3524 case ocDBArea:
3525 case ocTableRef:
3526 if (isDBDataModified(rCxt.mrDoc, **pp))
3527 aRes.mbNameModified = true;
3528 break;
3529 default:
3530 ; // nothing
3536 return aRes;
3539 void ScTokenArray::MoveReferenceColReorder(
3540 const ScAddress& rPos, SCTAB nTab, SCROW nRow1, SCROW nRow2, const sc::ColRowReorderMapType& rColMap )
3542 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
3543 for (size_t j=0; j<2; ++j)
3545 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
3546 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
3547 for (; pp != pEnd; ++pp)
3549 FormulaToken* p = aPtrs.getHandledToken(j,pp);
3550 if (!p)
3551 continue;
3553 switch (p->GetType())
3555 case svSingleRef:
3557 ScSingleRefData& rRef = *p->GetSingleRef();
3558 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rPos);
3560 if (aAbs.Tab() == nTab && nRow1 <= aAbs.Row() && aAbs.Row() <= nRow2)
3562 // Inside reordered row range.
3563 sc::ColRowReorderMapType::const_iterator it = rColMap.find(aAbs.Col());
3564 if (it != rColMap.end())
3566 // This column is reordered.
3567 SCCOL nNewCol = it->second;
3568 aAbs.SetCol(nNewCol);
3569 rRef.SetAddress(*mxSheetLimits, aAbs, rPos);
3573 break;
3574 case svDoubleRef:
3576 ScComplexRefData& rRef = *p->GetDoubleRef();
3577 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rPos);
3579 if (aAbs.aStart.Tab() != aAbs.aEnd.Tab())
3580 // Must be a single-sheet reference.
3581 break;
3583 if (aAbs.aStart.Col() != aAbs.aEnd.Col())
3584 // Whole range must fit in a single column.
3585 break;
3587 if (aAbs.aStart.Tab() == nTab && nRow1 <= aAbs.aStart.Row() && aAbs.aEnd.Row() <= nRow2)
3589 // Inside reordered row range.
3590 sc::ColRowReorderMapType::const_iterator it = rColMap.find(aAbs.aStart.Col());
3591 if (it != rColMap.end())
3593 // This column is reordered.
3594 SCCOL nNewCol = it->second;
3595 aAbs.aStart.SetCol(nNewCol);
3596 aAbs.aEnd.SetCol(nNewCol);
3597 rRef.SetRange(*mxSheetLimits, aAbs, rPos);
3601 break;
3602 default:
3609 void ScTokenArray::MoveReferenceRowReorder( const ScAddress& rPos, SCTAB nTab, SCCOL nCol1, SCCOL nCol2, const sc::ColRowReorderMapType& rRowMap )
3611 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
3612 for (size_t j=0; j<2; ++j)
3614 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
3615 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
3616 for (; pp != pEnd; ++pp)
3618 FormulaToken* p = aPtrs.getHandledToken(j,pp);
3619 if (!p)
3620 continue;
3622 switch (p->GetType())
3624 case svSingleRef:
3626 ScSingleRefData& rRef = *p->GetSingleRef();
3627 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rPos);
3629 if (aAbs.Tab() == nTab && nCol1 <= aAbs.Col() && aAbs.Col() <= nCol2)
3631 // Inside reordered column range.
3632 sc::ColRowReorderMapType::const_iterator it = rRowMap.find(aAbs.Row());
3633 if (it != rRowMap.end())
3635 // This column is reordered.
3636 SCROW nNewRow = it->second;
3637 aAbs.SetRow(nNewRow);
3638 rRef.SetAddress(*mxSheetLimits, aAbs, rPos);
3642 break;
3643 case svDoubleRef:
3645 ScComplexRefData& rRef = *p->GetDoubleRef();
3646 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rPos);
3648 if (aAbs.aStart.Tab() != aAbs.aEnd.Tab())
3649 // Must be a single-sheet reference.
3650 break;
3652 if (aAbs.aStart.Row() != aAbs.aEnd.Row())
3653 // Whole range must fit in a single row.
3654 break;
3656 if (aAbs.aStart.Tab() == nTab && nCol1 <= aAbs.aStart.Col() && aAbs.aEnd.Col() <= nCol2)
3658 // Inside reordered column range.
3659 sc::ColRowReorderMapType::const_iterator it = rRowMap.find(aAbs.aStart.Row());
3660 if (it != rRowMap.end())
3662 // This row is reordered.
3663 SCROW nNewRow = it->second;
3664 aAbs.aStart.SetRow(nNewRow);
3665 aAbs.aEnd.SetRow(nNewRow);
3666 rRef.SetRange(*mxSheetLimits, aAbs, rPos);
3670 break;
3671 default:
3678 namespace {
3680 bool adjustSingleRefInName(
3681 ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt, const ScAddress& rPos,
3682 ScComplexRefData* pEndOfComplex )
3684 ScAddress aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3686 if (aAbs.Tab() < rCxt.maRange.aStart.Tab() || rCxt.maRange.aEnd.Tab() < aAbs.Tab())
3688 // This references a sheet that has not shifted. Don't change it.
3689 return false;
3692 if (!rCxt.maRange.Contains(rRef.toAbs(rCxt.mrDoc, rPos)))
3693 return false;
3695 bool bChanged = false;
3697 if (rCxt.mnColDelta && !rRef.IsColRel())
3699 // Adjust absolute column reference.
3700 if (rCxt.maRange.aStart.Col() <= rRef.Col() && rRef.Col() <= rCxt.maRange.aEnd.Col())
3702 if (pEndOfComplex)
3704 if (pEndOfComplex->IncEndColSticky(rCxt.mrDoc, rCxt.mnColDelta, rPos))
3705 bChanged = true;
3707 else
3709 rRef.IncCol(rCxt.mnColDelta);
3710 bChanged = true;
3715 if (rCxt.mnRowDelta && !rRef.IsRowRel())
3717 // Adjust absolute row reference.
3718 if (rCxt.maRange.aStart.Row() <= rRef.Row() && rRef.Row() <= rCxt.maRange.aEnd.Row())
3720 if (pEndOfComplex)
3722 if (pEndOfComplex->IncEndRowSticky(rCxt.mrDoc, rCxt.mnRowDelta, rPos))
3723 bChanged = true;
3725 else
3727 rRef.IncRow(rCxt.mnRowDelta);
3728 bChanged = true;
3733 if (!rRef.IsTabRel() && rCxt.mnTabDelta)
3735 // Sheet range has already been checked above.
3736 rRef.IncTab(rCxt.mnTabDelta);
3737 bChanged = true;
3740 return bChanged;
3743 bool adjustDoubleRefInName(
3744 ScComplexRefData& rRef, const sc::RefUpdateContext& rCxt, const ScAddress& rPos )
3746 bool bRefChanged = false;
3747 if (rCxt.mrDoc.IsExpandRefs())
3749 if (rCxt.mnRowDelta > 0 && !rRef.Ref1.IsRowRel() && !rRef.Ref2.IsRowRel())
3751 ScRange aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3752 // Expand only if at least two rows tall.
3753 if (aAbs.aStart.Row() < aAbs.aEnd.Row())
3755 // Check and see if we should expand the range at the top.
3756 ScRange aSelectedRange = getSelectedRange(rCxt);
3757 if (aSelectedRange.Intersects(aAbs))
3759 // Selection intersects the referenced range. Only expand the
3760 // bottom position.
3761 rRef.IncEndRowSticky(rCxt.mrDoc, rCxt.mnRowDelta, rPos);
3762 return true;
3766 if (rCxt.mnColDelta > 0 && !rRef.Ref1.IsColRel() && !rRef.Ref2.IsColRel())
3768 ScRange aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3769 // Expand only if at least two columns wide.
3770 if (aAbs.aStart.Col() < aAbs.aEnd.Col())
3772 // Check and see if we should expand the range at the left.
3773 ScRange aSelectedRange = getSelectedRange(rCxt);
3774 if (aSelectedRange.Intersects(aAbs))
3776 // Selection intersects the referenced range. Only expand the
3777 // right position.
3778 rRef.IncEndColSticky(rCxt.mrDoc, rCxt.mnColDelta, rPos);
3779 return true;
3785 if ((rCxt.mnRowDelta && rRef.IsEntireCol(rCxt.mrDoc.GetSheetLimits()))
3786 || (rCxt.mnColDelta && rRef.IsEntireRow(rCxt.mrDoc.GetSheetLimits())))
3788 sc::RefUpdateContext aCxt( rCxt.mrDoc);
3789 // We only need a few parameters of RefUpdateContext.
3790 aCxt.maRange = rCxt.maRange;
3791 aCxt.mnColDelta = rCxt.mnColDelta;
3792 aCxt.mnRowDelta = rCxt.mnRowDelta;
3793 aCxt.mnTabDelta = rCxt.mnTabDelta;
3795 // References to entire col/row are not to be adjusted in the other axis.
3796 if (aCxt.mnRowDelta && rRef.IsEntireCol(rCxt.mrDoc.GetSheetLimits()))
3797 aCxt.mnRowDelta = 0;
3798 if (aCxt.mnColDelta && rRef.IsEntireRow(rCxt.mrDoc.GetSheetLimits()))
3799 aCxt.mnColDelta = 0;
3800 if (!aCxt.mnColDelta && !aCxt.mnRowDelta && !aCxt.mnTabDelta)
3801 // early bailout
3802 return bRefChanged;
3804 // Ref2 before Ref1 for sticky ends.
3805 if (adjustSingleRefInName(rRef.Ref2, aCxt, rPos, &rRef))
3806 bRefChanged = true;
3808 if (adjustSingleRefInName(rRef.Ref1, aCxt, rPos, nullptr))
3809 bRefChanged = true;
3811 else
3813 // Ref2 before Ref1 for sticky ends.
3814 if (adjustSingleRefInName(rRef.Ref2, rCxt, rPos, &rRef))
3815 bRefChanged = true;
3817 if (adjustSingleRefInName(rRef.Ref1, rCxt, rPos, nullptr))
3818 bRefChanged = true;
3821 return bRefChanged;
3826 sc::RefUpdateResult ScTokenArray::AdjustReferenceInName(
3827 const sc::RefUpdateContext& rCxt, const ScAddress& rPos )
3829 if (rCxt.meMode == URM_MOVE)
3830 return AdjustReferenceInMovedName(rCxt, rPos);
3832 sc::RefUpdateResult aRes;
3834 if (rCxt.meMode == URM_COPY)
3835 // Copying cells does not modify named expressions.
3836 return aRes;
3838 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
3839 for (size_t j=0; j<2; ++j)
3841 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
3842 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
3843 for (; pp != pEnd; ++pp)
3845 FormulaToken* p = aPtrs.getHandledToken(j,pp);
3846 if (!p)
3847 continue;
3849 switch (p->GetType())
3851 case svSingleRef:
3853 ScSingleRefData& rRef = *p->GetSingleRef();
3854 if (rCxt.mnRowDelta < 0)
3856 // row(s) deleted.
3858 if (rRef.IsRowRel())
3859 // Don't modify relative references in names.
3860 break;
3862 ScAddress aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3864 if (aAbs.Col() < rCxt.maRange.aStart.Col() || rCxt.maRange.aEnd.Col() < aAbs.Col())
3865 // column of the reference is not in the deleted column range.
3866 break;
3868 if (aAbs.Tab() > rCxt.maRange.aEnd.Tab() || aAbs.Tab() < rCxt.maRange.aStart.Tab())
3869 // wrong tables
3870 break;
3872 const SCROW nDelStartRow = rCxt.maRange.aStart.Row() + rCxt.mnRowDelta;
3873 const SCROW nDelEndRow = nDelStartRow - rCxt.mnRowDelta - 1;
3875 if (nDelStartRow <= aAbs.Row() && aAbs.Row() <= nDelEndRow)
3877 // This reference is deleted.
3878 rRef.SetRowDeleted(true);
3879 aRes.mbReferenceModified = true;
3880 break;
3883 else if (rCxt.mnColDelta < 0)
3885 // column(s) deleted.
3887 if (rRef.IsColRel())
3888 // Don't modify relative references in names.
3889 break;
3891 ScAddress aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3893 if (aAbs.Row() < rCxt.maRange.aStart.Row() || rCxt.maRange.aEnd.Row() < aAbs.Row())
3894 // row of the reference is not in the deleted row range.
3895 break;
3897 if (aAbs.Tab() > rCxt.maRange.aEnd.Tab() || aAbs.Tab() < rCxt.maRange.aStart.Tab())
3898 // wrong tables
3899 break;
3901 const SCCOL nDelStartCol = rCxt.maRange.aStart.Col() + rCxt.mnColDelta;
3902 const SCCOL nDelEndCol = nDelStartCol - rCxt.mnColDelta - 1;
3904 if (nDelStartCol <= aAbs.Col() && aAbs.Col() <= nDelEndCol)
3906 // This reference is deleted.
3907 rRef.SetColDeleted(true);
3908 aRes.mbReferenceModified = true;
3909 break;
3913 if (adjustSingleRefInName(rRef, rCxt, rPos, nullptr))
3914 aRes.mbReferenceModified = true;
3916 break;
3917 case svDoubleRef:
3919 ScComplexRefData& rRef = *p->GetDoubleRef();
3920 ScRange aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3922 if (aAbs.aStart.Tab() > rCxt.maRange.aEnd.Tab() || aAbs.aEnd.Tab() < rCxt.maRange.aStart.Tab())
3923 // Sheet references not affected.
3924 break;
3926 if (rCxt.maRange.Contains(aAbs))
3928 // This range is entirely within the shifted region.
3929 if (adjustDoubleRefInName(rRef, rCxt, rPos))
3930 aRes.mbReferenceModified = true;
3932 else if (rCxt.mnRowDelta < 0)
3934 // row(s) deleted.
3936 if (rRef.IsEntireCol(rCxt.mrDoc.GetSheetLimits()))
3937 // Rows of entire columns are not affected.
3938 break;
3940 if (rRef.Ref1.IsRowRel() || rRef.Ref2.IsRowRel())
3941 // Don't modify relative references in names.
3942 break;
3944 if (aAbs.aStart.Col() < rCxt.maRange.aStart.Col() || rCxt.maRange.aEnd.Col() < aAbs.aEnd.Col())
3945 // column range of the reference is not entirely in the deleted column range.
3946 break;
3948 ScRange aDeleted = rCxt.maRange;
3949 aDeleted.aStart.IncRow(rCxt.mnRowDelta);
3950 aDeleted.aEnd.SetRow(aDeleted.aStart.Row()-rCxt.mnRowDelta-1);
3952 if (aAbs.aEnd.Row() < aDeleted.aStart.Row() || aDeleted.aEnd.Row() < aAbs.aStart.Row())
3953 // reference range doesn't intersect with the deleted range.
3954 break;
3956 if (aDeleted.aStart.Row() <= aAbs.aStart.Row() && aAbs.aEnd.Row() <= aDeleted.aEnd.Row())
3958 // This reference is entirely deleted.
3959 rRef.Ref1.SetRowDeleted(true);
3960 rRef.Ref2.SetRowDeleted(true);
3961 aRes.mbReferenceModified = true;
3962 break;
3965 if (aAbs.aStart.Row() < aDeleted.aStart.Row())
3967 if (!aAbs.IsEndRowSticky(rCxt.mrDoc))
3969 if (aDeleted.aEnd.Row() < aAbs.aEnd.Row())
3970 // Deleted in the middle. Make the reference shorter.
3971 rRef.Ref2.IncRow(rCxt.mnRowDelta);
3972 else
3973 // Deleted at tail end. Cut off the lower part.
3974 rRef.Ref2.SetAbsRow(aDeleted.aStart.Row()-1);
3977 else
3979 // Deleted at the top. Cut the top off and shift up.
3980 rRef.Ref1.SetAbsRow(aDeleted.aEnd.Row()+1);
3981 rRef.Ref1.IncRow(rCxt.mnRowDelta);
3982 if (!aAbs.IsEndRowSticky(rCxt.mrDoc))
3983 rRef.Ref2.IncRow(rCxt.mnRowDelta);
3986 aRes.mbReferenceModified = true;
3988 else if (rCxt.mnColDelta < 0)
3990 // column(s) deleted.
3992 if (rRef.IsEntireRow(rCxt.mrDoc.GetSheetLimits()))
3993 // Rows of entire rows are not affected.
3994 break;
3996 if (rRef.Ref1.IsColRel() || rRef.Ref2.IsColRel())
3997 // Don't modify relative references in names.
3998 break;
4000 if (aAbs.aStart.Row() < rCxt.maRange.aStart.Row() || rCxt.maRange.aEnd.Row() < aAbs.aEnd.Row())
4001 // row range of the reference is not entirely in the deleted row range.
4002 break;
4004 ScRange aDeleted = rCxt.maRange;
4005 aDeleted.aStart.IncCol(rCxt.mnColDelta);
4006 aDeleted.aEnd.SetCol(aDeleted.aStart.Col()-rCxt.mnColDelta-1);
4008 if (aAbs.aEnd.Col() < aDeleted.aStart.Col() || aDeleted.aEnd.Col() < aAbs.aStart.Col())
4009 // reference range doesn't intersect with the deleted range.
4010 break;
4012 if (aDeleted.aStart.Col() <= aAbs.aStart.Col() && aAbs.aEnd.Col() <= aDeleted.aEnd.Col())
4014 // This reference is entirely deleted.
4015 rRef.Ref1.SetColDeleted(true);
4016 rRef.Ref2.SetColDeleted(true);
4017 aRes.mbReferenceModified = true;
4018 break;
4021 if (aAbs.aStart.Col() < aDeleted.aStart.Col())
4023 if (!aAbs.IsEndColSticky(rCxt.mrDoc))
4025 if (aDeleted.aEnd.Col() < aAbs.aEnd.Col())
4026 // Deleted in the middle. Make the reference shorter.
4027 rRef.Ref2.IncCol(rCxt.mnColDelta);
4028 else
4029 // Deleted at tail end. Cut off the right part.
4030 rRef.Ref2.SetAbsCol(aDeleted.aStart.Col()-1);
4033 else
4035 // Deleted at the left. Cut the left off and shift left.
4036 rRef.Ref1.SetAbsCol(aDeleted.aEnd.Col()+1);
4037 rRef.Ref1.IncCol(rCxt.mnColDelta);
4038 if (!aAbs.IsEndColSticky(rCxt.mrDoc))
4039 rRef.Ref2.IncCol(rCxt.mnColDelta);
4042 aRes.mbReferenceModified = true;
4044 else if (rCxt.maRange.Intersects(aAbs))
4046 if (rCxt.mnColDelta && rCxt.maRange.aStart.Row() <= aAbs.aStart.Row() && aAbs.aEnd.Row() <= rCxt.maRange.aEnd.Row())
4048 if (adjustDoubleRefInName(rRef, rCxt, rPos))
4049 aRes.mbReferenceModified = true;
4051 if (rCxt.mnRowDelta && rCxt.maRange.aStart.Col() <= aAbs.aStart.Col() && aAbs.aEnd.Col() <= rCxt.maRange.aEnd.Col())
4053 if (adjustDoubleRefInName(rRef, rCxt, rPos))
4054 aRes.mbReferenceModified = true;
4057 else if (rCxt.mnRowDelta > 0 && rCxt.mrDoc.IsExpandRefs())
4059 // Check if we could expand range reference by the bottom
4060 // edge. For named expressions, we only expand absolute
4061 // references. Reference must be at least two rows
4062 // tall.
4063 if (!rRef.Ref1.IsRowRel() && !rRef.Ref2.IsRowRel() &&
4064 aAbs.aStart.Row() < aAbs.aEnd.Row() &&
4065 aAbs.aEnd.Row()+1 == rCxt.maRange.aStart.Row())
4067 // Expand by the bottom edge.
4068 rRef.Ref2.IncRow(rCxt.mnRowDelta);
4069 aRes.mbReferenceModified = true;
4072 else if (rCxt.mnColDelta > 0 && rCxt.mrDoc.IsExpandRefs())
4074 // Check if we could expand range reference by the right
4075 // edge. For named expressions, we only expand absolute
4076 // references. Reference must be at least two
4077 // columns wide.
4078 if (!rRef.Ref1.IsColRel() && !rRef.Ref2.IsColRel() &&
4079 aAbs.aStart.Col() < aAbs.aEnd.Col() &&
4080 aAbs.aEnd.Col()+1 == rCxt.maRange.aStart.Col())
4082 // Expand by the right edge.
4083 rRef.Ref2.IncCol(rCxt.mnColDelta);
4084 aRes.mbReferenceModified = true;
4088 break;
4089 default:
4095 return aRes;
4098 sc::RefUpdateResult ScTokenArray::AdjustReferenceInMovedName( const sc::RefUpdateContext& rCxt, const ScAddress& rPos )
4100 // When moving, the range is the destination range.
4101 ScRange aOldRange = rCxt.maRange;
4102 ScRange aErrorMoveRange( ScAddress::UNINITIALIZED );
4103 if (!aOldRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta, aErrorMoveRange, rCxt.mrDoc))
4105 assert(!"can't move");
4108 // In a named expression, we'll move the reference only when the reference
4109 // is entirely absolute.
4111 sc::RefUpdateResult aRes;
4113 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4114 for (size_t j=0; j<2; ++j)
4116 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4117 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4118 for (; pp != pEnd; ++pp)
4120 FormulaToken* p = aPtrs.getHandledToken(j,pp);
4121 if (!p)
4122 continue;
4124 switch (p->GetType())
4126 case svSingleRef:
4128 ScSingleRefData& rRef = *p->GetSingleRef();
4129 if (rRef.IsColRel() || rRef.IsRowRel() || rRef.IsTabRel())
4130 continue;
4132 ScAddress aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
4134 // Do not update the reference in transposed case (cut paste transposed).
4135 // The reference will be updated in UpdateTranspose().
4136 if (rCxt.mbTransposed && aOldRange.Contains(aAbs))
4137 break;
4139 if (aOldRange.Contains(aAbs))
4141 ScAddress aErrorPos( ScAddress::UNINITIALIZED );
4142 if (!aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos, rCxt.mrDoc))
4143 aAbs = aErrorPos;
4144 aRes.mbReferenceModified = true;
4147 rRef.SetAddress(rCxt.mrDoc.GetSheetLimits(), aAbs, rPos);
4149 break;
4150 case svDoubleRef:
4152 ScComplexRefData& rRef = *p->GetDoubleRef();
4153 if (rRef.Ref1.IsColRel() || rRef.Ref1.IsRowRel() || rRef.Ref1.IsTabRel() ||
4154 rRef.Ref2.IsColRel() || rRef.Ref2.IsRowRel() || rRef.Ref2.IsTabRel())
4155 continue;
4157 ScRange aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
4159 // Do not update the reference in transposed case (cut paste transposed).
4160 // The reference will be updated in UpdateTranspose().
4161 if (rCxt.mbTransposed && aOldRange.Contains(aAbs))
4162 break;
4164 if (aOldRange.Contains(aAbs))
4166 ScRange aErrorRange( ScAddress::UNINITIALIZED );
4167 if (!aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorRange, rCxt.mrDoc))
4168 aAbs = aErrorRange;
4169 aRes.mbReferenceModified = true;
4172 rRef.SetRange(rCxt.mrDoc.GetSheetLimits(), aAbs, rPos);
4174 break;
4175 default:
4181 return aRes;
4184 namespace {
4186 bool adjustSingleRefOnDeletedTab( const ScSheetLimits& rLimits, ScSingleRefData& rRef, SCTAB nDelPos, SCTAB nSheets, const ScAddress& rOldPos, const ScAddress& rNewPos )
4188 ScAddress aAbs = rRef.toAbs(rLimits, rOldPos);
4189 if (nDelPos <= aAbs.Tab() && aAbs.Tab() < nDelPos + nSheets)
4191 rRef.SetTabDeleted(true);
4192 return true;
4195 if (nDelPos < aAbs.Tab())
4197 // Reference sheet needs to be adjusted.
4198 aAbs.IncTab(-1*nSheets);
4199 rRef.SetAddress(rLimits, aAbs, rNewPos);
4200 return true;
4202 else if (rOldPos.Tab() != rNewPos.Tab())
4204 // Cell itself has moved.
4205 rRef.SetAddress(rLimits, aAbs, rNewPos);
4206 return true;
4209 return false;
4212 bool adjustSingleRefOnInsertedTab( const ScSheetLimits& rLimits, ScSingleRefData& rRef, SCTAB nInsPos, SCTAB nSheets, const ScAddress& rOldPos, const ScAddress& rNewPos )
4214 ScAddress aAbs = rRef.toAbs(rLimits, rOldPos);
4215 if (nInsPos <= aAbs.Tab())
4217 // Reference sheet needs to be adjusted.
4218 aAbs.IncTab(nSheets);
4219 rRef.SetAddress(rLimits, aAbs, rNewPos);
4220 return true;
4222 else if (rOldPos.Tab() != rNewPos.Tab())
4224 // Cell itself has moved.
4225 rRef.SetAddress(rLimits, aAbs, rNewPos);
4226 return true;
4229 return false;
4232 bool adjustDoubleRefOnDeleteTab(const ScSheetLimits& rLimits, ScComplexRefData& rRef, SCTAB nDelPos, SCTAB nSheets, const ScAddress& rOldPos, const ScAddress& rNewPos)
4234 ScSingleRefData& rRef1 = rRef.Ref1;
4235 ScSingleRefData& rRef2 = rRef.Ref2;
4236 ScAddress aStartPos = rRef1.toAbs(rLimits, rOldPos);
4237 ScAddress aEndPos = rRef2.toAbs(rLimits, rOldPos);
4238 bool bMoreThanOneTab = aStartPos.Tab() != aEndPos.Tab();
4239 bool bModified = false;
4240 if (bMoreThanOneTab && aStartPos.Tab() == nDelPos && nDelPos + nSheets <= aEndPos.Tab())
4242 if (rRef1.IsTabRel() && aStartPos.Tab() < rOldPos.Tab())
4244 rRef1.IncTab(nSheets);
4245 bModified = true;
4248 else
4250 bModified = adjustSingleRefOnDeletedTab(rLimits, rRef1, nDelPos, nSheets, rOldPos, rNewPos);
4253 if (bMoreThanOneTab && aEndPos.Tab() == nDelPos && aStartPos.Tab() <= nDelPos - nSheets)
4255 if (!rRef2.IsTabRel() || rOldPos.Tab() < aEndPos.Tab())
4257 rRef2.IncTab(-nSheets);
4258 bModified = true;
4261 else
4263 bModified |= adjustSingleRefOnDeletedTab(rLimits, rRef2, nDelPos, nSheets, rOldPos, rNewPos);
4265 return bModified;
4270 sc::RefUpdateResult ScTokenArray::AdjustReferenceOnDeletedTab( const sc::RefUpdateDeleteTabContext& rCxt, const ScAddress& rOldPos )
4272 sc::RefUpdateResult aRes;
4273 ScAddress aNewPos = rOldPos;
4274 ScRangeUpdater::UpdateDeleteTab( aNewPos, rCxt);
4276 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4277 for (size_t j=0; j<2; ++j)
4279 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4280 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4281 for (; pp != pEnd; ++pp)
4283 FormulaToken* p = aPtrs.getHandledToken(j,pp);
4284 if (!p)
4285 continue;
4287 switch (p->GetType())
4289 case svSingleRef:
4291 ScSingleRefData& rRef = *p->GetSingleRef();
4292 if (adjustSingleRefOnDeletedTab(*mxSheetLimits, rRef, rCxt.mnDeletePos, rCxt.mnSheets, rOldPos, aNewPos))
4293 aRes.mbReferenceModified = true;
4295 break;
4296 case svDoubleRef:
4298 ScComplexRefData& rRef = *p->GetDoubleRef();
4299 aRes.mbReferenceModified |= adjustDoubleRefOnDeleteTab(*mxSheetLimits, rRef, rCxt.mnDeletePos, rCxt.mnSheets, rOldPos, aNewPos);
4301 break;
4302 default:
4306 // For ocTableRef p is the inner token of *pp, so have a separate
4307 // condition here.
4308 if ((*pp)->GetType() == svIndex)
4310 switch ((*pp)->GetOpCode())
4312 case ocName:
4314 SCTAB nOldTab = (*pp)->GetSheet();
4315 if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
4316 aRes.mbNameModified = true;
4317 if (rCxt.mnDeletePos <= nOldTab)
4319 aRes.mbNameModified = true;
4320 if (rCxt.mnDeletePos + rCxt.mnSheets <= nOldTab)
4321 (*pp)->SetSheet( nOldTab - rCxt.mnSheets);
4322 else
4323 // Would point to a deleted sheet. Invalidate.
4324 (*pp)->SetSheet( SCTAB_MAX);
4327 break;
4328 case ocDBArea:
4329 case ocTableRef:
4330 if (isDBDataModified(rCxt.mrDoc, **pp))
4331 aRes.mbNameModified = true;
4332 break;
4333 default:
4334 ; // nothing
4339 return aRes;
4342 sc::RefUpdateResult ScTokenArray::AdjustReferenceOnInsertedTab( const sc::RefUpdateInsertTabContext& rCxt, const ScAddress& rOldPos )
4344 sc::RefUpdateResult aRes;
4345 ScAddress aNewPos = rOldPos;
4346 if (rCxt.mnInsertPos <= rOldPos.Tab())
4347 aNewPos.IncTab(rCxt.mnSheets);
4349 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4350 for (size_t j=0; j<2; ++j)
4352 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4353 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4354 for (; pp != pEnd; ++pp)
4356 FormulaToken* p = aPtrs.getHandledToken(j,pp);
4357 if (!p)
4358 continue;
4360 switch (p->GetType())
4362 case svSingleRef:
4364 ScSingleRefData& rRef = *p->GetSingleRef();
4365 if (adjustSingleRefOnInsertedTab(*mxSheetLimits, rRef, rCxt.mnInsertPos, rCxt.mnSheets, rOldPos, aNewPos))
4366 aRes.mbReferenceModified = true;
4368 break;
4369 case svDoubleRef:
4371 ScComplexRefData& rRef = *p->GetDoubleRef();
4372 if (adjustSingleRefOnInsertedTab(*mxSheetLimits, rRef.Ref1, rCxt.mnInsertPos, rCxt.mnSheets, rOldPos, aNewPos))
4373 aRes.mbReferenceModified = true;
4374 if (adjustSingleRefOnInsertedTab(*mxSheetLimits, rRef.Ref2, rCxt.mnInsertPos, rCxt.mnSheets, rOldPos, aNewPos))
4375 aRes.mbReferenceModified = true;
4377 break;
4378 default:
4382 // For ocTableRef p is the inner token of *pp, so have a separate
4383 // condition here.
4384 if ((*pp)->GetType() == svIndex)
4386 switch ((*pp)->GetOpCode())
4388 case ocName:
4390 SCTAB nOldTab = (*pp)->GetSheet();
4391 if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
4392 aRes.mbNameModified = true;
4393 if (rCxt.mnInsertPos <= nOldTab)
4395 aRes.mbNameModified = true;
4396 (*pp)->SetSheet( nOldTab + rCxt.mnSheets);
4399 break;
4400 case ocDBArea:
4401 case ocTableRef:
4402 if (isDBDataModified(rCxt.mrDoc, **pp))
4403 aRes.mbNameModified = true;
4404 break;
4405 default:
4406 ; // nothing
4411 return aRes;
4414 namespace {
4416 bool adjustTabOnMove( ScAddress& rPos, const sc::RefUpdateMoveTabContext& rCxt )
4418 SCTAB nNewTab = rCxt.getNewTab(rPos.Tab());
4419 if (nNewTab == rPos.Tab())
4420 return false;
4422 rPos.SetTab(nNewTab);
4423 return true;
4428 sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMovedTab( const sc::RefUpdateMoveTabContext& rCxt, const ScAddress& rOldPos )
4430 sc::RefUpdateResult aRes;
4431 if (rCxt.mnOldPos == rCxt.mnNewPos)
4432 return aRes;
4434 ScAddress aNewPos = rOldPos;
4435 if (adjustTabOnMove(aNewPos, rCxt))
4437 aRes.mbReferenceModified = true;
4438 aRes.mbValueChanged = true;
4439 aRes.mnTab = aNewPos.Tab(); // this sets the new tab position used when deleting
4442 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4443 for (size_t j=0; j<2; ++j)
4445 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4446 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4447 for (; pp != pEnd; ++pp)
4449 FormulaToken* p = aPtrs.getHandledToken(j,pp);
4450 if (!p)
4451 continue;
4453 switch (p->GetType())
4455 case svSingleRef:
4457 ScSingleRefData& rRef = *p->GetSingleRef();
4458 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
4459 if (adjustTabOnMove(aAbs, rCxt))
4460 aRes.mbReferenceModified = true;
4461 rRef.SetAddress(*mxSheetLimits, aAbs, aNewPos);
4463 break;
4464 case svDoubleRef:
4466 ScComplexRefData& rRef = *p->GetDoubleRef();
4467 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
4468 if (adjustTabOnMove(aAbs.aStart, rCxt))
4469 aRes.mbReferenceModified = true;
4470 if (adjustTabOnMove(aAbs.aEnd, rCxt))
4471 aRes.mbReferenceModified = true;
4472 rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
4474 break;
4475 default:
4479 // For ocTableRef p is the inner token of *pp, so have a separate
4480 // condition here.
4481 if ((*pp)->GetType() == svIndex)
4483 switch ((*pp)->GetOpCode())
4485 case ocName:
4487 SCTAB nOldTab = (*pp)->GetSheet();
4488 if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
4489 aRes.mbNameModified = true;
4490 SCTAB nNewTab = rCxt.getNewTab( nOldTab);
4491 if (nNewTab != nOldTab)
4493 aRes.mbNameModified = true;
4494 (*pp)->SetSheet( nNewTab);
4497 break;
4498 case ocDBArea:
4499 case ocTableRef:
4500 if (isDBDataModified(rCxt.mrDoc, **pp))
4501 aRes.mbNameModified = true;
4502 break;
4503 default:
4504 ; // nothing
4510 return aRes;
4513 void ScTokenArray::AdjustReferenceOnMovedOrigin( const ScAddress& rOldPos, const ScAddress& rNewPos )
4515 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4516 for (size_t j=0; j<2; ++j)
4518 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4519 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4520 for (; pp != pEnd; ++pp)
4522 FormulaToken* p = aPtrs.getHandledToken(j,pp);
4523 if (!p)
4524 continue;
4526 switch (p->GetType())
4528 case svSingleRef:
4529 case svExternalSingleRef:
4531 ScSingleRefData& rRef = *p->GetSingleRef();
4532 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
4533 rRef.SetAddress(*mxSheetLimits, aAbs, rNewPos);
4535 break;
4536 case svDoubleRef:
4537 case svExternalDoubleRef:
4539 ScComplexRefData& rRef = *p->GetDoubleRef();
4540 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
4541 rRef.SetRange(*mxSheetLimits, aAbs, rNewPos);
4543 break;
4544 default:
4551 void ScTokenArray::AdjustReferenceOnMovedOriginIfOtherSheet( const ScAddress& rOldPos, const ScAddress& rNewPos )
4553 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4554 for (size_t j=0; j<2; ++j)
4556 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4557 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4558 for (; pp != pEnd; ++pp)
4560 FormulaToken* p = aPtrs.getHandledToken(j,pp);
4561 if (!p)
4562 continue;
4564 bool bAdjust = false;
4565 switch (p->GetType())
4567 case svExternalSingleRef:
4568 bAdjust = true; // always
4569 [[fallthrough]];
4570 case svSingleRef:
4572 ScSingleRefData& rRef = *p->GetSingleRef();
4573 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
4574 if (!bAdjust)
4575 bAdjust = (aAbs.Tab() != rOldPos.Tab());
4576 if (bAdjust)
4577 rRef.SetAddress(*mxSheetLimits, aAbs, rNewPos);
4579 break;
4580 case svExternalDoubleRef:
4581 bAdjust = true; // always
4582 [[fallthrough]];
4583 case svDoubleRef:
4585 ScComplexRefData& rRef = *p->GetDoubleRef();
4586 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
4587 if (!bAdjust)
4588 bAdjust = (rOldPos.Tab() < aAbs.aStart.Tab() || aAbs.aEnd.Tab() < rOldPos.Tab());
4589 if (bAdjust)
4590 rRef.SetRange(*mxSheetLimits, aAbs, rNewPos);
4592 break;
4593 default:
4600 void ScTokenArray::AdjustReferenceOnCopy( const ScAddress& rNewPos )
4602 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN, false);
4603 for (size_t j=0; j<2; ++j)
4605 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4606 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4607 for (; pp != pEnd; ++pp)
4609 FormulaToken* p = aPtrs.getHandledToken(j,pp);
4610 if (!p)
4611 continue;
4613 switch (p->GetType())
4615 case svDoubleRef:
4617 ScComplexRefData& rRef = *p->GetDoubleRef();
4618 rRef.PutInOrder( rNewPos);
4620 break;
4621 default:
4628 namespace {
4630 void clearTabDeletedFlag( const ScSheetLimits& rLimits, ScSingleRefData& rRef, const ScAddress& rPos, SCTAB nStartTab, SCTAB nEndTab )
4632 if (!rRef.IsTabDeleted())
4633 return;
4635 ScAddress aAbs = rRef.toAbs(rLimits, rPos);
4636 if (nStartTab <= aAbs.Tab() && aAbs.Tab() <= nEndTab)
4637 rRef.SetTabDeleted(false);
4642 void ScTokenArray::ClearTabDeleted( const ScAddress& rPos, SCTAB nStartTab, SCTAB nEndTab )
4644 if (nEndTab < nStartTab)
4645 return;
4647 FormulaToken** p = pCode.get();
4648 FormulaToken** pEnd = p + static_cast<size_t>(nLen);
4649 for (; p != pEnd; ++p)
4651 switch ((*p)->GetType())
4653 case svSingleRef:
4655 formula::FormulaToken* pToken = *p;
4656 ScSingleRefData& rRef = *pToken->GetSingleRef();
4657 clearTabDeletedFlag(*mxSheetLimits, rRef, rPos, nStartTab, nEndTab);
4659 break;
4660 case svDoubleRef:
4662 formula::FormulaToken* pToken = *p;
4663 ScComplexRefData& rRef = *pToken->GetDoubleRef();
4664 clearTabDeletedFlag(*mxSheetLimits, rRef.Ref1, rPos, nStartTab, nEndTab);
4665 clearTabDeletedFlag(*mxSheetLimits, rRef.Ref2, rPos, nStartTab, nEndTab);
4667 break;
4668 default:
4674 namespace {
4676 void checkBounds(
4677 const ScSheetLimits& rLimits,
4678 const ScAddress& rPos, SCROW nGroupLen, const ScRange& rCheckRange,
4679 const ScSingleRefData& rRef, std::vector<SCROW>& rBounds, const ScRange* pDeletedRange )
4681 if (!rRef.IsRowRel())
4682 return;
4684 ScRange aAbs(rRef.toAbs(rLimits, rPos));
4685 aAbs.aEnd.IncRow(nGroupLen-1);
4686 if (!rCheckRange.Intersects(aAbs) && (!pDeletedRange || !pDeletedRange->Intersects(aAbs)))
4687 return;
4689 // Get the boundary row positions.
4690 if (aAbs.aEnd.Row() < rCheckRange.aStart.Row() && (!pDeletedRange || aAbs.aEnd.Row() < pDeletedRange->aStart.Row()))
4691 // No intersections.
4692 return;
4694 // rCheckRange may be a virtual non-existent row being shifted in.
4695 if (aAbs.aStart.Row() <= rCheckRange.aStart.Row() && rCheckRange.aStart.Row() < rLimits.GetMaxRowCount())
4697 // +-+ <---- top
4698 // | |
4699 // +--+-+--+ <---- boundary row position
4700 // | | | |
4701 // | |
4702 // +-------+
4704 // Add offset from the reference top to the cell position.
4705 SCROW nOffset = rCheckRange.aStart.Row() - aAbs.aStart.Row();
4706 rBounds.push_back(rPos.Row()+nOffset);
4708 // Same for deleted range.
4709 if (pDeletedRange && aAbs.aStart.Row() <= pDeletedRange->aStart.Row())
4711 SCROW nOffset = pDeletedRange->aStart.Row() - aAbs.aStart.Row();
4712 SCROW nRow = rPos.Row() + nOffset;
4713 // Unlike for rCheckRange, for pDeletedRange nRow can be anywhere>=0.
4714 if (rLimits.ValidRow(nRow))
4715 rBounds.push_back(nRow);
4718 if (aAbs.aEnd.Row() >= rCheckRange.aEnd.Row())
4720 // only check for end range
4722 // +-------+
4723 // | |
4724 // | | | |
4725 // +--+-+--+ <---- boundary row position
4726 // | |
4727 // +-+
4729 // Ditto.
4730 SCROW nOffset = rCheckRange.aEnd.Row() + 1 - aAbs.aStart.Row();
4731 rBounds.push_back(rPos.Row()+nOffset);
4733 // Same for deleted range.
4734 if (pDeletedRange && aAbs.aEnd.Row() >= pDeletedRange->aEnd.Row())
4736 SCROW nOffset = pDeletedRange->aEnd.Row() + 1 - aAbs.aStart.Row();
4737 SCROW nRow = rPos.Row() + nOffset;
4738 // Unlike for rCheckRange, for pDeletedRange nRow can be ~anywhere.
4739 if (rLimits.ValidRow(nRow))
4740 rBounds.push_back(nRow);
4744 void checkBounds(
4745 const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen,
4746 const ScSingleRefData& rRef, std::vector<SCROW>& rBounds)
4748 if (!rRef.IsRowRel())
4749 return;
4751 ScRange aDeletedRange( ScAddress::UNINITIALIZED );
4752 const ScRange* pDeletedRange = nullptr;
4754 ScRange aCheckRange = rCxt.maRange;
4755 if (rCxt.meMode == URM_MOVE)
4757 // Check bounds against the old range prior to the move.
4758 ScRange aErrorRange( ScAddress::UNINITIALIZED );
4759 if (!aCheckRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta, aErrorRange, rCxt.mrDoc))
4761 assert(!"can't move");
4764 // Check bounds also against the range moved into.
4765 pDeletedRange = &rCxt.maRange;
4767 else if (rCxt.meMode == URM_INSDEL &&
4768 ((rCxt.mnColDelta < 0 && rCxt.maRange.aStart.Col() > 0) ||
4769 (rCxt.mnRowDelta < 0 && rCxt.maRange.aStart.Row() > 0)))
4771 // Check bounds also against deleted range where cells are shifted
4772 // into and references need to be invalidated.
4773 aDeletedRange = getSelectedRange( rCxt);
4774 pDeletedRange = &aDeletedRange;
4777 checkBounds(rCxt.mrDoc.GetSheetLimits(), rPos, nGroupLen, aCheckRange, rRef, rBounds, pDeletedRange);
4782 void ScTokenArray::CheckRelativeReferenceBounds(
4783 const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen, std::vector<SCROW>& rBounds ) const
4785 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4786 for (size_t j=0; j<2; ++j)
4788 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4789 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4790 for (; pp != pEnd; ++pp)
4792 FormulaToken* p = aPtrs.getHandledToken(j,pp);
4793 if (!p)
4794 continue;
4796 switch (p->GetType())
4798 case svSingleRef:
4800 checkBounds(rCxt, rPos, nGroupLen, *p->GetSingleRef(), rBounds);
4802 break;
4803 case svDoubleRef:
4805 const ScComplexRefData& rRef = *p->GetDoubleRef();
4806 checkBounds(rCxt, rPos, nGroupLen, rRef.Ref1, rBounds);
4807 checkBounds(rCxt, rPos, nGroupLen, rRef.Ref2, rBounds);
4809 break;
4810 default:
4817 void ScTokenArray::CheckRelativeReferenceBounds(
4818 const ScAddress& rPos, SCROW nGroupLen, const ScRange& rRange, std::vector<SCROW>& rBounds ) const
4820 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4821 for (size_t j=0; j<2; ++j)
4823 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4824 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4825 for (; pp != pEnd; ++pp)
4827 FormulaToken* p = aPtrs.getHandledToken(j,pp);
4828 if (!p)
4829 continue;
4831 switch (p->GetType())
4833 case svSingleRef:
4835 const ScSingleRefData& rRef = *p->GetSingleRef();
4836 checkBounds(*mxSheetLimits, rPos, nGroupLen, rRange, rRef, rBounds, nullptr);
4838 break;
4839 case svDoubleRef:
4841 const ScComplexRefData& rRef = *p->GetDoubleRef();
4842 checkBounds(*mxSheetLimits, rPos, nGroupLen, rRange, rRef.Ref1, rBounds, nullptr);
4843 checkBounds(*mxSheetLimits, rPos, nGroupLen, rRange, rRef.Ref2, rBounds, nullptr);
4845 break;
4846 default:
4853 void ScTokenArray::CheckExpandReferenceBounds(
4854 const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen, std::vector<SCROW>& rBounds ) const
4856 const SCROW nInsRow = rCxt.maRange.aStart.Row();
4857 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4858 for (size_t j=0; j<2; ++j)
4860 FormulaToken* const * pp = aPtrs.maPointerRange[j].mpStart;
4861 const FormulaToken* const * pEnd = aPtrs.maPointerRange[j].mpStop;
4862 for (; pp != pEnd; ++pp)
4864 const FormulaToken* p = aPtrs.getHandledToken(j,pp);
4865 if (!p)
4866 continue;
4868 switch (p->GetType())
4870 case svDoubleRef:
4872 const ScComplexRefData& rRef = *p->GetDoubleRef();
4873 bool bStartRowRelative = rRef.Ref1.IsRowRel();
4874 bool bEndRowRelative = rRef.Ref2.IsRowRel();
4876 // For absolute references nothing needs to be done, they stay
4877 // the same for all and if to be expanded the group will be
4878 // adjusted later.
4879 if (!bStartRowRelative && !bEndRowRelative)
4880 break; // switch
4882 ScRange aAbsStart(rRef.toAbs(*mxSheetLimits, rPos));
4883 ScAddress aPos(rPos);
4884 aPos.IncRow(nGroupLen);
4885 ScRange aAbsEnd(rRef.toAbs(*mxSheetLimits, aPos));
4886 // References must be at least two rows to be expandable.
4887 if ((aAbsStart.aEnd.Row() - aAbsStart.aStart.Row() < 1) &&
4888 (aAbsEnd.aEnd.Row() - aAbsEnd.aStart.Row() < 1))
4889 break; // switch
4891 // Only need to process if an edge may be touching the
4892 // insertion row anywhere within the run of the group.
4893 if (!((aAbsStart.aStart.Row() <= nInsRow && nInsRow <= aAbsEnd.aStart.Row()) ||
4894 (aAbsStart.aEnd.Row() <= nInsRow && nInsRow <= aAbsEnd.aEnd.Row())))
4895 break; // switch
4897 SCROW nStartRow = aAbsStart.aStart.Row();
4898 SCROW nEndRow = aAbsStart.aEnd.Row();
4899 // Position on first relevant range.
4900 SCROW nOffset = 0;
4901 if (nEndRow + 1 < nInsRow)
4903 if (bEndRowRelative)
4905 nOffset = nInsRow - nEndRow - 1;
4906 nEndRow += nOffset;
4907 if (bStartRowRelative)
4908 nStartRow += nOffset;
4910 else // bStartRowRelative==true
4912 nOffset = nInsRow - nStartRow;
4913 nStartRow += nOffset;
4914 // Start is overtaking End, swap.
4915 bStartRowRelative = false;
4916 bEndRowRelative = true;
4919 for (SCROW i = nOffset; i < nGroupLen; ++i)
4921 bool bSplit = (nStartRow == nInsRow || nEndRow + 1 == nInsRow);
4922 if (bSplit)
4923 rBounds.push_back( rPos.Row() + i);
4925 if (bEndRowRelative)
4926 ++nEndRow;
4927 if (bStartRowRelative)
4929 ++nStartRow;
4930 if (!bEndRowRelative && nStartRow == nEndRow)
4932 // Start is overtaking End, swap.
4933 bStartRowRelative = false;
4934 bEndRowRelative = true;
4937 if (nInsRow < nStartRow || (!bStartRowRelative && nInsRow <= nEndRow))
4939 if (bSplit && (++i < nGroupLen))
4940 rBounds.push_back( rPos.Row() + i);
4941 break; // for, out of range now
4945 break;
4946 default:
4953 namespace {
4955 void appendDouble( const sc::TokenStringContext& rCxt, OUStringBuffer& rBuf, double fVal )
4957 if (rCxt.mxOpCodeMap->isEnglish())
4959 rtl::math::doubleToUStringBuffer(
4960 rBuf, fVal, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true);
4962 else
4964 SvtSysLocale aSysLocale;
4965 rtl::math::doubleToUStringBuffer(
4966 rBuf, fVal,
4967 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
4968 aSysLocale.GetLocaleData().getNumDecimalSep()[0], true);
4972 void appendString( OUStringBuffer& rBuf, const OUString& rStr )
4974 rBuf.append('"');
4975 rBuf.append(rStr.replaceAll("\"", "\"\""));
4976 rBuf.append('"');
4979 void appendTokenByType( ScSheetLimits& rLimits, sc::TokenStringContext& rCxt, OUStringBuffer& rBuf, const FormulaToken& rToken,
4980 const ScAddress& rPos, bool bFromRangeName )
4982 if (rToken.IsExternalRef())
4984 size_t nFileId = rToken.GetIndex();
4985 OUString aTabName = rToken.GetString().getString();
4986 if (nFileId >= rCxt.maExternalFileNames.size())
4987 // out of bound
4988 return;
4990 OUString aFileName = rCxt.maExternalFileNames[nFileId];
4992 switch (rToken.GetType())
4994 case svExternalName:
4995 rBuf.append(rCxt.mpRefConv->makeExternalNameStr(nFileId, aFileName, aTabName));
4996 break;
4997 case svExternalSingleRef:
4998 rCxt.mpRefConv->makeExternalRefStr(
4999 rLimits, rBuf, rPos, nFileId, aFileName, aTabName, *rToken.GetSingleRef());
5000 break;
5001 case svExternalDoubleRef:
5003 sc::TokenStringContext::IndexNamesMapType::const_iterator it =
5004 rCxt.maExternalCachedTabNames.find(nFileId);
5006 if (it == rCxt.maExternalCachedTabNames.end())
5007 return;
5009 rCxt.mpRefConv->makeExternalRefStr(
5010 rLimits, rBuf, rPos, nFileId, aFileName, it->second, aTabName,
5011 *rToken.GetDoubleRef());
5013 break;
5014 default:
5015 // warning, not error, otherwise we may end up with a never
5016 // ending message box loop if this was the cursor cell to be redrawn.
5017 OSL_FAIL("appendTokenByType: unknown type of ocExternalRef");
5019 return;
5022 OpCode eOp = rToken.GetOpCode();
5023 switch (rToken.GetType())
5025 case svDouble:
5026 appendDouble(rCxt, rBuf, rToken.GetDouble());
5027 break;
5028 case svString:
5030 OUString aStr = rToken.GetString().getString();
5031 if (eOp == ocBad || eOp == ocStringXML || eOp == ocStringName)
5033 rBuf.append(aStr);
5034 return;
5037 appendString(rBuf, aStr);
5039 break;
5040 case svSingleRef:
5042 if (rCxt.mpRefConv)
5044 const ScSingleRefData& rRef = *rToken.GetSingleRef();
5045 ScComplexRefData aRef;
5046 aRef.Ref1 = rRef;
5047 aRef.Ref2 = rRef;
5048 rCxt.mpRefConv->makeRefStr(rLimits, rBuf, rCxt.meGram, rPos, rCxt.maErrRef, rCxt.maTabNames, aRef, true,
5049 bFromRangeName);
5051 else
5052 rBuf.append(rCxt.maErrRef);
5054 break;
5055 case svDoubleRef:
5057 if (rCxt.mpRefConv)
5059 const ScComplexRefData& rRef = *rToken.GetDoubleRef();
5060 rCxt.mpRefConv->makeRefStr(rLimits, rBuf, rCxt.meGram, rPos, rCxt.maErrRef, rCxt.maTabNames, rRef, false,
5061 bFromRangeName);
5063 else
5064 rBuf.append(rCxt.maErrRef);
5066 break;
5067 case svMatrix:
5069 const ScMatrix* pMat = rToken.GetMatrix();
5070 if (!pMat)
5071 return;
5073 size_t nC, nMaxC, nR, nMaxR;
5074 pMat->GetDimensions(nMaxC, nMaxR);
5076 rBuf.append(rCxt.mxOpCodeMap->getSymbol(ocArrayOpen));
5077 for (nR = 0 ; nR < nMaxR ; ++nR)
5079 if (nR > 0)
5081 rBuf.append(rCxt.mxOpCodeMap->getSymbol(ocArrayRowSep));
5084 for (nC = 0 ; nC < nMaxC ; ++nC)
5086 if (nC > 0)
5088 rBuf.append(rCxt.mxOpCodeMap->getSymbol(ocArrayColSep));
5091 if (pMat->IsValue(nC, nR))
5093 if (pMat->IsBoolean(nC, nR))
5095 bool bVal = pMat->GetDouble(nC, nR) != 0.0;
5096 rBuf.append(rCxt.mxOpCodeMap->getSymbol(bVal ? ocTrue : ocFalse));
5098 else
5100 FormulaError nErr = pMat->GetError(nC, nR);
5101 if (nErr != FormulaError::NONE)
5102 rBuf.append(ScGlobal::GetErrorString(nErr));
5103 else
5104 appendDouble(rCxt, rBuf, pMat->GetDouble(nC, nR));
5107 else if (pMat->IsEmpty(nC, nR))
5109 // Skip it.
5111 else if (pMat->IsStringOrEmpty(nC, nR))
5112 appendString(rBuf, pMat->GetString(nC, nR).getString());
5115 rBuf.append(rCxt.mxOpCodeMap->getSymbol(ocArrayClose));
5117 break;
5118 case svIndex:
5120 typedef sc::TokenStringContext::IndexNameMapType NameType;
5122 sal_uInt16 nIndex = rToken.GetIndex();
5123 switch (eOp)
5125 case ocName:
5127 SCTAB nTab = rToken.GetSheet();
5128 if (nTab < 0)
5130 // global named range
5131 NameType::const_iterator it = rCxt.maGlobalRangeNames.find(nIndex);
5132 if (it == rCxt.maGlobalRangeNames.end())
5134 rBuf.append(ScCompiler::GetNativeSymbol(ocErrName));
5135 break;
5138 rBuf.append(it->second);
5140 else
5142 // sheet-local named range
5143 if (nTab != rPos.Tab())
5145 // On other sheet.
5146 OUString aName;
5147 if (o3tl::make_unsigned(nTab) < rCxt.maTabNames.size())
5148 aName = rCxt.maTabNames[nTab];
5149 if (!aName.isEmpty())
5151 ScCompiler::CheckTabQuotes( aName, rCxt.mpRefConv->meConv);
5152 rBuf.append( aName);
5154 else
5155 rBuf.append(ScCompiler::GetNativeSymbol(ocErrName));
5156 rBuf.append( rCxt.mpRefConv->getSpecialSymbol( ScCompiler::Convention::SHEET_SEPARATOR));
5159 sc::TokenStringContext::TabIndexMapType::const_iterator itTab = rCxt.maSheetRangeNames.find(nTab);
5160 if (itTab == rCxt.maSheetRangeNames.end())
5162 rBuf.append(ScCompiler::GetNativeSymbol(ocErrName));
5163 break;
5166 const NameType& rNames = itTab->second;
5167 NameType::const_iterator it = rNames.find(nIndex);
5168 if (it == rNames.end())
5170 rBuf.append(ScCompiler::GetNativeSymbol(ocErrName));
5171 break;
5174 rBuf.append(it->second);
5177 break;
5178 case ocDBArea:
5179 case ocTableRef:
5181 NameType::const_iterator it = rCxt.maNamedDBs.find(nIndex);
5182 if (it != rCxt.maNamedDBs.end())
5183 rBuf.append(it->second);
5185 break;
5186 default:
5187 rBuf.append(ScCompiler::GetNativeSymbol(ocErrName));
5190 break;
5191 case svExternal:
5193 // mapped or translated name of AddIns
5194 OUString aAddIn = rToken.GetExternal();
5195 bool bMapped = rCxt.mxOpCodeMap->isPODF(); // ODF 1.1 directly uses programmatical name
5196 if (!bMapped && rCxt.mxOpCodeMap->hasExternals())
5198 const ExternalHashMap& rExtMap = rCxt.mxOpCodeMap->getReverseExternalHashMap();
5199 ExternalHashMap::const_iterator it = rExtMap.find(aAddIn);
5200 if (it != rExtMap.end())
5202 aAddIn = it->second;
5203 bMapped = true;
5207 if (!bMapped && !rCxt.mxOpCodeMap->isEnglish())
5208 ScGlobal::GetAddInCollection()->LocalizeString(aAddIn);
5210 rBuf.append(aAddIn);
5212 break;
5213 case svError:
5215 FormulaError nErr = rToken.GetError();
5216 OpCode eOpErr;
5217 switch (nErr)
5219 break;
5220 case FormulaError::DivisionByZero:
5221 eOpErr = ocErrDivZero;
5222 break;
5223 case FormulaError::NoValue:
5224 eOpErr = ocErrValue;
5225 break;
5226 case FormulaError::NoRef:
5227 eOpErr = ocErrRef;
5228 break;
5229 case FormulaError::NoName:
5230 eOpErr = ocErrName;
5231 break;
5232 case FormulaError::IllegalFPOperation:
5233 eOpErr = ocErrNum;
5234 break;
5235 case FormulaError::NotAvailable:
5236 eOpErr = ocErrNA;
5237 break;
5238 case FormulaError::NoCode:
5239 default:
5240 eOpErr = ocErrNull;
5242 rBuf.append(rCxt.mxOpCodeMap->getSymbol(eOpErr));
5244 break;
5245 case svByte:
5246 case svJump:
5247 case svFAP:
5248 case svMissing:
5249 case svSep:
5250 default:
5257 OUString ScTokenArray::CreateString( sc::TokenStringContext& rCxt, const ScAddress& rPos ) const
5259 if (!nLen)
5260 return OUString();
5262 OUStringBuffer aBuf;
5264 FormulaToken** p = pCode.get();
5265 FormulaToken** pEnd = p + static_cast<size_t>(nLen);
5266 for (; p != pEnd; ++p)
5268 const FormulaToken* pToken = *p;
5269 OpCode eOp = pToken->GetOpCode();
5270 /* FIXME: why does this ignore the count of spaces? */
5271 if (eOp == ocSpaces)
5273 // TODO : Handle intersection operator '!!'.
5274 aBuf.append(' ');
5275 continue;
5277 else if (eOp == ocWhitespace)
5279 aBuf.append( pToken->GetChar());
5280 continue;
5283 if (eOp < rCxt.mxOpCodeMap->getSymbolCount())
5284 aBuf.append(rCxt.mxOpCodeMap->getSymbol(eOp));
5286 appendTokenByType(*mxSheetLimits, rCxt, aBuf, *pToken, rPos, IsFromRangeName());
5289 return aBuf.makeStringAndClear();
5292 namespace {
5294 void wrapAddress( ScAddress& rPos, SCCOL nMaxCol, SCROW nMaxRow )
5296 if (rPos.Col() > nMaxCol)
5297 rPos.SetCol(rPos.Col() % (nMaxCol+1));
5298 if (rPos.Row() > nMaxRow)
5299 rPos.SetRow(rPos.Row() % (nMaxRow+1));
5302 template<typename T> void wrapRange( T& n1, T& n2, T nMax )
5304 if (n2 > nMax)
5306 if (n1 == 0)
5307 n2 = nMax; // Truncate to full range instead of wrapping to a weird range.
5308 else
5309 n2 = n2 % (nMax+1);
5311 if (n1 > nMax)
5312 n1 = n1 % (nMax+1);
5315 void wrapColRange( ScRange& rRange, SCCOL nMaxCol )
5317 SCCOL nCol1 = rRange.aStart.Col();
5318 SCCOL nCol2 = rRange.aEnd.Col();
5319 wrapRange( nCol1, nCol2, nMaxCol);
5320 rRange.aStart.SetCol( nCol1);
5321 rRange.aEnd.SetCol( nCol2);
5324 void wrapRowRange( ScRange& rRange, SCROW nMaxRow )
5326 SCROW nRow1 = rRange.aStart.Row();
5327 SCROW nRow2 = rRange.aEnd.Row();
5328 wrapRange( nRow1, nRow2, nMaxRow);
5329 rRange.aStart.SetRow( nRow1);
5330 rRange.aEnd.SetRow( nRow2);
5335 void ScTokenArray::WrapReference( const ScAddress& rPos, SCCOL nMaxCol, SCROW nMaxRow )
5337 FormulaToken** p = pCode.get();
5338 FormulaToken** pEnd = p + static_cast<size_t>(nLen);
5339 for (; p != pEnd; ++p)
5341 switch ((*p)->GetType())
5343 case svSingleRef:
5345 formula::FormulaToken* pToken = *p;
5346 ScSingleRefData& rRef = *pToken->GetSingleRef();
5347 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rPos);
5348 wrapAddress(aAbs, nMaxCol, nMaxRow);
5349 rRef.SetAddress(*mxSheetLimits, aAbs, rPos);
5351 break;
5352 case svDoubleRef:
5354 formula::FormulaToken* pToken = *p;
5355 ScComplexRefData& rRef = *pToken->GetDoubleRef();
5356 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rPos);
5357 // Entire columns/rows are sticky.
5358 if (!rRef.IsEntireCol(*mxSheetLimits) && !rRef.IsEntireRow(*mxSheetLimits))
5360 wrapColRange( aAbs, nMaxCol);
5361 wrapRowRange( aAbs, nMaxRow);
5363 else if (rRef.IsEntireCol(*mxSheetLimits) && !rRef.IsEntireRow(*mxSheetLimits))
5364 wrapColRange( aAbs, nMaxCol);
5365 else if (!rRef.IsEntireCol(*mxSheetLimits) && rRef.IsEntireRow(*mxSheetLimits))
5366 wrapRowRange( aAbs, nMaxRow);
5367 // else nothing if both, column and row, are entire.
5368 aAbs.PutInOrder();
5369 rRef.SetRange(*mxSheetLimits, aAbs, rPos);
5371 break;
5372 default:
5378 sal_Int32 ScTokenArray::GetWeight() const
5380 sal_Int32 nResult = 0;
5381 for (auto i = 0; i < nRPN; ++i)
5383 switch ((*pRPN[i]).GetType())
5385 case svDoubleRef:
5387 const auto pComplexRef = (*pRPN[i]).GetDoubleRef();
5389 // Number of cells referenced divided by 10.
5390 const double nRows = 1 + (pComplexRef->Ref2.Row() - pComplexRef->Ref1.Row());
5391 const double nCols = 1 + (pComplexRef->Ref2.Col() - pComplexRef->Ref1.Col());
5392 const double nNumCellsTerm = nRows * nCols / 10.0;
5394 if (nNumCellsTerm + nResult < SAL_MAX_INT32)
5395 nResult += nNumCellsTerm;
5396 else
5397 nResult = SAL_MAX_INT32;
5399 break;
5400 default:
5405 if (nResult == 0)
5406 nResult = 1;
5408 return nResult;
5411 #if DEBUG_FORMULA_COMPILER
5413 void ScTokenArray::Dump() const
5415 cout << "+++ Normal Tokens +++" << endl;
5416 for (sal_uInt16 i = 0; i < nLen; ++i)
5418 DumpToken(*pCode[i]);
5421 cout << "+++ RPN Tokens +++" << endl;
5422 for (sal_uInt16 i = 0; i < nRPN; ++i)
5424 DumpToken(*pRPN[i]);
5427 #endif
5429 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */