diff options
Diffstat (limited to 'sc/source/core/tool/calcconfig.cxx')
-rw-r--r-- | sc/source/core/tool/calcconfig.cxx | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/sc/source/core/tool/calcconfig.cxx b/sc/source/core/tool/calcconfig.cxx new file mode 100644 index 000000000..7eb36d73a --- /dev/null +++ b/sc/source/core/tool/calcconfig.cxx @@ -0,0 +1,241 @@ +/* -*- 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/. + */ + +#include <ostream> + +#include <formula/FormulaCompiler.hxx> +#include <formula/grammar.hxx> +#include <formula/opcode.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> +#include <unotools/configmgr.hxx> + +#include <calcconfig.hxx> + +#include <comphelper/configurationlistener.hxx> + +using comphelper::ConfigurationListener; + +static rtl::Reference<ConfigurationListener> const & getMiscListener() +{ + static rtl::Reference<ConfigurationListener> xListener(new ConfigurationListener("/org.openoffice.Office.Common/Misc")); + return xListener; +} + +static rtl::Reference<ConfigurationListener> const & getFormulaCalculationListener() +{ + static rtl::Reference<ConfigurationListener> xListener(new ConfigurationListener("/org.openoffice.Office.Calc/Formula/Calculation")); + return xListener; +} + +static ForceCalculationType forceCalculationTypeInit() +{ + const char* env = getenv( "SC_FORCE_CALCULATION" ); + if( env != nullptr ) + { + if( strcmp( env, "opencl" ) == 0 ) + { + SAL_INFO("sc.core.formulagroup", "Forcing calculations to use OpenCL"); + return ForceCalculationOpenCL; + } + if( strcmp( env, "threads" ) == 0 ) + { + SAL_INFO("sc.core.formulagroup", "Forcing calculations to use threads"); + return ForceCalculationThreads; + } + if( strcmp( env, "core" ) == 0 ) + { + SAL_INFO("sc.core.formulagroup", "Forcing calculations to use core"); + return ForceCalculationCore; + } + SAL_WARN("sc.core.formulagroup", "Unrecognized value of SC_FORCE_CALCULATION"); + abort(); + } + return ForceCalculationNone; +} + +ForceCalculationType ScCalcConfig::getForceCalculationType() +{ + static const ForceCalculationType type = forceCalculationTypeInit(); + return type; +} + +bool ScCalcConfig::isOpenCLEnabled() +{ + if (utl::ConfigManager::IsFuzzing()) + return false; + static ForceCalculationType force = getForceCalculationType(); + if( force != ForceCalculationNone ) + return force == ForceCalculationOpenCL; + static comphelper::ConfigurationListenerProperty<bool> gOpenCLEnabled(getMiscListener(), "UseOpenCL"); + return gOpenCLEnabled.get(); +} + +bool ScCalcConfig::isThreadingEnabled() +{ + if (utl::ConfigManager::IsFuzzing()) + return false; + static ForceCalculationType force = getForceCalculationType(); + if( force != ForceCalculationNone ) + return force == ForceCalculationThreads; + static comphelper::ConfigurationListenerProperty<bool> gThreadingEnabled(getFormulaCalculationListener(), "UseThreadedCalculationForFormulaGroups"); + return gThreadingEnabled.get(); +} + +ScCalcConfig::ScCalcConfig() : + meStringRefAddressSyntax(formula::FormulaGrammar::CONV_UNSPECIFIED), + meStringConversion(StringConversion::LOCALE), // old LibreOffice behavior + mbEmptyStringAsZero(false), + mbHasStringRefSyntax(false) +{ + setOpenCLConfigToDefault(); +} + +void ScCalcConfig::setOpenCLConfigToDefault() +{ + // Keep in order of opcode value, is that clearest? (Random order, + // at least, would make no sense at all.) + static const OpCodeSet pDefaultOpenCLSubsetOpCodes(new o3tl::sorted_vector<OpCode>({ + ocAdd, + ocSub, + ocNegSub, + ocMul, + ocDiv, + ocPow, + ocRandom, + ocSin, + ocCos, + ocTan, + ocArcTan, + ocExp, + ocLn, + ocSqrt, + ocStdNormDist, + ocSNormInv, + ocRound, + ocPower, + ocSumProduct, + ocMin, + ocMax, + ocSum, + ocProduct, + ocAverage, + ocCount, + ocVar, + ocNormDist, + ocVLookup, + ocCorrel, + ocCovar, + ocPearson, + ocSlope, + ocSumIfs})); + + // Note that these defaults better be kept in sync with those in + // officecfg/registry/schema/org/openoffice/Office/Calc.xcs. + // Crazy. + mbOpenCLSubsetOnly = true; + mbOpenCLAutoSelect = true; + mnOpenCLMinimumFormulaGroupSize = 100; + mpOpenCLSubsetOpCodes = pDefaultOpenCLSubsetOpCodes; +} + +void ScCalcConfig::reset() +{ + *this = ScCalcConfig(); +} + +void ScCalcConfig::MergeDocumentSpecific( const ScCalcConfig& r ) +{ + // String conversion options are per document. + meStringConversion = r.meStringConversion; + mbEmptyStringAsZero = r.mbEmptyStringAsZero; + // INDIRECT ref syntax is per document. + meStringRefAddressSyntax = r.meStringRefAddressSyntax; + mbHasStringRefSyntax = r.mbHasStringRefSyntax; +} + +void ScCalcConfig::SetStringRefSyntax( formula::FormulaGrammar::AddressConvention eConv ) +{ + meStringRefAddressSyntax = eConv; + mbHasStringRefSyntax = true; +} + +bool ScCalcConfig::operator== (const ScCalcConfig& r) const +{ + return meStringRefAddressSyntax == r.meStringRefAddressSyntax && + meStringConversion == r.meStringConversion && + mbEmptyStringAsZero == r.mbEmptyStringAsZero && + mbHasStringRefSyntax == r.mbHasStringRefSyntax && + mbOpenCLSubsetOnly == r.mbOpenCLSubsetOnly && + mbOpenCLAutoSelect == r.mbOpenCLAutoSelect && + maOpenCLDevice == r.maOpenCLDevice && + mnOpenCLMinimumFormulaGroupSize == r.mnOpenCLMinimumFormulaGroupSize && + *mpOpenCLSubsetOpCodes == *r.mpOpenCLSubsetOpCodes; +} + +bool ScCalcConfig::operator!= (const ScCalcConfig& r) const +{ + return !operator==(r); +} + +OUString ScOpCodeSetToSymbolicString(const ScCalcConfig::OpCodeSet& rOpCodes) +{ + OUStringBuffer result(256); + formula::FormulaCompiler aCompiler; + formula::FormulaCompiler::OpCodeMapPtr pOpCodeMap(aCompiler.GetOpCodeMap(css::sheet::FormulaLanguage::ENGLISH)); + + for (auto i = rOpCodes->begin(); i != rOpCodes->end(); ++i) + { + if (i != rOpCodes->begin()) + result.append(';'); + result.append(pOpCodeMap->getSymbol(*i)); + } + + return result.makeStringAndClear(); +} + +ScCalcConfig::OpCodeSet ScStringToOpCodeSet(std::u16string_view rOpCodes) +{ + ScCalcConfig::OpCodeSet result = std::make_shared<o3tl::sorted_vector< OpCode >>(); + formula::FormulaCompiler aCompiler; + formula::FormulaCompiler::OpCodeMapPtr pOpCodeMap(aCompiler.GetOpCodeMap(css::sheet::FormulaLanguage::ENGLISH)); + + const formula::OpCodeHashMap& rHashMap(pOpCodeMap->getHashMap()); + + sal_Int32 fromIndex(0); + sal_Int32 semicolon; + OUString s(OUString::Concat(rOpCodes) + ";"); + + while ((semicolon = s.indexOf(';', fromIndex)) >= 0) + { + if (semicolon > fromIndex) + { + OUString element(s.copy(fromIndex, semicolon - fromIndex)); + sal_Int32 n = element.toInt32(); + if (n > 0 || (n == 0 && element == "0")) + result->insert(static_cast<OpCode>(n)); + else + { + auto opcode(rHashMap.find(element)); + if (opcode != rHashMap.end()) + result->insert(opcode->second); + else + SAL_WARN("sc.opencl", "Unrecognized OpCode " << element << " in OpCode set string"); + } + } + fromIndex = semicolon+1; + } + // HACK: Both unary and binary minus have the same string but different opcodes. + if( result->find( ocSub ) != result->end()) + result->insert( ocNegSub ); + + return result; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |