cache2.h 29.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* Spell-QTL  Software suite for the QTL analysis of modern datasets.
 * Copyright (C) 2016,2017  Damien Leroux <damien.leroux@inra.fr>, Sylvain Jasson <sylvain.jasson@inra.fr>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

Damien Leroux's avatar
Damien Leroux committed
18
19
20
#ifndef _SPEL_CACHE_2_H_
#define _SPEL_CACHE_2_H_

21
22
#include "cache/base.h"
#include "disk_hashtable.h"
23
24
#include "task_pool.h"
#include "stl_output.h"
Damien Leroux's avatar
Damien Leroux committed
25

26
27
28
29
30
31
32
33
34
35
36
template <typename Ret, typename... Args>
computation_registry<value<Ret>, Ret (*) (Args...), value<typename clean_type<Args>::type>...>&
__get_registry()
{
    static computation_registry<value<Ret>, Ret (*) (Args...), value<typename clean_type<Args>::type>...> _reg_;
    /*MSG_DEBUG("Registry at " << (&_reg_));*/
    return _reg_;
}


template <typename Ret, typename... Args>
37
38
39
40
41
42
    struct async_computation<Ret(Args...)>;

template <typename Ret, typename... Args>
computation_registry<std::shared_ptr<async_computation<Ret(Args...)>>,
                     Ret (*) (Args...),
                     value<typename clean_type<Args>::type>...>&
43
44
__get_in_progress_registry()
{
45
46
47
    static computation_registry<std::shared_ptr<async_computation<Ret(Args...)>>,
                                Ret (*) (Args...),
                                value<typename clean_type<Args>::type>...> _reg_;
48
49
50
51
52
53
54
55
56
    /*MSG_DEBUG("Registry at " << (&_reg_));*/
    return _reg_;
}


template <typename Ret, typename... Args>
std::mutex& __get_in_progress_mutex() { static std::mutex _; return _; }

template <typename Ret, typename... Args>
57
58
59
void
unregister_task_in_progress(Ret (*f) (Args...),
                            const value<typename clean_type<Args>::type>&... args)
60
61
{
    __get_in_progress_mutex<Ret, Args...>().lock();
62
    __get_in_progress_registry<Ret, Args...>().remove(f, args...);
63
64
65
66
67
    __get_in_progress_mutex<Ret, Args...>().unlock();
}


template <typename Ret, typename... Args>
68
69
70
71
std::shared_ptr<async_computation<Ret(Args...)>>
register_task_in_progress(std::shared_ptr<async_computation<Ret(Args...)>> v,
                          Ret (*f) (Args...),
                          const value<typename clean_type<Args>::type>&... args)
72
{
Damien Leroux's avatar
Damien Leroux committed
73
    /*__get_in_progress_mutex<Ret, Args...>().lock();*/
74
    __get_in_progress_registry<Ret, Args...>().get(f, args...) = v;
Damien Leroux's avatar
Damien Leroux committed
75
    /*__get_in_progress_mutex<Ret, Args...>().unlock();*/
76
    return v;
77
78
}

Damien Leroux's avatar
Damien Leroux committed
79
80

template <typename Ret, typename... Args>
81
    struct async_computation<Ret(Args...)> : public Task {
Damien Leroux's avatar
Damien Leroux committed
82
83
84
85
86
        typedef async_computation<Ret(Args...)> this_type;
        typedef Ret value_type;
        typedef Ret (*computation_function_pointer_type) (Args...);
        typedef std::packaged_task<Ret(Args...)> task_type;

87
88
89
90
91
        async_computation(const async_computation&) = delete;
        async_computation() = delete;

//        ~async_computation() { if (m_thread.joinable()) { m_thread.join(); } }

92
        async_computation(CachingPolicy _Sync, computation_function_pointer_type func,
Damien Leroux's avatar
Damien Leroux committed
93
94
                          const value<typename clean_type<Args>::type>&... args)
            : dependencies(args...)
95
            , m_storage_init(false)
Damien Leroux's avatar
Damien Leroux committed
96
            , m_storage()
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
            , m_future()
            , m_compute([=] () {
/*
                    bool previous = m_started.exchange(true);
                    if (previous) {
                        MSG_DEBUG("Task " << get_func_name(func) << " already run. Returning.");
//                        unregister_task_in_progress(func, {*args}...);
                        TaskPool::release_slot();
                        TaskPool::remove_task(m_thread.get_id());
                        return;
                    }
*/
                    std::string func_name = get_func_name(func);
                    chrono_trace _(func_name);
                    if (0) {
//                        msg_handler_t::cout() << "INVOKING " << func_name << "(…)" << std::endl;
                        std::stringstream ss;
                        ss << "INVOKING " << func_name << "(" << std::endl;
                        std::vector<std::string> avec;
                        do_with_arg_pack(avec.push_back(MESSAGE(args)));
                        for (size_t i = 0; i < avec.size() - 1; ++i) {
                            ss << avec[i] << ", ";
                        }
                        msg_handler_t::cout() << ss.str() << ')';
                    }
                    std::thread::id this_id = std::this_thread::get_id();
//                                active_settings->thread_stacks[this_id].push_back(func_name);
                    MSG_DEBUG("[" << this_id << ',' << (this_id == active_settings->main_thread) << "] ENTER " << func_name);
                    msg_handler_t::run_hooks();
                    auto ret = func(*args...);
//                                active_settings->thread_stacks[this_id].pop_back();
                    msg_handler_t::run_hooks();
                    unregister_task_in_progress(func, {*args}...);
                    TaskPool::release_slot();
//                    TaskPool::remove_task(m_thread->get_id());
                    MSG_DEBUG("[" << this_id << ',' << (this_id == active_settings->main_thread) << "] LEAVE " << func_name);
                    m_started_cv.notify_all();
                    return ret;
                })
136
            , mutex()
137
138
139
140
141
142
143
144
145
146
147
148
            , m_started(false)
            , m_started_cv()
            , m_storage_waiting(false)
            , m_storage_waiting_cv()
        {
//            MSG_DEBUG("In constructor, thread " << (&m_thread) << " should not be joinable: " << std::boolalpha << m_thread.joinable());
            std::unique_lock<std::mutex> lock(mutex);
//            if (!m_started) {
//                m_started.store(true);
                TaskPool::enqueue(this);
//            }
        }
Damien Leroux's avatar
Damien Leroux committed
149

Damien Leroux's avatar
Damien Leroux committed
150
151
        async_computation(CachingPolicy _Sync, std::function<Ret(Args...)>& proxy,
                          computation_function_pointer_type func,
Damien Leroux's avatar
Damien Leroux committed
152
153
                          const value<typename clean_type<Args>::type>&... args)
            : dependencies(args...)
154
155
            , m_storage_init(false)
//            , m_thread()
Damien Leroux's avatar
Damien Leroux committed
156
            , m_storage()
Damien Leroux's avatar
Damien Leroux committed
157
            /*, m_future(active_settings->enqueue(_Sync, func, *args...))*/
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
//            , m_promise()
            , m_future()
            , m_compute([=] () {
                    m_started_cv.notify_all();
/*
                    bool previous = m_started.exchange(true);
                    if (previous) {
                        MSG_DEBUG("Task " << get_func_name(func) << " already run. Returning.");
//                        unregister_task_in_progress(func, {*args}...);
                        TaskPool::release_slot();
                        TaskPool::remove_task(m_thread.get_id());
                        return;
                    }
*/
                    std::string func_name = get_func_name(func);
                    chrono_trace _(func_name);
                    if (0) {
//                        msg_handler_t::cout() << "INVOKING " << func_name << "(" << std::endl;
                        std::stringstream ss;
                        ss << "INVOKING " << func_name << "(…)" << std::endl;
                        std::vector<std::string> avec;
                        do_with_arg_pack(avec.push_back(MESSAGE(args)));
                        for (size_t i = 0; i < avec.size() - 1; ++i) {
                            ss << avec[i] << ", ";
                        }
                        msg_handler_t::cout() << ss.str() << ')';
                    }
                    std::thread::id this_id = std::this_thread::get_id();
//                                active_settings->thread_stacks[this_id].push_back(func_name);
                    MSG_DEBUG("[" << this_id << ',' << (this_id == active_settings->main_thread) << "] p ENTER " << func_name);
//                    msg_handler_t::run_hooks();
//                    m_promise.set_value(proxy(*args...));
                    auto ret = proxy(*args...);
                    MSG_DEBUG("[" << this_id << ',' << (this_id == active_settings->main_thread) << "] p LEAVE " << func_name);
//                                active_settings->thread_stacks[this_id].pop_back();
//                    msg_handler_t::run_hooks();
                    unregister_task_in_progress(func, {*args}...);
                    TaskPool::release_slot();
//                    TaskPool::remove_task(m_thread->get_id());
                    m_started_cv.notify_all();
                    return ret;
                })
200
            /*, m_future(std::async(func, *args...))*/
201
            , mutex()
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
            , m_started(false)
            , m_started_cv()
            , m_storage_waiting(false)
            , m_storage_waiting_cv()
        {
//            MSG_DEBUG("In constructor (w/ proxy), thread " << (&m_thread) << " should not be joinable: " << std::boolalpha << m_thread.joinable());
            std::unique_lock<std::mutex> lock(mutex);
//            if (!m_started) {
//                m_started.store(true);
                TaskPool::enqueue(this);
//            }
        }

        bool has_run() const override { return m_started; }

        std::thread::id run() override
        {
            std::unique_lock<std::mutex> lock(mutex);
            if (m_started) {
                MSG_ERROR("Task has already run.", "");
                return {};
            } else {
                m_future = std::async(std::launch::async, m_compute);
//                m_thread.reset(new std::thread(std::move(m_compute)));
//                m_thread = new std::thread(std::move(m_compute));
//                m_thread.detach();
//                return m_thread->get_id();
                m_started = true;
                m_started_cv.notify_all();
                return {};
            }
        }
Damien Leroux's avatar
Damien Leroux committed
234
235
236

        value_type& __get_noconst()
        {
Damien Leroux's avatar
Damien Leroux committed
237
238
239
240
            /*std::lock_guard<decltype(mutex)> read_guard(mutex);*/
            /*if (m_future.valid()) {*/
                /*return m_storage = m_future.get();*/
            /*}*/
241
242
243
244
245
//            mutex.lock();
//            if (!m_storage_init && m_future.valid()) {
//                mutex.unlock();
            if (m_storage_init) {
                return m_storage;
Damien Leroux's avatar
Damien Leroux committed
246
            }
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
                TaskPool::wait([this]() {
//                    mutex.lock();
                    std::unique_lock<std::mutex> lock(mutex);
                    if (!m_started) {
                        m_started_cv.wait(lock, [this]() -> bool { return m_started; });
                    }
                    if (!m_storage_init && m_future.valid()) {
                        bool waiting_for_storage = m_storage_waiting.exchange(true);
                        if (waiting_for_storage) {
                            m_storage_waiting_cv.wait(lock, [this] () -> bool { return m_storage_init; });
                        } else {
                            m_storage = m_future.get();
                            m_storage_init.store(true);
                            m_storage_waiting_cv.notify_all();
                        }
                    }
//                    mutex.unlock();
                });
//                mutex.lock();
//            }
//            mutex.unlock();
Damien Leroux's avatar
Damien Leroux committed
268
269
270
271
272
273
274
275
276
277
            return m_storage;
        }

        const value_type& __get_const() const
        {
            return const_cast<this_type*>(this)->__get_noconst();
        }

    protected:
        std::tuple<value<typename clean_type<Args>::type>...> dependencies;
278
279
        std::atomic_bool m_storage_init;
//        std::unique_ptr<std::thread> m_thread;
Damien Leroux's avatar
Damien Leroux committed
280
281
        value_type m_storage;
        std::future<Ret> m_future;
282
283
284
285
286
287
        std::function<Ret()> m_compute;
        std::mutex mutex;
        std::atomic_bool m_started;
        std::condition_variable m_started_cv;
        std::atomic_bool m_storage_waiting;
        std::condition_variable m_storage_waiting_cv;
Damien Leroux's avatar
Damien Leroux committed
288
289
    };

290
291
292
293
294
295
template <typename Ret, typename... Args>
std::shared_ptr<async_computation<Ret(Args...)>>
    make_async_computation(CachingPolicy& _Sync,
                           Ret (*func) (Args...),
                           const value<typename clean_type<Args>::type>&... args)
    {
296
297
298
299
300
        /*struct _mac_guard {*/
            /*_mac_guard() { __get_in_progress_mutex<Ret, Args...>().lock(); }*/
            /*~_mac_guard() { __get_in_progress_mutex<Ret, Args...>().unlock(); }*/
        /*} _;*/
        std::lock_guard<std::mutex> scope_lock(__get_in_progress_mutex<Ret, Args...>());
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
        auto& r = __get_in_progress_registry<Ret, Args...>();
        auto exists = r.find(func, args...);
        if (exists) {
            return *exists;
        } else {
            std::shared_ptr<async_computation<Ret(Args...)>>
                ac(new async_computation<Ret(Args...)>(_Sync, func, args...));
            return r.get(func, args...) = register_task_in_progress(ac, func, args...);
        }
    }


template <typename Ret, typename... Args>
std::shared_ptr<async_computation<Ret(Args...)>>
    make_async_computation(CachingPolicy& _Sync,
                           Ret (*func) (Args...),
                           std::function<Ret(Args...)>& proxy,
                           const value<typename clean_type<Args>::type>&... args)
    {
320
321
322
323
324
        /*struct _mac_guard {*/
            /*_mac_guard() { __get_in_progress_mutex<Ret, Args...>().lock(); }*/
            /*~_mac_guard() { __get_in_progress_mutex<Ret, Args...>().unlock(); }*/
        /*} _;*/
        std::lock_guard<std::mutex> scope_lock(__get_in_progress_mutex<Ret, Args...>());
325
326
327
328
329
330
        auto& r = __get_in_progress_registry<Ret, Args...>();
        auto exists = r.find(func, args...);
        if (exists) {
            return *exists;
        } else {
            std::shared_ptr<async_computation<Ret(Args...)>>
Damien Leroux's avatar
Damien Leroux committed
331
                ac(new async_computation<Ret(Args...)>(_Sync, proxy, func, args...));
332
333
334
335
            return r.get(func, args...) = register_task_in_progress(ac, func, args...);
        }
    }

Damien Leroux's avatar
Damien Leroux committed
336

337
338
339
340
341
342
#ifndef NDEBUG
#define THIS_ARG_MAY_BE_UNUSED(x) x
#else
#define THIS_ARG_MAY_BE_UNUSED(x)
#endif

Damien Leroux's avatar
Damien Leroux committed
343
344
345
346
template <typename Ret, typename... Args>
    struct cached_computation<Ret(Args...)> {
        typedef Ret value_type;

347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
        cached_computation(const std::string& name, Ret (*f) (Args...), const value<typename clean_type<Args>::type>&... THIS_ARG_MAY_BE_UNUSED(args))
            : m_name(name)
            , m_func(f)
#ifndef NDEBUG
            , dump_call()
#endif
        {
#ifndef NDEBUG
            dump_call = [=] () {
                std::stringstream ss;
                ss << m_name << '(';
                std::vector<std::string> avec;
                do_with_arg_pack(avec.push_back(MESSAGE(args)));
                for (size_t i = 0; i < avec.size() - 1; ++i) {
                    ss << avec[i] << ", ";
                }
                ss << avec.back() << ')';
                return ss.str();
            };
#endif
            /*MSG_DEBUG("NEW CACHED_COMPUTATION WITH ARGS " << dump());*/
            /*MSG_DEBUG("MD5 (accum) = " << m_md5_hash.accum);*/
            /*MSG_DEBUG("MD5 (append) = " << m_md5_hash.append);*/
            /*std::cout << "NEW CACHED_COMPUTATION " << m_md5_hash.accum << ' ' << m_md5_hash.append << std::endl;*/
        }

        std::string
            dump()
            {
#ifndef NDEBUG
                return dump_call();
#else
                return m_name;
#endif
            }

        Ret operator () (Args... x)
        {
385
            static disk_hashtable<Ret(Args...)> dht(MESSAGE(active_settings->work_directory << '/' << active_settings->name << ".cache/" << m_name));
386
387
388
389
390
391
392
393
394
395
396
397
            return dht.get_or_compute(m_func, std::forward<Args>(x)...);
        }

        std::string m_name;
        Ret (*m_func) (Args...);

#ifndef NDEBUG
        std::function<std::string()> dump_call;
#endif
    };


Damien Leroux's avatar
Damien Leroux committed
398
399
400
401
402
template <typename Ret, typename... Args>
    struct computed_value<Ret(Args...)> : generic_value_interface<Ret> {
        typedef Ret value_type;
        typedef std::function<Ret(Args...)> computation_type;

403
        computed_value(CachingPolicy _Sync, Ret (*func) (Args...), const value<typename clean_type<Args>::type>&... args)
Damien Leroux's avatar
Damien Leroux committed
404
            : m_hash(compute_hash(args...))
405
            , m_task(make_async_computation<Ret, Args...>(_Sync, func, args...))
Damien Leroux's avatar
Damien Leroux committed
406
407
408
409
        {}

        virtual
            value_type& operator * ()
410
            override { return m_task->__get_noconst(); }
Damien Leroux's avatar
Damien Leroux committed
411
412
        virtual
            value_type* operator -> ()
413
            override { return &m_task->__get_noconst(); }
Damien Leroux's avatar
Damien Leroux committed
414
415
        virtual
            const value_type& operator * () const
416
            override { return m_task->__get_const(); }
Damien Leroux's avatar
Damien Leroux committed
417
418
        virtual
            const value_type* operator -> () const
419
            override { return &m_task->__get_const(); }
Damien Leroux's avatar
Damien Leroux committed
420
421
422
423
424
425
426
427

        virtual
            size_t hash() const
            override { return m_hash; }
        virtual
            md5_digest& md5(md5_digest& md) const
            override { return md; }

428
    /*protected:*/
Damien Leroux's avatar
Damien Leroux committed
429
        size_t m_hash;
430
        std::shared_ptr<async_computation<Ret(Args...)>> m_task;
Damien Leroux's avatar
Damien Leroux committed
431
432
433
434
435
436
437
    };

template <typename Ret, typename... Args>
    struct cached_computed_value<Ret(Args...)> : generic_value_interface<Ret> {
        typedef Ret value_type;
        typedef std::function<Ret(Args...)> computation_type;

438
        cached_computed_value(CachingPolicy _Sync, Ret (*func) (Args...), const value<typename clean_type<Args>::type>&... args)
439
            : m_comp(get_func_name(func), func, args...)
Damien Leroux's avatar
Damien Leroux committed
440
            , m_comp_proxy([this](Args... x) { return m_comp(x...); })
441
            , m_task(make_async_computation<Ret, Args...>(_Sync, func, m_comp_proxy, args...))
Damien Leroux's avatar
Damien Leroux committed
442
        {}
443
444
            /*m_hash = m_comp.m_md5_hash.md5.context;*/
        /*}*/
Damien Leroux's avatar
Damien Leroux committed
445
446
447

        virtual
            value_type& operator * ()
448
            override { return m_task->__get_noconst(); }
Damien Leroux's avatar
Damien Leroux committed
449
450
        virtual
            value_type* operator -> ()
451
            override { return &m_task->__get_noconst(); }
Damien Leroux's avatar
Damien Leroux committed
452
453
        virtual
            const value_type& operator * () const
454
            override { return m_task->__get_const(); }
Damien Leroux's avatar
Damien Leroux committed
455
456
        virtual
            const value_type* operator -> () const
457
            override { return &m_task->__get_const(); }
Damien Leroux's avatar
Damien Leroux committed
458
459

        virtual
460
461
462
            size_t hash() const override
            /*override { return m_hash; }*/
            {
463
                (void)m_task->__get_const();
464
465
466
                MSG_ERROR("hash is not implemented for cached_computed_value", "");
                return 0;
                /*return m_comp.m_md5_hash.md5.context;*/
467
            }
Damien Leroux's avatar
Damien Leroux committed
468
        virtual
469
470
            md5_digest& md5(md5_digest& md) const override
            {
471
                (void)m_task->__get_const();
472
473
474
475
                /*return md.blend(m_comp.m_md5_hash.md5.context);*/
                MSG_ERROR("md5 is not implemented for cached_computed_value", "");
                /*return md.blend(m_comp.m_md5_hash.md5.context);*/
                return md;
476
477
            }
            /*override { return md; }*/
Damien Leroux's avatar
Damien Leroux committed
478

479
    /*protected:*/
Damien Leroux's avatar
Damien Leroux committed
480
481
        cached_computation<Ret(Args...)> m_comp;
        std::function<Ret(Args...)> m_comp_proxy;
482
        std::shared_ptr<async_computation<Ret(Args...)>> m_task;
483
        /*size_t m_hash;*/
Damien Leroux's avatar
Damien Leroux committed
484
485
486
    };


Damien Leroux's avatar
Damien Leroux committed
487
488
489
/*template <typename X>*/
/*value<X> as_value(X&& x) { return {x}; }*/

Damien Leroux's avatar
Damien Leroux committed
490
491
492
493
494
495
496
497
498
499
500
#if 0
template <typename ValueType, typename... AllArgs> struct registry_impl_type;
template <typename ValueType>
    struct registry_impl_type<ValueType> { typedef ValueType type; };
template <typename ValueType, typename Arg0, typename... OtherArgs>
    struct registry_impl_type<ValueType, Arg0, OtherArgs...> {
        typedef std::unordered_map<Arg0, registry_impl_type<ValueType, OtherArgs...>::type> type;
    };
#endif


501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
#if 0
static inline
std::mutex& __get_lock(void* fptr)
{
    struct m_wrap { std::mutex mutex; m_wrap() : mutex() {} m_wrap(const m_wrap&) : mutex() {} };
    static std::unordered_map<void*, m_wrap> _;
    return _[fptr].mutex;
    /*auto it = _.find(fptr);*/
    /*if (it == _.end()) {*/
        /*bool discard;*/
        /*std::tie(it, discard) = _.insert({fptr, {}});*/
    /*}*/
    /*return it->second;*/
}
#endif
Damien Leroux's avatar
Damien Leroux committed
516
517
518


template <typename Ret, typename... Args>
519
520
521
struct with_disk_cache_traits {
	typedef cached_computed_value<Ret(Args...)> type;
};
Damien Leroux's avatar
Damien Leroux committed
522
523

template <typename Ret, typename... Args>
524
525
526
struct without_disk_cache_traits {
	typedef computed_value<Ret(Args...)> type;
};
Damien Leroux's avatar
Damien Leroux committed
527

528
529
template <int _Policy, typename Ret, typename... Args>
struct disk_cache_traits;
Damien Leroux's avatar
Damien Leroux committed
530

531
template <typename Ret, typename... Args>
532
struct disk_cache_traits<Oneshot, Ret, Args...> : without_disk_cache_traits<Ret, Args...> {};
533
534

template <typename Ret, typename... Args>
535
struct disk_cache_traits<Disk, Ret, Args...> : with_disk_cache_traits<Ret, Args...> {};
Damien Leroux's avatar
Damien Leroux committed
536

537
538
539
540
541
542
543
template <typename Ret, typename... Args>
struct with_mem_cache_traits {
	typedef value<Ret>& return_type;

	template <typename _Maker>
		static
		return_type
544
		create(CachingPolicy _Sync, Ret (&f) (Args...), const clean_value_type<Args>&... x)
545
		{
546
547
            static std::recursive_mutex _;
            std::lock_guard<decltype(_)> lock_guard(_);
548

549
            /*value<Ret>* ret_in_progress = __get_in_progress_registry<Ret, Args...>().find(&f, x...);*/
550

551
552
553
            /*if (ret_in_progress) {*/
                /*return *ret_in_progress;*/
            /*}*/
554

555
556
557
			/*MSG_DEBUG("new value with mem cache");*/
			return_type ret = __get_registry<Ret, Args...>().get(&f, x...);
			if (!ret.valid()) {
558
				ret = new _Maker(_Sync, f, x...);
559
560
561
562
563
564
565
566
567
568
569
570
			}
			return ret;
		}
};

template <typename Ret, typename... Args>
struct without_mem_cache_traits {
	typedef value<Ret> return_type;

	template <typename _Maker>
		static
		return_type
571
		create(CachingPolicy _Sync, Ret (&f) (Args...), const clean_value_type<Args>&... x)
572
		{
573
574
            static std::recursive_mutex _;
            std::lock_guard<decltype(_)> lock_guard(_);
575
            /*value<Ret>* ret_in_progress = __get_in_progress_registry<Ret, Args...>().find(&f, x...);*/
576

577
578
579
            /*if (ret_in_progress) {*/
                /*return *ret_in_progress;*/
            /*}*/
580

581
			/*MSG_DEBUG("new value without mem cache");*/
582
			return_type ret = new _Maker(_Sync, f, x...);
583
584
585
586
587
588
589
590
			return ret;
		}
};

template <int _Policy, typename Ret, typename... Args>
struct mem_cache_traits;

template <typename Ret, typename... Args>
591
struct mem_cache_traits<Oneshot, Ret, Args...> : without_mem_cache_traits<Ret, Args...> {};
592
593

template <typename Ret, typename... Args>
594
struct mem_cache_traits<Mem, Ret, Args...> : with_mem_cache_traits<Ret, Args...> {};
595

596
597
template <CachingPolicy _Policy = Oneshot, typename Ret, typename... Args>
typename mem_cache_traits<_Policy & Mem, Ret, Args...>::return_type
598
599
make_value(Ret (&f) (Args...), const clean_value_type<Args>&... x)
{
600
601
	typedef mem_cache_traits<_Policy & Mem, Ret, Args...> mem_policy;
	typedef disk_cache_traits<_Policy & Disk, Ret, Args...> disk_policy;
602
	return mem_policy::template create<typename disk_policy::type>(_Policy, f, x...);
603
}
Damien Leroux's avatar
Damien Leroux committed
604
605


606
607
template <typename... X> struct tuple;

608
template <CachingPolicy C, typename F, typename R, typename P> struct make_coll_impl;
Damien Leroux's avatar
Damien Leroux committed
609
610
611
612
613
614
615
616
617
618

template <typename A, typename B> struct types_must_be_identical : std::integral_constant<bool, false> {};
template <> struct types_must_be_identical<int, double> : std::integral_constant<bool, false> {};
template <> struct types_must_be_identical<double, int> : std::integral_constant<bool, false> {};
template <typename A> struct types_must_be_identical<A, A> : std::integral_constant<bool, true> {};
template <typename A> struct types_must_be_identical<const A&, A> : std::integral_constant<bool, true> {};
template <typename A> struct types_must_be_identical<A&, A> : std::integral_constant<bool, true> {};
template <typename A> struct types_must_be_identical<const A, A> : std::integral_constant<bool, true> {};

template <typename LA, typename LB> struct type_lists_must_be_identical;
619
template <> struct type_lists_must_be_identical<tuple<>, tuple<>> {};
Damien Leroux's avatar
Damien Leroux committed
620
621

template <typename A0, typename... A, typename B0, typename... B>
622
623
    struct type_lists_must_be_identical<tuple<A0, A...>, tuple<B0, B...>>
            : type_lists_must_be_identical<tuple<A...>, tuple<B...>> {
Damien Leroux's avatar
Damien Leroux committed
624
625
626
        static_assert(types_must_be_identical<A0, B0>::value, "INVALID PARAMETER TYPE.");
    };

627
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs, typename... ErrArgs>
628
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<>, tuple<ErrArgs...>> {
Damien Leroux's avatar
Damien Leroux committed
629
630
631
632
    void operator () (collection<Ret>& coll,
                      Ret (&f) (FuncArgs...),
                      ErrArgs... errargs)
    {
633
        type_lists_must_be_identical<tuple<FuncArgs...>, tuple<typename ErrArgs::value_type...>>();
634
        coll.push_back(make_value<_Policy>(f, errargs...));
Damien Leroux's avatar
Damien Leroux committed
635
636
637
    }
};

638
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs>
639
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<>, tuple<clean_value_type<FuncArgs>...>> {
Damien Leroux's avatar
Damien Leroux committed
640
641
642
643
    void operator () (collection<Ret>& coll,
                      Ret (&f) (FuncArgs...),
                      const value<typename clean_type<FuncArgs>::type>&... pargs)
    {
644
        coll.push_back(make_value<_Policy>(f, pargs...));
Damien Leroux's avatar
Damien Leroux committed
645
646
647
648
    }
};


649
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs, typename VT, typename... ArgsRemaining, typename... PreviousArgs>
650
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<value<VT>, ArgsRemaining...>, tuple<PreviousArgs...>> {
Damien Leroux's avatar
Damien Leroux committed
651
652
653
654
655
656
657
    void operator () (collection<Ret>& coll,
                      Ret (&f) (FuncArgs...),
                      const value<VT>& car,
                      const ArgsRemaining&... cdr,
                      const PreviousArgs&... pargs)
    {
        make_coll_impl<
658
			_Policy,
Damien Leroux's avatar
Damien Leroux committed
659
            Ret(FuncArgs...),
660
661
            tuple<ArgsRemaining...>,
            tuple<PreviousArgs..., value<VT>>>() (coll, f, cdr..., pargs..., car);
Damien Leroux's avatar
Damien Leroux committed
662
663
664
    }
};

665
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs, typename T, typename... ArgsRemaining, typename... PreviousArgs>
666
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<range<T>, ArgsRemaining...>, tuple<PreviousArgs...>> {
Damien Leroux's avatar
Damien Leroux committed
667
668
669
670
671
672
673
674
675
    void operator () (collection<Ret>& coll,
                      Ret (&f) (FuncArgs...),
                      const range<T>& car,
                      const ArgsRemaining&... cdr,
                      const PreviousArgs&... pargs)
    {
        typedef value<T> vtype;
        for (const vtype& v: car) {
            make_coll_impl<
676
				_Policy,
Damien Leroux's avatar
Damien Leroux committed
677
                Ret(FuncArgs...),
678
679
                tuple<ArgsRemaining...>,
                tuple<PreviousArgs..., vtype>>() (coll, f, cdr..., pargs..., v);
Damien Leroux's avatar
Damien Leroux committed
680
681
682
683
        }
    }
};

684
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs, typename T, typename... ArgsRemaining, typename... PreviousArgs>
685
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<collection<T>, ArgsRemaining...>, tuple<PreviousArgs...>> {
Damien Leroux's avatar
Damien Leroux committed
686
687
688
689
690
691
692
693
694
    void operator () (collection<Ret>& coll,
                      Ret (&f) (FuncArgs...),
                      const collection<T>& car,
                      const ArgsRemaining&... cdr,
                      const PreviousArgs&... pargs)
    {
        typedef value<T> vtype;
        for (const vtype& v: car) {
            make_coll_impl<
695
				_Policy,
Damien Leroux's avatar
Damien Leroux committed
696
                Ret(FuncArgs...),
697
698
                tuple<ArgsRemaining...>,
                tuple<PreviousArgs..., vtype>>() (coll, f, cdr..., pargs..., v);
Damien Leroux's avatar
Damien Leroux committed
699
700
701
702
        }
    }
};

703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs, typename T, typename... ArgsRemaining, typename... PreviousArgs>
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<as_collection<T>, ArgsRemaining...>, tuple<PreviousArgs...>> {
    void operator () (collection<Ret>& coll,
                      Ret (&f) (FuncArgs...),
                      const as_collection<T>& car,
                      const ArgsRemaining&... cdr,
                      const PreviousArgs&... pargs)
    {
        typedef value<typename T::value_type> vtype;
        for (const vtype& v: car) {
            make_coll_impl<
				_Policy,
                Ret(FuncArgs...),
                tuple<ArgsRemaining...>,
                tuple<PreviousArgs..., vtype>>() (coll, f, cdr..., pargs..., v);
        }
    }
};

Damien Leroux's avatar
Damien Leroux committed
722
723


724
template <CachingPolicy _Policy = Oneshot, typename Ret, typename... Args, typename... CollArgs>
Damien Leroux's avatar
Damien Leroux committed
725
726
727
728
collection<Ret>
make_collection(Ret (&f) (Args...), CollArgs... args)
{
    collection<Ret> ret;
729
    make_coll_impl<_Policy, Ret(Args...), tuple<CollArgs...>, tuple<>>() (ret, f, args...);
Damien Leroux's avatar
Damien Leroux committed
730
731
732
733
    return ret;
}


734

735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
//template <typename T1, typename T2>
//std::ostream& operator << (std::ostream& os, const std::pair<T1, T2>& p) { return os << p.first << ':' << p.second; }
//
//template <typename T1, typename T2>
//std::ostream& operator << (std::ostream& os, const std::map<T1, T2>& m)
//{
//    auto i = m.begin(), j = m.end();
//    os << '{';
//    if (i != j) {
//        os << (*i);
//        for (++i; i != j; ++i) {
//            os << ' ' << (*i);
//        }
//    }
//    return os << '}';
//}
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773



template <typename T>
std::ostream&
operator << (std::ostream& os, const collection<T>& coll)
{
    for (const auto& k: coll) {
        os << '\t' << k << std::endl;
    }
#if 0
    auto i = coll.begin(), j = coll.end();
    if (i == j) {
        return os;
    }
    os << (**i);
    for (++i; i != j; ++i) {
        os << ' ' << (**i);
    }
#endif
    return os;
}

Damien Leroux's avatar
Damien Leroux committed
774
775
#endif