I have a struct:
struct event {
uint16_t id;
uint8_t type;
std::string name;
// many more fields (either string or integer types)
};
A boolean expression(stored in a string):
name = "xyz" and (id = 10 or type = 5)
I have a vector of event objects(thousands) std::vector<event>
and want to check if they satisfy the boolean expression.
std::pair<std::string, std::string>
, where the first value is the struct field name and second is the value. For example, 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
...
}
The struct contains 10 members. I want to avoid the unnecessary comparisons. In the worst case, an AST terminal node (for example, pair<"type", "5000">
) might result in 10 comparisons.
I tried constructing this lookup map:
std::map<std::string, std::size_t> fields;
fields["name"] = offsetof(event, name);
fields["id"] = offsetof(event, id);
fields["type"] = offsetof(event, type);
Using this map, I can simplify match()
to:
bool match(const event& ev, const ast::node& node) {
const auto offset = fields[node.first];
return ((ev + offset) == node.second); // DOESN'T WORK
}
I can access the struct member at an offset using (eventObj + offset)
. How do I convert it to the correct data type for the comparison to work?
For now, all the field values in AST terminal nodes are std::string
. How do I convert it to the correct type during tokenizer or parsing step? I can store the AST node as std::pair<std::string, std::any>
but still need the type information for std::any_cast
.
Both of these can be solved if I can somehow store the type information in the fields map. I am not sure how.
Build a map from field name to std::function<std::function<bool(event const&)>(std::string const&)>
, like:
lookup["name"]=[](auto str){
return [val=std::move(str)](auto& e){
return e.name==val;
};
};
now you can convert your pairs into test functions.
Now your
name = "xyz" and (id = 10 or type = 5)
becomes
tree(
lookup["name"]("xyz"),
std::logical_and<>{},
tree(
lookup["id"]("17"),
std::logical_or<>{},
lookup["type"]("5")
)
);
with piles of work.