结构成员的布尔表达式求值器
Boolean expression evaluator on struct members
背景
我有一个结构:
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")
)
);
有成堆的工作。
背景
我有一个结构:
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")
)
);
有成堆的工作。