Commit b4bd2f58 authored by Damien Leroux's avatar Damien Leroux
Browse files

Improved API to computed values and collections.

parent 94ecaebd
......@@ -18,6 +18,7 @@
#define DEFAULT_CACHE_DIR "/tmp/"
msg_handler_t::lock_type msg_handler_t::mutex;
namespace cache {
namespace predicate {
......@@ -59,28 +60,29 @@ using computed_type = std::future<Type>;
template <typename Class, typename Type, typename... Dependencies>
struct computed_value : value<computed_type<Type>> {
struct async_computed_value : value<computed_type<Type>> {
/*virtual Type do_compute(const Dependencies&...) = 0;*/
typedef typename make_sequence<sizeof...(Dependencies)>::type indices;
computed_value(const std::tuple<Dependencies...>& dep)
async_computed_value(const std::tuple<Dependencies...>& dep)
: dependencies(dep)
{ val = async_compute_cache(); }
computed_value(std::tuple<Dependencies...>&& dep)
async_computed_value(std::tuple<Dependencies...>&& dep)
: dependencies(std::move(dep))
{ val = async_compute_cache(); }
computed_value(const Dependencies&... dep)
async_computed_value(const Dependencies&... dep)
: dependencies(dep...)
{ val = async_compute_cache(); }
computed_value(Dependencies&&... dep)
async_computed_value(Dependencies&&... dep)
: dependencies(std::move(dep)...)
{ val = async_compute_cache(); }
virtual ~computed_value()
async_computed_value(const async_computed_value<Class, Type, Dependencies...>&) = delete;
async_computed_value(async_computed_value<Class, Type, Dependencies...>&&) = delete;
virtual ~async_computed_value()
{
std::cout << "destroying task ";
_print_tuple(std::cout, dependencies);
std::cout << std::endl;
/*DEBUG("destroying task " << dependencies);*/
}
std::string cache_filename() const
......@@ -119,14 +121,14 @@ private:
ERROR("File " << path << " is not readable.", "Check permissions for file " << path);
unlink(path.c_str());
} else if (load(path, ret)) {
INFO("Reloading data from path " << path);
INFO(dependencies << " Reloading data from path " << path);
return ret;
} else {
INFO("Cache invalid. Computing data and caching in " << path);
INFO(dependencies << " Cache invalid. Computing data and caching in " << path);
compute_and_save(path, ret);
}
} else {
INFO("Computing data and caching in " << path);
INFO(dependencies << " Computing data and caching in " << path);
compute_and_save(path, ret);
}
return ret;
......@@ -254,11 +256,51 @@ public:
};
template <typename Class, typename Type, typename... Dependencies>
struct computed_value : value<Type> {
typedef Type value_type;
typedef std::tuple<Dependencies...> dependencies_type;
typedef async_computed_value<Class, Type, Dependencies...> task_type;
std::shared_ptr<task_type> task;
computed_value(Dependencies&&... d)
: value<Type>(), task(new task_type(d...))
{}
computed_value(const Dependencies&... d)
: value<Type>(), task(new task_type(d...))
{}
computed_value(std::tuple<Dependencies...>&& t)
: value<Type>(), task(new task_type(t))
{}
computed_value(const std::tuple<Dependencies...>& t)
: value<Type>(), task(new task_type(t))
{}
computed_value(const computed_value<Class, Type, Dependencies...>& cv)
: value<Type>(), task(cv.task)
{}
computed_value(computed_value<Class, Type, Dependencies...>&& cv)
: value<Type>(), task(cv.task)
{}
operator Type ()
{
return *task;
}
};
template <typename T>
struct naked_type {
typedef typename std::remove_cv<
typename std::remove_pointer<
typename std::remove_reference<T>
::type>::type>::type type;
};
template <bool val, typename TASK_CLASS, typename... Elems> struct detect_composite_impl;
template <typename TASK_CLASS, typename... Elems>
struct detect_composite_impl<true, TASK_CLASS, Elems...> {
static const bool composite = true;
typedef std::vector<std::shared_ptr<TASK_CLASS>> type;
typedef std::vector<TASK_CLASS> type;
};
template <typename TASK_CLASS, typename... Elems>
......@@ -270,7 +312,7 @@ struct detect_composite_impl<false, TASK_CLASS, Elems...> {
template <typename TASK_CLASS, typename... Elems>
struct detect_composite {
typedef detect_composite_impl<
if_any_type<predicate::is_composite, Elems...>::value,
if_any_type<predicate::is_composite, typename naked_type<Elems>::type...>::value,
TASK_CLASS,
Elems...> impl;
typedef typename impl::type type;
......@@ -282,13 +324,13 @@ struct make_task_helper;
template <typename TASK_CLASS, typename... Elems>
struct make_task_helper<true, TASK_CLASS, Elems...> {
static std::vector<std::shared_ptr<TASK_CLASS>> make(const std::tuple<Elems...>& t)
static std::vector<TASK_CLASS> make(const std::tuple<Elems...>& t)
{
std::vector<std::shared_ptr<TASK_CLASS>> ret;
std::vector<TASK_CLASS> ret;
cartesian_product<Elems...> cp(t);
do {
/*ret.emplace_back(TASK_CLASS::get(*cp));*/
ret.emplace_back(new TASK_CLASS(*cp));
ret.emplace_back(TASK_CLASS(*cp));
} while (cp.next());
return ret;
}
......@@ -337,15 +379,79 @@ struct make_task_helper<false, TASK_CLASS, Elems...> {
static TASK_CLASS make(const std::tuple<Elems...>& t) { return TASK_CLASS(t); }
};
template <typename TASK_CLASS, typename... Elems>
auto make_task(std::tuple<Elems...>& t)
auto make_task(const std::tuple<Elems...>& t)
-> typename detect_composite<TASK_CLASS, Elems...>::type
{
std::cout << "make_task with " << t << std::endl;
DEBUG("make_task with " << t);
return make_task_helper<detect_composite<TASK_CLASS, Elems...>::composite, TASK_CLASS, Elems...>::make(t);
}
template <typename TASK_CLASS, typename... Elems>
auto make_task(std::tuple<Elems...>&& t)
-> typename detect_composite<TASK_CLASS, Elems...>::type
{
DEBUG("make_task with " << t);
return make_task_helper<detect_composite<TASK_CLASS, Elems...>::composite, TASK_CLASS, Elems...>::make(std::move(t));
}
template <typename Class>
struct computed_collection : value<std::vector<Class>> {
/*template <typename DepTuple> struct expand_tuple;*/
/*template <typename... Dependencies>*/
/*struct expand_tuple<std::tuple<Dependencies...>> {*/
/*typedef async_computed_value<computed_collection<Class>, std::vector<Class>, Dependencies...>*/
/*};*/
using value<std::vector<Class>>::val;
typedef std::vector<typename Class::value_type> value_type;
value_type value_cache;
template <typename... Dependencies>
struct compute_async
: async_computed_value<compute_async<Dependencies...>,
std::vector<typename Class::value_type>,
Dependencies...>
{
using async_computed_value<compute_async<Dependencies...>,
std::vector<typename Class::value_type>,
Dependencies...>::async_computed_value;
virtual std::vector<typename Class::value_type>
do_compute(const Dependencies&... x)
{
std::vector<typename Class::value_type> ret;
for (auto& tsk: make_task<Class>(std::make_tuple(x...))) {
ret.push_back(tsk);
}
return ret;
}
};
std::function <value_type()> fetch_async;
bool fetched;
template <typename... Dependencies>
computed_collection(const std::tuple<Dependencies...>& t)
/*: value<std::vector<Class>>({make_task<Class>(t)})*/
: value<std::vector<Class>>()
{
compute_async<Dependencies...>* task = new compute_async<Dependencies...>(t);
fetch_async = [=] () { value_type ret = *task; delete task; return ret; };
fetched = false;
}
operator std::vector<typename Class::value_type> ()
{
if (!fetched) {
value_cache = fetch_async();
}
return value_cache;
}
};
}
#endif
......
......@@ -3,6 +3,7 @@
#include <iostream>
#include <type_traits>
#include <Eigen/Core>
struct cache_input_traits {
typedef std::istream stream_type;
......@@ -96,5 +97,65 @@ operator & (cache_file<CACHE_DIRECTION>& c, std::tuple<Elems...>& t)
return operator &<0, sizeof...(Elems), CACHE_DIRECTION, Elems...> (c, t);
}
template <typename V, typename A>
cache_output&
operator & (cache_output& c, std::vector<V, A>& v)
{
size_t sz = v.size();
c & sz;
for (auto& x: v) { c & x; }
return c;
}
template <typename V, typename A>
cache_input&
operator & (cache_input& c, std::vector<V, A>& v)
{
size_t sz;
c & sz;
v.clear();
v.reserve(sz);
V tmp;
for (; sz > 0; --sz) { c & tmp; v.push_back(tmp); }
return c;
}
template <typename CACHE_DIRECTION, typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
cache_file<CACHE_DIRECTION>&
bidirectional_matrix_loop(cache_file<CACHE_DIRECTION>& c, Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>& mat)
{
for (int j = 0; j < mat.outerSize(); ++j) {
for (int i = 0; i < mat.innerSize(); ++i) {
c & mat(i, j);
}
}
return c;
}
template <typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
cache_output&
operator & (cache_output& c, Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>& mat)
{
size_t sz;
sz = mat.innerSize();
c & sz;
sz = mat.outerSize();
c & sz;
bidirectional_matrix_loop(c, mat);
return c;
}
template <typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
cache_input&
operator & (cache_input& c, Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>& mat)
{
size_t sz1, sz2;
c & sz1 & sz2;
mat.resize(sz1, sz2);
bidirectional_matrix_loop(c, mat);
return c;
}
#endif
......@@ -6,6 +6,7 @@
#include <set>
#include <utility>
#include <sstream>
#include <thread>
#define _WHITE "\x1b[37;1m"
#define _RED "\x1b[31;1m"
......@@ -14,6 +15,9 @@
#define _NORMAL "\x1b[0;m"
struct msg_handler_t {
typedef std::recursive_mutex lock_type;
typedef std::unique_lock<lock_type> scoped_lock_type;
struct state_t {
bool color;
std::set<std::string> workarounds;
......@@ -41,20 +45,33 @@ struct msg_handler_t {
static void check(bool fatal) { instance().check(fatal); }
static void reset() { instance().reset(); }
static lock_type mutex;
};
#define ERROR(_msg_expr_, _workaround_expr_) do {\
std::cerr << msg_handler_t::e() << "[ERR] " << _msg_expr_ << msg_handler_t::n() << std::endl;\
{msg_handler_t::scoped_lock_type _(msg_handler_t::mutex);\
std::cerr << msg_handler_t::e() << "[ERR] " << _msg_expr_ << msg_handler_t::n() << std::endl;}\
std::stringstream s; s << _workaround_expr_;\
if (s.str().size()) { msg_handler_t::instance().workarounds.insert(s.str()); } } while (0)
#define WARNING(_msg_expr_) std::cerr << msg_handler_t::w() << "[WRN] " << _msg_expr_ << msg_handler_t::n() << std::endl;
#define INFO(_msg_expr_) std::cout << msg_handler_t::i() << "[MSG] " << _msg_expr_ << msg_handler_t::n() << std::endl;
#define WARNING(_msg_expr_) do {\
msg_handler_t::scoped_lock_type _(msg_handler_t::mutex);\
std::cerr << msg_handler_t::w() << "[WRN] " << _msg_expr_ << msg_handler_t::n() << std::endl; } while(0)
#define INFO(_msg_expr_) do {\
msg_handler_t::scoped_lock_type _(msg_handler_t::mutex);\
std::cout << msg_handler_t::i() << "[MSG] " << _msg_expr_ << msg_handler_t::n() << std::endl; } while(0)
#define DEBUG(_msg_expr_) do {\
msg_handler_t::scoped_lock_type _(msg_handler_t::mutex);\
std::cout << _msg_expr_ << std::endl; } while(0)
inline void msg_handler_t::state_t::check(bool fatal)
{
msg_handler_t::scoped_lock_type _(msg_handler_t::mutex);
if (count > 0) {
std::cerr << info() << "[MSG] " << count;
if (count > 1) {
......
......@@ -3,6 +3,7 @@
using namespace cache;
#if 0
static double product_impl(double a, double b) { return a * b; }
struct product : cvalue(product_impl) { cvalue_ctor(product_impl); };
......@@ -14,7 +15,41 @@ struct mult : cvalue(product_int) {
cvalue_ctor(product_int);
};
#if 0
#else
struct product : cache::computed_value<product, double, value<double>, value<double>> {
using cache::computed_value<product, double, value<double>, value<double>>::computed_value;
/*using cache::computed_value<mult, int, value<int>, value<int>>::do_compute;*/
double do_compute(const value<double>& d1, const value<double>& d2)
{
return d1 * d2;
}
};
/*
struct mult_table : cache::computed_value<mult_table, std::vector<double>, value<double>> {
using cache::computed_value<mult_table, std::vector<double>, value<double>>::computed_value;
std::vector<double> do_compute(const value<double>& d)
{
auto tasklist = make_task<product>(std::make_tuple(d, range<double>{1, 11}));
std::vector<double> ret;
for (auto t: tasklist) {
ret.push_back((double) t);
}
DEBUG("ret size is " << ret.size());
return ret;
}
};
*/
struct mult_table : cache::computed_collection<product> {
using cache::computed_collection<product>::computed_collection;
};
struct mult : cache::computed_value<mult, int, value<int>, value<int>> {
using cache::computed_value<mult, int, value<int>, value<int>>::computed_value;
/*using cache::computed_value<mult, int, value<int>, value<int>>::do_compute;*/
......@@ -32,11 +67,10 @@ struct task {
task(const tuple_type& t)
: _(t)
{
std::cout << "task "
DEBUG("task "
<< std::get<0>(t) << ' '
<< std::get<1>(t) << ' '
<< std::get<2>(t)
<< std::endl;
<< std::get<2>(t));
}
};
......@@ -105,8 +139,20 @@ int main(int argc, char** argv)
auto rng = std::make_tuple(range<double>{1, 23}, value<double>{37});
auto table = make_task<product>(rng);
for (auto k: table) {
std::cout << k->dependencies << std::endl;
std::cout << ((double)*k) << std::endl;
double x = k;
DEBUG(k.task->dependencies << " => " << x);
}
DEBUG("====================");
auto tab_descr = std::make_tuple(value<double>{57}, range<double>{1., 24.});
/*std::vector<double> tab = make_task<mult_table>(tab_descr);*/
/*mult_table mt(tab_descr);*/
/*std::vector<double> tab = mt;*/
std::vector<double> tab = mult_table(tab_descr);
DEBUG("tab size = " << tab.size());
for (auto k: tab) {
DEBUG(k);
}
#endif
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment