Description
At the moment, once garbage collection is called (and actually collects something), all compute tables are completely reset, i.e., emptied. While this is fast, it is not necessarily efficient. The compute table most probably contains many entries that are still valid (i.e., all constituents have a non-zero reference count).
The compute table reset should only clear the table from dead entries (i.e., where at least one of the edges has a zero reference count). In this fashion, valid entries are kept in the tables and can be used for further computations.
A prototypical implementation would be
void clear() {
if (count > 0) {
for (auto& entry: table) {
// If this is an unused entry, there is no need to clear it
if (entry.leftOperand.p == nullptr && entry.rightOperand.p == nullptr) {
continue;
}
// If all constituents of the entry have a non-zero reference count,
// the entry is still valid and should not be cleared
// This assumes that as long as a node is alive, the respective complex
// numbers are alive as well.
const auto leftAlive = entry.leftOperand.p == nullptr || entry.leftOperand.p->ref > 0;
const auto rightAlive = entry.rightOperand.p == nullptr || entry.rightOperand.p->ref > 0;
const auto resultAlive = entry.result.p == nullptr || entry.result.p->ref > 0;
if (leftAlive && rightAlive && resultAlive) {
continue;
}
entry = Entry{};
--count;
}
}
}
It's important to think about how often such a scenario might happen during multiplication and addition assuming the way we currently perform reference counting (e.g., the ref count of operation matrices is never increased).