1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
/* -*- 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/.
*/
#pragma once
#include <array>
#include <vector>
#include <memory>
#include <i18nlangtag/lang.h>
#include <svl/numformat.hxx>
#include "types.hxx"
namespace formula
{
class FormulaTypedDoubleToken;
}
#define TOKEN_CACHE_SIZE 8
class ScDocument;
class SvNumberFormatter;
struct ScLookupCacheMap;
class ScInterpreter;
enum class SvNumFormatType : sal_Int16;
// SetNumberFormat() is not thread-safe, so calls to it need to be delayed to the main thread.
struct DelayedSetNumberFormat
{
SCCOL mCol;
SCROW mRow;
sal_uInt32 mnNumberFormat;
};
class ScInterpreterContextPool;
struct ScInterpreterContext
{
const ScDocument* mpDoc;
size_t mnTokenCachePos;
std::vector<formula::FormulaTypedDoubleToken*> maTokens;
std::vector<DelayedSetNumberFormat> maDelayedSetNumberFormat;
std::unique_ptr<ScLookupCacheMap> mxScLookupCache; // cache for lookups like VLOOKUP and MATCH
// Allocation cache for "aConditions" array in ScInterpreter::IterateParameterIfs()
// This is populated/used only when formula-group threading is enabled.
std::vector<sal_uInt8> maConditions;
ScInterpreter* pInterpreter;
ScInterpreterContext(const ScDocument& rDoc, SvNumberFormatter* pFormatter);
ScInterpreterContext() = delete;
~ScInterpreterContext();
SvNumberFormatter* GetFormatTable() const
{
if (mpFormatter == nullptr)
const_cast<ScInterpreterContext*>(this)->initFormatTable();
return mpFormatter;
}
SvNumFormatType GetNumberFormatType(sal_uInt32 nFIndex) const;
sal_uInt32 GetFormatForLanguageIfBuiltIn(sal_uInt32 nFormat, LanguageType eLnge) const;
private:
friend class ScInterpreterContextPool;
void ResetTokens();
void SetDocAndFormatter(const ScDocument& rDoc, SvNumberFormatter* pFormatter);
void Cleanup();
void ClearLookupCache(const ScDocument* pDoc);
void initFormatTable();
SvNumberFormatter* mpFormatter;
// Some temp caches of the 4 most recent results from NumberFormatting
// lookups.
struct NFBuiltIn
{
sal_uInt64 nKey;
sal_uInt32 nFormat;
NFBuiltIn()
: nKey(SAL_MAX_UINT64)
, nFormat(SAL_MAX_UINT32)
{
}
};
// from format+lang to builtin format
mutable std::array<NFBuiltIn, 4> maNFBuiltInCache;
struct NFType
{
sal_uInt32 nKey;
SvNumFormatType eType;
NFType()
: nKey(SAL_MAX_UINT32)
, eType(SvNumFormatType::ALL)
{
}
};
// from format index to type
mutable std::array<NFType, 4> maNFTypeCache;
};
class ScThreadedInterpreterContextGetterGuard;
class ScInterpreterContextGetterGuard;
class ScInterpreterContextPool
{
friend class ScThreadedInterpreterContextGetterGuard;
friend class ScInterpreterContextGetterGuard;
std::vector<std::unique_ptr<ScInterpreterContext>> maPool;
size_t mnNextFree;
bool mbThreaded;
ScInterpreterContextPool(bool bThreaded)
: mnNextFree(0)
, mbThreaded(bThreaded)
{
}
~ScInterpreterContextPool() {}
static ScInterpreterContextPool aThreadedInterpreterPool;
static ScInterpreterContextPool aNonThreadedInterpreterPool;
// API for threaded case
// Ensures nNumThreads elements in pool.
void Init(size_t nNumThreads, const ScDocument& rDoc, SvNumberFormatter* pFormatter);
// Returns ScInterpreterContext* for thread index nThreadIdx
ScInterpreterContext* GetInterpreterContextForThreadIdx(size_t nThreadIdx) const;
// API for non-threaded
// Ensures there is one unused element in the pool.
void Init(const ScDocument& rDoc, SvNumberFormatter* pFormatter);
// Returns ScInterpreterContext* for non-threaded use.
ScInterpreterContext* GetInterpreterContext() const;
// Common API for threaded/non-threaded
// Cleans up the contexts prepared by call to immediately previous Init() and
// marks them all as unused.
void ReturnToPool();
public:
// Only to be used to clear lookup cache in all pool elements
static void ClearLookupCaches(const ScDocument* pDoc);
};
class ScThreadedInterpreterContextGetterGuard
{
ScInterpreterContextPool& rPool;
public:
ScThreadedInterpreterContextGetterGuard(size_t nNumThreads, const ScDocument& rDoc,
SvNumberFormatter* pFormatter);
~ScThreadedInterpreterContextGetterGuard();
// Returns ScInterpreterContext* for thread index nThreadIdx
ScInterpreterContext* GetInterpreterContextForThreadIdx(size_t nThreadIdx) const;
};
class ScInterpreterContextGetterGuard
{
ScInterpreterContextPool& rPool;
#if !defined NDEBUG
size_t nContextIdx;
#endif
public:
ScInterpreterContextGetterGuard(const ScDocument& rDoc, SvNumberFormatter* pFormatter);
~ScInterpreterContextGetterGuard();
// Returns ScInterpreterContext* for non-threaded use.
ScInterpreterContext* GetInterpreterContext() const;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|