Line data Source code
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 78 : virtual ~MathExpression() = default; 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 78 : MathExpression::Create([[maybe_unused]] const char *pszExpression, 170 : const char *pszDialect) 171 : { 172 78 : if (EQUAL(pszDialect, "exprtk")) 173 : { 174 : #if GDAL_VRT_ENABLE_EXPRTK 175 : return std::make_unique<gdal::ExprtkExpression>(pszExpression); 176 : #else 177 0 : CPLError(CE_Failure, CPLE_IllegalArg, 178 : "Dialect '%s' is not supported by this GDAL build. A GDAL " 179 : "build with ExprTk is be needed.", 180 : pszDialect); 181 : #endif 182 : } 183 78 : else if (EQUAL(pszDialect, "muparser")) 184 : { 185 : #if GDAL_VRT_ENABLE_MUPARSER 186 78 : return std::make_unique<gdal::MuParserExpression>(pszExpression); 187 : #else 188 : CPLError(CE_Failure, CPLE_IllegalArg, 189 : "Dialect '%s' is not supported by this GDAL build. A GDAL " 190 : "build with muparser is be needed.", 191 : pszDialect); 192 : #endif 193 : } 194 : else 195 : { 196 0 : CPLError(CE_Failure, CPLE_IllegalArg, "Unknown expression dialect: %s", 197 : pszDialect); 198 : } 199 0 : return nullptr; 200 : } 201 : 202 : /*! @endcond */ 203 : 204 : } // namespace gdal