背景
我有一个结构:
struct event {
uint16_t id;
uint8_t type;
std::string name;
// many more fields (either string or integer types)
};
布尔表达式(存储在字符串中(:
name = "xyz" and (id = 10 or type = 5)
我有一个事件对象(数千(std::vector<event>
的向量,想检查它们是否满足布尔表达式。
到目前为止我已经实施的事情
- 我实现了一个标记化器和一个递归下降解析器,将布尔表达式转换为AST
- 将终端存储为
std::pair<std::string, std::string>
,其中第一个值是结构字段名称,第二个值是值。例如,std::pair<"name", "acbd">
- 我穿过树,每当它看到一个终端树节点时:
bool match(const event& ev, const ast::node& node) {
if (node.first == "name") {
return (ev.name == node.second);
} else if (node.first == "id") {
return (ev.id == std::stoi(node.second));
} else if (node.first == "type") {
return (ev.type == std::stoi(node.second));
} // more else if blocks for each member of event struct
...
}
问题
该结构包含10个成员。我想避免不必要的比较。在最坏的情况下,AST终端节点(例如,pair<"type", "5000">
(可能导致10个比较。
我试着构建这个查找图:
std::map<std::string, std::size_t> fields;
fields["name"] = offsetof(event, name);
fields["id"] = offsetof(event, id);
fields["type"] = offsetof(event, type);
使用这个映射,我可以将match()
简化为:
bool match(const event& ev, const ast::node& node) {
const auto offset = fields[node.first];
return ((ev + offset) == node.second); // DOESN'T WORK
}
我可以使用
(eventObj + offset)
访问偏移量处的结构成员。如何将其转换为正确的数据类型以便进行比较?目前,AST终端节点中的所有字段值都是
std::string
。如何在标记化或解析步骤中将其转换为正确的类型?我可以将AST节点存储为std::pair<std::string, std::any>
,但仍然需要std::any_cast
的类型信息。
如果我能以某种方式将类型信息存储在字段映射中,这两个问题都可以解决。我不知道怎么做。
构建从字段名称到std::function<std::function<bool(event const&)>(std::string const&)>
的映射,如:
lookup["name"]=[](auto str){
return [val=std::move(str)](auto& e){
return e.name==val;
};
};
现在您可以将您的配对转换为测试函数。
现在你的
name = "xyz" and (id = 10 or type = 5)
变为
tree(
lookup["name"]("xyz"),
std::logical_and<>{},
tree(
lookup["id"]("17"),
std::logical_or<>{},
lookup["type"]("5")
)
);
成堆的工作。