VLink  2.0.0
A high-performance communication middleware
exprtk_api.h
浏览该文件的文档.
1 /*
2  * Copyright (C) 2026 by Thun Lu. All rights reserved.
3  * Author: Thun Lu <thun.lu@zohomail.cn>
4  * Repo: https://github.com/thun-res/vlink
5  * _ __ __ _ __
6  * | | / / / / (_) ____ / /__
7  * | | / / / / / / / __ \ / //_/
8  * | |/ / / /___ / / / / / / / ,<
9  * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 
24 /**
25  * @file exprtk_api.h
26  * @brief Thin, ABI-stable facade over the ExprTk mathematical expression engine.
27  *
28  * @details
29  * ExprTk (@c thirdparty/exprtk/include/exprtk/exprtk.hpp) is a header-only template
30  * library of roughly 46k lines. Every translation unit that includes it instantiates
31  * the full parser/optimizer/evaluator for @c double, which previously caused the same
32  * engine to be compiled into nine separate object files (CLI dump, analyzer, perception,
33  * the three webviz converters, and so on). The result was severe object-code bloat and
34  * long compile times.
35  *
36  * This header exposes the small subset of ExprTk that VLink actually uses behind two
37  * opaque PIMPL classes. The real ExprTk templates are compiled exactly once, inside the
38  * @c vlink::exprtk_api shared library; consumers include only this header and link
39  * @c vlink::exprtk_api, so ExprTk never enters their translation units again.
40  *
41  * @par Usage model
42  * The classes mirror the ExprTk compile-then-evaluate workflow one-to-one:
43  * 1. Build a @ref vlink::ExprtkSymbolTable, registering constants and variables.
44  * Variables are bound @b by-reference, so the caller-owned storage must outlive the
45  * symbol table and must not be relocated (e.g. reserve a @c std::vector up front).
46  * 2. Create a @ref vlink::ExprtkExpression and register the symbol table into it.
47  * 3. Call @ref vlink::ExprtkExpression::compile once.
48  * 4. Update the bound variable storage and call @ref vlink::ExprtkExpression::value
49  * as many times as needed; each call re-reads the current variable values.
50  *
51  * @code
52  * // Evaluate "a + b * 2" with a == 3, b == 4 -> 11
53  * double a = 3.0;
54  * double b = 4.0;
55  *
56  * vlink::ExprtkSymbolTable symbols;
57  * symbols.add_constants(); // pi, epsilon, inf, ...
58  * symbols.add_variable("a", a); // bound by reference
59  * symbols.add_variable("b", b); // bound by reference
60  *
61  * vlink::ExprtkExpression expr;
62  * expr.register_symbol_table(symbols);
63  *
64  * if (expr.compile("a + b * 2")) {
65  * double result = expr.value(); // 11.0
66  * b = 10.0;
67  * result = expr.value(); // 23.0, no recompilation needed
68  * }
69  * @endcode
70  *
71  * @note The value type is fixed to @c double, which matches every existing VLink call
72  * site. Only a single @ref vlink::ExprtkSymbolTable may be registered into a given
73  * @ref vlink::ExprtkExpression, but one symbol table may be registered into many
74  * expressions to share variable storage.
75  */
76 
77 #pragma once
78 
79 #undef VLINK_EXPRTK_API_EXPORT
80 #ifdef VLINK_EXPRTK_API_LIBRARY_STATIC
81 #define VLINK_EXPRTK_API_EXPORT
82 #elif defined(_WIN32) || defined(__CYGWIN__)
83 #ifdef VLINK_EXPRTK_API_LIBRARY
84 #define VLINK_EXPRTK_API_EXPORT __declspec(dllexport)
85 #else
86 #define VLINK_EXPRTK_API_EXPORT __declspec(dllimport)
87 #endif
88 #else
89 #define VLINK_EXPRTK_API_EXPORT __attribute__((visibility("default")))
90 #endif
91 
92 #include <memory>
93 #include <string>
94 
95 #include "../base/macros.h"
96 
97 namespace vlink {
98 
99 class ExprtkExpression;
100 
101 /**
102  * @class ExprtkSymbolTable
103  * @brief Opaque wrapper around @c exprtk::symbol_table<double>.
104  *
105  * @details
106  * Holds the named constants and variables an expression may reference. Variables are
107  * registered by reference: the symbol table stores the address of the supplied
108  * @c double, so the referenced storage must stay alive and at a fixed address for the
109  * whole lifetime of the symbol table and any expression compiled against it.
110  *
111  * The class is move-only; the underlying ExprTk symbol table lives on the heap behind a
112  * @c std::unique_ptr, so moving the wrapper never relocates it.
113  */
115  public:
116  /**
117  * @brief Construct an empty symbol table.
118  */
120 
121  /**
122  * @brief Destroy the symbol table and release the underlying ExprTk state.
123  */
125 
126  /**
127  * @brief Move constructor; transfers ownership of the underlying ExprTk state.
128  */
130 
131  /**
132  * @brief Move assignment; transfers ownership of the underlying ExprTk state.
133  */
134  ExprtkSymbolTable& operator=(ExprtkSymbolTable&&) noexcept;
135 
136  /**
137  * @brief Register the standard ExprTk constants (@c pi, @c epsilon, @c inf, ...).
138  *
139  * @details Mirrors @c exprtk::symbol_table<double>::add_constants().
140  */
141  void add_constants();
142 
143  /**
144  * @brief Register a named variable bound by reference.
145  *
146  * @param name Identifier used inside expression strings.
147  * @param value Reference to caller-owned storage; its address is captured, so it must
148  * outlive this table and must not be relocated after registration.
149  * @return @c true if the variable was added, @c false on a duplicate or invalid name.
150  */
151  bool add_variable(const std::string& name, double& value);
152 
153  private:
154  friend class ExprtkExpression;
155 
156  struct Impl;
157  std::unique_ptr<Impl> impl_;
158 
160 };
161 
162 /**
163  * @class ExprtkExpression
164  * @brief Opaque wrapper around @c exprtk::expression<double> plus its compiler.
165  *
166  * @details
167  * Bundles a compiled expression and the one-shot parser used to build it. Register a
168  * @ref ExprtkSymbolTable, call @ref compile once, then call @ref value repeatedly; the
169  * referenced symbol table must outlive the expression.
170  *
171  * The class is move-only; the underlying ExprTk expression lives on the heap behind a
172  * @c std::unique_ptr, so moving the wrapper never relocates it.
173  */
175  public:
176  /**
177  * @brief Construct an empty, uncompiled expression.
178  */
180 
181  /**
182  * @brief Destroy the expression and release the underlying ExprTk state.
183  */
185 
186  /**
187  * @brief Move constructor; transfers ownership of the underlying ExprTk state.
188  */
190 
191  /**
192  * @brief Move assignment; transfers ownership of the underlying ExprTk state.
193  */
194  ExprtkExpression& operator=(ExprtkExpression&&) noexcept;
195 
196  /**
197  * @brief Bind a symbol table to this expression.
198  *
199  * @param symbol_table The table whose constants and variables the expression resolves
200  * against. It must outlive this expression; only its address is
201  * referenced. Call before @ref compile.
202  */
203  void register_symbol_table(ExprtkSymbolTable& symbol_table);
204 
205  /**
206  * @brief Compile an expression string against the registered symbol table.
207  *
208  * @param expression The ExprTk expression source to compile.
209  * @return @c true on success; @c false if the string failed to parse, in which case
210  * @ref value must not be called.
211  *
212  * @note Intended to be called once per object. A registered symbol table is required.
213  */
214  bool compile(const std::string& expression);
215 
216  /**
217  * @brief Evaluate the compiled expression using the current variable values.
218  *
219  * @return The evaluated result. Undefined if @ref compile has not returned @c true.
220  */
221  double value() const;
222 
223  private:
224  struct Impl;
225  std::unique_ptr<Impl> impl_;
226 
228 };
229 
230 } // namespace vlink
#define VLINK_EXPRTK_API_EXPORT
Definition: exprtk_api.h:89
#define VLINK_DISALLOW_COPY_AND_ASSIGN(classname)
Deletes the copy constructor and copy-assignment operator of classname.
Definition: macros.h:174