/src/gdal/frmts/vrt/vrtexpression.h
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: Virtual GDAL Datasets |
4 | | * Purpose: Implementation of MathExpression |
5 | | * Author: Daniel Baston |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2024, ISciences LLC |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #pragma once |
14 | | |
15 | | #include "cpl_error.h" |
16 | | |
17 | | #include <string_view> |
18 | | #include <vector> |
19 | | |
20 | | namespace gdal |
21 | | { |
22 | | |
23 | | /** |
24 | | * Class to support evaluation of a mathematical expression |
25 | | */ |
26 | | class MathExpression |
27 | | { |
28 | | public: |
29 | | virtual ~MathExpression(); |
30 | | |
31 | | /** |
32 | | * Create a MathExpression using a specified dialect. |
33 | | * @param pszExpression The body of the expression, e.g. "X + 3" |
34 | | * @param pszDialect The expression dialect, e.g. "muparser" |
35 | | * @return a MathExpression using the specified dialect, or nullptr on error. |
36 | | */ |
37 | | static std::unique_ptr<MathExpression> Create(const char *pszExpression, |
38 | | const char *pszDialect); |
39 | | |
40 | | /** |
41 | | * Register a variable to be used in the expression. |
42 | | * |
43 | | * The value of the variable may be changed during repeated evaluations of |
44 | | * the expression, but its location in memory may not. |
45 | | * |
46 | | * @param osVariable The name of the variable |
47 | | * @param pdfLocation The location of the variable's value |
48 | | * |
49 | | * @since 3.11 |
50 | | */ |
51 | | virtual void RegisterVariable(std::string_view osVariable, |
52 | | double *pdfLocation) = 0; |
53 | | |
54 | | /** |
55 | | * Register a vector to be used in the expression. |
56 | | * |
57 | | * The values and size of the vector may be changed during repeated evaluations |
58 | | * of the expression, but its location in memory may not. |
59 | | * |
60 | | * @param osVariable The name of the vector |
61 | | * @param padfLocation The location of the vector |
62 | | * |
63 | | * @since 3.11 |
64 | | */ |
65 | | virtual void RegisterVector(std::string_view osVariable, |
66 | | std::vector<double> *padfLocation) = 0; |
67 | | |
68 | | /** |
69 | | * Compile the expression. |
70 | | * |
71 | | * If not called explicitly, the expression will be compiled the first time |
72 | | * the expression is evaluated. |
73 | | * |
74 | | * @return CE_None if the expression can be successfully parsed and all |
75 | | * symbols have been registered, CE_Failure otherwise. |
76 | | * |
77 | | * @since 3.11 |
78 | | */ |
79 | | virtual CPLErr Compile() = 0; |
80 | | |
81 | | /** |
82 | | * Evaluate the expression. |
83 | | * |
84 | | * @return CE_None if the expression was successfully evaluated, CE_Failure otherwise. |
85 | | * |
86 | | * @since 3.11 |
87 | | */ |
88 | | virtual CPLErr Evaluate() = 0; |
89 | | |
90 | | /** |
91 | | * Access the results from the last time the expression was evaluated. |
92 | | * |
93 | | * The returned vector may be reused on subsequent evaluations of the expression. |
94 | | * |
95 | | * @return a reference to the vector in which results are stored. |
96 | | * |
97 | | * @since 3.11 |
98 | | */ |
99 | | virtual const std::vector<double> &Results() const = 0; |
100 | | }; |
101 | | |
102 | | /*! @cond Doxygen_Suppress */ |
103 | | |
104 | | #if GDAL_VRT_ENABLE_EXPRTK |
105 | | |
106 | | /** |
107 | | * Class to support evaluation of an expression using the exprtk library. |
108 | | */ |
109 | | class ExprtkExpression : public MathExpression |
110 | | { |
111 | | public: |
112 | | explicit ExprtkExpression(std::string_view osExpression); |
113 | | |
114 | | virtual ~ExprtkExpression(); |
115 | | |
116 | | void RegisterVariable(std::string_view osVariable, |
117 | | double *pdfLocation) override; |
118 | | |
119 | | void RegisterVector(std::string_view osVariable, |
120 | | std::vector<double> *padfLocation) override; |
121 | | |
122 | | CPLErr Compile() override; |
123 | | |
124 | | CPLErr Evaluate() override; |
125 | | |
126 | | const std::vector<double> &Results() const override; |
127 | | |
128 | | private: |
129 | | class Impl; |
130 | | |
131 | | std::unique_ptr<Impl> m_pImpl; |
132 | | }; |
133 | | |
134 | | #endif |
135 | | |
136 | | #if GDAL_VRT_ENABLE_MUPARSER |
137 | | |
138 | | /** |
139 | | * Class to support evaluation of an expression using the muparser library. |
140 | | */ |
141 | | class MuParserExpression : public MathExpression |
142 | | { |
143 | | public: |
144 | | explicit MuParserExpression(std::string_view osExpression); |
145 | | |
146 | | virtual ~MuParserExpression(); |
147 | | |
148 | | void RegisterVariable(std::string_view osVariable, |
149 | | double *pdfLocation) override; |
150 | | |
151 | | void RegisterVector(std::string_view osVariable, |
152 | | std::vector<double> *padfLocation) override; |
153 | | |
154 | | CPLErr Compile() override; |
155 | | |
156 | | CPLErr Evaluate() override; |
157 | | |
158 | | const std::vector<double> &Results() const override; |
159 | | |
160 | | private: |
161 | | class Impl; |
162 | | |
163 | | std::unique_ptr<Impl> m_pImpl; |
164 | | }; |
165 | | |
166 | | #endif |
167 | | |
168 | | inline std::unique_ptr<MathExpression> |
169 | | MathExpression::Create([[maybe_unused]] const char *pszExpression, |
170 | | const char *pszDialect) |
171 | 0 | { |
172 | 0 | if (EQUAL(pszDialect, "exprtk")) |
173 | 0 | { |
174 | | #if GDAL_VRT_ENABLE_EXPRTK |
175 | | return std::make_unique<gdal::ExprtkExpression>(pszExpression); |
176 | | #else |
177 | 0 | CPLError(CE_Failure, CPLE_IllegalArg, |
178 | 0 | "Dialect '%s' is not supported by this GDAL build. A GDAL " |
179 | 0 | "build with ExprTk is needed.", |
180 | 0 | pszDialect); |
181 | 0 | #endif |
182 | 0 | } |
183 | 0 | else if (EQUAL(pszDialect, "muparser")) |
184 | 0 | { |
185 | | #if GDAL_VRT_ENABLE_MUPARSER |
186 | | return std::make_unique<gdal::MuParserExpression>(pszExpression); |
187 | | #else |
188 | 0 | CPLError(CE_Failure, CPLE_IllegalArg, |
189 | 0 | "Dialect '%s' is not supported by this GDAL build. A GDAL " |
190 | 0 | "build with muparser is needed.", |
191 | 0 | pszDialect); |
192 | 0 | #endif |
193 | 0 | } |
194 | 0 | else |
195 | 0 | { |
196 | 0 | CPLError(CE_Failure, CPLE_IllegalArg, "Unknown expression dialect: %s", |
197 | 0 | pszDialect); |
198 | 0 | } |
199 | 0 | return nullptr; |
200 | 0 | } |
201 | | |
202 | | /*! @endcond */ |
203 | | |
204 | | } // namespace gdal |