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

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

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

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


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

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


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

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


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

Damien Leroux's avatar
Damien Leroux committed
79
80

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

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

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

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

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

        bool has_run() const override { return m_started; }

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

        value_type& __get_noconst()
        {
Damien Leroux's avatar
Damien Leroux committed
241
242
243
244
            /*std::lock_guard<decltype(mutex)> read_guard(mutex);*/
            /*if (m_future.valid()) {*/
                /*return m_storage = m_future.get();*/
            /*}*/
245
246
247
248
249
//            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
250
            }
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
                TaskPool::wait([this]() {
//                    mutex.lock();
                    std::unique_lock<std::mutex> lock(mutex);
                    if (!m_started) {
                        m_started_cv.wait(lock, [this]() -> bool { return m_started; });
                    }
                    if (!m_storage_init && m_future.valid()) {
                        bool waiting_for_storage = m_storage_waiting.exchange(true);
                        if (waiting_for_storage) {
                            m_storage_waiting_cv.wait(lock, [this] () -> bool { return m_storage_init; });
                        } else {
                            m_storage = m_future.get();
                            m_storage_init.store(true);
                            m_storage_waiting_cv.notify_all();
                        }
                    }
//                    mutex.unlock();
                });
//                mutex.lock();
//            }
//            mutex.unlock();
Damien Leroux's avatar
Damien Leroux committed
272
273
274
275
276
277
278
279
280
281
            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;
282
283
        std::atomic_bool m_storage_init;
//        std::unique_ptr<std::thread> m_thread;
Damien Leroux's avatar
Damien Leroux committed
284
285
        value_type m_storage;
        std::future<Ret> m_future;
286
287
288
289
290
291
        std::function<Ret()> m_compute;
        std::mutex mutex;
        std::atomic_bool m_started;
        std::condition_variable m_started_cv;
        std::atomic_bool m_storage_waiting;
        std::condition_variable m_storage_waiting_cv;
Damien Leroux's avatar
Damien Leroux committed
292
293
    };

294
295
296
297
298
299
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)
    {
300
301
302
303
304
        /*struct _mac_guard {*/
            /*_mac_guard() { __get_in_progress_mutex<Ret, Args...>().lock(); }*/
            /*~_mac_guard() { __get_in_progress_mutex<Ret, Args...>().unlock(); }*/
        /*} _;*/
        std::lock_guard<std::mutex> scope_lock(__get_in_progress_mutex<Ret, Args...>());
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
        auto& r = __get_in_progress_registry<Ret, Args...>();
        auto exists = r.find(func, args...);
        if (exists) {
            return *exists;
        } else {
            std::shared_ptr<async_computation<Ret(Args...)>>
                ac(new async_computation<Ret(Args...)>(_Sync, func, args...));
            return r.get(func, args...) = register_task_in_progress(ac, func, args...);
        }
    }


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

Damien Leroux's avatar
Damien Leroux committed
340

341
342
343
344
345
346
#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
347
348
349
350
template <typename Ret, typename... Args>
    struct cached_computation<Ret(Args...)> {
        typedef Ret value_type;

351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
        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)
        {
389
            static disk_hashtable<Ret(Args...)> dht(MESSAGE(active_settings->work_directory << '/' << active_settings->name << ".cache/" << m_name));
390
391
392
393
394
395
396
397
398
399
400
401
            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
402
403
404
405
406
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;

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

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

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

432
    /*protected:*/
Damien Leroux's avatar
Damien Leroux committed
433
        size_t m_hash;
434
        std::shared_ptr<async_computation<Ret(Args...)>> m_task;
Damien Leroux's avatar
Damien Leroux committed
435
436
437
438
439
440
441
    };

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;

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

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

        virtual
464
465
466
            size_t hash() const override
            /*override { return m_hash; }*/
            {
467
                (void)m_task->__get_const();
468
469
470
                MSG_ERROR("hash is not implemented for cached_computed_value", "");
                return 0;
                /*return m_comp.m_md5_hash.md5.context;*/
471
            }
Damien Leroux's avatar
Damien Leroux committed
472
        virtual
473
474
            md5_digest& md5(md5_digest& md) const override
            {
475
                (void)m_task->__get_const();
476
477
478
479
                /*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;
480
481
            }
            /*override { return md; }*/
Damien Leroux's avatar
Damien Leroux committed
482

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


Damien Leroux's avatar
Damien Leroux committed
491
492
493
/*template <typename X>*/
/*value<X> as_value(X&& x) { return {x}; }*/

Damien Leroux's avatar
Damien Leroux committed
494
495
496
497
498
499
500
501
502
503
504
#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


505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
#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
520
521
522


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

template <typename Ret, typename... Args>
528
529
530
struct without_disk_cache_traits {
	typedef computed_value<Ret(Args...)> type;
};
Damien Leroux's avatar
Damien Leroux committed
531

532
533
template <int _Policy, typename Ret, typename... Args>
struct disk_cache_traits;
Damien Leroux's avatar
Damien Leroux committed
534

535
template <typename Ret, typename... Args>
536
struct disk_cache_traits<Oneshot, Ret, Args...> : without_disk_cache_traits<Ret, Args...> {};
537
538

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

541
542
543
544
545
546
547
template <typename Ret, typename... Args>
struct with_mem_cache_traits {
	typedef value<Ret>& return_type;

	template <typename _Maker>
		static
		return_type
548
		create(CachingPolicy _Sync, Ret (&f) (Args...), const clean_value_type<Args>&... x)
549
		{
550
551
            static std::recursive_mutex _;
            std::lock_guard<decltype(_)> lock_guard(_);
552

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

555
556
557
            /*if (ret_in_progress) {*/
                /*return *ret_in_progress;*/
            /*}*/
558

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

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

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

581
582
583
            /*if (ret_in_progress) {*/
                /*return *ret_in_progress;*/
            /*}*/
584

585
			/*MSG_DEBUG("new value without mem cache");*/
586
			return_type ret = new _Maker(_Sync, f, x...);
587
588
589
590
591
592
593
594
			return ret;
		}
};

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

template <typename Ret, typename... Args>
595
struct mem_cache_traits<Oneshot, Ret, Args...> : without_mem_cache_traits<Ret, Args...> {};
596
597

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

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


610
611
template <typename... X> struct tuple;

612
template <CachingPolicy C, typename F, typename R, typename P> struct make_coll_impl;
Damien Leroux's avatar
Damien Leroux committed
613
614
615
616
617
618
619
620
621
622

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;
623
template <> struct type_lists_must_be_identical<tuple<>, tuple<>> {};
Damien Leroux's avatar
Damien Leroux committed
624
625

template <typename A0, typename... A, typename B0, typename... B>
626
627
    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
628
629
630
        static_assert(types_must_be_identical<A0, B0>::value, "INVALID PARAMETER TYPE.");
    };

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

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


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

669
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs, typename T, typename... ArgsRemaining, typename... PreviousArgs>
670
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<range<T>, ArgsRemaining...>, tuple<PreviousArgs...>> {
Damien Leroux's avatar
Damien Leroux committed
671
672
673
674
675
676
677
678
679
    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<
680
				_Policy,
Damien Leroux's avatar
Damien Leroux committed
681
                Ret(FuncArgs...),
682
683
                tuple<ArgsRemaining...>,
                tuple<PreviousArgs..., vtype>>() (coll, f, cdr..., pargs..., v);
Damien Leroux's avatar
Damien Leroux committed
684
685
686
687
        }
    }
};

688
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs, typename T, typename... ArgsRemaining, typename... PreviousArgs>
689
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<collection<T>, ArgsRemaining...>, tuple<PreviousArgs...>> {
Damien Leroux's avatar
Damien Leroux committed
690
691
692
693
694
695
696
697
698
    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<
699
				_Policy,
Damien Leroux's avatar
Damien Leroux committed
700
                Ret(FuncArgs...),
701
702
                tuple<ArgsRemaining...>,
                tuple<PreviousArgs..., vtype>>() (coll, f, cdr..., pargs..., v);
Damien Leroux's avatar
Damien Leroux committed
703
704
705
706
        }
    }
};

707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
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
726
727


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


738

739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
//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 << '}';
//}
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777



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
778
779
#endif