mirror of
https://github.com/NixOS/nix
synced 2025-07-06 21:41:48 +02:00
Extract a generic computeClosure
function
Move the `closure` logic of `computeFSClosure` to its own (templated) function. This doesn’t bring much by itself (except for the ability to properly test the “closure” functionality independently from the rest), but it allows reusing it (in particular for the realisations which will require a very similar closure computation)
This commit is contained in:
parent
7234cf39be
commit
184558834a
3 changed files with 193 additions and 79 deletions
69
src/libutil/closure.hh
Normal file
69
src/libutil/closure.hh
Normal file
|
@ -0,0 +1,69 @@
|
|||
#include <set>
|
||||
#include <future>
|
||||
#include "sync.hh"
|
||||
|
||||
using std::set;
|
||||
|
||||
namespace nix {
|
||||
|
||||
template<typename T>
|
||||
using GetEdgesAsync = std::function<void(const T &, std::function<void(std::promise<set<T>> &)>)>;
|
||||
|
||||
template<typename T>
|
||||
void computeClosure(
|
||||
const set<T> startElts,
|
||||
set<T> & res,
|
||||
GetEdgesAsync<T> getEdgesAsync
|
||||
)
|
||||
{
|
||||
struct State
|
||||
{
|
||||
size_t pending;
|
||||
set<T> & res;
|
||||
std::exception_ptr exc;
|
||||
};
|
||||
|
||||
Sync<State> state_(State{0, res, 0});
|
||||
|
||||
std::function<void(const T &)> enqueue;
|
||||
|
||||
std::condition_variable done;
|
||||
|
||||
enqueue = [&](const T & current) -> void {
|
||||
{
|
||||
auto state(state_.lock());
|
||||
if (state->exc) return;
|
||||
if (!state->res.insert(current).second) return;
|
||||
state->pending++;
|
||||
}
|
||||
|
||||
getEdgesAsync(current, [&](std::promise<set<T>> & prom) {
|
||||
try {
|
||||
auto children = prom.get_future().get();
|
||||
for (auto & child : children)
|
||||
enqueue(child);
|
||||
{
|
||||
auto state(state_.lock());
|
||||
assert(state->pending);
|
||||
if (!--state->pending) done.notify_one();
|
||||
}
|
||||
} catch (...) {
|
||||
auto state(state_.lock());
|
||||
if (!state->exc) state->exc = std::current_exception();
|
||||
assert(state->pending);
|
||||
if (!--state->pending) done.notify_one();
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
for (auto & startElt : startElts)
|
||||
enqueue(startElt);
|
||||
|
||||
{
|
||||
auto state(state_.lock());
|
||||
while (state->pending) state.wait(done);
|
||||
if (state->exc) std::rethrow_exception(state->exc);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue