1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <interpretercontext.hxx>
21 #include <svl/numformat.hxx>
22 #include <svl/zforlist.hxx>
24 #include <document.hxx>
25 #include <comphelper/random.hxx>
26 #include <formula/token.hxx>
27 #include <lookupcache.hxx>
28 #include <rangecache.hxx>
31 ScInterpreterContextPool
ScInterpreterContextPool::aThreadedInterpreterPool(true);
32 ScInterpreterContextPool
ScInterpreterContextPool::aNonThreadedInterpreterPool(false);
34 ScInterpreterContext::ScInterpreterContext(const ScDocument
& rDoc
, SvNumberFormatter
* pFormatter
)
37 , maTokens(TOKEN_CACHE_SIZE
, nullptr)
38 // create a per-interpreter Random Number Generator, seeded from the global rng, so we don't have
39 // to lock a mutex to generate a random number
40 , aRNG(comphelper::rng::uniform_uint_distribution(0, std::numeric_limits
<sal_uInt32
>::max()))
41 , pInterpreter(nullptr)
42 , mpFormatter(pFormatter
)
46 mpFormatData
= nullptr;
50 prepFormatterForRoMode(pFormatter
);
53 ScInterpreterContext::~ScInterpreterContext() { ResetTokens(); }
55 void ScInterpreterContext::ResetTokens()
57 for (auto p
: maTokens
)
62 std::fill(maTokens
.begin(), maTokens
.end(), nullptr);
65 void ScInterpreterContext::SetDocAndFormatter(const ScDocument
& rDoc
, SvNumberFormatter
* pFormatter
)
69 mxScLookupCache
.reset();
72 if (mpFormatter
!= pFormatter
)
74 mpFormatter
= pFormatter
;
76 // formatter has changed
77 prepFormatterForRoMode(pFormatter
);
80 std::fill(maNFBuiltInCache
.begin(), maNFBuiltInCache
.end(), NFBuiltIn());
81 std::fill(maNFTypeCache
.begin(), maNFTypeCache
.end(), NFType());
85 void ScInterpreterContext::prepFormatterForRoMode(SvNumberFormatter
* pFormatter
)
87 pFormatter
->PrepForRoMode();
88 mpFormatData
= &pFormatter
->GetROFormatData();
89 mpNatNum
= &pFormatter
->GetNatNum();
90 mxLanguageData
.reset(new SvNFLanguageData(pFormatter
->GetROLanguageData()));
91 mxAuxFormatKeyMap
.reset(new SvNFFormatData::DefaultFormatKeysMap
);
92 maROPolicy
= SvNFEngine::GetROPolicy(*mpFormatData
, *mxAuxFormatKeyMap
);
95 void ScInterpreterContext::initFormatTable()
97 mpFormatter
= mpDoc
->GetFormatTable(); // will assert if not main thread
98 prepFormatterForRoMode(mpFormatter
);
101 void ScInterpreterContext::MergeDefaultFormatKeys(SvNumberFormatter
& rFormatter
) const
103 rFormatter
.MergeDefaultFormatKeys(*mxAuxFormatKeyMap
);
106 void ScInterpreterContext::Cleanup()
108 // Do not disturb mxScLookupCache.
109 maConditions
.clear();
110 maDelayedSetNumberFormat
.clear();
114 void ScInterpreterContext::ClearLookupCache(const ScDocument
* pDoc
)
118 mxScLookupCache
.reset();
119 mxLanguageData
.reset();
120 mxAuxFormatKeyMap
.reset();
121 mpFormatter
= nullptr;
122 mpFormatData
= nullptr;
127 SvNumFormatType
ScInterpreterContext::NFGetType(sal_uInt32 nFIndex
) const
129 if (!mpDoc
->IsThreadedGroupCalcInProgress())
130 return GetFormatTable()->GetType(nFIndex
);
132 auto aFind
= std::find_if(maNFTypeCache
.begin(), maNFTypeCache
.end(),
133 [nFIndex
](const NFType
& e
) { return e
.nKey
== nFIndex
; });
134 if (aFind
!= maNFTypeCache
.end())
137 SvNumFormatType eType
= mpFormatData
->GetType(nFIndex
);
139 std::move_backward(maNFTypeCache
.begin(),
140 std::next(maNFTypeCache
.begin(), maNFTypeCache
.size() - 1),
141 maNFTypeCache
.end());
142 maNFTypeCache
[0].nKey
= nFIndex
;
143 maNFTypeCache
[0].eType
= eType
;
148 const SvNumberformat
* ScInterpreterContext::NFGetFormatEntry(sal_uInt32 nKey
) const
150 if (!mpDoc
->IsThreadedGroupCalcInProgress())
151 return GetFormatTable()->GetEntry(nKey
);
152 return mpFormatData
->GetFormatEntry(nKey
);
155 bool ScInterpreterContext::NFIsTextFormat(sal_uInt32 nFIndex
) const
157 if (!mpDoc
->IsThreadedGroupCalcInProgress())
158 return GetFormatTable()->IsTextFormat(nFIndex
);
159 return mpFormatData
->IsTextFormat(nFIndex
);
162 const Date
& ScInterpreterContext::NFGetNullDate() const
164 if (!mpDoc
->IsThreadedGroupCalcInProgress())
165 return GetFormatTable()->GetNullDate();
166 return mxLanguageData
->GetNullDate();
169 sal_uInt32
ScInterpreterContext::NFGetTimeFormat(double fNumber
, LanguageType eLnge
,
170 bool bForceDuration
) const
172 if (!mpDoc
->IsThreadedGroupCalcInProgress())
173 return GetFormatTable()->GetTimeFormat(fNumber
, eLnge
, bForceDuration
);
174 return SvNFEngine::GetTimeFormat(*mxLanguageData
, *mpFormatData
, *mpNatNum
, maROPolicy
, fNumber
,
175 eLnge
, bForceDuration
);
178 sal_uInt32
ScInterpreterContext::NFGetFormatIndex(NfIndexTableOffset nTabOff
,
179 LanguageType eLnge
) const
181 if (!mpDoc
->IsThreadedGroupCalcInProgress())
182 return GetFormatTable()->GetFormatIndex(nTabOff
, eLnge
);
183 return SvNFEngine::GetFormatIndex(*mxLanguageData
, maROPolicy
, *mpNatNum
, nTabOff
, eLnge
);
185 OUString
ScInterpreterContext::NFGetFormatDecimalSep(sal_uInt32 nFormat
) const
187 if (!mpDoc
->IsThreadedGroupCalcInProgress())
188 return GetFormatTable()->GetFormatDecimalSep(nFormat
);
189 return SvNFEngine::GetFormatDecimalSep(*mxLanguageData
, *mpFormatData
, nFormat
);
192 sal_uInt16
ScInterpreterContext::NFGetFormatPrecision(sal_uInt32 nFormat
) const
194 if (!mpDoc
->IsThreadedGroupCalcInProgress())
195 return GetFormatTable()->GetFormatPrecision(nFormat
);
196 return SvNFEngine::GetFormatPrecision(*mxLanguageData
, *mpFormatData
, nFormat
);
199 sal_uInt32
ScInterpreterContext::NFGetFormatForLanguageIfBuiltIn(sal_uInt32 nFormat
,
200 LanguageType eLnge
) const
202 if (!mpDoc
->IsThreadedGroupCalcInProgress())
203 return GetFormatTable()->GetFormatForLanguageIfBuiltIn(nFormat
, eLnge
);
205 sal_uInt64 nKey
= (static_cast<sal_uInt64
>(nFormat
) << 32) | eLnge
.get();
207 auto aFind
= std::find_if(maNFBuiltInCache
.begin(), maNFBuiltInCache
.end(),
208 [nKey
](const NFBuiltIn
& e
) { return e
.nKey
== nKey
; });
209 if (aFind
!= maNFBuiltInCache
.end())
210 return aFind
->nFormat
;
212 nFormat
= SvNFEngine::GetFormatForLanguageIfBuiltIn(*mxLanguageData
, *mpNatNum
, maROPolicy
,
215 std::move_backward(maNFBuiltInCache
.begin(),
216 std::next(maNFBuiltInCache
.begin(), maNFBuiltInCache
.size() - 1),
217 maNFBuiltInCache
.end());
218 maNFBuiltInCache
[0].nKey
= nKey
;
219 maNFBuiltInCache
[0].nFormat
= nFormat
;
224 sal_uInt32
ScInterpreterContext::NFGetStandardFormat(SvNumFormatType eType
, LanguageType eLnge
)
226 if (!mpDoc
->IsThreadedGroupCalcInProgress())
227 return GetFormatTable()->GetStandardFormat(eType
, eLnge
);
228 return SvNFEngine::GetStandardFormat(*mxLanguageData
, *mpFormatData
, *mpNatNum
, maROPolicy
,
232 sal_uInt32
ScInterpreterContext::NFGetStandardFormat(sal_uInt32 nFIndex
, SvNumFormatType eType
,
235 if (!mpDoc
->IsThreadedGroupCalcInProgress())
236 return GetFormatTable()->GetStandardFormat(nFIndex
, eType
, eLnge
);
237 return SvNFEngine::GetStandardFormat(*mxLanguageData
, *mpFormatData
, *mpNatNum
, maROPolicy
,
238 nFIndex
, eType
, eLnge
);
241 void ScInterpreterContext::NFGetInputLineString(const double& fOutNumber
, sal_uInt32 nFIndex
,
242 OUString
& rOutString
, bool bFiltering
,
243 bool bForceSystemLocale
) const
245 if (!mpDoc
->IsThreadedGroupCalcInProgress())
246 return GetFormatTable()->GetInputLineString(fOutNumber
, nFIndex
, rOutString
, bFiltering
,
248 return SvNFEngine::GetInputLineString(*mxLanguageData
, *mpFormatData
, *mpNatNum
, maROPolicy
,
249 fOutNumber
, nFIndex
, rOutString
, bFiltering
,
252 void ScInterpreterContext::NFGetOutputString(const double& fOutNumber
, sal_uInt32 nFIndex
,
253 OUString
& sOutString
, const Color
** ppColor
,
254 bool bUseStarFormat
) const
256 if (!mpDoc
->IsThreadedGroupCalcInProgress())
257 return GetFormatTable()->GetOutputString(fOutNumber
, nFIndex
, sOutString
, ppColor
,
259 return SvNFEngine::GetOutputString(*mxLanguageData
, *mpFormatData
, *mpNatNum
, maROPolicy
,
260 fOutNumber
, nFIndex
, sOutString
, ppColor
, bUseStarFormat
);
263 void ScInterpreterContext::NFGetOutputString(const OUString
& sString
, sal_uInt32 nFIndex
,
264 OUString
& sOutString
, const Color
** ppColor
,
265 bool bUseStarFormat
) const
267 if (!mpDoc
->IsThreadedGroupCalcInProgress())
268 return GetFormatTable()->GetOutputString(sString
, nFIndex
, sOutString
, ppColor
,
270 return SvNFEngine::GetOutputString(*mxLanguageData
, *mpFormatData
, sString
, nFIndex
, sOutString
,
271 ppColor
, bUseStarFormat
);
274 sal_uInt32
ScInterpreterContext::NFGetStandardIndex(LanguageType eLnge
) const
276 if (!mpDoc
->IsThreadedGroupCalcInProgress())
277 return GetFormatTable()->GetStandardIndex(eLnge
);
278 return SvNFEngine::GetStandardIndex(*mxLanguageData
, *mpFormatData
, *mpNatNum
, maROPolicy
,
282 bool ScInterpreterContext::NFGetPreviewString(const OUString
& sFormatString
, double fPreviewNumber
,
283 OUString
& sOutString
, const Color
** ppColor
,
286 if (!mpDoc
->IsThreadedGroupCalcInProgress())
287 return GetFormatTable()->GetPreviewString(sFormatString
, fPreviewNumber
, sOutString
,
289 return SvNFEngine::GetPreviewString(*mxLanguageData
, *mpFormatData
, *mpNatNum
, maROPolicy
,
290 sFormatString
, fPreviewNumber
, sOutString
, ppColor
, eLnge
,
293 bool ScInterpreterContext::NFGetPreviewString(const OUString
& sFormatString
,
294 const OUString
& sPreviewString
, OUString
& sOutString
,
295 const Color
** ppColor
, LanguageType eLnge
)
297 if (!mpDoc
->IsThreadedGroupCalcInProgress())
298 return GetFormatTable()->GetPreviewString(sFormatString
, sPreviewString
, sOutString
,
300 return SvNFEngine::GetPreviewString(*mxLanguageData
, *mpFormatData
, *mpNatNum
, maROPolicy
,
301 sFormatString
, sPreviewString
, sOutString
, ppColor
, eLnge
);
304 bool ScInterpreterContext::NFGetPreviewStringGuess(const OUString
& sFormatString
,
305 double fPreviewNumber
, OUString
& sOutString
,
306 const Color
** ppColor
, LanguageType eLnge
)
308 if (!mpDoc
->IsThreadedGroupCalcInProgress())
309 return GetFormatTable()->GetPreviewStringGuess(sFormatString
, fPreviewNumber
, sOutString
,
311 return SvNFEngine::GetPreviewStringGuess(*mxLanguageData
, *mpFormatData
, *mpNatNum
, maROPolicy
,
312 sFormatString
, fPreviewNumber
, sOutString
, ppColor
,
316 OUString
ScInterpreterContext::NFGenerateFormat(sal_uInt32 nIndex
, LanguageType eLnge
,
317 bool bThousand
, bool bIsRed
, sal_uInt16 nPrecision
,
318 sal_uInt16 nLeadingCnt
)
320 if (!mpDoc
->IsThreadedGroupCalcInProgress())
321 return GetFormatTable()->GenerateFormat(nIndex
, eLnge
, bThousand
, bIsRed
, nPrecision
,
323 return SvNFEngine::GenerateFormat(*mxLanguageData
, *mpFormatData
, *mpNatNum
, maROPolicy
, nIndex
,
324 eLnge
, bThousand
, bIsRed
, nPrecision
, nLeadingCnt
);
326 OUString
ScInterpreterContext::NFGetCalcCellReturn(sal_uInt32 nFormat
) const
328 if (!mpDoc
->IsThreadedGroupCalcInProgress())
329 return GetFormatTable()->GetCalcCellReturn(nFormat
);
330 return mpFormatData
->GetCalcCellReturn(nFormat
);
333 sal_uInt16
ScInterpreterContext::NFExpandTwoDigitYear(sal_uInt16 nYear
) const
335 if (!mpDoc
->IsThreadedGroupCalcInProgress())
336 return GetFormatTable()->ExpandTwoDigitYear(nYear
);
337 return mxLanguageData
->ExpandTwoDigitYear(nYear
);
340 bool ScInterpreterContext::NFIsNumberFormat(const OUString
& sString
, sal_uInt32
& F_Index
,
341 double& fOutNumber
, SvNumInputOptions eInputOptions
)
343 if (!mpDoc
->IsThreadedGroupCalcInProgress())
344 return GetFormatTable()->IsNumberFormat(sString
, F_Index
, fOutNumber
, eInputOptions
);
345 return SvNFEngine::IsNumberFormat(*mxLanguageData
, *mpFormatData
, *mpNatNum
, maROPolicy
,
346 sString
, F_Index
, fOutNumber
, eInputOptions
);
349 /* ScInterpreterContextPool */
352 void ScInterpreterContextPool::Init(size_t nNumThreads
, const ScDocument
& rDoc
,
353 SvNumberFormatter
* pFormatter
)
356 size_t nOldSize
= maPool
.size();
357 maPool
.resize(nNumThreads
);
358 for (size_t nIdx
= 0; nIdx
< nNumThreads
; ++nIdx
)
360 if (nIdx
>= nOldSize
)
361 maPool
[nIdx
].reset(new ScInterpreterContext(rDoc
, pFormatter
));
363 maPool
[nIdx
]->SetDocAndFormatter(rDoc
, pFormatter
);
367 ScInterpreterContext
*
368 ScInterpreterContextPool::GetInterpreterContextForThreadIdx(size_t nThreadIdx
) const
371 assert(nThreadIdx
< maPool
.size());
372 return maPool
[nThreadIdx
].get();
375 // Non-Threaded version
376 void ScInterpreterContextPool::Init(const ScDocument
& rDoc
, SvNumberFormatter
* pFormatter
)
379 assert(mnNextFree
<= maPool
.size());
380 bool bCreateNew
= (maPool
.size() == mnNextFree
);
381 size_t nCurrIdx
= mnNextFree
;
384 maPool
.resize(maPool
.size() + 1);
385 maPool
[nCurrIdx
].reset(new ScInterpreterContext(rDoc
, pFormatter
));
388 maPool
[nCurrIdx
]->SetDocAndFormatter(rDoc
, pFormatter
);
393 ScInterpreterContext
* ScInterpreterContextPool::GetInterpreterContext() const
396 assert(mnNextFree
&& (mnNextFree
<= maPool
.size()));
397 return maPool
[mnNextFree
- 1].get();
400 void ScInterpreterContextPool::ReturnToPool()
404 for (size_t nIdx
= 0; nIdx
< maPool
.size(); ++nIdx
)
405 maPool
[nIdx
]->Cleanup();
409 assert(mnNextFree
&& (mnNextFree
<= maPool
.size()));
411 maPool
[mnNextFree
]->Cleanup();
416 void ScInterpreterContextPool::ClearLookupCaches(const ScDocument
* pDoc
)
418 for (auto& rPtr
: aThreadedInterpreterPool
.maPool
)
419 rPtr
->ClearLookupCache(pDoc
);
420 for (auto& rPtr
: aNonThreadedInterpreterPool
.maPool
)
421 rPtr
->ClearLookupCache(pDoc
);
425 void ScInterpreterContextPool::ModuleExiting()
427 for (auto& rPtr
: aThreadedInterpreterPool
.maPool
)
428 rPtr
->mxLanguageData
.reset();
429 for (auto& rPtr
: aNonThreadedInterpreterPool
.maPool
)
430 rPtr
->mxLanguageData
.reset();
433 /* ScThreadedInterpreterContextGetterGuard */
435 ScThreadedInterpreterContextGetterGuard::ScThreadedInterpreterContextGetterGuard(
436 size_t nNumThreads
, const ScDocument
& rDoc
, SvNumberFormatter
* pFormatter
)
437 : rPool(ScInterpreterContextPool::aThreadedInterpreterPool
)
439 rPool
.Init(nNumThreads
, rDoc
, pFormatter
);
442 ScThreadedInterpreterContextGetterGuard::~ScThreadedInterpreterContextGetterGuard()
444 rPool
.ReturnToPool();
447 ScInterpreterContext
*
448 ScThreadedInterpreterContextGetterGuard::GetInterpreterContextForThreadIdx(size_t nThreadIdx
) const
450 return rPool
.GetInterpreterContextForThreadIdx(nThreadIdx
);
453 /* ScInterpreterContextGetterGuard */
455 ScInterpreterContextGetterGuard::ScInterpreterContextGetterGuard(const ScDocument
& rDoc
,
456 SvNumberFormatter
* pFormatter
)
457 : rPool(ScInterpreterContextPool::aNonThreadedInterpreterPool
)
459 , nContextIdx(rPool
.mnNextFree
)
462 rPool
.Init(rDoc
, pFormatter
);
465 ScInterpreterContextGetterGuard::~ScInterpreterContextGetterGuard()
467 assert(nContextIdx
== (rPool
.mnNextFree
- 1));
468 rPool
.ReturnToPool();
471 ScInterpreterContext
* ScInterpreterContextGetterGuard::GetInterpreterContext() const
473 return rPool
.GetInterpreterContext();
476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */