c++ - 将一组集合转换为单个范围
问题描述
我在创建某种类型的范围时遇到了麻烦。
在 LLVM(编译器基础设施)中,a Module
(可能是翻译单元的代码)的组织方式如下:
llvm::Module m{...}; // A module could be a single translation unit.
for(const auto &func : m){
for(const auto &basic_block : func){
for(const auto &inst : basic_block){
}
}
}
在我正在处理的代码中,拥有一个创建包含在模块或函数中的一系列指令的函数非常方便。例如:
llvm::Module m;
llvm::Function f;
InstSet temp;
temp.insert(instructions(m));
temp.insert(instructions(f));
但是,我无法优雅地实现范围。我尝试过的事情:
- 实现自定义迭代器。事实证明它真的很乱,即使我想做的事情应该很简单......
- 使用协程实现。虽然效果稍微好一些,但性能却令人无法接受(调查后慢了大约 10 倍)。
我的问题是,有没有我遗漏的优雅解决方案?如果没有,我想知道为什么要理解我试图以错误方式解决的问题。
编辑(我在下面添加了自己的实现):
这是使用协程的实现(已完成):
struct InstructionsGenerator {
struct promise_type;
using Handle = coroutine_handle<promise_type>;
struct promise_type {
const Instruction *i;
auto get_return_object() -> InstructionsGenerator { return {Handle::from_promise(*this)}; }
auto yield_value(const Instruction &y) -> suspend_always {
i = &y;
return {};
}
auto initial_suspend() -> suspend_never { return {}; };
auto final_suspend() -> suspend_always { return {}; };
auto return_void() -> void {}
};
Handle h;
};
auto instructions_generator(const Module &m) -> InstructionsGenerator {
for (const auto &f : m) {
for (const auto &bb : f) {
for (const auto &i : instructions(bb)) {
co_yield i;
}
}
}
}
struct InstructionRange {
struct iterator {
optional<InstructionsGenerator> g;
auto operator++() -> auto & {
g->h();
return *this;
}
auto operator*() const -> auto & { return *(g->h.promise().i); }
auto operator==(const iterator & /*unused*/) const -> bool { return g->h.done(); }
};
iterator b;
[[nodiscard]] auto begin() const -> iterator { return b; }
[[nodiscard]] auto end() const -> iterator { return {nullopt}; };
~InstructionRange() {
if (b.g) {
b.g->h.destroy();
}
}
InstructionRange(InstructionsGenerator fi) : b{fi} {}
InstructionRange(InstructionRange &&r) noexcept : b{r.b} { r.b.g = nullopt; }
};
auto instructions(const Module &m) -> InstructionRange { return {instructions_generator(m)}; };
这是使用自定义迭代器的实现(未完成。在意识到它太麻烦后放弃了它。):
// The real implementation was templated but to give you the idea, I've simplified it.
struct LiftedRange {
llvm::Module& m;
public:
struct iterator {
llvm::Module& m;
llvm::Module::iterator l1;
llvm::Function::iterator l2;
auto operator*(); // Skipped for brevity.
auto operator==(); // Skipped for brevity.
auto operator++(){
if(next(l2) != l1.end()){
++l2;
return *this;
}
do {
++l1;
while(l1->empty() || l1 != m.end()); // Avoid empty sets.
l2 = l1->begin();
return *this;
}
};
auto begin(); // Skipped for brevity.
auto end(); // Skipped for brevity.
};
解决方案
推荐阅读
- mongodb - 如果递减的字段值为负,则在 mongodb 中返回零
- javascript - 在 Javascript 中结合 EventListener 和闭包
- c# - 在 MVC-4 (C# ) 中最好是使用一个可以在很多地方使用的大对象,还是几个与视图对齐的小对象
- amazon-s3 - 渲染失败。无法在 AWS S3 上发送 Grafana 警报图像以进行渲染以在 Slack 警报中使用
- php - PHP Ajax 请求接收整个 html 代码作为响应,而不是我的 html 标记
- r - 如何跨列累计求和
- php - Delete From ,语句查询失败
- python - Python 是 32 位的,选择的编译器是 64 位的
- flutter - 状态管理和全局变量
- discord.js - TypeError:无法读取 Discord.js 未定义的属性“成员”