Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Virtual GDAL Datasets
4 : * Purpose: Implementation of GDALExpressionEvaluator.
5 : * Author: Daniel Baston
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2024, ISciences LLC
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "vrtexpression.h"
14 : #include "cpl_string.h"
15 :
16 : #include <map>
17 : #include <muParser.h>
18 :
19 : namespace gdal
20 : {
21 :
22 : /*! @cond Doxygen_Suppress */
23 : class MuParserExpression::Impl
24 : {
25 : public:
26 19 : explicit Impl(std::string_view osExpression)
27 38 : : m_osExpression(std::string(osExpression)), m_oVectors{}, m_oParser{},
28 57 : m_adfResults{1}, m_bIsCompiled{false}
29 : {
30 19 : }
31 :
32 89 : void Register(std::string_view osVariable, double *pdfValue)
33 : {
34 89 : m_oParser.DefineVar(std::string(osVariable), pdfValue);
35 89 : }
36 :
37 27 : CPLErr Compile()
38 : {
39 : try
40 : {
41 54 : CPLString tmpExpression(m_osExpression);
42 :
43 40 : for (const auto &[osVec, osElems] : m_oVectors)
44 : {
45 13 : tmpExpression.replaceAll(osVec, osElems);
46 : }
47 :
48 27 : m_oParser.SetExpr(tmpExpression);
49 : }
50 0 : catch (const mu::Parser::exception_type &e)
51 : {
52 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.GetMsg().c_str());
53 0 : return CE_Failure;
54 : }
55 0 : catch (const std::exception &e)
56 : {
57 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
58 0 : return CE_Failure;
59 : }
60 :
61 27 : return CE_None;
62 : }
63 :
64 57 : CPLErr Evaluate()
65 : {
66 57 : if (!m_bIsCompiled)
67 : {
68 19 : if (auto eErr = Compile(); eErr != CE_None)
69 : {
70 0 : return eErr;
71 : }
72 :
73 19 : m_bIsCompiled = true;
74 : }
75 :
76 : try
77 : {
78 : int nResults;
79 57 : const double *dfResults = m_oParser.Eval(nResults);
80 56 : m_adfResults.resize(nResults);
81 56 : std::copy(dfResults, dfResults + nResults, m_adfResults.begin());
82 : }
83 1 : catch (const mu::Parser::exception_type &e)
84 : {
85 1 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.GetMsg().c_str());
86 1 : return CE_Failure;
87 : }
88 0 : catch (const std::exception &e)
89 : {
90 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
91 0 : return CE_Failure;
92 : }
93 :
94 56 : return CE_None;
95 : }
96 :
97 : CPLString m_osExpression;
98 : std::map<CPLString, CPLString> m_oVectors;
99 : mu::Parser m_oParser;
100 : std::vector<double> m_adfResults;
101 : bool m_bIsCompiled;
102 : };
103 :
104 19 : MuParserExpression::MuParserExpression(std::string_view osExpression)
105 19 : : m_pImpl{std::make_unique<Impl>(osExpression)}
106 :
107 : {
108 19 : }
109 :
110 38 : MuParserExpression::~MuParserExpression()
111 : {
112 38 : }
113 :
114 8 : CPLErr MuParserExpression::Compile()
115 : {
116 8 : return m_pImpl->Compile();
117 : }
118 :
119 89 : void MuParserExpression::RegisterVariable(std::string_view osVariable,
120 : double *pdfValue)
121 : {
122 89 : m_pImpl->Register(osVariable, pdfValue);
123 89 : }
124 :
125 7 : void MuParserExpression::RegisterVector(std::string_view osVariable,
126 : std::vector<double> *padfValues)
127 : {
128 : // muparser does not support vector variables, so we simulate them
129 : // by creating a scalar variable for each element, and then replacing
130 : // the name of the vector by a list of its elements before compiling
131 : // the expression.
132 14 : CPLString osElementVarName;
133 14 : CPLString osElementsList;
134 7 : std::string osVectorVarName(osVariable);
135 :
136 : int nElementVarNameLength = static_cast<int>(
137 7 : 4 + osVectorVarName.size() + std::log10(padfValues->size()));
138 7 : osElementsList.reserve(padfValues->size() *
139 7 : (1 + nElementVarNameLength)); // +1 for commas
140 :
141 36 : for (std::size_t i = 0; i < padfValues->size(); i++)
142 : {
143 : osElementVarName.Printf("__%s_%d", osVectorVarName.c_str(),
144 29 : static_cast<int>(i));
145 29 : RegisterVariable(osElementVarName, padfValues->data() + i);
146 :
147 29 : if (i > 0)
148 : {
149 22 : osElementsList += ",";
150 : }
151 29 : osElementsList += osElementVarName;
152 : }
153 :
154 7 : m_pImpl->m_oVectors[std::string(osVariable)] = osElementsList;
155 7 : }
156 :
157 57 : CPLErr MuParserExpression::Evaluate()
158 : {
159 57 : return m_pImpl->Evaluate();
160 : }
161 :
162 71 : const std::vector<double> &MuParserExpression::Results() const
163 : {
164 71 : return m_pImpl->m_adfResults;
165 : }
166 :
167 : /*! @endcond Doxygen_Suppress */
168 :
169 : } // namespace gdal
|