Avoid potential negative array index access to cached text.
[LibreOffice.git] / sc / source / core / tool / interpretercontext.cxx
blobcef2524b76c4cd2bd54c1e7a36b3374281b2ec4c
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 #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>
29 #include <algorithm>
31 ScInterpreterContextPool ScInterpreterContextPool::aThreadedInterpreterPool(true);
32 ScInterpreterContextPool ScInterpreterContextPool::aNonThreadedInterpreterPool(false);
34 ScInterpreterContext::ScInterpreterContext(const ScDocument& rDoc, SvNumberFormatter* pFormatter)
35 : mpDoc(&rDoc)
36 , mnTokenCachePos(0)
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 ScInterpreterContext::~ScInterpreterContext() { ResetTokens(); }
48 void ScInterpreterContext::ResetTokens()
50 for (auto p : maTokens)
51 if (p)
52 p->DecRef();
54 mnTokenCachePos = 0;
55 std::fill(maTokens.begin(), maTokens.end(), nullptr);
58 void ScInterpreterContext::SetDocAndFormatter(const ScDocument& rDoc, SvNumberFormatter* pFormatter)
60 if (mpDoc != &rDoc)
62 mxScLookupCache.reset();
63 mpDoc = &rDoc;
65 if (mpFormatter != pFormatter)
67 mpFormatter = pFormatter;
69 // drop cache
70 std::fill(maNFBuiltInCache.begin(), maNFBuiltInCache.end(), NFBuiltIn());
71 std::fill(maNFTypeCache.begin(), maNFTypeCache.end(), NFType());
75 void ScInterpreterContext::initFormatTable()
77 mpFormatter = mpDoc->GetFormatTable(); // will assert if not main thread
80 void ScInterpreterContext::Cleanup()
82 // Do not disturb mxScLookupCache.
83 maConditions.clear();
84 maDelayedSetNumberFormat.clear();
85 ResetTokens();
88 void ScInterpreterContext::ClearLookupCache(const ScDocument* pDoc)
90 if (pDoc == mpDoc)
91 mxScLookupCache.reset();
94 SvNumFormatType ScInterpreterContext::GetNumberFormatType(sal_uInt32 nFIndex) const
96 if (!mpDoc->IsThreadedGroupCalcInProgress())
98 return mpFormatter->GetType(nFIndex);
101 auto aFind = std::find_if(maNFTypeCache.begin(), maNFTypeCache.end(),
102 [nFIndex](const NFType& e) { return e.nKey == nFIndex; });
103 if (aFind != maNFTypeCache.end())
104 return aFind->eType;
106 SvNumFormatType eType = mpFormatter->GetType(nFIndex);
108 std::move_backward(maNFTypeCache.begin(),
109 std::next(maNFTypeCache.begin(), maNFTypeCache.size() - 1),
110 maNFTypeCache.end());
111 maNFTypeCache[0].nKey = nFIndex;
112 maNFTypeCache[0].eType = eType;
114 return eType;
117 sal_uInt32 ScInterpreterContext::GetFormatForLanguageIfBuiltIn(sal_uInt32 nFormat,
118 LanguageType eLnge) const
120 if (!mpFormatter)
121 return nFormat;
123 if (!mpDoc->IsThreadedGroupCalcInProgress())
124 return mpFormatter->GetFormatForLanguageIfBuiltIn(nFormat, eLnge);
126 sal_uInt64 nKey = (static_cast<sal_uInt64>(nFormat) << 32) | eLnge.get();
128 auto aFind = std::find_if(maNFBuiltInCache.begin(), maNFBuiltInCache.end(),
129 [nKey](const NFBuiltIn& e) { return e.nKey == nKey; });
130 if (aFind != maNFBuiltInCache.end())
131 return aFind->nFormat;
133 nFormat = mpFormatter->GetFormatForLanguageIfBuiltIn(nFormat, eLnge);
135 std::move_backward(maNFBuiltInCache.begin(),
136 std::next(maNFBuiltInCache.begin(), maNFBuiltInCache.size() - 1),
137 maNFBuiltInCache.end());
138 maNFBuiltInCache[0].nKey = nKey;
139 maNFBuiltInCache[0].nFormat = nFormat;
141 return nFormat;
144 /* ScInterpreterContextPool */
146 // Threaded version
147 void ScInterpreterContextPool::Init(size_t nNumThreads, const ScDocument& rDoc,
148 SvNumberFormatter* pFormatter)
150 assert(mbThreaded);
151 size_t nOldSize = maPool.size();
152 maPool.resize(nNumThreads);
153 for (size_t nIdx = 0; nIdx < nNumThreads; ++nIdx)
155 if (nIdx >= nOldSize)
156 maPool[nIdx].reset(new ScInterpreterContext(rDoc, pFormatter));
157 else
158 maPool[nIdx]->SetDocAndFormatter(rDoc, pFormatter);
162 ScInterpreterContext*
163 ScInterpreterContextPool::GetInterpreterContextForThreadIdx(size_t nThreadIdx) const
165 assert(mbThreaded);
166 assert(nThreadIdx < maPool.size());
167 return maPool[nThreadIdx].get();
170 // Non-Threaded version
171 void ScInterpreterContextPool::Init(const ScDocument& rDoc, SvNumberFormatter* pFormatter)
173 assert(!mbThreaded);
174 assert(mnNextFree <= maPool.size());
175 bool bCreateNew = (maPool.size() == mnNextFree);
176 size_t nCurrIdx = mnNextFree;
177 if (bCreateNew)
179 maPool.resize(maPool.size() + 1);
180 maPool[nCurrIdx].reset(new ScInterpreterContext(rDoc, pFormatter));
182 else
183 maPool[nCurrIdx]->SetDocAndFormatter(rDoc, pFormatter);
185 ++mnNextFree;
188 ScInterpreterContext* ScInterpreterContextPool::GetInterpreterContext() const
190 assert(!mbThreaded);
191 assert(mnNextFree && (mnNextFree <= maPool.size()));
192 return maPool[mnNextFree - 1].get();
195 void ScInterpreterContextPool::ReturnToPool()
197 if (mbThreaded)
199 for (size_t nIdx = 0; nIdx < maPool.size(); ++nIdx)
200 maPool[nIdx]->Cleanup();
202 else
204 assert(mnNextFree && (mnNextFree <= maPool.size()));
205 --mnNextFree;
206 maPool[mnNextFree]->Cleanup();
210 // static
211 void ScInterpreterContextPool::ClearLookupCaches(const ScDocument* pDoc)
213 for (auto& rPtr : aThreadedInterpreterPool.maPool)
214 rPtr->ClearLookupCache(pDoc);
215 for (auto& rPtr : aNonThreadedInterpreterPool.maPool)
216 rPtr->ClearLookupCache(pDoc);
219 /* ScThreadedInterpreterContextGetterGuard */
221 ScThreadedInterpreterContextGetterGuard::ScThreadedInterpreterContextGetterGuard(
222 size_t nNumThreads, const ScDocument& rDoc, SvNumberFormatter* pFormatter)
223 : rPool(ScInterpreterContextPool::aThreadedInterpreterPool)
225 rPool.Init(nNumThreads, rDoc, pFormatter);
228 ScThreadedInterpreterContextGetterGuard::~ScThreadedInterpreterContextGetterGuard()
230 rPool.ReturnToPool();
233 ScInterpreterContext*
234 ScThreadedInterpreterContextGetterGuard::GetInterpreterContextForThreadIdx(size_t nThreadIdx) const
236 return rPool.GetInterpreterContextForThreadIdx(nThreadIdx);
239 /* ScInterpreterContextGetterGuard */
241 ScInterpreterContextGetterGuard::ScInterpreterContextGetterGuard(const ScDocument& rDoc,
242 SvNumberFormatter* pFormatter)
243 : rPool(ScInterpreterContextPool::aNonThreadedInterpreterPool)
244 #if !defined NDEBUG
245 , nContextIdx(rPool.mnNextFree)
246 #endif
248 rPool.Init(rDoc, pFormatter);
251 ScInterpreterContextGetterGuard::~ScInterpreterContextGetterGuard()
253 assert(nContextIdx == (rPool.mnNextFree - 1));
254 rPool.ReturnToPool();
257 ScInterpreterContext* ScInterpreterContextGetterGuard::GetInterpreterContext() const
259 return rPool.GetInterpreterContext();
262 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */