/src/libreoffice/sc/inc/interpretercontext.hxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | */ |
9 | | |
10 | | #pragma once |
11 | | |
12 | | #include <array> |
13 | | #include <memory> |
14 | | #include <random> |
15 | | #include <vector> |
16 | | #include <i18nlangtag/mslangid.hxx> |
17 | | #include <svl/numformat.hxx> |
18 | | #include "types.hxx" |
19 | | |
20 | | namespace formula |
21 | | { |
22 | | class FormulaTypedDoubleToken; |
23 | | } |
24 | | |
25 | 631k | #define TOKEN_CACHE_SIZE 8 |
26 | | |
27 | | class Color; |
28 | | class ScDocument; |
29 | | struct ScLookupCacheMap; |
30 | | class ScInterpreter; |
31 | | |
32 | | // SetNumberFormat() is not thread-safe, so calls to it need to be delayed to the main thread. |
33 | | struct DelayedSetNumberFormat |
34 | | { |
35 | | SCCOL mCol; |
36 | | SCROW mRow; |
37 | | sal_uInt32 mnNumberFormat; |
38 | | }; |
39 | | |
40 | | struct ScInterpreterContext |
41 | | { |
42 | | const ScDocument* mpDoc; |
43 | | size_t mnTokenCachePos; |
44 | | std::vector<formula::FormulaTypedDoubleToken*> maTokens; |
45 | | std::vector<DelayedSetNumberFormat> maDelayedSetNumberFormat; |
46 | | std::unique_ptr<ScLookupCacheMap> mxScLookupCache; // cache for lookups like VLOOKUP and MATCH |
47 | | // Allocation cache for "aConditions" array in ScInterpreter::IterateParameterIfs() |
48 | | // This is populated/used only when formula-group threading is enabled. |
49 | | std::vector<sal_uInt8> maConditions; |
50 | | std::mt19937 aRNG; |
51 | | ScInterpreter* pInterpreter; |
52 | | |
53 | | ScInterpreterContext(const ScDocument& rDoc, SvNumberFormatter* pFormatter); |
54 | | |
55 | | ScInterpreterContext() = delete; |
56 | | |
57 | | ~ScInterpreterContext(); |
58 | | |
59 | | SvNumberFormatter* GetFormatTable() const |
60 | 6.54M | { |
61 | 6.54M | if (mpFormatter == nullptr) |
62 | 50.6k | const_cast<ScInterpreterContext*>(this)->initFormatTable(); |
63 | 6.54M | return mpFormatter; |
64 | 6.54M | } |
65 | | |
66 | | SvNumFormatType NFGetType(sal_uInt32 nFIndex) const; |
67 | | const SvNumberformat* NFGetFormatEntry(sal_uInt32 nKey) const; |
68 | | sal_uInt32 NFGetFormatIndex(NfIndexTableOffset, LanguageType eLnge = LANGUAGE_DONTKNOW) const; |
69 | | bool NFIsTextFormat(sal_uInt32 nFIndex) const; |
70 | | sal_uInt32 NFGetTimeFormat(double fNumber, LanguageType eLnge, bool bForceDuration) const; |
71 | | const Date& NFGetNullDate() const; |
72 | | OUString NFGetFormatDecimalSep(sal_uInt32 nFormat) const; |
73 | | sal_uInt16 NFGetFormatPrecision(sal_uInt32 nFormat) const; |
74 | | |
75 | | sal_uInt32 NFGetFormatForLanguageIfBuiltIn(sal_uInt32 nFormat, LanguageType eLnge) const; |
76 | | |
77 | | bool NFIsNumberFormat(const OUString& sString, sal_uInt32& F_Index, double& fOutNumber, |
78 | | SvNumInputOptions eInputOptions = SvNumInputOptions::NONE); |
79 | | |
80 | | OUString NFGetInputLineString(const double& fOutNumber, sal_uInt32 nFIndex, |
81 | | bool bFiltering = false, bool bForceSystemLocale = false) const; |
82 | | |
83 | | void NFGetOutputString(const double& fOutNumber, sal_uInt32 nFIndex, OUString& sOutString, |
84 | | const Color** ppColor, bool bUseStarFormat = false) const; |
85 | | |
86 | | void NFGetOutputString(const OUString& sString, sal_uInt32 nFIndex, OUString& sOutString, |
87 | | const Color** ppColor, bool bUseStarFormat = false) const; |
88 | | |
89 | | sal_uInt32 NFGetStandardFormat(SvNumFormatType eType, LanguageType eLnge = LANGUAGE_DONTKNOW); |
90 | | sal_uInt32 NFGetStandardFormat(sal_uInt32 nFIndex, SvNumFormatType eType, LanguageType eLnge); |
91 | | |
92 | | bool NFGetPreviewString(const OUString& sFormatString, double fPreviewNumber, |
93 | | OUString& sOutString, const Color** ppColor, LanguageType eLnge); |
94 | | bool NFGetPreviewString(const OUString& sFormatString, const OUString& sPreviewString, |
95 | | OUString& sOutString, const Color** ppColor, |
96 | | LanguageType eLnge = LANGUAGE_DONTKNOW); |
97 | | bool NFGetPreviewStringGuess(const OUString& sFormatString, double fPreviewNumber, |
98 | | OUString& sOutString, const Color** ppColor, |
99 | | LanguageType eLnge = LANGUAGE_DONTKNOW); |
100 | | |
101 | | sal_uInt32 NFGetStandardIndex(LanguageType eLnge = LANGUAGE_DONTKNOW) const; |
102 | | |
103 | | OUString NFGenerateFormat(sal_uInt32 nIndex, LanguageType eLnge = LANGUAGE_DONTKNOW, |
104 | | bool bThousand = false, bool IsRed = false, sal_uInt16 nPrecision = 0, |
105 | | sal_uInt16 nLeadingCnt = 1); |
106 | | |
107 | | sal_uInt16 NFExpandTwoDigitYear(sal_uInt16 nYear) const; |
108 | | |
109 | | OUString NFGetCalcCellReturn(sal_uInt32 nFormat) const; |
110 | | |
111 | | void MergeDefaultFormatKeys(SvNumberFormatter& rFormatter) const; |
112 | | |
113 | | private: |
114 | | friend class ScInterpreterContextPool; |
115 | | void ResetTokens(); |
116 | | void SetDocAndFormatter(const ScDocument& rDoc, SvNumberFormatter* pFormatter); |
117 | | void Cleanup(); |
118 | | void ClearLookupCache(const ScDocument* pDoc); |
119 | | void initFormatTable(); |
120 | | void prepFormatterForRoMode(SvNumberFormatter* pFormatter); |
121 | | |
122 | | // During threaded calculation, where we don't need to add to the number |
123 | | // format data, we can access the numbering data with a RO unlocked view of |
124 | | // the NumberFormat's data and a throw-away object for currently used language |
125 | | // This is essentially an exploded view of mpFormatter |
126 | | std::unique_ptr<SvNFLanguageData> mxLanguageData; |
127 | | // FormatData can be driven read-only, but may want to cache some data, |
128 | | // in RO Mode we can cache per thread to mxAuxFormatKeyMap, and |
129 | | // discard or merge after threaded calculation is over |
130 | | std::unique_ptr<SvNFFormatData::DefaultFormatKeysMap> mxAuxFormatKeyMap; |
131 | | |
132 | | const SvNFFormatData* mpFormatData; |
133 | | const NativeNumberWrapper* mpNatNum; |
134 | | SvNFEngine::Accessor maROPolicy; |
135 | | |
136 | | // Some temp caches of the 4 most recent results from NumberFormatting |
137 | | // lookups. |
138 | | struct NFBuiltIn |
139 | | { |
140 | | sal_uInt64 nKey; |
141 | | sal_uInt32 nFormat; |
142 | | NFBuiltIn() |
143 | 670k | : nKey(SAL_MAX_UINT64) |
144 | 670k | , nFormat(SAL_MAX_UINT32) |
145 | 670k | { |
146 | 670k | } |
147 | | }; |
148 | | // from format+lang to builtin format |
149 | | mutable std::array<NFBuiltIn, 4> maNFBuiltInCache; |
150 | | struct NFType |
151 | | { |
152 | | sal_uInt32 nKey; |
153 | | SvNumFormatType eType; |
154 | | NFType() |
155 | 670k | : nKey(SAL_MAX_UINT32) |
156 | 670k | , eType(SvNumFormatType::ALL) |
157 | 670k | { |
158 | 670k | } |
159 | | }; |
160 | | // from format index to type |
161 | | mutable std::array<NFType, 4> maNFTypeCache; |
162 | | |
163 | | // Formatter used when non-nthreaded calculation |
164 | | SvNumberFormatter* mpFormatter; |
165 | | }; |
166 | | |
167 | | class ScInterpreterContextPool |
168 | | { |
169 | | friend class ScThreadedInterpreterContextGetterGuard; |
170 | | friend class ScInterpreterContextGetterGuard; |
171 | | |
172 | | std::vector<std::unique_ptr<ScInterpreterContext>> maPool; |
173 | | size_t mnNextFree; |
174 | | bool mbThreaded; |
175 | | |
176 | | ScInterpreterContextPool(bool bThreaded) |
177 | 44 | : mnNextFree(0) |
178 | 44 | , mbThreaded(bThreaded) |
179 | 44 | { |
180 | 44 | } |
181 | | |
182 | 0 | ~ScInterpreterContextPool() {} |
183 | | |
184 | | static ScInterpreterContextPool aThreadedInterpreterPool; |
185 | | static ScInterpreterContextPool aNonThreadedInterpreterPool; |
186 | | |
187 | | // API for threaded case |
188 | | |
189 | | // Ensures nNumThreads elements in pool. |
190 | | void Init(size_t nNumThreads, const ScDocument& rDoc, SvNumberFormatter* pFormatter); |
191 | | |
192 | | // Returns ScInterpreterContext* for thread index nThreadIdx |
193 | | ScInterpreterContext* GetInterpreterContextForThreadIdx(size_t nThreadIdx) const; |
194 | | |
195 | | // API for non-threaded |
196 | | |
197 | | // Ensures there is one unused element in the pool. |
198 | | void Init(const ScDocument& rDoc, SvNumberFormatter* pFormatter); |
199 | | |
200 | | // Returns ScInterpreterContext* for non-threaded use. |
201 | | ScInterpreterContext* GetInterpreterContext() const; |
202 | | |
203 | | // Common API for threaded/non-threaded |
204 | | |
205 | | // Cleans up the contexts prepared by call to immediately previous Init() and |
206 | | // marks them all as unused. |
207 | | void ReturnToPool(); |
208 | | |
209 | | public: |
210 | | // Only to be used to clear lookup cache in all pool elements |
211 | | static void ClearLookupCaches(const ScDocument* pDoc); |
212 | | // Called from ScModule dtor, drop all resources |
213 | | static void ModuleExiting(); |
214 | | }; |
215 | | |
216 | | class ScThreadedInterpreterContextGetterGuard |
217 | | { |
218 | | ScInterpreterContextPool& rPool; |
219 | | |
220 | | public: |
221 | | ScThreadedInterpreterContextGetterGuard(size_t nNumThreads, const ScDocument& rDoc, |
222 | | SvNumberFormatter* pFormatter); |
223 | | ~ScThreadedInterpreterContextGetterGuard(); |
224 | | |
225 | | // Returns ScInterpreterContext* for thread index nThreadIdx |
226 | | ScInterpreterContext* GetInterpreterContextForThreadIdx(size_t nThreadIdx) const; |
227 | | }; |
228 | | |
229 | | class ScInterpreterContextGetterGuard |
230 | | { |
231 | | ScInterpreterContextPool& rPool; |
232 | | #if !defined NDEBUG |
233 | | size_t nContextIdx; |
234 | | #endif |
235 | | |
236 | | public: |
237 | | ScInterpreterContextGetterGuard(const ScDocument& rDoc, SvNumberFormatter* pFormatter); |
238 | | ~ScInterpreterContextGetterGuard(); |
239 | | |
240 | | // Returns ScInterpreterContext* for non-threaded use. |
241 | | ScInterpreterContext* GetInterpreterContext() const; |
242 | | }; |
243 | | |
244 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ |