0

背景

我有一个结构:

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。
  • 将终端存储为 a 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
}
  1. 我可以使用(eventObj + offset). 如何将其转换为正确的数据类型以进行比较?

  2. 目前,AST 终端节点中的所有字段值都是std::string. 如何在分词器或解析步骤中将其转换为正确的类型?我可以将 AST 节点存储为std::pair<std::string, std::any>但仍需要std::any_cast.

如果我能以某种方式将类型信息存储在字段映射中,这两个问题都可以解决。我不确定如何。

4

1 回答 1

2

构建从字段名称到 的映射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")
  )
);

与成堆的工作。

于 2021-06-05T20:26:27.150 回答