summaryrefslogtreecommitdiff
path: root/sc/inc/interpretercontext.hxx
blob: 4f66f29e31b62366d80f880f00749a4ba7413002 (plain)
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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
/* -*- 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 <memory>
#include <random>
#include <vector>
#include <i18nlangtag/mslangid.hxx>
#include <svl/numformat.hxx>
#include "types.hxx"

namespace formula
{
class FormulaTypedDoubleToken;
}

#define TOKEN_CACHE_SIZE 8

class Color;
class ScDocument;
struct ScLookupCacheMap;
class ScInterpreter;

// 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;
    std::mt19937 aRNG;
    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 NFGetType(sal_uInt32 nFIndex) const;
    const SvNumberformat* NFGetFormatEntry(sal_uInt32 nKey) const;
    sal_uInt32 NFGetFormatIndex(NfIndexTableOffset, LanguageType eLnge = LANGUAGE_DONTKNOW) const;
    bool NFIsTextFormat(sal_uInt32 nFIndex) const;
    sal_uInt32 NFGetTimeFormat(double fNumber, LanguageType eLnge, bool bForceDuration) const;
    const Date& NFGetNullDate() const;
    OUString NFGetFormatDecimalSep(sal_uInt32 nFormat) const;
    sal_uInt16 NFGetFormatPrecision(sal_uInt32 nFormat) const;

    sal_uInt32 NFGetFormatForLanguageIfBuiltIn(sal_uInt32 nFormat, LanguageType eLnge) const;

    bool NFIsNumberFormat(const OUString& sString, sal_uInt32& F_Index, double& fOutNumber,
                          SvNumInputOptions eInputOptions = SvNumInputOptions::NONE);

    OUString NFGetInputLineString(const double& fOutNumber, sal_uInt32 nFIndex,
                                  bool bFiltering = false, bool bForceSystemLocale = false) const;

    void NFGetOutputString(const double& fOutNumber, sal_uInt32 nFIndex, OUString& sOutString,
                           const Color** ppColor, bool bUseStarFormat = false) const;

    void NFGetOutputString(const OUString& sString, sal_uInt32 nFIndex, OUString& sOutString,
                           const Color** ppColor, bool bUseStarFormat = false) const;

    sal_uInt32 NFGetStandardFormat(SvNumFormatType eType, LanguageType eLnge = LANGUAGE_DONTKNOW);
    sal_uInt32 NFGetStandardFormat(sal_uInt32 nFIndex, SvNumFormatType eType, LanguageType eLnge);

    bool NFGetPreviewString(const OUString& sFormatString, double fPreviewNumber,
                            OUString& sOutString, const Color** ppColor, LanguageType eLnge);
    bool NFGetPreviewString(const OUString& sFormatString, const OUString& sPreviewString,
                            OUString& sOutString, const Color** ppColor,
                            LanguageType eLnge = LANGUAGE_DONTKNOW);
    bool NFGetPreviewStringGuess(const OUString& sFormatString, double fPreviewNumber,
                                 OUString& sOutString, const Color** ppColor,
                                 LanguageType eLnge = LANGUAGE_DONTKNOW);

    sal_uInt32 NFGetStandardIndex(LanguageType eLnge = LANGUAGE_DONTKNOW) const;

    OUString NFGenerateFormat(sal_uInt32 nIndex, LanguageType eLnge = LANGUAGE_DONTKNOW,
                              bool bThousand = false, bool IsRed = false, sal_uInt16 nPrecision = 0,
                              sal_uInt16 nLeadingCnt = 1);

    sal_uInt16 NFExpandTwoDigitYear(sal_uInt16 nYear) const;

    OUString NFGetCalcCellReturn(sal_uInt32 nFormat) const;

    void MergeDefaultFormatKeys(SvNumberFormatter& rFormatter) const;

private:
    friend class ScInterpreterContextPool;
    void ResetTokens();
    void SetDocAndFormatter(const ScDocument& rDoc, SvNumberFormatter* pFormatter);
    void Cleanup();
    void ClearLookupCache(const ScDocument* pDoc);
    void initFormatTable();
    void prepFormatterForRoMode(SvNumberFormatter* pFormatter);

    // During threaded calculation, where we don't need to add to the number
    // format data, we can access the numbering data with a RO unlocked view of
    // the NumberFormat's data and a throw-away object for currently used language
    // This is essentially an exploded view of mpFormatter
    std::unique_ptr<SvNFLanguageData> mxLanguageData;
    // FormatData can be driven read-only, but may want to cache some data,
    // in RO Mode we can cache per thread to mxAuxFormatKeyMap, and
    // discard or merge after threaded calculation is over
    std::unique_ptr<SvNFFormatData::DefaultFormatKeysMap> mxAuxFormatKeyMap;

    const SvNFFormatData* mpFormatData;
    const NativeNumberWrapper* mpNatNum;
    SvNFEngine::Accessor maROPolicy;

    // 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;

    // Formatter used when non-nthreaded calculation
    SvNumberFormatter* mpFormatter;
};

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);
    // Called from ScModule dtor, drop all resources
    static void ModuleExiting();
};

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: */