バックグラウンド
私は構造体を持っています:
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>
ます。最初の値は構造体フィールド名で、2 番目の値は値です。例えば、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
。
これらは両方とも、フィールド マップに何らかの形で型情報を格納できれば解決できます。方法がわかりません。