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);
123
                    if (0) {
124
125
126
127
//                        msg_handler_t::cout() << "INVOKING " << func_name << "(…)" << std::endl;
                        std::stringstream ss;
                        ss << "INVOKING " << func_name << "(" << std::endl;
                        std::vector<std::string> avec;
128
                        do_with_arg_pack(avec.push_back(SPELL_STRING(args)));
129
130
131
                        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);
199
                    if (0) {
Damien Leroux's avatar
Damien Leroux committed
200
//                        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
                        std::vector<std::string> avec;
204
                        do_with_arg_pack(avec.push_back(SPELL_STRING(args)));
205
206
207
                        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
        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;
402
                do_with_arg_pack(avec.push_back(SPELL_STRING(args)));
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
                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(SPELL_STRING(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