/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include ScInterpreterContextPool ScInterpreterContextPool::aThreadedInterpreterPool(true); ScInterpreterContextPool ScInterpreterContextPool::aNonThreadedInterpreterPool(false); ScInterpreterContext::ScInterpreterContext(const ScDocument& rDoc, SvNumberFormatter* pFormatter) : mpDoc(&rDoc) , mnTokenCachePos(0) , maTokens(TOKEN_CACHE_SIZE, nullptr) // create a per-interpreter Random Number Generator, seeded from the global rng, so we don't have // to lock a mutex to generate a random number , aRNG(comphelper::rng::uniform_uint_distribution(0, std::numeric_limits::max())) , pInterpreter(nullptr) , mpFormatter(pFormatter) { if (!pFormatter) { mpFormatData = nullptr; mpNatNum = nullptr; } else prepFormatterForRoMode(pFormatter); } ScInterpreterContext::~ScInterpreterContext() { ResetTokens(); } void ScInterpreterContext::ResetTokens() { for (auto p : maTokens) if (p) p->DecRef(); mnTokenCachePos = 0; std::fill(maTokens.begin(), maTokens.end(), nullptr); } void ScInterpreterContext::SetDocAndFormatter(const ScDocument& rDoc, SvNumberFormatter* pFormatter) { if (mpDoc != &rDoc) { mxScLookupCache.reset(); mpDoc = &rDoc; } if (mpFormatter != pFormatter) { mpFormatter = pFormatter; // formatter has changed prepFormatterForRoMode(pFormatter); // drop cache std::fill(maNFBuiltInCache.begin(), maNFBuiltInCache.end(), NFBuiltIn()); std::fill(maNFTypeCache.begin(), maNFTypeCache.end(), NFType()); } } void ScInterpreterContext::prepFormatterForRoMode(SvNumberFormatter* pFormatter) { pFormatter->PrepForRoMode(); mpFormatData = &pFormatter->GetROFormatData(); mpNatNum = &pFormatter->GetNatNum(); mxLanguageData.reset(new SvNFLanguageData(pFormatter->GetROLanguageData())); mxAuxFormatKeyMap.reset(new SvNFFormatData::DefaultFormatKeysMap); maROPolicy = SvNFEngine::GetROPolicy(*mpFormatData, *mxAuxFormatKeyMap); } void ScInterpreterContext::initFormatTable() { mpFormatter = mpDoc->GetFormatTable(); // will assert if not main thread prepFormatterForRoMode(mpFormatter); } void ScInterpreterContext::MergeDefaultFormatKeys(SvNumberFormatter& rFormatter) const { rFormatter.MergeDefaultFormatKeys(*mxAuxFormatKeyMap); } void ScInterpreterContext::Cleanup() { // Do not disturb mxScLookupCache. maConditions.clear(); maDelayedSetNumberFormat.clear(); ResetTokens(); } void ScInterpreterContext::ClearLookupCache(const ScDocument* pDoc) { if (pDoc == mpDoc) { mxScLookupCache.reset(); mxLanguageData.reset(); mxAuxFormatKeyMap.reset(); mpFormatter = nullptr; mpFormatData = nullptr; mpNatNum = nullptr; } } SvNumFormatType ScInterpreterContext::NFGetType(sal_uInt32 nFIndex) const { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetType(nFIndex); auto aFind = std::find_if(maNFTypeCache.begin(), maNFTypeCache.end(), [nFIndex](const NFType& e) { return e.nKey == nFIndex; }); if (aFind != maNFTypeCache.end()) return aFind->eType; SvNumFormatType eType = mpFormatData->GetType(nFIndex); std::move_backward(maNFTypeCache.begin(), std::next(maNFTypeCache.begin(), maNFTypeCache.size() - 1), maNFTypeCache.end()); maNFTypeCache[0].nKey = nFIndex; maNFTypeCache[0].eType = eType; return eType; } const SvNumberformat* ScInterpreterContext::NFGetFormatEntry(sal_uInt32 nKey) const { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetEntry(nKey); return mpFormatData->GetFormatEntry(nKey); } bool ScInterpreterContext::NFIsTextFormat(sal_uInt32 nFIndex) const { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->IsTextFormat(nFIndex); return mpFormatData->IsTextFormat(nFIndex); } const Date& ScInterpreterContext::NFGetNullDate() const { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetNullDate(); return mxLanguageData->GetNullDate(); } sal_uInt32 ScInterpreterContext::NFGetTimeFormat(double fNumber, LanguageType eLnge, bool bForceDuration) const { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetTimeFormat(fNumber, eLnge, bForceDuration); return SvNFEngine::GetTimeFormat(*mxLanguageData, *mpFormatData, *mpNatNum, maROPolicy, fNumber, eLnge, bForceDuration); } sal_uInt32 ScInterpreterContext::NFGetFormatIndex(NfIndexTableOffset nTabOff, LanguageType eLnge) const { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetFormatIndex(nTabOff, eLnge); return SvNFEngine::GetFormatIndex(*mxLanguageData, maROPolicy, *mpNatNum, nTabOff, eLnge); } OUString ScInterpreterContext::NFGetFormatDecimalSep(sal_uInt32 nFormat) const { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetFormatDecimalSep(nFormat); return SvNFEngine::GetFormatDecimalSep(*mxLanguageData, *mpFormatData, nFormat); } sal_uInt16 ScInterpreterContext::NFGetFormatPrecision(sal_uInt32 nFormat) const { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetFormatPrecision(nFormat); return SvNFEngine::GetFormatPrecision(*mxLanguageData, *mpFormatData, nFormat); } sal_uInt32 ScInterpreterContext::NFGetFormatForLanguageIfBuiltIn(sal_uInt32 nFormat, LanguageType eLnge) const { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetFormatForLanguageIfBuiltIn(nFormat, eLnge); sal_uInt64 nKey = (static_cast(nFormat) << 32) | eLnge.get(); auto aFind = std::find_if(maNFBuiltInCache.begin(), maNFBuiltInCache.end(), [nKey](const NFBuiltIn& e) { return e.nKey == nKey; }); if (aFind != maNFBuiltInCache.end()) return aFind->nFormat; nFormat = SvNFEngine::GetFormatForLanguageIfBuiltIn(*mxLanguageData, *mpNatNum, maROPolicy, nFormat, eLnge); std::move_backward(maNFBuiltInCache.begin(), std::next(maNFBuiltInCache.begin(), maNFBuiltInCache.size() - 1), maNFBuiltInCache.end()); maNFBuiltInCache[0].nKey = nKey; maNFBuiltInCache[0].nFormat = nFormat; return nFormat; } sal_uInt32 ScInterpreterContext::NFGetStandardFormat(SvNumFormatType eType, LanguageType eLnge) { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetStandardFormat(eType, eLnge); return SvNFEngine::GetStandardFormat(*mxLanguageData, *mpFormatData, *mpNatNum, maROPolicy, eType, eLnge); } sal_uInt32 ScInterpreterContext::NFGetStandardFormat(sal_uInt32 nFIndex, SvNumFormatType eType, LanguageType eLnge) { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetStandardFormat(nFIndex, eType, eLnge); return SvNFEngine::GetStandardFormat(*mxLanguageData, *mpFormatData, *mpNatNum, maROPolicy, nFIndex, eType, eLnge); } OUString ScInterpreterContext::NFGetInputLineString(const double& fOutNumber, sal_uInt32 nFIndex, bool bFiltering, bool bForceSystemLocale) const { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetInputLineString(fOutNumber, nFIndex, bFiltering, bForceSystemLocale); return SvNFEngine::GetInputLineString(*mxLanguageData, *mpFormatData, *mpNatNum, maROPolicy, fOutNumber, nFIndex, bFiltering, bForceSystemLocale); } void ScInterpreterContext::NFGetOutputString(const double& fOutNumber, sal_uInt32 nFIndex, OUString& sOutString, const Color** ppColor, bool bUseStarFormat) const { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetOutputString(fOutNumber, nFIndex, sOutString, ppColor, bUseStarFormat); return SvNFEngine::GetOutputString(*mxLanguageData, *mpFormatData, *mpNatNum, maROPolicy, fOutNumber, nFIndex, sOutString, ppColor, bUseStarFormat); } void ScInterpreterContext::NFGetOutputString(const OUString& sString, sal_uInt32 nFIndex, OUString& sOutString, const Color** ppColor, bool bUseStarFormat) const { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetOutputString(sString, nFIndex, sOutString, ppColor, bUseStarFormat); return SvNFEngine::GetOutputString(*mxLanguageData, *mpFormatData, sString, nFIndex, sOutString, ppColor, bUseStarFormat); } sal_uInt32 ScInterpreterContext::NFGetStandardIndex(LanguageType eLnge) const { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetStandardIndex(eLnge); return SvNFEngine::GetStandardIndex(*mxLanguageData, *mpFormatData, *mpNatNum, maROPolicy, eLnge); } bool ScInterpreterContext::NFGetPreviewString(const OUString& sFormatString, double fPreviewNumber, OUString& sOutString, const Color** ppColor, LanguageType eLnge) { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetPreviewString(sFormatString, fPreviewNumber, sOutString, ppColor, eLnge); return SvNFEngine::GetPreviewString(*mxLanguageData, *mpFormatData, *mpNatNum, maROPolicy, sFormatString, fPreviewNumber, sOutString, ppColor, eLnge, false); } bool ScInterpreterContext::NFGetPreviewString(const OUString& sFormatString, const OUString& sPreviewString, OUString& sOutString, const Color** ppColor, LanguageType eLnge) { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetPreviewString(sFormatString, sPreviewString, sOutString, ppColor, eLnge); return SvNFEngine::GetPreviewString(*mxLanguageData, *mpFormatData, *mpNatNum, maROPolicy, sFormatString, sPreviewString, sOutString, ppColor, eLnge); } bool ScInterpreterContext::NFGetPreviewStringGuess(const OUString& sFormatString, double fPreviewNumber, OUString& sOutString, const Color** ppColor, LanguageType eLnge) { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetPreviewStringGuess(sFormatString, fPreviewNumber, sOutString, ppColor, eLnge); return SvNFEngine::GetPreviewStringGuess(*mxLanguageData, *mpFormatData, *mpNatNum, maROPolicy, sFormatString, fPreviewNumber, sOutString, ppColor, eLnge); } OUString ScInterpreterContext::NFGenerateFormat(sal_uInt32 nIndex, LanguageType eLnge, bool bThousand, bool bIsRed, sal_uInt16 nPrecision, sal_uInt16 nLeadingCnt) { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GenerateFormat(nIndex, eLnge, bThousand, bIsRed, nPrecision, nLeadingCnt); return SvNFEngine::GenerateFormat(*mxLanguageData, *mpFormatData, *mpNatNum, maROPolicy, nIndex, eLnge, bThousand, bIsRed, nPrecision, nLeadingCnt); } OUString ScInterpreterContext::NFGetCalcCellReturn(sal_uInt32 nFormat) const { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->GetCalcCellReturn(nFormat); return mpFormatData->GetCalcCellReturn(nFormat); } sal_uInt16 ScInterpreterContext::NFExpandTwoDigitYear(sal_uInt16 nYear) const { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->ExpandTwoDigitYear(nYear); return mxLanguageData->ExpandTwoDigitYear(nYear); } bool ScInterpreterContext::NFIsNumberFormat(const OUString& sString, sal_uInt32& F_Index, double& fOutNumber, SvNumInputOptions eInputOptions) { if (!mpDoc->IsThreadedGroupCalcInProgress()) return GetFormatTable()->IsNumberFormat(sString, F_Index, fOutNumber, eInputOptions); return SvNFEngine::IsNumberFormat(*mxLanguageData, *mpFormatData, *mpNatNum, maROPolicy, sString, F_Index, fOutNumber, eInputOptions); } /* ScInterpreterContextPool */ // Threaded version void ScInterpreterContextPool::Init(size_t nNumThreads, const ScDocument& rDoc, SvNumberFormatter* pFormatter) { assert(mbThreaded); size_t nOldSize = maPool.size(); maPool.resize(nNumThreads); for (size_t nIdx = 0; nIdx < nNumThreads; ++nIdx) { if (nIdx >= nOldSize) maPool[nIdx].reset(new ScInterpreterContext(rDoc, pFormatter)); else maPool[nIdx]->SetDocAndFormatter(rDoc, pFormatter); } } ScInterpreterContext* ScInterpreterContextPool::GetInterpreterContextForThreadIdx(size_t nThreadIdx) const { assert(mbThreaded); assert(nThreadIdx < maPool.size()); return maPool[nThreadIdx].get(); } // Non-Threaded version void ScInterpreterContextPool::Init(const ScDocument& rDoc, SvNumberFormatter* pFormatter) { assert(!mbThreaded); assert(mnNextFree <= maPool.size()); bool bCreateNew = (maPool.size() == mnNextFree); size_t nCurrIdx = mnNextFree; if (bCreateNew) { maPool.resize(maPool.size() + 1); maPool[nCurrIdx].reset(new ScInterpreterContext(rDoc, pFormatter)); } else maPool[nCurrIdx]->SetDocAndFormatter(rDoc, pFormatter); ++mnNextFree; } ScInterpreterContext* ScInterpreterContextPool::GetInterpreterContext() const { assert(!mbThreaded); assert(mnNextFree && (mnNextFree <= maPool.size())); return maPool[mnNextFree - 1].get(); } void ScInterpreterContextPool::ReturnToPool() { if (mbThreaded) { for (size_t nIdx = 0; nIdx < maPool.size(); ++nIdx) maPool[nIdx]->Cleanup(); } else { assert(mnNextFree && (mnNextFree <= maPool.size())); --mnNextFree; maPool[mnNextFree]->Cleanup(); } } // static void ScInterpreterContextPool::ClearLookupCaches(const ScDocument* pDoc) { for (auto& rPtr : aThreadedInterpreterPool.maPool) rPtr->ClearLookupCache(pDoc); for (auto& rPtr : aNonThreadedInterpreterPool.maPool) rPtr->ClearLookupCache(pDoc); } // static void ScInterpreterContextPool::ModuleExiting() { for (auto& rPtr : aThreadedInterpreterPool.maPool) rPtr->mxLanguageData.reset(); for (auto& rPtr : aNonThreadedInterpreterPool.maPool) rPtr->mxLanguageData.reset(); } /* ScThreadedInterpreterContextGetterGuard */ ScThreadedInterpreterContextGetterGuard::ScThreadedInterpreterContextGetterGuard( size_t nNumThreads, const ScDocument& rDoc, SvNumberFormatter* pFormatter) : rPool(ScInterpreterContextPool::aThreadedInterpreterPool) { rPool.Init(nNumThreads, rDoc, pFormatter); } ScThreadedInterpreterContextGetterGuard::~ScThreadedInterpreterContextGetterGuard() { rPool.ReturnToPool(); } ScInterpreterContext* ScThreadedInterpreterContextGetterGuard::GetInterpreterContextForThreadIdx(size_t nThreadIdx) const { return rPool.GetInterpreterContextForThreadIdx(nThreadIdx); } /* ScInterpreterContextGetterGuard */ ScInterpreterContextGetterGuard::ScInterpreterContextGetterGuard(const ScDocument& rDoc, SvNumberFormatter* pFormatter) : rPool(ScInterpreterContextPool::aNonThreadedInterpreterPool) #if !defined NDEBUG , nContextIdx(rPool.mnNextFree) #endif { rPool.Init(rDoc, pFormatter); } ScInterpreterContextGetterGuard::~ScInterpreterContextGetterGuard() { assert(nContextIdx == (rPool.mnNextFree - 1)); rPool.ReturnToPool(); } ScInterpreterContext* ScInterpreterContextGetterGuard::GetInterpreterContext() const { return rPool.GetInterpreterContext(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */