Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / include / formula / tokenarray.hxx
blob330543d427dce47ce2856eef22bc88e2d23cecc5
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 #ifndef INCLUDED_FORMULA_TOKENARRAY_HXX
21 #define INCLUDED_FORMULA_TOKENARRAY_HXX
23 #include <climits>
24 #include <memory>
25 #include <ostream>
26 #include <type_traits>
27 #include <unordered_set>
28 #include <unordered_map>
29 #include <vector>
31 #include <formula/ExternalReferenceHelper.hxx>
32 #include <formula/formuladllapi.h>
33 #include <formula/opcode.hxx>
34 #include <formula/token.hxx>
35 #include <o3tl/typed_flags_set.hxx>
36 #include <rtl/ustring.hxx>
37 #include <sal/types.h>
39 namespace com::sun::star {
40 namespace sheet { struct FormulaToken; }
43 namespace com::sun::star::uno { template <typename > class Sequence; }
44 namespace formula { class FormulaTokenArray; }
46 namespace svl {
48 class SharedString;
49 class SharedStringPool;
53 // RecalcMode access only via TokenArray SetExclusiveRecalcMode...() /
54 // IsRecalcMode...()
56 // Only one of the exclusive bits can be set and one must be set,
57 // handled by TokenArray SetExclusiveRecalcMode...() methods.
58 // Exclusive bits are ordered by priority, AddRecalcMode() relies on that.
59 enum class ScRecalcMode : sal_uInt8
61 ALWAYS = 0x01, // exclusive, always
62 ONLOAD_MUST = 0x02, // exclusive, always after load
63 ONLOAD_ONCE = 0x04, // exclusive, once after load, import filter
64 ONLOAD_LENIENT = 0x08, // exclusive, lenient after load (eg. macros not always, aliens, ...)
65 NORMAL = 0x10, // exclusive
66 FORCED = 0x20, // combined, also if cell isn't visible, for macros with side effects
67 ONREFMOVE = 0x40, // combined, if reference was moved
68 EMask = ALWAYS | ONLOAD_MUST | ONLOAD_LENIENT | ONLOAD_ONCE | NORMAL // mask of exclusive bits
70 namespace o3tl
72 template<> struct typed_flags<ScRecalcMode> : is_typed_flags<ScRecalcMode, 0x7f> {};
75 namespace formula
78 class FORMULA_DLLPUBLIC MissingConvention
80 public:
81 enum Convention
83 FORMULA_MISSING_CONVENTION_PODF,
84 FORMULA_MISSING_CONVENTION_ODFF,
85 FORMULA_MISSING_CONVENTION_OOXML
87 explicit MissingConvention( Convention eConvention ) : meConvention(eConvention) {}
88 bool isPODF() const { return meConvention == FORMULA_MISSING_CONVENTION_PODF; }
89 bool isODFF() const { return meConvention == FORMULA_MISSING_CONVENTION_ODFF; }
90 bool isOOXML() const { return meConvention == FORMULA_MISSING_CONVENTION_OOXML; }
91 Convention getConvention() const { return meConvention; }
92 private:
93 Convention meConvention;
96 class FORMULA_DLLPUBLIC MissingConventionODF : public MissingConvention
98 public:
99 explicit MissingConventionODF( bool bODFF ) :
100 MissingConvention( bODFF ?
101 MissingConvention::FORMULA_MISSING_CONVENTION_ODFF :
102 MissingConvention::FORMULA_MISSING_CONVENTION_PODF)
105 // Implementation and usage only in token.cxx
106 inline bool isRewriteNeeded( OpCode eOp ) const;
109 class FORMULA_DLLPUBLIC MissingConventionOOXML : public MissingConvention
111 public:
112 explicit MissingConventionOOXML() : MissingConvention( MissingConvention::FORMULA_MISSING_CONVENTION_OOXML) {}
113 // Implementation and usage only in token.cxx
114 static inline bool isRewriteNeeded( OpCode eOp );
117 typedef std::unordered_set<OpCode, std::hash<std::underlying_type<OpCode>::type> > unordered_opcode_set;
119 class FORMULA_DLLPUBLIC FormulaTokenArrayStandardRange
121 private:
122 FormulaToken** mpBegin;
123 FormulaToken** mpEnd;
125 public:
126 FormulaTokenArrayStandardRange(FormulaToken** pBegin, sal_uInt16 nSize) :
127 mpBegin(pBegin),
128 mpEnd(pBegin + nSize)
132 FormulaToken** begin() const
134 return mpBegin;
137 FormulaToken** end() const
139 return mpEnd;
143 class FORMULA_DLLPUBLIC FormulaTokenArrayReferencesIterator
145 private:
146 FormulaToken** maIter;
147 FormulaToken** maEnd;
149 void nextReference()
151 while (maIter != maEnd)
153 switch ((*maIter)->GetType())
155 case svSingleRef:
156 case svDoubleRef:
157 case svExternalSingleRef:
158 case svExternalDoubleRef:
159 return;
160 default:
161 ++maIter;
166 enum class Dummy { Flag };
168 FormulaTokenArrayReferencesIterator(const FormulaTokenArrayStandardRange& rRange, Dummy) :
169 maIter(rRange.end()),
170 maEnd(rRange.end())
174 public:
175 FormulaTokenArrayReferencesIterator(const FormulaTokenArrayStandardRange& rRange) :
176 maIter(rRange.begin()),
177 maEnd(rRange.end())
179 nextReference();
182 FormulaTokenArrayReferencesIterator operator++(int)
184 FormulaTokenArrayReferencesIterator result(*this);
185 operator++();
186 return result;
189 FormulaTokenArrayReferencesIterator const & operator++()
191 assert(maIter != maEnd);
192 ++maIter;
193 nextReference();
194 return *this;
197 FormulaToken* operator*() const
199 return *maIter;
202 bool operator==(const FormulaTokenArrayReferencesIterator& rhs) const
204 return maIter == rhs.maIter;
207 bool operator!=(const FormulaTokenArrayReferencesIterator& rhs) const
209 return !operator==(rhs);
212 static FormulaTokenArrayReferencesIterator endOf(const FormulaTokenArrayStandardRange& rRange)
214 return FormulaTokenArrayReferencesIterator(rRange, Dummy::Flag);
218 class FORMULA_DLLPUBLIC FormulaTokenArrayReferencesRange
220 private:
221 const FormulaTokenArray& mrFTA;
223 public:
224 FormulaTokenArrayReferencesRange(const FormulaTokenArray& rFTA) :
225 mrFTA(rFTA)
229 FormulaTokenArrayReferencesIterator begin();
231 FormulaTokenArrayReferencesIterator end();
234 class FORMULA_DLLPUBLIC FormulaTokenArray
236 protected:
237 std::unique_ptr<FormulaToken*[]> pCode; // Token code array
238 FormulaToken** pRPN; // RPN array
239 sal_uInt16 nLen; // Length of token array
240 sal_uInt16 nRPN; // Length of RPN array
241 FormulaError nError; // Error code
242 ScRecalcMode nMode; // Flags to indicate when to recalc this code
243 bool bHyperLink :1; // If HYPERLINK() occurs in the formula.
244 bool mbFromRangeName :1; // If this array originates from a named expression
245 bool mbShareable :1; // Whether or not it can be shared with adjacent cells.
246 bool mbFinalized :1; // Whether code arrays have their final used size and no more tokens can be added.
248 protected:
249 void Assign( const FormulaTokenArray& );
250 void Assign( sal_uInt16 nCode, FormulaToken **pTokens );
251 void Move( FormulaTokenArray&& );
253 /// Also used by the compiler. The token MUST had been allocated with new!
254 FormulaToken* Add( FormulaToken* );
256 public:
257 enum ReplaceMode
259 CODE_ONLY, ///< replacement only in pCode
260 CODE_AND_RPN ///< replacement in pCode and pRPN
263 /** Also used by the compiler. The token MUST had been allocated with new!
264 @param nOffset
265 Absolute offset in pCode of the token to be replaced.
266 @param eMode
267 If CODE_ONLY only the token in pCode at nOffset is replaced.
268 If CODE_AND_RPN the token in pCode at nOffset is replaced;
269 if the original token was also referenced in the pRPN array
270 then that reference is replaced with a reference to the new
271 token as well.
273 FormulaToken* ReplaceToken( sal_uInt16 nOffset, FormulaToken*, ReplaceMode eMode );
275 /** Remove a sequence of tokens from pCode array, and pRPN array if the
276 tokens are referenced there.
278 nLen and nRPN are adapted.
280 @param nOffset
281 Start offset into pCode.
282 @param nCount
283 Count of tokens to remove.
285 @return Count of tokens removed.
287 sal_uInt16 RemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount );
289 FormulaTokenArray();
290 /** Assignment with incrementing references of FormulaToken entries
291 (not copied!) */
292 FormulaTokenArray( const FormulaTokenArray& );
293 FormulaTokenArray( FormulaTokenArray&& );
294 virtual ~FormulaTokenArray();
296 virtual void Clear();
299 * The array has its final used size and no more token can be added.
301 void Finalize();
303 void SetFromRangeName( bool b ) { mbFromRangeName = b; }
304 bool IsFromRangeName() const { return mbFromRangeName; }
306 void SetShareable( bool b ) { mbShareable = b; }
309 * Check if this token array is shareable between multiple adjacent
310 * formula cells. Certain tokens may not function correctly when shared.
312 * @return true if the token array is shareable, false otherwise.
314 bool IsShareable() const { return mbShareable; }
316 void DelRPN();
317 FormulaToken* FirstToken() const;
319 /// Return pCode[nIdx], or nullptr if nIdx is out of bounds
320 FormulaToken* TokenAt( sal_uInt16 nIdx) const
322 if (nIdx >= nLen)
323 return nullptr;
324 return pCode[nIdx];
327 /// Peek at nIdx-1 if not out of bounds, decrements nIdx if successful. Returns NULL if not.
328 FormulaToken* PeekPrev( sal_uInt16 & nIdx ) const;
330 /// Return the opcode at pCode[nIdx-1], ocNone if nIdx-1 is out of bounds
331 OpCode OpCodeBefore( sal_uInt16 nIdx) const
333 if (nIdx == 0 || nIdx > nLen)
334 return ocNone;
336 return pCode[nIdx-1]->GetOpCode();
339 FormulaToken* FirstRPNToken() const;
340 FormulaToken* LastRPNToken() const;
342 bool HasReferences() const;
344 bool HasExternalRef() const;
345 bool HasOpCode( OpCode ) const;
346 bool HasOpCodeRPN( OpCode ) const;
347 /// Token of type svIndex or opcode ocColRowName
348 bool HasNameOrColRowName() const;
351 * Check if the token array contains any of specified opcode tokens.
353 * @param rOpCodes collection of opcodes to check against.
355 * @return true if the token array contains at least one of the specified
356 * opcode tokens, false otherwise.
358 bool HasOpCodes( const unordered_opcode_set& rOpCodes ) const;
360 /// Assign pRPN to point to a newly created array filled with the data from pData
361 void CreateNewRPNArrayFromData( FormulaToken** pData, sal_uInt16 nSize )
363 pRPN = new FormulaToken*[ nSize ];
364 nRPN = nSize;
365 memcpy( pRPN, pData, nSize * sizeof( FormulaToken* ) );
368 FormulaToken** GetArray() const { return pCode.get(); }
370 FormulaTokenArrayStandardRange Tokens() const
372 return FormulaTokenArrayStandardRange(pCode.get(), nLen);
375 FormulaToken** GetCode() const { return pRPN; }
377 FormulaTokenArrayStandardRange RPNTokens() const
379 return FormulaTokenArrayStandardRange(pRPN, nRPN);
382 FormulaTokenArrayReferencesRange References() const
384 return FormulaTokenArrayReferencesRange(*this);
387 sal_uInt16 GetLen() const { return nLen; }
388 sal_uInt16 GetCodeLen() const { return nRPN; }
389 FormulaError GetCodeError() const { return nError; }
390 void SetCodeError( FormulaError n ) { nError = n; }
391 void SetHyperLink( bool bVal ) { bHyperLink = bVal; }
392 bool IsHyperLink() const { return bHyperLink; }
394 ScRecalcMode GetRecalcMode() const { return nMode; }
396 void SetCombinedBitsRecalcMode( ScRecalcMode nBits )
397 { nMode |= nBits & ~ScRecalcMode::EMask; }
398 ScRecalcMode GetCombinedBitsRecalcMode() const
399 { return nMode & ~ScRecalcMode::EMask; }
401 /** Exclusive bits already set in nMode are zero'ed, nBits
402 may contain combined bits, but only one exclusive bit
403 may be set! */
404 void SetMaskedRecalcMode( ScRecalcMode nBits )
405 { nMode = GetCombinedBitsRecalcMode() | nBits; }
407 /** Bits aren't set directly but validated and handled
408 according to priority if more than one exclusive bit
409 was set. */
410 void AddRecalcMode( ScRecalcMode nBits );
412 void ClearRecalcMode() { nMode = ScRecalcMode::NORMAL; }
413 void SetExclusiveRecalcModeNormal()
414 { SetMaskedRecalcMode( ScRecalcMode::NORMAL ); }
415 void SetExclusiveRecalcModeAlways()
416 { SetMaskedRecalcMode( ScRecalcMode::ALWAYS ); }
417 void SetRecalcModeForced()
418 { nMode |= ScRecalcMode::FORCED; }
419 void SetRecalcModeOnRefMove()
420 { nMode |= ScRecalcMode::ONREFMOVE; }
421 bool IsRecalcModeNormal() const
422 { return bool(nMode & ScRecalcMode::NORMAL); }
423 bool IsRecalcModeAlways() const
424 { return bool(nMode & ScRecalcMode::ALWAYS); }
425 bool IsRecalcModeForced() const
426 { return bool(nMode & ScRecalcMode::FORCED); }
427 bool IsRecalcModeOnRefMove() const
428 { return bool(nMode & ScRecalcMode::ONREFMOVE); }
429 /** Whether recalculation must happen after import, for
430 example OOXML. */
431 bool IsRecalcModeMustAfterImport() const
432 { return (nMode & ScRecalcMode::EMask) <= ScRecalcMode::ONLOAD_ONCE; }
433 void ClearRecalcModeMustAfterImport()
435 if (IsRecalcModeMustAfterImport() && !IsRecalcModeAlways())
436 SetExclusiveRecalcModeNormal();
439 /** Get OpCode of the most outer function */
440 inline OpCode GetOuterFuncOpCode() const;
442 /** Operators +,-,*,/,^,&,=,<>,<,>,<=,>=
443 with DoubleRef in Formula? */
444 bool HasMatrixDoubleRefOps() const;
446 virtual FormulaToken* AddOpCode(OpCode e);
448 /** Adds the single token to array.
449 Derived classes must override it when they want to support derived classes from FormulaToken.
450 @return true when an error occurs
452 virtual bool AddFormulaToken(
453 const css::sheet::FormulaToken& rToken, svl::SharedStringPool& rSPool,
454 ExternalReferenceHelper* pExtRef );
456 /** fill the array with the tokens from the sequence.
457 It calls AddFormulaToken for each token in the list.
458 @param _aSequence the token to add
459 @return true when an error occurs
461 bool Fill(
462 const css::uno::Sequence<css::sheet::FormulaToken>& rSequence,
463 svl::SharedStringPool& rSPool, ExternalReferenceHelper* pExtRef );
466 * Do some checking based on the individual tokens. For now, we use this
467 * only to check whether we can vectorize the token array.
469 virtual void CheckToken( const FormulaToken& t );
472 * Call CheckToken() for all RPN tokens.
474 void CheckAllRPNTokens();
476 /** Clones the token and then adds the clone to the pCode array.
477 For just new'ed tokens use Add() instead of cloning it again.
478 Use this AddToken() when adding a token from another origin.
480 FormulaToken* AddToken( const FormulaToken& );
482 FormulaToken* AddString( const svl::SharedString& rStr );
483 FormulaToken* AddDouble( double fVal );
484 void AddExternal( const sal_Unicode* pStr );
485 /** Xcl import may play dirty tricks with OpCode!=ocExternal.
486 Others don't use! */
487 FormulaToken* AddExternal( const OUString& rStr, OpCode eOp = ocExternal );
488 FormulaToken* AddBad( const OUString& rStr ); /// ocBad with OUString
489 FormulaToken* AddStringXML( const OUString& rStr ); /// ocStringXML with OUString, temporary during import
491 virtual FormulaToken* MergeArray( );
493 /** Assignment with incrementing references of FormulaToken entries
494 (not copied!) */
495 FormulaTokenArray& operator=( const FormulaTokenArray& );
496 FormulaTokenArray& operator=( FormulaTokenArray&& );
498 /** Determines if this formula needs any changes to convert it to something
499 previous versions of OOo could consume (Plain Old Formula, pre-ODFF, or
500 also ODFF) */
501 bool NeedsPodfRewrite( const MissingConventionODF & rConv );
503 /** Determines if this formula needs any changes to convert it to OOXML. */
504 bool NeedsOoxmlRewrite();
506 /** Rewrites to Plain Old Formula or OOXML, substituting missing parameters. The
507 FormulaTokenArray* returned is new'ed. */
508 FormulaTokenArray* RewriteMissing( const MissingConvention & rConv );
510 /** Determines if this formula may be followed by a reference. */
511 bool MayReferenceFollow();
513 /** Re-intern SharedString in case the SharedStringPool differs. */
514 void ReinternStrings( svl::SharedStringPool& rPool );
517 inline OpCode FormulaTokenArray::GetOuterFuncOpCode() const
519 if ( pRPN && nRPN )
520 return pRPN[nRPN-1]->GetOpCode();
521 return ocNone;
524 inline FormulaTokenArrayReferencesIterator FormulaTokenArrayReferencesRange::begin()
526 return FormulaTokenArrayReferencesIterator(mrFTA.Tokens());
529 inline FormulaTokenArrayReferencesIterator FormulaTokenArrayReferencesRange::end()
531 return FormulaTokenArrayReferencesIterator::endOf(mrFTA.Tokens());
534 class FORMULA_DLLPUBLIC FormulaTokenIterator
536 struct Item
538 public:
539 const FormulaTokenArray* pArr;
540 short nPC;
541 short nStop;
543 Item(const FormulaTokenArray* arr, short pc, short stop);
546 std::vector<Item> maStack;
548 public:
549 FormulaTokenIterator( const FormulaTokenArray& );
550 ~FormulaTokenIterator();
551 void Reset();
552 const FormulaToken* Next();
553 const FormulaToken* PeekNextOperator();
554 bool IsEndOfPath() const; /// if a jump or subroutine path is done
555 bool HasStacked() const { return maStack.size() > 1; }
556 short GetPC() const { return maStack.back().nPC; }
558 /** Jump or subroutine call.
559 Program counter values will be incremented before code is executed =>
560 positions are to be passed with -1 offset.
561 @param nStart
562 Start on code at position nStart+1 (yes, pass with offset -1)
563 @param nNext
564 After subroutine continue with instruction at position nNext+1
565 @param nStop
566 Stop before reaching code at position nStop. If not specified the
567 default is to either run the entire code, or to stop if an ocSep or
568 ocClose is encountered, which are only present in ocIf or ocChoose
569 jumps.
571 void Jump( short nStart, short nNext, short nStop = SHRT_MAX );
572 void Push( const FormulaTokenArray* );
573 void Pop();
575 /** Reconstruct the iterator afresh from a token array
577 void ReInit( const FormulaTokenArray& );
579 private:
580 const FormulaToken* GetNonEndOfPathToken( short nIdx ) const;
583 // For use in SAL_INFO, SAL_WARN etc
585 template<typename charT, typename traits>
586 inline std::basic_ostream<charT, traits> & operator <<(std::basic_ostream<charT, traits> & stream, const FormulaTokenArray& point)
588 stream <<
589 static_cast<const void*>(&point) <<
590 ":{nLen=" << point.GetLen() <<
591 ",nRPN=" << point.GetCodeLen() <<
592 ",pCode=" << static_cast<void*>(point.GetArray()) <<
593 ",pRPN=" << static_cast<void*>(point.GetCode()) <<
594 "}";
596 return stream;
599 class FORMULA_DLLPUBLIC FormulaTokenArrayPlainIterator
601 private:
602 const FormulaTokenArray* mpFTA;
603 sal_uInt16 mnIndex; // Current step index
605 public:
606 FormulaTokenArrayPlainIterator( const FormulaTokenArray& rFTA ) :
607 mpFTA( &rFTA ),
608 mnIndex( 0 )
612 void Reset()
614 mnIndex = 0;
617 sal_uInt16 GetIndex() const
619 return mnIndex;
622 FormulaToken* First()
624 mnIndex = 0;
625 return Next();
628 void Jump(sal_uInt16 nIndex)
630 mnIndex = nIndex;
633 void StepBack()
635 assert(mnIndex > 0);
636 mnIndex--;
639 FormulaToken* Next();
640 FormulaToken* NextNoSpaces();
641 FormulaToken* GetNextName();
642 FormulaToken* GetNextReference();
643 FormulaToken* GetNextReferenceRPN();
644 FormulaToken* GetNextReferenceOrName();
645 FormulaToken* GetNextColRowName();
646 FormulaToken* PeekNext();
647 FormulaToken* PeekPrevNoSpaces() const; /// Only after Reset/First/Next/Last/Prev!
648 FormulaToken* PeekNextNoSpaces() const; /// Only after Reset/First/Next/Last/Prev!
650 FormulaToken* FirstRPN()
652 mnIndex = 0;
653 return NextRPN();
656 FormulaToken* NextRPN();
658 FormulaToken* LastRPN()
660 mnIndex = mpFTA->GetCodeLen();
661 return PrevRPN();
664 FormulaToken* PrevRPN();
666 void AfterRemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount );
670 } // formula
672 #endif // INCLUDED_FORMULA_TOKENARRAY_HXX
674 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */