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 ScInterpreterContext::~ScInterpreterContext() { ResetTokens(); }
48 void ScInterpreterContext::ResetTokens()
50 for (auto p
: maTokens
)
55 std::fill(maTokens
.begin(), maTokens
.end(), nullptr);
58 void ScInterpreterContext::SetDocAndFormatter(const ScDocument
& rDoc
, SvNumberFormatter
* pFormatter
)
62 mxScLookupCache
.reset();
65 if (mpFormatter
!= pFormatter
)
67 mpFormatter
= pFormatter
;
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.
84 maDelayedSetNumberFormat
.clear();
88 void ScInterpreterContext::ClearLookupCache(const ScDocument
* pDoc
)
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())
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
;
117 sal_uInt32
ScInterpreterContext::GetFormatForLanguageIfBuiltIn(sal_uInt32 nFormat
,
118 LanguageType eLnge
) const
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
;
144 /* ScInterpreterContextPool */
147 void ScInterpreterContextPool::Init(size_t nNumThreads
, const ScDocument
& rDoc
,
148 SvNumberFormatter
* pFormatter
)
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
));
158 maPool
[nIdx
]->SetDocAndFormatter(rDoc
, pFormatter
);
162 ScInterpreterContext
*
163 ScInterpreterContextPool::GetInterpreterContextForThreadIdx(size_t nThreadIdx
) const
166 assert(nThreadIdx
< maPool
.size());
167 return maPool
[nThreadIdx
].get();
170 // Non-Threaded version
171 void ScInterpreterContextPool::Init(const ScDocument
& rDoc
, SvNumberFormatter
* pFormatter
)
174 assert(mnNextFree
<= maPool
.size());
175 bool bCreateNew
= (maPool
.size() == mnNextFree
);
176 size_t nCurrIdx
= mnNextFree
;
179 maPool
.resize(maPool
.size() + 1);
180 maPool
[nCurrIdx
].reset(new ScInterpreterContext(rDoc
, pFormatter
));
183 maPool
[nCurrIdx
]->SetDocAndFormatter(rDoc
, pFormatter
);
188 ScInterpreterContext
* ScInterpreterContextPool::GetInterpreterContext() const
191 assert(mnNextFree
&& (mnNextFree
<= maPool
.size()));
192 return maPool
[mnNextFree
- 1].get();
195 void ScInterpreterContextPool::ReturnToPool()
199 for (size_t nIdx
= 0; nIdx
< maPool
.size(); ++nIdx
)
200 maPool
[nIdx
]->Cleanup();
204 assert(mnNextFree
&& (mnNextFree
<= maPool
.size()));
206 maPool
[mnNextFree
]->Cleanup();
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
)
245 , nContextIdx(rPool
.mnNextFree
)
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: */