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