2026-05-15 12:25:30 +08:00
|
|
|
|
// eqpalg/utility/expression_engine.cpp
|
|
|
|
|
|
#include <eqpalg/utility/expression_engine.h>
|
|
|
|
|
|
#include <glob/SingletonTemplate.h>
|
|
|
|
|
|
#include <eqpalg/gb_item_memory.h>
|
|
|
|
|
|
#include <mix_cc/type/mix_time.h>
|
|
|
|
|
|
#include <log4cplus/LOG.h>
|
|
|
|
|
|
|
|
|
|
|
|
ExpressionEngine::ExpressionEngine(std::map<std::string, double>& mm_vars,
|
|
|
|
|
|
std::vector<std::string>& m_tags)
|
|
|
|
|
|
: mm_vars_(mm_vars), m_tags_(m_tags) {}
|
|
|
|
|
|
|
|
|
|
|
|
// 惰性初始化 VarsCache(首次变量刷新时调用)
|
|
|
|
|
|
static void ensureVarCache(VarsCache& vc, size_t tag_count) {
|
|
|
|
|
|
if (vc.tag_num == 0 && tag_count > 0) {
|
|
|
|
|
|
vc.init(tag_count, 6);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int ExpressionEngine::registerExpression(const std::string& name,
|
|
|
|
|
|
const std::string& raw_exp_str) {
|
|
|
|
|
|
if (exps_.count(name)) return 0; // 已注册,幂等
|
|
|
|
|
|
|
|
|
|
|
|
auto& entry = exps_[name];
|
|
|
|
|
|
entry.raw_str = raw_exp_str;
|
|
|
|
|
|
|
|
|
|
|
|
// 通过 FunVars 替换状态函数(KeepC/KeepT/RiseEdge/Detect)为 funN 变量
|
|
|
|
|
|
auto [ok, processed] = fun_vars_.add_exp_str(raw_exp_str, &mm_vars_);
|
|
|
|
|
|
if (!ok) return -1;
|
|
|
|
|
|
entry.processed_str = processed;
|
|
|
|
|
|
|
|
|
|
|
|
// 编译表达式
|
|
|
|
|
|
try {
|
|
|
|
|
|
entry.ptr = std::make_unique<MExp>(processed, &mm_vars_);
|
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 从表达式中提取 hold(n,T) 模式
|
|
|
|
|
|
initHoldExpStr(processed);
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int ExpressionEngine::registerRawExpression(const std::string& name,
|
|
|
|
|
|
const std::string& raw_exp_str) {
|
|
|
|
|
|
if (exps_.count(name)) return 0;
|
|
|
|
|
|
|
|
|
|
|
|
auto& entry = exps_[name];
|
|
|
|
|
|
entry.raw_str = raw_exp_str;
|
|
|
|
|
|
entry.processed_str = raw_exp_str;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
entry.ptr = std::make_unique<MExp>(raw_exp_str, &mm_vars_);
|
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double ExpressionEngine::evaluate(const std::string& name) {
|
|
|
|
|
|
auto it = exps_.find(name);
|
|
|
|
|
|
if (it == exps_.end()) return 0.0;
|
|
|
|
|
|
return it->second.ptr->evaluate();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool ExpressionEngine::evaluateBool(const std::string& name) {
|
|
|
|
|
|
return static_cast<bool>(evaluate(name));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int ExpressionEngine::initHoldExpStr(const std::string& exp_str) {
|
2026-05-15 12:30:11 +08:00
|
|
|
|
auto hold_sub_strs = HoldTime::find_substr(exp_str, "_HE");
|
|
|
|
|
|
for (const auto& sub_str : hold_sub_strs) {
|
|
|
|
|
|
bool flag;
|
|
|
|
|
|
double timeM;
|
|
|
|
|
|
std::string tagi;
|
|
|
|
|
|
std::string var_name;
|
|
|
|
|
|
std::tie(flag, timeM, tagi, var_name) = HoldTime::find_hold(sub_str);
|
|
|
|
|
|
if (flag) {
|
|
|
|
|
|
if (hold_times_.find(var_name) == hold_times_.end()) {
|
|
|
|
|
|
hold_times_.emplace(std::make_pair(
|
|
|
|
|
|
var_name, std::make_unique<HoldTime>(timeM, tagi, var_name)));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
refreshHoldVars();
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ========== FunVars 控制 ==========
|
|
|
|
|
|
|
|
|
|
|
|
void ExpressionEngine::autoResetFunVars() {
|
|
|
|
|
|
if (fun_vars_need_reset_) {
|
|
|
|
|
|
fun_vars_.refresh_fun_vars(true, &mm_vars_);
|
|
|
|
|
|
fun_vars_need_reset_ = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ExpressionEngine::markFunVarsNeedReset() {
|
|
|
|
|
|
fun_vars_need_reset_ = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ExpressionEngine::forceResetFunVars() {
|
|
|
|
|
|
fun_vars_.refresh_fun_vars(true, &mm_vars_);
|
|
|
|
|
|
fun_vars_need_reset_ = false;
|
2026-05-15 12:25:30 +08:00
|
|
|
|
}
|
2026-05-15 12:27:58 +08:00
|
|
|
|
|
|
|
|
|
|
void ExpressionEngine::refreshFromMemory(
|
|
|
|
|
|
const TimePoint& now_time,
|
|
|
|
|
|
mix_cc::time_range_t& query_time_range) {
|
|
|
|
|
|
|
|
|
|
|
|
ensureVarCache(var_cache_, m_tags_.size());
|
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < m_tags_.size(); i++) {
|
|
|
|
|
|
double current =
|
|
|
|
|
|
SingletonTemplate<GlobaltemSharedMemory>::GetInstance()[m_tags_[i]];
|
|
|
|
|
|
|
|
|
|
|
|
// pN = 旧 tagN
|
|
|
|
|
|
mm_vars_[var_cache_.p_keys[i]] = mm_vars_[var_cache_.tag_keys[i]];
|
|
|
|
|
|
// tagN = 当前值
|
|
|
|
|
|
mm_vars_[var_cache_.tag_keys[i]] = current;
|
|
|
|
|
|
|
|
|
|
|
|
// pvN 历史移位
|
|
|
|
|
|
for (size_t j = PV_NUM - 1; j > 0; j--) {
|
|
|
|
|
|
mm_vars_[var_cache_.pv_keys[i][j]] =
|
|
|
|
|
|
mm_vars_[var_cache_.pv_keys[i][j - 1]];
|
|
|
|
|
|
}
|
|
|
|
|
|
mm_vars_[var_cache_.pv_keys[i][0]] = current;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
mm_vars_["now"] = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
|
|
|
|
now_time.time_since_epoch())
|
|
|
|
|
|
.count();
|
|
|
|
|
|
|
|
|
|
|
|
fun_vars_.refresh_fun_vars(false, &mm_vars_);
|
|
|
|
|
|
query_time_range.set_right(now_time);
|
|
|
|
|
|
refreshHoldVars();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ExpressionEngine::refreshFromIhdRow(
|
|
|
|
|
|
int row,
|
|
|
|
|
|
const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>& queried_data,
|
|
|
|
|
|
const std::vector<TimePoint>& queried_time,
|
|
|
|
|
|
TimePoint& now_time,
|
|
|
|
|
|
mix_cc::time_range_t& query_time_range) {
|
|
|
|
|
|
|
|
|
|
|
|
if (queried_data.rows() == 0 || queried_data.cols() == 0) return;
|
|
|
|
|
|
if (row < 0 || row >= queried_data.rows()) return;
|
|
|
|
|
|
if (static_cast<int>(m_tags_.size()) > queried_data.cols()) return;
|
|
|
|
|
|
|
|
|
|
|
|
ensureVarCache(var_cache_, m_tags_.size());
|
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < m_tags_.size(); i++) {
|
|
|
|
|
|
// pN = 旧 tagN
|
|
|
|
|
|
mm_vars_[var_cache_.p_keys[i]] = mm_vars_[var_cache_.tag_keys[i]];
|
|
|
|
|
|
// tagN = 当前行数据
|
|
|
|
|
|
mm_vars_[var_cache_.tag_keys[i]] = queried_data(row, i);
|
|
|
|
|
|
|
|
|
|
|
|
// pvN 历史移位
|
|
|
|
|
|
for (size_t j = PV_NUM - 1; j > 0; j--) {
|
|
|
|
|
|
mm_vars_[var_cache_.pv_keys[i][j]] =
|
|
|
|
|
|
mm_vars_[var_cache_.pv_keys[i][j - 1]];
|
|
|
|
|
|
}
|
|
|
|
|
|
mm_vars_[var_cache_.pv_keys[i][0]] =
|
|
|
|
|
|
mm_vars_[var_cache_.tag_keys[i]];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
mm_vars_["now"] =
|
|
|
|
|
|
mix_cc::mix_time_t(queried_time[row]).to_milliseconds();
|
|
|
|
|
|
|
|
|
|
|
|
now_time = queried_time[row];
|
|
|
|
|
|
query_time_range.set_right(queried_time[row]);
|
|
|
|
|
|
|
|
|
|
|
|
fun_vars_.refresh_fun_vars(false, &mm_vars_);
|
|
|
|
|
|
refreshHoldVars();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ExpressionEngine::refreshHoldVars() {
|
2026-05-15 12:30:11 +08:00
|
|
|
|
for (auto& kv : hold_times_) {
|
|
|
|
|
|
mm_vars_[kv.first] =
|
|
|
|
|
|
static_cast<double>(kv.second->update_value(mm_vars_[kv.second->tagi]));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ========== 调试 ==========
|
|
|
|
|
|
|
|
|
|
|
|
void ExpressionEngine::printVars(const std::string& exp_str) {
|
|
|
|
|
|
// Debug method — prints all variables to LOG
|
2026-05-15 12:27:58 +08:00
|
|
|
|
}
|