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/.
12 #include <formula/FormulaCompiler.hxx>
13 #include <formula/grammar.hxx>
14 #include <formula/opcode.hxx>
15 #include <rtl/ustring.hxx>
16 #include <sal/log.hxx>
17 #include <comphelper/configuration.hxx>
19 #include <calcconfig.hxx>
21 #include <comphelper/configurationlistener.hxx>
23 using comphelper::ConfigurationListener
;
25 static rtl::Reference
<ConfigurationListener
> const & getMiscListener()
27 static rtl::Reference
<ConfigurationListener
> xListener(new ConfigurationListener(u
"/org.openoffice.Office.Common/Misc"_ustr
));
31 static rtl::Reference
<ConfigurationListener
> const & getFormulaCalculationListener()
33 static rtl::Reference
<ConfigurationListener
> xListener(new ConfigurationListener(u
"/org.openoffice.Office.Calc/Formula/Calculation"_ustr
));
37 static ForceCalculationType
forceCalculationTypeInit()
39 const char* env
= getenv( "SC_FORCE_CALCULATION" );
42 if( strcmp( env
, "opencl" ) == 0 )
44 SAL_INFO("sc.core.formulagroup", "Forcing calculations to use OpenCL");
45 return ForceCalculationOpenCL
;
47 if( strcmp( env
, "threads" ) == 0 )
49 SAL_INFO("sc.core.formulagroup", "Forcing calculations to use threads");
50 return ForceCalculationThreads
;
52 if( strcmp( env
, "core" ) == 0 )
54 SAL_INFO("sc.core.formulagroup", "Forcing calculations to use core");
55 return ForceCalculationCore
;
57 SAL_WARN("sc.core.formulagroup", "Unrecognized value of SC_FORCE_CALCULATION");
60 return ForceCalculationNone
;
63 ForceCalculationType
ScCalcConfig::getForceCalculationType()
65 static const ForceCalculationType type
= forceCalculationTypeInit();
69 bool ScCalcConfig::isOpenCLEnabled()
71 if (comphelper::IsFuzzing())
73 static ForceCalculationType force
= getForceCalculationType();
74 if( force
!= ForceCalculationNone
)
75 return force
== ForceCalculationOpenCL
;
76 static comphelper::ConfigurationListenerProperty
<bool> gOpenCLEnabled(getMiscListener(), u
"UseOpenCL"_ustr
);
77 return gOpenCLEnabled
.get();
80 bool ScCalcConfig::isThreadingEnabled()
82 if (comphelper::IsFuzzing())
84 static ForceCalculationType force
= getForceCalculationType();
85 if( force
!= ForceCalculationNone
)
86 return force
== ForceCalculationThreads
;
87 static comphelper::ConfigurationListenerProperty
<bool> gThreadingEnabled(getFormulaCalculationListener(), u
"UseThreadedCalculationForFormulaGroups"_ustr
);
88 return gThreadingEnabled
.get();
91 ScCalcConfig::ScCalcConfig() :
92 meStringRefAddressSyntax(formula::FormulaGrammar::CONV_UNSPECIFIED
),
93 meStringConversion(StringConversion::LOCALE
), // old LibreOffice behavior
94 mbEmptyStringAsZero(false),
95 mbHasStringRefSyntax(false)
97 setOpenCLConfigToDefault();
100 void ScCalcConfig::setOpenCLConfigToDefault()
102 // Keep in order of opcode value, is that clearest? (Random order,
103 // at least, would make no sense at all.)
104 static const OpCodeSet
pDefaultOpenCLSubsetOpCodes(new o3tl::sorted_vector
<OpCode
>({
139 // Note that these defaults better be kept in sync with those in
140 // officecfg/registry/schema/org/openoffice/Office/Calc.xcs.
142 mbOpenCLSubsetOnly
= true;
143 mbOpenCLAutoSelect
= true;
144 mnOpenCLMinimumFormulaGroupSize
= 100;
145 mpOpenCLSubsetOpCodes
= pDefaultOpenCLSubsetOpCodes
;
148 void ScCalcConfig::reset()
150 *this = ScCalcConfig();
153 void ScCalcConfig::MergeDocumentSpecific( const ScCalcConfig
& r
)
155 // String conversion options are per document.
156 meStringConversion
= r
.meStringConversion
;
157 mbEmptyStringAsZero
= r
.mbEmptyStringAsZero
;
158 // INDIRECT ref syntax is per document.
159 meStringRefAddressSyntax
= r
.meStringRefAddressSyntax
;
160 mbHasStringRefSyntax
= r
.mbHasStringRefSyntax
;
163 void ScCalcConfig::SetStringRefSyntax( formula::FormulaGrammar::AddressConvention eConv
)
165 meStringRefAddressSyntax
= eConv
;
166 mbHasStringRefSyntax
= true;
169 bool ScCalcConfig::operator== (const ScCalcConfig
& r
) const
171 return meStringRefAddressSyntax
== r
.meStringRefAddressSyntax
&&
172 meStringConversion
== r
.meStringConversion
&&
173 mbEmptyStringAsZero
== r
.mbEmptyStringAsZero
&&
174 mbHasStringRefSyntax
== r
.mbHasStringRefSyntax
&&
175 mbOpenCLSubsetOnly
== r
.mbOpenCLSubsetOnly
&&
176 mbOpenCLAutoSelect
== r
.mbOpenCLAutoSelect
&&
177 maOpenCLDevice
== r
.maOpenCLDevice
&&
178 mnOpenCLMinimumFormulaGroupSize
== r
.mnOpenCLMinimumFormulaGroupSize
&&
179 *mpOpenCLSubsetOpCodes
== *r
.mpOpenCLSubsetOpCodes
;
182 bool ScCalcConfig::operator!= (const ScCalcConfig
& r
) const
184 return !operator==(r
);
187 OUString
ScOpCodeSetToSymbolicString(const ScCalcConfig::OpCodeSet
& rOpCodes
)
189 OUStringBuffer
result(256);
190 formula::FormulaCompiler aCompiler
;
191 formula::FormulaCompiler::OpCodeMapPtr
pOpCodeMap(aCompiler
.GetOpCodeMap(css::sheet::FormulaLanguage::ENGLISH
));
193 for (auto i
= rOpCodes
->begin(); i
!= rOpCodes
->end(); ++i
)
195 if (i
!= rOpCodes
->begin())
197 result
.append(pOpCodeMap
->getSymbol(*i
));
200 return result
.makeStringAndClear();
203 ScCalcConfig::OpCodeSet
ScStringToOpCodeSet(std::u16string_view rOpCodes
)
205 ScCalcConfig::OpCodeSet result
= std::make_shared
<o3tl::sorted_vector
< OpCode
>>();
206 formula::FormulaCompiler aCompiler
;
207 formula::FormulaCompiler::OpCodeMapPtr
pOpCodeMap(aCompiler
.GetOpCodeMap(css::sheet::FormulaLanguage::ENGLISH
));
209 const formula::OpCodeHashMap
& rHashMap(pOpCodeMap
->getHashMap());
211 sal_Int32
fromIndex(0);
213 OUString
s(OUString::Concat(rOpCodes
) + ";");
215 while ((semicolon
= s
.indexOf(';', fromIndex
)) >= 0)
217 if (semicolon
> fromIndex
)
219 OUString
element(s
.copy(fromIndex
, semicolon
- fromIndex
));
220 sal_Int32 n
= element
.toInt32();
221 if (n
> 0 || (n
== 0 && element
== "0"))
222 result
->insert(static_cast<OpCode
>(n
));
225 auto opcode(rHashMap
.find(element
));
226 if (opcode
!= rHashMap
.end())
227 result
->insert(opcode
->second
);
229 SAL_WARN("sc.opencl", "Unrecognized OpCode " << element
<< " in OpCode set string");
232 fromIndex
= semicolon
+1;
234 // HACK: Both unary and binary minus have the same string but different opcodes.
235 if( result
->find( ocSub
) != result
->end())
236 result
->insert( ocNegSub
);
241 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */