feat: Add generator for chain and search. - #275
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces generator-based iteration for the core inference engines (search_t and chain_t), and wires that iteration model through the Python bindings so engines can be consumed via for ... in ... while keeping the existing callback-style execute() API.
Changes:
- Add
iterator()generators tods::search_tandds::chain_t, and re-implementexecute()on top of them. - Expose generator iteration to Python via a new bound
Iteratorhelper plus__iter__in the Python wrapper classes. - Bump the C++ language standard to C++23 and update C++ chain tests’ expected counts.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_chain.cc | Updates expected chain_t::execute() counts to reflect step-wise yielding behavior. |
| src/search.cc | Adds search_t::iterator() generator and refactors execute() to iterate it. |
| src/chain.cc | Adds chain_t::iterator() generator (recursive yielding) and refactors execute() accordingly. |
| include/ds/search.hh | Declares search_t::iterator() and includes <generator>. |
| include/ds/chain.hh | Declares chain_t::iterator() and includes <generator>. |
| apyds/search_t.py | Adds Search.__iter__() that consumes the bound iterator and yields cloned Rules. |
| apyds/chain_t.py | Adds Chain.__iter__() that consumes the bound iterator and yields cloned Rules. |
| apyds/ds.cc | Adds a C++ Iterator wrapper around std::generator and binds iter() for Search/Chain. |
| CMakeLists.txt | Raises the project C++ standard requirement to C++23. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
Comment on lines
+70
to
+72
| /// @brief 执行一轮搜索操作,以生成器方式迭代所有匹配的规则。 | ||
| /// @return 生成器,每次迭代返回一个匹配的规则指针。 | ||
| std::generator<rule_t*> iterator(); |
| target_sources(${PROJECT_NAME} PRIVATE ${SOURCES}) | ||
| target_include_directories(${PROJECT_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>) | ||
| target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20) | ||
| target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23) |
Comment on lines
197
to
+214
| @@ -177,4 +207,12 @@ PYBIND11_MODULE(_ds, m, py::mod_gil_not_used()) { | |||
| chain_t.def("reset", &ds::chain_t::reset); | |||
| chain_t.def("add", &ds::chain_t::add); | |||
| chain_t.def("execute", &ds::chain_t::execute); | |||
| chain_t.def( | |||
| "iter", | |||
| [](ds::chain_t& self) { return Iterator(std::move(self.iterator())); }, | |||
| py::return_value_policy::reference_internal | |||
| ); | |||
| length_t execute(const std::function<bool(rule_t*)>& callback); | ||
|
|
||
| /// @brief 执行一轮搜索操作,以生成器方式迭代所有匹配的规则。 | ||
| /// @return 生成器,每次迭代返回一个匹配的规则指针。 |
Comment on lines
+77
to
+81
| ++current_cycle; | ||
| for (auto it = temp_facts.begin(); it != temp_facts.end();) { | ||
| auto node = temp_facts.extract(it++); | ||
| facts.emplace(std::move(node.value()), current_cycle); | ||
| } |
Comment on lines
+126
to
+128
| co_yield std::ranges::elements_of( | ||
| chain_recursive(chain_recursive, rule.get(), buffer.get(), reinterpret_cast<std::byte*>(buffer.get()) + buffer_size) | ||
| ); |
Comment on lines
+68
to
+84
| // RAII guard,确保无论是否提前退出,清理代码都会执行 | ||
| struct guard_t { | ||
| std::function<void()> cleanup; | ||
| ~guard_t() { | ||
| cleanup(); | ||
| } | ||
| } guard{[&]() { | ||
| ++current_cycle; | ||
| for (auto it = temp_rules.begin(); it != temp_rules.end();) { | ||
| auto node = temp_rules.extract(it++); | ||
| rules.emplace(std::move(node.value()), current_cycle); | ||
| } | ||
| for (auto it = temp_facts.begin(); it != temp_facts.end();) { | ||
| auto node = temp_facts.extract(it++); | ||
| facts.emplace(std::move(node.value()), current_cycle); | ||
| } | ||
| }}; |
Comment on lines
+70
to
+82
| // RAII guard,确保无论是否提前退出,清理代码都会执行 | ||
| struct guard_t { | ||
| std::function<void()> cleanup; | ||
| ~guard_t() { | ||
| cleanup(); | ||
| } | ||
| } guard{[&]() { | ||
| ++current_cycle; | ||
| for (auto it = temp_facts.begin(); it != temp_facts.end();) { | ||
| auto node = temp_facts.extract(it++); | ||
| facts.emplace(std::move(node.value()), current_cycle); | ||
| } | ||
| }}; |
Comment on lines
+13
to
+25
| ds::rule_t* next() { | ||
| if (initialized) { | ||
| ++*iterator; | ||
| } else { | ||
| iterator = std::make_unique<iterator_t>(generator.begin()); | ||
| initialized = true; | ||
| } | ||
| if (*iterator == generator.end()) { | ||
| return nullptr; | ||
| } | ||
| ds::rule_t* result = **iterator; | ||
| return result; | ||
| } |
Comment on lines
+135
to
143
| length_t chain_t::execute(const std::function<bool(rule_t*)>& callback) { | ||
| length_t count = 0; | ||
| for (auto* rule : iterator()) { | ||
| ++count; | ||
| if (callback(rule)) { | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| if (!break_all) { | ||
| done_cycle = current_cycle; | ||
| } | ||
| ++current_cycle; | ||
| length_t count = temp_facts.size(); | ||
| for (auto it = temp_facts.begin(); it != temp_facts.end();) { | ||
| auto node = temp_facts.extract(it++); | ||
| facts.emplace(std::move(node.value()), current_cycle); | ||
| } | ||
| return count; |
hzhangxyz
force-pushed
the
dev/generator
branch
10 times, most recently
from
March 15, 2026 04:55
988eb7c to
d3b7f77
Compare
hzhangxyz
force-pushed
the
dev/generator
branch
from
March 15, 2026 05:00
d3b7f77 to
eb5d969
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.