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
                    /*
124
125
126
127
128
129
130
131
132
133
134
                    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() << ')';
                    }
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);
138
                    msg_handler_t::run_hooks();
139
                     */
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
                    /*
200
201
202
203
204
205
206
207
208
209
210
                    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() << ')';
                    }
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
                     */
217
//                     mutex.lock();
218
                    auto ret = proxy(*args...);
219
//                     mutex.unlock();
220
//                    MSG_DEBUG("[" << this_id << ',' << (this_id == active_settings->main_thread) << "] p LEAVE " << func_name);
221
222
223
224
225
//                                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());
226
227
228
229
230

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

231
232
                    return ret;
                })
233
            /*, m_future(std::async(func, *args...))*/
234
            , mutex()
235
236
237
238
239
240
            , 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());
241
//             std::unique_lock<std::mutex> lock(mutex);
242
243
244
245
246
247
248
249
250
251
252
253
254
255
//            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 {
256
                std::unique_lock<std::mutex> lock(mutex);
257
258
259
260
261
262
263
264
                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
265
266
267

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

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

Damien Leroux's avatar
Damien Leroux committed
380

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

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
428
        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)
        {
429
            static disk_hashtable<Ret(Args...)> dht(MESSAGE(active_settings->work_directory << '/' << active_settings->name << ".cache/" << m_name));
430
431
432
433
434
435
436
437
438
439
440
441
            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
442
443
444
445
446
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;

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

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

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

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

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;

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

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

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

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


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

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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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


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

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

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

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


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


778

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



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