cache2.h 30.8 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
{
73
//     __get_in_progress_mutex<Ret, Args...>().lock();
74
    __get_in_progress_registry<Ret, Args...>().get(f, args...) = v;
75
//     __get_in_progress_mutex<Ret, Args...>().unlock();
76
    return v;
77
78
}

Damien Leroux's avatar
Damien Leroux committed
79

80
81
82
83
84
85
86
template <typename Ret, typename... Args>
struct lock_in_progress_mutex {
    lock_in_progress_mutex() { __get_in_progress_mutex<Ret, Args...>().lock(); }
    ~lock_in_progress_mutex() { __get_in_progress_mutex<Ret, Args...>().unlock(); }
};


Damien Leroux's avatar
Damien Leroux committed
87
template <typename Ret, typename... Args>
88
    struct async_computation<Ret(Args...)> : public Task {
Damien Leroux's avatar
Damien Leroux committed
89
90
91
92
93
        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;

94
95
96
97
98
        async_computation(const async_computation&) = delete;
        async_computation() = delete;

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

99
        async_computation(CachingPolicy _Sync, computation_function_pointer_type func,
Damien Leroux's avatar
Damien Leroux committed
100
101
                          const value<typename clean_type<Args>::type>&... args)
            : dependencies(args...)
102
            , m_storage_init(false)
Damien Leroux's avatar
Damien Leroux committed
103
            , m_storage()
104
105
            , m_future()
            , m_compute([=] () {
106
107
108
109
110
                {
                    std::unique_lock<std::mutex> lock(mutex);
                    m_started = true;
                    m_started_cv.notify_all();
                }
111
112
113
114
115
116
117
118
119
120
121
122
/*
                    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);
Damien Leroux's avatar
Damien Leroux committed
123
                    if (1) {
124
125
126
127
128
129
130
131
//                        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] << ", ";
                        }
Damien Leroux's avatar
Damien Leroux committed
132
133
                        ss << ')' << std::endl;
                        msg_handler_t::cout() << ss.str();
134
                    }
135
//                    std::thread::id this_id = std::this_thread::get_id();
136
//                                active_settings->thread_stacks[this_id].push_back(func_name);
137
//                    MSG_DEBUG("[" << this_id << ',' << (this_id == active_settings->main_thread) << "] ENTER " << func_name);
Damien Leroux's avatar
Damien Leroux committed
138
139
//                     msg_handler_t::run_hooks();

140
141
                    auto ret = func(*args...);
//                                active_settings->thread_stacks[this_id].pop_back();
142
//                    msg_handler_t::run_hooks();
143
144
145
                    unregister_task_in_progress(func, {*args}...);
                    TaskPool::release_slot();
//                    TaskPool::remove_task(m_thread->get_id());
146
//                    MSG_DEBUG("[" << this_id << ',' << (this_id == active_settings->main_thread) << "] LEAVE " << func_name);
147
148
149
//                     mutex.lock();
//                     m_started_cv.notify_all();
//                     mutex.unlock();
150
151
                    return ret;
                })
152
            , mutex()
153
154
155
156
157
158
            , 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());
159
//             std::unique_lock<std::mutex> lock(mutex);
160
161
162
163
164
//            if (!m_started) {
//                m_started.store(true);
                TaskPool::enqueue(this);
//            }
        }
Damien Leroux's avatar
Damien Leroux committed
165

Damien Leroux's avatar
Damien Leroux committed
166
167
        async_computation(CachingPolicy _Sync, std::function<Ret(Args...)>& proxy,
                          computation_function_pointer_type func,
Damien Leroux's avatar
Damien Leroux committed
168
169
                          const value<typename clean_type<Args>::type>&... args)
            : dependencies(args...)
170
171
            , m_storage_init(false)
//            , m_thread()
Damien Leroux's avatar
Damien Leroux committed
172
            , m_storage()
Damien Leroux's avatar
Damien Leroux committed
173
            /*, m_future(active_settings->enqueue(_Sync, func, *args...))*/
174
175
176
//            , m_promise()
            , m_future()
            , m_compute([=] () {
177
178
179
                {
                    std::unique_lock<std::mutex> lock(mutex);
                    m_started = true;
180
                    m_started_cv.notify_all();
181
182
183
184
185
186
                }

//                     {
//                         std::unique_lock<std::mutex> lock(mutex);
//                         m_started_cv.notify_all();
//                     }
187
188
189
190
191
192
193
194
195
196
197
198
/*
                    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);
Damien Leroux's avatar
Damien Leroux committed
199
200
                    if (1) {
//                        msg_handler_t::cout() << "INVOKING " << func_name << "(…)" << std::endl;
201
                        std::stringstream ss;
Damien Leroux's avatar
Damien Leroux committed
202
                        ss << "INVOKING " << func_name << "(" << std::endl;
203
204
205
206
207
                        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] << ", ";
                        }
Damien Leroux's avatar
Damien Leroux committed
208
209
                        ss << ')' << std::endl;
                        msg_handler_t::cout() << ss.str();
210
                    }
211
//                    std::thread::id this_id = std::this_thread::get_id();
212
//                                active_settings->thread_stacks[this_id].push_back(func_name);
213
//                    MSG_DEBUG("[" << this_id << ',' << (this_id == active_settings->main_thread) << "] p ENTER " << func_name);
214
215
//                    msg_handler_t::run_hooks();
//                    m_promise.set_value(proxy(*args...));
216
//                     mutex.lock();
217
                    auto ret = proxy(*args...);
218
//                     mutex.unlock();
219
//                    MSG_DEBUG("[" << this_id << ',' << (this_id == active_settings->main_thread) << "] p LEAVE " << func_name);
220
221
222
223
224
//                                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());
225
226
227
228
229

//                     mutex.lock();
//                     m_started_cv.notify_all();
//                     mutex.unlock();

230
231
                    return ret;
                })
232
            /*, m_future(std::async(func, *args...))*/
233
            , mutex()
234
235
236
237
238
239
            , 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());
240
//             std::unique_lock<std::mutex> lock(mutex);
241
242
243
244
245
246
247
248
249
250
251
252
253
254
//            if (!m_started) {
//                m_started.store(true);
                TaskPool::enqueue(this);
//            }
        }

        bool has_run() const override { return m_started; }

        std::thread::id run() override
        {
            if (m_started) {
                MSG_ERROR("Task has already run.", "");
                return {};
            } else {
255
                std::unique_lock<std::mutex> lock(mutex);
256
257
258
259
260
261
262
263
                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();
                return {};
            }
        }
Damien Leroux's avatar
Damien Leroux committed
264
265
266

        value_type& __get_noconst()
        {
Damien Leroux's avatar
Damien Leroux committed
267
268
269
270
            /*std::lock_guard<decltype(mutex)> read_guard(mutex);*/
            /*if (m_future.valid()) {*/
                /*return m_storage = m_future.get();*/
            /*}*/
271
272
273
274
275
//            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
276
            }
277
//             TaskPool::wait([&lock, this]() {
278
//                    mutex.lock();
279
280
281
            TaskPool::release_slot();
            {
                if (!m_started.load()) {
282
                    std::unique_lock<std::mutex> lock(mutex);
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
                    m_started_cv.wait(lock, [this]() { return m_started.load(); });
                }
//                 if (!m_storage_init && m_future.valid()) {
                    bool waiting_for_storage = m_storage_waiting.exchange(true);
                    if (waiting_for_storage) {
                        std::unique_lock<std::mutex> lock(mutex);
                        m_storage_waiting_cv.wait(lock, [this] () -> bool { return m_storage_init; });
                    } else {
//                         mutex.unlock();
                        m_storage = m_future.get();
                        std::unique_lock<std::mutex> lock(mutex);
//                         mutex.lock();
                        m_storage_init.store(true);
                        m_storage_waiting_cv.notify_all();
//                         mutex.unlock();
298
                    }
299
300
301
//                 }
            }
            TaskPool::take_slot();
302
//                    mutex.unlock();
303
//             });
304
305
306
//                mutex.lock();
//            }
//            mutex.unlock();
Damien Leroux's avatar
Damien Leroux committed
307
308
309
310
311
312
313
314
315
316
            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;
317
        mutable std::atomic_bool m_storage_init;
318
//        std::unique_ptr<std::thread> m_thread;
319
320
        mutable value_type m_storage;
        mutable std::future<Ret> m_future;
321
        std::function<Ret()> m_compute;
322
323
324
325
326
        mutable std::mutex mutex;
        mutable std::atomic_bool m_started;
        mutable std::condition_variable m_started_cv;
        mutable std::atomic_bool m_storage_waiting;
        mutable std::condition_variable m_storage_waiting_cv;
Damien Leroux's avatar
Damien Leroux committed
327
328
    };

329
330
331
332
333
334
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)
    {
335
336
337
338
        /*struct _mac_guard {*/
            /*_mac_guard() { __get_in_progress_mutex<Ret, Args...>().lock(); }*/
            /*~_mac_guard() { __get_in_progress_mutex<Ret, Args...>().unlock(); }*/
        /*} _;*/
339
//         std::lock_guard<std::mutex> scope_lock(__get_in_progress_mutex<Ret, Args...>());
340
341
342
343
344
345
346
        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...));
347
            lock_in_progress_mutex<Ret, Args...> _;
348
349
350
351
352
353
354
355
356
357
358
359
            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)
    {
360
361
362
363
        /*struct _mac_guard {*/
            /*_mac_guard() { __get_in_progress_mutex<Ret, Args...>().lock(); }*/
            /*~_mac_guard() { __get_in_progress_mutex<Ret, Args...>().unlock(); }*/
        /*} _;*/
364
365
//         std::lock_guard<std::mutex> scope_lock(__get_in_progress_mutex<Ret, Args...>());
        __get_in_progress_mutex<Ret, Args...>().lock();
366
367
        auto& r = __get_in_progress_registry<Ret, Args...>();
        auto exists = r.find(func, args...);
368
        __get_in_progress_mutex<Ret, Args...>().unlock();
369
370
371
372
        if (exists) {
            return *exists;
        } else {
            std::shared_ptr<async_computation<Ret(Args...)>>
Damien Leroux's avatar
Damien Leroux committed
373
                ac(new async_computation<Ret(Args...)>(_Sync, proxy, func, args...));
374
            lock_in_progress_mutex<Ret, Args...> _;
375
376
377
378
            return r.get(func, args...) = register_task_in_progress(ac, func, args...);
        }
    }

Damien Leroux's avatar
Damien Leroux committed
379

380
381
382
383
384
385
#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
386
387
388
389
template <typename Ret, typename... Args>
    struct cached_computation<Ret(Args...)> {
        typedef Ret value_type;

390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
        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)
        {
428
            static disk_hashtable<Ret(Args...)> dht(MESSAGE(active_settings->work_directory << '/' << active_settings->name << ".cache/" << m_name));
429
430
431
432
433
434
435
436
437
438
439
440
            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
441
442
443
444
445
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;

446
        computed_value(CachingPolicy _Sync, Ret (*func) (Args...), const value<typename clean_type<Args>::type>&... args)
Damien Leroux's avatar
Damien Leroux committed
447
            : m_hash(compute_hash(args...))
448
            , m_task(make_async_computation<Ret, Args...>(_Sync, func, args...))
Damien Leroux's avatar
Damien Leroux committed
449
450
451
452
        {}

        virtual
            value_type& operator * ()
453
            override { return m_task->__get_noconst(); }
Damien Leroux's avatar
Damien Leroux committed
454
455
        virtual
            value_type* operator -> ()
456
            override { return &m_task->__get_noconst(); }
Damien Leroux's avatar
Damien Leroux committed
457
458
        virtual
            const value_type& operator * () const
459
            override { return m_task->__get_const(); }
Damien Leroux's avatar
Damien Leroux committed
460
461
        virtual
            const value_type* operator -> () const
462
            override { return &m_task->__get_const(); }
Damien Leroux's avatar
Damien Leroux committed
463
464
465
466
467
468
469
470

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

471
    /*protected:*/
Damien Leroux's avatar
Damien Leroux committed
472
        size_t m_hash;
473
        std::shared_ptr<async_computation<Ret(Args...)>> m_task;
Damien Leroux's avatar
Damien Leroux committed
474
475
476
477
478
479
480
    };

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;

481
        cached_computed_value(CachingPolicy _Sync, Ret (*func) (Args...), const value<typename clean_type<Args>::type>&... args)
482
            : m_comp(get_func_name(func), func, args...)
Damien Leroux's avatar
Damien Leroux committed
483
            , m_comp_proxy([this](Args... x) { return m_comp(x...); })
484
            , m_task(make_async_computation<Ret, Args...>(_Sync, func, m_comp_proxy, args...))
Damien Leroux's avatar
Damien Leroux committed
485
        {}
486
487
            /*m_hash = m_comp.m_md5_hash.md5.context;*/
        /*}*/
Damien Leroux's avatar
Damien Leroux committed
488
489
490

        virtual
            value_type& operator * ()
491
            override { return m_task->__get_noconst(); }
Damien Leroux's avatar
Damien Leroux committed
492
493
        virtual
            value_type* operator -> ()
494
            override { return &m_task->__get_noconst(); }
Damien Leroux's avatar
Damien Leroux committed
495
496
        virtual
            const value_type& operator * () const
497
            override { return m_task->__get_const(); }
Damien Leroux's avatar
Damien Leroux committed
498
499
        virtual
            const value_type* operator -> () const
500
            override { return &m_task->__get_const(); }
Damien Leroux's avatar
Damien Leroux committed
501
502

        virtual
503
504
505
            size_t hash() const override
            /*override { return m_hash; }*/
            {
506
                (void)m_task->__get_const();
507
508
509
                MSG_ERROR("hash is not implemented for cached_computed_value", "");
                return 0;
                /*return m_comp.m_md5_hash.md5.context;*/
510
            }
Damien Leroux's avatar
Damien Leroux committed
511
        virtual
512
513
            md5_digest& md5(md5_digest& md) const override
            {
514
                (void)m_task->__get_const();
515
516
517
518
                /*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;
519
520
            }
            /*override { return md; }*/
Damien Leroux's avatar
Damien Leroux committed
521

522
    /*protected:*/
Damien Leroux's avatar
Damien Leroux committed
523
524
        cached_computation<Ret(Args...)> m_comp;
        std::function<Ret(Args...)> m_comp_proxy;
525
        std::shared_ptr<async_computation<Ret(Args...)>> m_task;
526
        /*size_t m_hash;*/
Damien Leroux's avatar
Damien Leroux committed
527
528
529
    };


Damien Leroux's avatar
Damien Leroux committed
530
531
532
/*template <typename X>*/
/*value<X> as_value(X&& x) { return {x}; }*/

Damien Leroux's avatar
Damien Leroux committed
533
534
535
536
537
538
539
540
541
542
543
#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


544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
#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
559
560
561


template <typename Ret, typename... Args>
562
563
564
struct with_disk_cache_traits {
	typedef cached_computed_value<Ret(Args...)> type;
};
Damien Leroux's avatar
Damien Leroux committed
565
566

template <typename Ret, typename... Args>
567
568
569
struct without_disk_cache_traits {
	typedef computed_value<Ret(Args...)> type;
};
Damien Leroux's avatar
Damien Leroux committed
570

571
572
template <int _Policy, typename Ret, typename... Args>
struct disk_cache_traits;
Damien Leroux's avatar
Damien Leroux committed
573

574
template <typename Ret, typename... Args>
575
struct disk_cache_traits<Oneshot, Ret, Args...> : without_disk_cache_traits<Ret, Args...> {};
576
577

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

580
581
582
583
584
585
586
template <typename Ret, typename... Args>
struct with_mem_cache_traits {
	typedef value<Ret>& return_type;

	template <typename _Maker>
		static
		return_type
587
		create(CachingPolicy _Sync, Ret (&f) (Args...), const clean_value_type<Args>&... x)
588
		{
589
590
            static std::recursive_mutex _;
            std::lock_guard<decltype(_)> lock_guard(_);
591

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

594
595
596
            /*if (ret_in_progress) {*/
                /*return *ret_in_progress;*/
            /*}*/
597

598
599
600
			/*MSG_DEBUG("new value with mem cache");*/
			return_type ret = __get_registry<Ret, Args...>().get(&f, x...);
			if (!ret.valid()) {
601
				ret = new _Maker(_Sync, f, x...);
602
603
604
605
606
607
608
609
610
611
612
613
			}
			return ret;
		}
};

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

	template <typename _Maker>
		static
		return_type
614
		create(CachingPolicy _Sync, Ret (&f) (Args...), const clean_value_type<Args>&... x)
615
		{
616
617
            static std::recursive_mutex _;
            std::lock_guard<decltype(_)> lock_guard(_);
618
            /*value<Ret>* ret_in_progress = __get_in_progress_registry<Ret, Args...>().find(&f, x...);*/
619

620
621
622
            /*if (ret_in_progress) {*/
                /*return *ret_in_progress;*/
            /*}*/
623

624
			/*MSG_DEBUG("new value without mem cache");*/
625
			return_type ret = new _Maker(_Sync, f, x...);
626
627
628
629
630
631
632
633
			return ret;
		}
};

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

template <typename Ret, typename... Args>
634
struct mem_cache_traits<Oneshot, Ret, Args...> : without_mem_cache_traits<Ret, Args...> {};
635
636

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

639
640
template <CachingPolicy _Policy = Oneshot, typename Ret, typename... Args>
typename mem_cache_traits<_Policy & Mem, Ret, Args...>::return_type
641
642
make_value(Ret (&f) (Args...), const clean_value_type<Args>&... x)
{
643
644
	typedef mem_cache_traits<_Policy & Mem, Ret, Args...> mem_policy;
	typedef disk_cache_traits<_Policy & Disk, Ret, Args...> disk_policy;
645
	return mem_policy::template create<typename disk_policy::type>(_Policy, f, x...);
646
}
Damien Leroux's avatar
Damien Leroux committed
647
648


649
650
template <typename... X> struct tuple;

651
template <CachingPolicy C, typename F, typename R, typename P> struct make_coll_impl;
Damien Leroux's avatar
Damien Leroux committed
652
653
654
655
656
657
658
659
660
661

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;
662
template <> struct type_lists_must_be_identical<tuple<>, tuple<>> {};
Damien Leroux's avatar
Damien Leroux committed
663
664

template <typename A0, typename... A, typename B0, typename... B>
665
666
    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
667
668
669
        static_assert(types_must_be_identical<A0, B0>::value, "INVALID PARAMETER TYPE.");
    };

670
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs, typename... ErrArgs>
671
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<>, tuple<ErrArgs...>> {
Damien Leroux's avatar
Damien Leroux committed
672
673
674
675
    void operator () (collection<Ret>& coll,
                      Ret (&f) (FuncArgs...),
                      ErrArgs... errargs)
    {
676
        type_lists_must_be_identical<tuple<FuncArgs...>, tuple<typename ErrArgs::value_type...>>();
677
        coll.push_back(make_value<_Policy>(f, errargs...));
Damien Leroux's avatar
Damien Leroux committed
678
679
680
    }
};

681
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs>
682
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<>, tuple<clean_value_type<FuncArgs>...>> {
Damien Leroux's avatar
Damien Leroux committed
683
684
685
686
    void operator () (collection<Ret>& coll,
                      Ret (&f) (FuncArgs...),
                      const value<typename clean_type<FuncArgs>::type>&... pargs)
    {
687
        coll.push_back(make_value<_Policy>(f, pargs...));
Damien Leroux's avatar
Damien Leroux committed
688
689
690
691
    }
};


692
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs, typename VT, typename... ArgsRemaining, typename... PreviousArgs>
693
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<value<VT>, ArgsRemaining...>, tuple<PreviousArgs...>> {
Damien Leroux's avatar
Damien Leroux committed
694
695
696
697
698
699
700
    void operator () (collection<Ret>& coll,
                      Ret (&f) (FuncArgs...),
                      const value<VT>& car,
                      const ArgsRemaining&... cdr,
                      const PreviousArgs&... pargs)
    {
        make_coll_impl<
701
			_Policy,
Damien Leroux's avatar
Damien Leroux committed
702
            Ret(FuncArgs...),
703
704
            tuple<ArgsRemaining...>,
            tuple<PreviousArgs..., value<VT>>>() (coll, f, cdr..., pargs..., car);
Damien Leroux's avatar
Damien Leroux committed
705
706
707
    }
};

708
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs, typename T, typename... ArgsRemaining, typename... PreviousArgs>
709
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<range<T>, ArgsRemaining...>, tuple<PreviousArgs...>> {
Damien Leroux's avatar
Damien Leroux committed
710
711
712
713
714
715
716
717
718
    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<
719
				_Policy,
Damien Leroux's avatar
Damien Leroux committed
720
                Ret(FuncArgs...),
721
722
                tuple<ArgsRemaining...>,
                tuple<PreviousArgs..., vtype>>() (coll, f, cdr..., pargs..., v);
Damien Leroux's avatar
Damien Leroux committed
723
724
725
726
        }
    }
};

727
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs, typename T, typename... ArgsRemaining, typename... PreviousArgs>
728
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<collection<T>, ArgsRemaining...>, tuple<PreviousArgs...>> {
Damien Leroux's avatar
Damien Leroux committed
729
730
731
732
733
734
735
736
737
    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<
738
				_Policy,
Damien Leroux's avatar
Damien Leroux committed
739
                Ret(FuncArgs...),
740
741
                tuple<ArgsRemaining...>,
                tuple<PreviousArgs..., vtype>>() (coll, f, cdr..., pargs..., v);
Damien Leroux's avatar
Damien Leroux committed
742
743
744
745
        }
    }
};

746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
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
765
766


767
template <CachingPolicy _Policy = Oneshot, typename Ret, typename... Args, typename... CollArgs>
Damien Leroux's avatar
Damien Leroux committed
768
769
770
771
collection<Ret>
make_collection(Ret (&f) (Args...), CollArgs... args)
{
    collection<Ret> ret;
772
    make_coll_impl<_Policy, Ret(Args...), tuple<CollArgs...>, tuple<>>() (ret, f, args...);
Damien Leroux's avatar
Damien Leroux committed
773
774
775
776
    return ret;
}


777

778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
//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 << '}';
//}
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816



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
817
818
#endif