nss: upgrade to release 3.73
[LibreOffice.git] / include / formula / tokenarray.hxx
blob87377cb228e0f88b734adba7db6e4e3507bcc16f
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 );
252 /// Also used by the compiler. The token MUST had been allocated with new!
253 FormulaToken* Add( FormulaToken* );
255 public:
256 enum ReplaceMode
258 CODE_ONLY, ///< replacement only in pCode
259 CODE_AND_RPN ///< replacement in pCode and pRPN
262 /** Also used by the compiler. The token MUST had been allocated with new!
263 @param nOffset
264 Absolute offset in pCode of the token to be replaced.
265 @param eMode
266 If CODE_ONLY only the token in pCode at nOffset is replaced.
267 If CODE_AND_RPN the token in pCode at nOffset is replaced;
268 if the original token was also referenced in the pRPN array
269 then that reference is replaced with a reference to the new
270 token as well.
272 FormulaToken* ReplaceToken( sal_uInt16 nOffset, FormulaToken*, ReplaceMode eMode );
274 /** Remove a sequence of tokens from pCode array, and pRPN array if the
275 tokens are referenced there.
277 nLen and nRPN are adapted.
279 @param nOffset
280 Start offset into pCode.
281 @param nCount
282 Count of tokens to remove.
284 @return Count of tokens removed.
286 sal_uInt16 RemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount );
288 FormulaTokenArray();
289 /** Assignment with incrementing references of FormulaToken entries
290 (not copied!) */
291 FormulaTokenArray( const FormulaTokenArray& );
292 virtual ~FormulaTokenArray();
294 virtual void Clear();
297 * The array has its final used size and no more token can be added.
299 void Finalize();
301 void SetFromRangeName( bool b ) { mbFromRangeName = b; }
302 bool IsFromRangeName() const { return mbFromRangeName; }
304 void SetShareable( bool b ) { mbShareable = b; }
307 * Check if this token array is shareable between multiple adjacent
308 * formula cells. Certain tokens may not function correctly when shared.
310 * @return true if the token array is shareable, false otherwise.
312 bool IsShareable() const { return mbShareable; }
314 void DelRPN();
315 FormulaToken* FirstToken() const;
317 /// Return pCode[nIdx], or nullptr if nIdx is out of bounds
318 FormulaToken* TokenAt( sal_uInt16 nIdx) const
320 if (nIdx >= nLen)
321 return nullptr;
322 return pCode[nIdx];
325 /// Peek at nIdx-1 if not out of bounds, decrements nIdx if successful. Returns NULL if not.
326 FormulaToken* PeekPrev( sal_uInt16 & nIdx ) const;
328 /// Return the opcode at pCode[nIdx-1], ocNone if nIdx-1 is out of bounds
329 OpCode OpCodeBefore( sal_uInt16 nIdx) const
331 if (nIdx == 0 || nIdx > nLen)
332 return ocNone;
334 return pCode[nIdx-1]->GetOpCode();
337 FormulaToken* FirstRPNToken() const;
339 bool HasReferences() const;
341 bool HasExternalRef() const;
342 bool HasOpCode( OpCode ) const;
343 bool HasOpCodeRPN( OpCode ) const;
344 /// Token of type svIndex or opcode ocColRowName
345 bool HasNameOrColRowName() const;
348 * Check if the token array contains any of specified opcode tokens.
350 * @param rOpCodes collection of opcodes to check against.
352 * @return true if the token array contains at least one of the specified
353 * opcode tokens, false otherwise.
355 bool HasOpCodes( const unordered_opcode_set& rOpCodes ) const;
357 /// Assign pRPN to point to a newly created array filled with the data from pData
358 void CreateNewRPNArrayFromData( FormulaToken** pData, sal_uInt16 nSize )
360 pRPN = new FormulaToken*[ nSize ];
361 nRPN = nSize;
362 memcpy( pRPN, pData, nSize * sizeof( FormulaToken* ) );
365 FormulaToken** GetArray() const { return pCode.get(); }
367 FormulaTokenArrayStandardRange Tokens() const
369 return FormulaTokenArrayStandardRange(pCode.get(), nLen);
372 FormulaToken** GetCode() const { return pRPN; }
374 FormulaTokenArrayStandardRange RPNTokens() const
376 return FormulaTokenArrayStandardRange(pRPN, nRPN);
379 FormulaTokenArrayReferencesRange References() const
381 return FormulaTokenArrayReferencesRange(*this);
384 sal_uInt16 GetLen() const { return nLen; }
385 sal_uInt16 GetCodeLen() const { return nRPN; }
386 FormulaError GetCodeError() const { return nError; }
387 void SetCodeError( FormulaError n ) { nError = n; }
388 void SetHyperLink( bool bVal ) { bHyperLink = bVal; }
389 bool IsHyperLink() const { return bHyperLink; }
391 ScRecalcMode GetRecalcMode() const { return nMode; }
393 void SetCombinedBitsRecalcMode( ScRecalcMode nBits )
394 { nMode |= nBits & ~ScRecalcMode::EMask; }
395 ScRecalcMode GetCombinedBitsRecalcMode() const
396 { return nMode & ~ScRecalcMode::EMask; }
398 /** Exclusive bits already set in nMode are zero'ed, nBits
399 may contain combined bits, but only one exclusive bit
400 may be set! */
401 void SetMaskedRecalcMode( ScRecalcMode nBits )
402 { nMode = GetCombinedBitsRecalcMode() | nBits; }
404 /** Bits aren't set directly but validated and handled
405 according to priority if more than one exclusive bit
406 was set. */
407 void AddRecalcMode( ScRecalcMode nBits );
409 void ClearRecalcMode() { nMode = ScRecalcMode::NORMAL; }
410 void SetExclusiveRecalcModeNormal()
411 { SetMaskedRecalcMode( ScRecalcMode::NORMAL ); }
412 void SetExclusiveRecalcModeAlways()
413 { SetMaskedRecalcMode( ScRecalcMode::ALWAYS ); }
414 void SetRecalcModeForced()
415 { nMode |= ScRecalcMode::FORCED; }
416 void SetRecalcModeOnRefMove()
417 { nMode |= ScRecalcMode::ONREFMOVE; }
418 bool IsRecalcModeNormal() const
419 { return bool(nMode & ScRecalcMode::NORMAL); }
420 bool IsRecalcModeAlways() const
421 { return bool(nMode & ScRecalcMode::ALWAYS); }
422 bool IsRecalcModeForced() const
423 { return bool(nMode & ScRecalcMode::FORCED); }
424 bool IsRecalcModeOnRefMove() const
425 { return bool(nMode & ScRecalcMode::ONREFMOVE); }
426 /** Whether recalculation must happen after import, for
427 example OOXML. */
428 bool IsRecalcModeMustAfterImport() const
429 { return (nMode & ScRecalcMode::EMask) <= ScRecalcMode::ONLOAD_ONCE; }
431 /** Get OpCode of the most outer function */
432 inline OpCode GetOuterFuncOpCode() const;
434 /** Operators +,-,*,/,^,&,=,<>,<,>,<=,>=
435 with DoubleRef in Formula? */
436 bool HasMatrixDoubleRefOps() const;
438 virtual FormulaToken* AddOpCode(OpCode e);
440 /** Adds the single token to array.
441 Derived classes must override it when they want to support derived classes from FormulaToken.
442 @return true when an error occurs
444 virtual bool AddFormulaToken(
445 const css::sheet::FormulaToken& rToken, svl::SharedStringPool& rSPool,
446 ExternalReferenceHelper* pExtRef );
448 /** fill the array with the tokens from the sequence.
449 It calls AddFormulaToken for each token in the list.
450 @param _aSequence the token to add
451 @return true when an error occurs
453 bool Fill(
454 const css::uno::Sequence<css::sheet::FormulaToken>& rSequence,
455 svl::SharedStringPool& rSPool, ExternalReferenceHelper* pExtRef );
458 * Do some checking based on the individual tokens. For now, we use this
459 * only to check whether we can vectorize the token array.
461 virtual void CheckToken( const FormulaToken& t );
464 * Call CheckToken() for all RPN tokens.
466 void CheckAllRPNTokens();
468 /** Clones the token and then adds the clone to the pCode array.
469 For just new'ed tokens use Add() instead of cloning it again.
470 Use this AddToken() when adding a token from another origin.
472 FormulaToken* AddToken( const FormulaToken& );
474 FormulaToken* AddString( const svl::SharedString& rStr );
475 FormulaToken* AddDouble( double fVal );
476 void AddExternal( const sal_Unicode* pStr );
477 /** Xcl import may play dirty tricks with OpCode!=ocExternal.
478 Others don't use! */
479 FormulaToken* AddExternal( const OUString& rStr, OpCode eOp = ocExternal );
480 FormulaToken* AddBad( const OUString& rStr ); /// ocBad with OUString
481 FormulaToken* AddStringXML( const OUString& rStr ); /// ocStringXML with OUString, temporary during import
483 virtual FormulaToken* MergeArray( );
485 /** Assignment with incrementing references of FormulaToken entries
486 (not copied!) */
487 FormulaTokenArray& operator=( const FormulaTokenArray& );
489 /** Determines if this formula needs any changes to convert it to something
490 previous versions of OOo could consume (Plain Old Formula, pre-ODFF, or
491 also ODFF) */
492 bool NeedsPodfRewrite( const MissingConventionODF & rConv );
494 /** Determines if this formula needs any changes to convert it to OOXML. */
495 bool NeedsOoxmlRewrite();
497 /** Rewrites to Plain Old Formula or OOXML, substituting missing parameters. The
498 FormulaTokenArray* returned is new'ed. */
499 FormulaTokenArray* RewriteMissing( const MissingConvention & rConv );
501 /** Determines if this formula may be followed by a reference. */
502 bool MayReferenceFollow();
504 /** Re-intern SharedString in case the SharedStringPool differs. */
505 void ReinternStrings( svl::SharedStringPool& rPool );
508 inline OpCode FormulaTokenArray::GetOuterFuncOpCode() const
510 if ( pRPN && nRPN )
511 return pRPN[nRPN-1]->GetOpCode();
512 return ocNone;
515 inline FormulaTokenArrayReferencesIterator FormulaTokenArrayReferencesRange::begin()
517 return FormulaTokenArrayReferencesIterator(mrFTA.Tokens());
520 inline FormulaTokenArrayReferencesIterator FormulaTokenArrayReferencesRange::end()
522 return FormulaTokenArrayReferencesIterator::endOf(mrFTA.Tokens());
525 class FORMULA_DLLPUBLIC FormulaTokenIterator
527 struct Item
529 public:
530 const FormulaTokenArray* pArr;
531 short nPC;
532 short nStop;
534 Item(const FormulaTokenArray* arr, short pc, short stop);
537 std::vector<Item> maStack;
539 public:
540 FormulaTokenIterator( const FormulaTokenArray& );
541 ~FormulaTokenIterator();
542 void Reset();
543 const FormulaToken* Next();
544 const FormulaToken* PeekNextOperator();
545 bool IsEndOfPath() const; /// if a jump or subroutine path is done
546 bool HasStacked() const { return maStack.size() > 1; }
547 short GetPC() const { return maStack.back().nPC; }
549 /** Jump or subroutine call.
550 Program counter values will be incremented before code is executed =>
551 positions are to be passed with -1 offset.
552 @param nStart
553 Start on code at position nStart+1 (yes, pass with offset -1)
554 @param nNext
555 After subroutine continue with instruction at position nNext+1
556 @param nStop
557 Stop before reaching code at position nStop. If not specified the
558 default is to either run the entire code, or to stop if an ocSep or
559 ocClose is encountered, which are only present in ocIf or ocChoose
560 jumps.
562 void Jump( short nStart, short nNext, short nStop = SHRT_MAX );
563 void Push( const FormulaTokenArray* );
564 void Pop();
566 /** Reconstruct the iterator afresh from a token array
568 void ReInit( const FormulaTokenArray& );
570 private:
571 const FormulaToken* GetNonEndOfPathToken( short nIdx ) const;
574 // For use in SAL_INFO, SAL_WARN etc
576 template<typename charT, typename traits>
577 inline std::basic_ostream<charT, traits> & operator <<(std::basic_ostream<charT, traits> & stream, const FormulaTokenArray& point)
579 stream <<
580 static_cast<const void*>(&point) <<
581 ":{nLen=" << point.GetLen() <<
582 ",nRPN=" << point.GetCodeLen() <<
583 ",pCode=" << static_cast<void*>(point.GetArray()) <<
584 ",pRPN=" << static_cast<void*>(point.GetCode()) <<
585 "}";
587 return stream;
590 class FORMULA_DLLPUBLIC FormulaTokenArrayPlainIterator
592 private:
593 const FormulaTokenArray* mpFTA;
594 sal_uInt16 mnIndex; // Current step index
596 public:
597 FormulaTokenArrayPlainIterator( const FormulaTokenArray& rFTA ) :
598 mpFTA( &rFTA ),
599 mnIndex( 0 )
603 void Reset()
605 mnIndex = 0;
608 sal_uInt16 GetIndex() const
610 return mnIndex;
613 FormulaToken* First()
615 mnIndex = 0;
616 return Next();
619 void Jump(sal_uInt16 nIndex)
621 mnIndex = nIndex;
624 void StepBack()
626 assert(mnIndex > 0);
627 mnIndex--;
630 FormulaToken* Next();
631 FormulaToken* NextNoSpaces();
632 FormulaToken* GetNextName();
633 FormulaToken* GetNextReference();
634 FormulaToken* GetNextReferenceRPN();
635 FormulaToken* GetNextReferenceOrName();
636 FormulaToken* GetNextColRowName();
637 FormulaToken* PeekNext();
638 FormulaToken* PeekPrevNoSpaces() const; /// Only after Reset/First/Next/Last/Prev!
639 FormulaToken* PeekNextNoSpaces() const; /// Only after Reset/First/Next/Last/Prev!
641 FormulaToken* FirstRPN()
643 mnIndex = 0;
644 return NextRPN();
647 FormulaToken* NextRPN();
649 FormulaToken* LastRPN()
651 mnIndex = mpFTA->GetCodeLen();
652 return PrevRPN();
655 FormulaToken* PrevRPN();
657 void AfterRemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount );
661 } // formula
663 #endif // INCLUDED_FORMULA_TOKENARRAY_HXX
665 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */