Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/inc/interpretercontext.hxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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/.
8
 */
9
10
#pragma once
11
12
#include <array>
13
#include <memory>
14
#include <random>
15
#include <vector>
16
#include <i18nlangtag/mslangid.hxx>
17
#include <svl/numformat.hxx>
18
#include "types.hxx"
19
20
namespace formula
21
{
22
class FormulaTypedDoubleToken;
23
}
24
25
631k
#define TOKEN_CACHE_SIZE 8
26
27
class Color;
28
class ScDocument;
29
struct ScLookupCacheMap;
30
class ScInterpreter;
31
32
// SetNumberFormat() is not thread-safe, so calls to it need to be delayed to the main thread.
33
struct DelayedSetNumberFormat
34
{
35
    SCCOL mCol;
36
    SCROW mRow;
37
    sal_uInt32 mnNumberFormat;
38
};
39
40
struct ScInterpreterContext
41
{
42
    const ScDocument* mpDoc;
43
    size_t mnTokenCachePos;
44
    std::vector<formula::FormulaTypedDoubleToken*> maTokens;
45
    std::vector<DelayedSetNumberFormat> maDelayedSetNumberFormat;
46
    std::unique_ptr<ScLookupCacheMap> mxScLookupCache; // cache for lookups like VLOOKUP and MATCH
47
    // Allocation cache for "aConditions" array in ScInterpreter::IterateParameterIfs()
48
    // This is populated/used only when formula-group threading is enabled.
49
    std::vector<sal_uInt8> maConditions;
50
    std::mt19937 aRNG;
51
    ScInterpreter* pInterpreter;
52
53
    ScInterpreterContext(const ScDocument& rDoc, SvNumberFormatter* pFormatter);
54
55
    ScInterpreterContext() = delete;
56
57
    ~ScInterpreterContext();
58
59
    SvNumberFormatter* GetFormatTable() const
60
6.54M
    {
61
6.54M
        if (mpFormatter == nullptr)
62
50.6k
            const_cast<ScInterpreterContext*>(this)->initFormatTable();
63
6.54M
        return mpFormatter;
64
6.54M
    }
65
66
    SvNumFormatType NFGetType(sal_uInt32 nFIndex) const;
67
    const SvNumberformat* NFGetFormatEntry(sal_uInt32 nKey) const;
68
    sal_uInt32 NFGetFormatIndex(NfIndexTableOffset, LanguageType eLnge = LANGUAGE_DONTKNOW) const;
69
    bool NFIsTextFormat(sal_uInt32 nFIndex) const;
70
    sal_uInt32 NFGetTimeFormat(double fNumber, LanguageType eLnge, bool bForceDuration) const;
71
    const Date& NFGetNullDate() const;
72
    OUString NFGetFormatDecimalSep(sal_uInt32 nFormat) const;
73
    sal_uInt16 NFGetFormatPrecision(sal_uInt32 nFormat) const;
74
75
    sal_uInt32 NFGetFormatForLanguageIfBuiltIn(sal_uInt32 nFormat, LanguageType eLnge) const;
76
77
    bool NFIsNumberFormat(const OUString& sString, sal_uInt32& F_Index, double& fOutNumber,
78
                          SvNumInputOptions eInputOptions = SvNumInputOptions::NONE);
79
80
    OUString NFGetInputLineString(const double& fOutNumber, sal_uInt32 nFIndex,
81
                                  bool bFiltering = false, bool bForceSystemLocale = false) const;
82
83
    void NFGetOutputString(const double& fOutNumber, sal_uInt32 nFIndex, OUString& sOutString,
84
                           const Color** ppColor, bool bUseStarFormat = false) const;
85
86
    void NFGetOutputString(const OUString& sString, sal_uInt32 nFIndex, OUString& sOutString,
87
                           const Color** ppColor, bool bUseStarFormat = false) const;
88
89
    sal_uInt32 NFGetStandardFormat(SvNumFormatType eType, LanguageType eLnge = LANGUAGE_DONTKNOW);
90
    sal_uInt32 NFGetStandardFormat(sal_uInt32 nFIndex, SvNumFormatType eType, LanguageType eLnge);
91
92
    bool NFGetPreviewString(const OUString& sFormatString, double fPreviewNumber,
93
                            OUString& sOutString, const Color** ppColor, LanguageType eLnge);
94
    bool NFGetPreviewString(const OUString& sFormatString, const OUString& sPreviewString,
95
                            OUString& sOutString, const Color** ppColor,
96
                            LanguageType eLnge = LANGUAGE_DONTKNOW);
97
    bool NFGetPreviewStringGuess(const OUString& sFormatString, double fPreviewNumber,
98
                                 OUString& sOutString, const Color** ppColor,
99
                                 LanguageType eLnge = LANGUAGE_DONTKNOW);
100
101
    sal_uInt32 NFGetStandardIndex(LanguageType eLnge = LANGUAGE_DONTKNOW) const;
102
103
    OUString NFGenerateFormat(sal_uInt32 nIndex, LanguageType eLnge = LANGUAGE_DONTKNOW,
104
                              bool bThousand = false, bool IsRed = false, sal_uInt16 nPrecision = 0,
105
                              sal_uInt16 nLeadingCnt = 1);
106
107
    sal_uInt16 NFExpandTwoDigitYear(sal_uInt16 nYear) const;
108
109
    OUString NFGetCalcCellReturn(sal_uInt32 nFormat) const;
110
111
    void MergeDefaultFormatKeys(SvNumberFormatter& rFormatter) const;
112
113
private:
114
    friend class ScInterpreterContextPool;
115
    void ResetTokens();
116
    void SetDocAndFormatter(const ScDocument& rDoc, SvNumberFormatter* pFormatter);
117
    void Cleanup();
118
    void ClearLookupCache(const ScDocument* pDoc);
119
    void initFormatTable();
120
    void prepFormatterForRoMode(SvNumberFormatter* pFormatter);
121
122
    // During threaded calculation, where we don't need to add to the number
123
    // format data, we can access the numbering data with a RO unlocked view of
124
    // the NumberFormat's data and a throw-away object for currently used language
125
    // This is essentially an exploded view of mpFormatter
126
    std::unique_ptr<SvNFLanguageData> mxLanguageData;
127
    // FormatData can be driven read-only, but may want to cache some data,
128
    // in RO Mode we can cache per thread to mxAuxFormatKeyMap, and
129
    // discard or merge after threaded calculation is over
130
    std::unique_ptr<SvNFFormatData::DefaultFormatKeysMap> mxAuxFormatKeyMap;
131
132
    const SvNFFormatData* mpFormatData;
133
    const NativeNumberWrapper* mpNatNum;
134
    SvNFEngine::Accessor maROPolicy;
135
136
    // Some temp caches of the 4 most recent results from NumberFormatting
137
    // lookups.
138
    struct NFBuiltIn
139
    {
140
        sal_uInt64 nKey;
141
        sal_uInt32 nFormat;
142
        NFBuiltIn()
143
670k
            : nKey(SAL_MAX_UINT64)
144
670k
            , nFormat(SAL_MAX_UINT32)
145
670k
        {
146
670k
        }
147
    };
148
    // from format+lang to builtin format
149
    mutable std::array<NFBuiltIn, 4> maNFBuiltInCache;
150
    struct NFType
151
    {
152
        sal_uInt32 nKey;
153
        SvNumFormatType eType;
154
        NFType()
155
670k
            : nKey(SAL_MAX_UINT32)
156
670k
            , eType(SvNumFormatType::ALL)
157
670k
        {
158
670k
        }
159
    };
160
    // from format index to type
161
    mutable std::array<NFType, 4> maNFTypeCache;
162
163
    // Formatter used when non-nthreaded calculation
164
    SvNumberFormatter* mpFormatter;
165
};
166
167
class ScInterpreterContextPool
168
{
169
    friend class ScThreadedInterpreterContextGetterGuard;
170
    friend class ScInterpreterContextGetterGuard;
171
172
    std::vector<std::unique_ptr<ScInterpreterContext>> maPool;
173
    size_t mnNextFree;
174
    bool mbThreaded;
175
176
    ScInterpreterContextPool(bool bThreaded)
177
44
        : mnNextFree(0)
178
44
        , mbThreaded(bThreaded)
179
44
    {
180
44
    }
181
182
0
    ~ScInterpreterContextPool() {}
183
184
    static ScInterpreterContextPool aThreadedInterpreterPool;
185
    static ScInterpreterContextPool aNonThreadedInterpreterPool;
186
187
    // API for threaded case
188
189
    // Ensures nNumThreads elements in pool.
190
    void Init(size_t nNumThreads, const ScDocument& rDoc, SvNumberFormatter* pFormatter);
191
192
    // Returns ScInterpreterContext* for thread index nThreadIdx
193
    ScInterpreterContext* GetInterpreterContextForThreadIdx(size_t nThreadIdx) const;
194
195
    // API for non-threaded
196
197
    // Ensures there is one unused element in the pool.
198
    void Init(const ScDocument& rDoc, SvNumberFormatter* pFormatter);
199
200
    // Returns ScInterpreterContext* for non-threaded use.
201
    ScInterpreterContext* GetInterpreterContext() const;
202
203
    // Common API for threaded/non-threaded
204
205
    // Cleans up the contexts prepared by call to immediately previous Init() and
206
    // marks them all as unused.
207
    void ReturnToPool();
208
209
public:
210
    // Only to be used to clear lookup cache in all pool elements
211
    static void ClearLookupCaches(const ScDocument* pDoc);
212
    // Called from ScModule dtor, drop all resources
213
    static void ModuleExiting();
214
};
215
216
class ScThreadedInterpreterContextGetterGuard
217
{
218
    ScInterpreterContextPool& rPool;
219
220
public:
221
    ScThreadedInterpreterContextGetterGuard(size_t nNumThreads, const ScDocument& rDoc,
222
                                            SvNumberFormatter* pFormatter);
223
    ~ScThreadedInterpreterContextGetterGuard();
224
225
    // Returns ScInterpreterContext* for thread index nThreadIdx
226
    ScInterpreterContext* GetInterpreterContextForThreadIdx(size_t nThreadIdx) const;
227
};
228
229
class ScInterpreterContextGetterGuard
230
{
231
    ScInterpreterContextPool& rPool;
232
#if !defined NDEBUG
233
    size_t nContextIdx;
234
#endif
235
236
public:
237
    ScInterpreterContextGetterGuard(const ScDocument& rDoc, SvNumberFormatter* pFormatter);
238
    ~ScInterpreterContextGetterGuard();
239
240
    // Returns ScInterpreterContext* for non-threaded use.
241
    ScInterpreterContext* GetInterpreterContext() const;
242
};
243
244
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */