Coverage Report

Created: 2025-06-13 06:18

/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