lean4-htt/src/util/task_builder.h
2017-03-23 09:00:59 +01:00

205 lines
6.1 KiB
C++

/*
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Gabriel Ebner
*/
#pragma once
#include "util/task.h"
#include "util/unit.h"
#include "util/list.h"
#include "util/cancellable.h"
#include <vector>
#include <algorithm>
#include <type_traits>
namespace lean {
template <class Res> task<Res> mk_pure_task(Res && res) { return std::make_shared<task_cell<Res>>(res); }
template <class Res> task<Res> mk_pure_task(Res const & res) { return std::make_shared<task_cell<Res>>(res); }
struct delegating_task_imp : public gtask_imp {
std::unique_ptr<gtask_imp> m_base;
delegating_task_imp(std::unique_ptr<gtask_imp> && base) : m_base(std::forward<std::unique_ptr<gtask_imp>>(base)) {}
void get_dependencies(buffer<gtask> & deps) override { m_base->get_dependencies(deps); }
void execute(void * result) override { return m_base->execute(result); }
};
struct cancellation_support {
cancellation_token m_ctok;
cancellation_support(cancellation_token const & ctok) : m_ctok(ctok) {}
std::unique_ptr<gtask_imp> operator()(std::unique_ptr<gtask_imp> &&);
};
template <class Fn>
struct depends_on_fn_wrapper : public delegating_task_imp {
Fn m_fn;
depends_on_fn_wrapper(std::unique_ptr<gtask_imp> && base, Fn && fn) :
delegating_task_imp(std::forward<std::unique_ptr<gtask_imp>>(base)), m_fn(std::forward<Fn>(fn)) {}
void get_dependencies(buffer<gtask> & deps) override {
m_fn(deps);
delegating_task_imp::get_dependencies(deps);
}
};
template <class Res>
class task_builder {
std::unique_ptr<gtask_imp> m_imp;
task_flags m_flags;
cancellation_token m_cancel_tok;
template <class Fn>
struct base_task_imp : public gtask_imp {
Fn m_fn;
base_task_imp(Fn && fn) : m_fn(fn) {}
void execute(void * result) override {
*static_cast<Res *>(result) = m_fn();
}
};
public:
task_builder() : task_builder([] { return Res(); }) {}
template <class Fn> task_builder(Fn && fn) :
m_imp(new base_task_imp<Fn>(std::forward<Fn>(fn))),
m_cancel_tok(global_cancellation_token()) {}
task_builder<Res> execute_eagerly() {
m_flags.m_eager_execution = true;
return std::move(*this);
}
template <class Wrapper>
task_builder<Res> wrap(Wrapper && wrapper) {
m_imp = wrapper(std::move(m_imp));
lean_assert(m_imp);
return std::move(*this);
}
task_builder<Res> set_cancellation_token(cancellation_token const & ctok) {
m_cancel_tok = ctok;
return std::move(*this);
}
template <class Fn>
task_builder<Res> depends_on_fn(Fn && fn) {
m_imp.reset(new depends_on_fn_wrapper<Fn>(std::move(m_imp), std::forward<Fn>(fn)));
return std::move(*this);
}
task_builder<Res> depends_on(gtask const & t) {
return depends_on_fn([t] (buffer<gtask> & deps) { deps.push_back(t); });
}
template <class Task>
task_builder<Res> depends_on(std::vector<Task> && ts) {
return depends_on_fn([ts] (buffer<gtask> & deps) {
for (auto & t : ts) deps.push_back(t);
});
}
template <class Task>
task_builder<Res> depends_on(std::vector<Task> const & ts) {
std::vector<Task> ts_ = ts;
return depends_on(std::move(ts_));
}
template <class Task>
task_builder<Res> depends_on(list<Task> const & ts) {
return depends_on_fn([ts] (buffer<gtask> & deps) {
for (auto & t : ts) deps.push_back(t);
});
}
task<Res> build_without_cancellation() {
return mk_task<Res>(std::move(m_imp), m_flags);
}
gtask build_dep_task() {
return execute_eagerly().build_without_cancellation();
}
task<Res> build() {
auto ctok = mk_cancellation_token(m_cancel_tok);
auto task = wrap(cancellation_support(ctok)).build_without_cancellation();
ctok->add_child(task);
return std::move(task);
}
};
template <class Res, class Fn, class Arg>
task_builder<Res> map(task<Arg> const & arg, Fn && fn) {
return std::move(task_builder<Res>([arg, fn] { return fn(get(arg)); }).depends_on(arg));
};
template <class Res>
task<std::vector<Res>> traverse(std::vector<task<Res>> const & ts) {
auto to_do = std::make_shared<std::vector<gtask>>();
for (gtask const & t : ts) {
if (!t->peek_is_finished()) {
to_do->push_back(t);
}
}
if (to_do->empty()) {
std::vector<Res> vs;
for (auto & t : ts) vs.push_back(get(t));
return mk_pure_task<std::vector<Res>>(vs);
}
return task_builder<std::vector<Res>>([ts] {
std::vector<Res> vs;
for (auto & t : ts) vs.push_back(get(t));
return std::move(vs);
}).depends_on_fn([to_do] (buffer<gtask> & deps) {
to_do->erase(std::remove_if(to_do->begin(), to_do->end(),
[] (gtask & t) { return t->peek_is_finished(); }),
to_do->end());
for (auto & t : *to_do) deps.push_back(t);
}).execute_eagerly().build();
}
template <class Fn, class T>
task<bool> any(std::vector<task<T>> const & ts, Fn && fn) {
std::vector<task<T>> unknown;
for (auto & t : ts) {
if (auto res = peek(t)) {
if (fn(*res))
return mk_pure_task(true);
} else {
unknown.push_back(t);
}
}
if (unknown.empty()) {
return mk_pure_task(false);
} else {
return map<bool>(traverse<T>(unknown), [=] (std::vector<T> ress) {
for (auto res : ress)
if (fn(res))
return true;
return false;
}).execute_eagerly().build();
}
}
template <class Fn>
gtask mk_dependency_task(Fn && fn) {
return task_builder<unit>().depends_on_fn(std::forward<Fn>(fn)).build_dep_task();
}
template <class Arg, class Fn>
gtask mk_deep_dependency(task<Arg> const & arg, Fn && fn) {
return mk_dependency_task([fn, arg] (buffer<gtask> & deps) {
deps.push_back(arg);
if (auto v = peek(arg)) {
fn(deps, *v);
}
});
};
}