cache2.h 23.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"
Damien Leroux's avatar
Damien Leroux committed
23
24


25
26
27
28
29
30
31
32
33
34
35
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>
36
37
38
39
40
41
    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>...>&
42
43
__get_in_progress_registry()
{
44
45
46
    static computation_registry<std::shared_ptr<async_computation<Ret(Args...)>>,
                                Ret (*) (Args...),
                                value<typename clean_type<Args>::type>...> _reg_;
47
48
49
50
51
52
53
54
55
    /*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>
56
57
58
void
unregister_task_in_progress(Ret (*f) (Args...),
                            const value<typename clean_type<Args>::type>&... args)
59
60
{
    __get_in_progress_mutex<Ret, Args...>().lock();
61
    __get_in_progress_registry<Ret, Args...>().remove(f, args...);
62
63
64
65
66
    __get_in_progress_mutex<Ret, Args...>().unlock();
}


template <typename Ret, typename... Args>
67
68
69
70
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)
71
{
Damien Leroux's avatar
Damien Leroux committed
72
    /*__get_in_progress_mutex<Ret, Args...>().lock();*/
73
    __get_in_progress_registry<Ret, Args...>().get(f, args...) = v;
Damien Leroux's avatar
Damien Leroux committed
74
    /*__get_in_progress_mutex<Ret, Args...>().unlock();*/
75
    return v;
76
77
}

Damien Leroux's avatar
Damien Leroux committed
78
79
80
81
82
83
84
85

template <typename Ret, typename... Args>
    struct async_computation<Ret(Args...)> {
        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;

86
        async_computation(CachingPolicy _Sync, computation_function_pointer_type func,
Damien Leroux's avatar
Damien Leroux committed
87
88
89
                          const value<typename clean_type<Args>::type>&... args)
            : dependencies(args...)
            , m_storage()
90
91
92
93
            , m_future(active_settings
                        ->enqueue(_Sync,
                            [=] (Args... args)
                            {
Damien Leroux's avatar
Damien Leroux committed
94
95
96
97
98
99
                                std::string func_name = get_func_name(func);
                                chrono_trace _(func_name);
                                std::thread::id this_id = std::this_thread::get_id();
                                active_settings->thread_stacks[this_id].push_back(func_name);
                                /*MSG_DEBUG("[" << this_id << ',' << (this_id == active_settings->main_thread) << "] ENTER " << func_name);*/
                                msg_handler_t::run_hooks();
100
                                Ret ret = func(args...);
Damien Leroux's avatar
Damien Leroux committed
101
102
103
                                /*MSG_DEBUG("[" << this_id << ',' << (this_id == active_settings->main_thread) << "] LEAVE " << func_name);*/
                                active_settings->thread_stacks[this_id].pop_back();
                                msg_handler_t::run_hooks();
104
                                unregister_task_in_progress(func, {args}...);
105
106
                                return ret;
                            }, *args...))
107
            , mutex()
108
        {  }
Damien Leroux's avatar
Damien Leroux committed
109

Damien Leroux's avatar
Damien Leroux committed
110
111
        async_computation(CachingPolicy _Sync, std::function<Ret(Args...)>& proxy,
                          computation_function_pointer_type func,
Damien Leroux's avatar
Damien Leroux committed
112
113
114
                          const value<typename clean_type<Args>::type>&... args)
            : dependencies(args...)
            , m_storage()
Damien Leroux's avatar
Damien Leroux committed
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
            /*, m_future(active_settings->enqueue(_Sync, func, *args...))*/
            , m_future(active_settings
                        ->enqueue(_Sync,
                            [=] (Args... args)
                            {
                                std::string func_name = get_func_name(func);
                                chrono_trace _(func_name);
                                std::thread::id this_id = std::this_thread::get_id();
                                active_settings->thread_stacks[this_id].push_back(func_name);
                                /*MSG_DEBUG("[" << this_id << ',' << (this_id == active_settings->main_thread) << "] ENTER " << func_name);*/
                                msg_handler_t::run_hooks();
                                Ret ret = proxy(args...);
                                /*MSG_DEBUG("[" << this_id << ',' << (this_id == active_settings->main_thread) << "] LEAVE " << func_name);*/
                                active_settings->thread_stacks[this_id].pop_back();
                                msg_handler_t::run_hooks();
                                unregister_task_in_progress(func, {args}...);
                                return ret;
                            }, *args...))
133
            /*, m_future(std::async(func, *args...))*/
134
            , mutex()
Damien Leroux's avatar
Damien Leroux committed
135
136
137
138
        {}

        value_type& __get_noconst()
        {
Damien Leroux's avatar
Damien Leroux committed
139
140
141
142
            /*std::lock_guard<decltype(mutex)> read_guard(mutex);*/
            /*if (m_future.valid()) {*/
                /*return m_storage = m_future.get();*/
            /*}*/
143
            mutex.lock();
Damien Leroux's avatar
Damien Leroux committed
144
            if (m_future.valid()) {
Damien Leroux's avatar
Damien Leroux committed
145
                m_storage = m_future.get();
Damien Leroux's avatar
Damien Leroux committed
146
            }
Damien Leroux's avatar
Damien Leroux committed
147
            mutex.unlock();
Damien Leroux's avatar
Damien Leroux committed
148
149
150
151
152
153
154
155
156
157
158
159
            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;
        value_type m_storage;
        std::future<Ret> m_future;
Damien Leroux's avatar
Damien Leroux committed
160
        std::recursive_mutex mutex;
Damien Leroux's avatar
Damien Leroux committed
161
162
    };

163
164
165
166
167
168
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)
    {
169
170
171
172
173
        /*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...>());
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
        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)
    {
193
194
195
196
197
        /*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...>());
198
199
200
201
202
203
        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
204
                ac(new async_computation<Ret(Args...)>(_Sync, proxy, func, args...));
205
206
207
208
            return r.get(func, args...) = register_task_in_progress(ac, func, args...);
        }
    }

Damien Leroux's avatar
Damien Leroux committed
209

210
211
212
213
214
215
#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
216
217
218
219
template <typename Ret, typename... Args>
    struct cached_computation<Ret(Args...)> {
        typedef Ret value_type;

220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
        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)
        {
258
            static disk_hashtable<Ret(Args...)> dht(MESSAGE(active_settings->work_directory << "/cache/" << m_name));
259
260
261
262
263
264
265
266
267
268
269
270
            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
271
272
273
274
275
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;

276
        computed_value(CachingPolicy _Sync, Ret (*func) (Args...), const value<typename clean_type<Args>::type>&... args)
Damien Leroux's avatar
Damien Leroux committed
277
            : m_hash(compute_hash(args...))
278
            , m_task(make_async_computation<Ret, Args...>(_Sync, func, args...))
Damien Leroux's avatar
Damien Leroux committed
279
280
281
282
        {}

        virtual
            value_type& operator * ()
283
            override { return m_task->__get_noconst(); }
Damien Leroux's avatar
Damien Leroux committed
284
285
        virtual
            value_type* operator -> ()
286
            override { return &m_task->__get_noconst(); }
Damien Leroux's avatar
Damien Leroux committed
287
288
        virtual
            const value_type& operator * () const
289
            override { return m_task->__get_const(); }
Damien Leroux's avatar
Damien Leroux committed
290
291
        virtual
            const value_type* operator -> () const
292
            override { return &m_task->__get_const(); }
Damien Leroux's avatar
Damien Leroux committed
293
294
295
296
297
298
299
300

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

301
    /*protected:*/
Damien Leroux's avatar
Damien Leroux committed
302
        size_t m_hash;
303
        std::shared_ptr<async_computation<Ret(Args...)>> m_task;
Damien Leroux's avatar
Damien Leroux committed
304
305
306
307
308
309
310
    };

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;

311
        cached_computed_value(CachingPolicy _Sync, Ret (*func) (Args...), const value<typename clean_type<Args>::type>&... args)
312
            : m_comp(get_func_name(func), func, args...)
Damien Leroux's avatar
Damien Leroux committed
313
            , m_comp_proxy([this](Args... x) { return m_comp(x...); })
314
            , m_task(make_async_computation<Ret, Args...>(_Sync, func, m_comp_proxy, args...))
Damien Leroux's avatar
Damien Leroux committed
315
        {}
316
317
            /*m_hash = m_comp.m_md5_hash.md5.context;*/
        /*}*/
Damien Leroux's avatar
Damien Leroux committed
318
319
320

        virtual
            value_type& operator * ()
321
            override { return m_task->__get_noconst(); }
Damien Leroux's avatar
Damien Leroux committed
322
323
        virtual
            value_type* operator -> ()
324
            override { return &m_task->__get_noconst(); }
Damien Leroux's avatar
Damien Leroux committed
325
326
        virtual
            const value_type& operator * () const
327
            override { return m_task->__get_const(); }
Damien Leroux's avatar
Damien Leroux committed
328
329
        virtual
            const value_type* operator -> () const
330
            override { return &m_task->__get_const(); }
Damien Leroux's avatar
Damien Leroux committed
331
332

        virtual
333
334
335
            size_t hash() const override
            /*override { return m_hash; }*/
            {
336
                (void)m_task->__get_const();
337
338
339
                MSG_ERROR("hash is not implemented for cached_computed_value", "");
                return 0;
                /*return m_comp.m_md5_hash.md5.context;*/
340
            }
Damien Leroux's avatar
Damien Leroux committed
341
        virtual
342
343
            md5_digest& md5(md5_digest& md) const override
            {
344
                (void)m_task->__get_const();
345
346
347
348
                /*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;
349
350
            }
            /*override { return md; }*/
Damien Leroux's avatar
Damien Leroux committed
351

352
    /*protected:*/
Damien Leroux's avatar
Damien Leroux committed
353
354
        cached_computation<Ret(Args...)> m_comp;
        std::function<Ret(Args...)> m_comp_proxy;
355
        std::shared_ptr<async_computation<Ret(Args...)>> m_task;
356
        /*size_t m_hash;*/
Damien Leroux's avatar
Damien Leroux committed
357
358
359
    };


Damien Leroux's avatar
Damien Leroux committed
360
361
362
/*template <typename X>*/
/*value<X> as_value(X&& x) { return {x}; }*/

Damien Leroux's avatar
Damien Leroux committed
363
364
365
366
367
368
369
370
371
372
373
#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


374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
#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
389
390
391


template <typename Ret, typename... Args>
392
393
394
struct with_disk_cache_traits {
	typedef cached_computed_value<Ret(Args...)> type;
};
Damien Leroux's avatar
Damien Leroux committed
395
396

template <typename Ret, typename... Args>
397
398
399
struct without_disk_cache_traits {
	typedef computed_value<Ret(Args...)> type;
};
Damien Leroux's avatar
Damien Leroux committed
400

401
402
template <int _Policy, typename Ret, typename... Args>
struct disk_cache_traits;
Damien Leroux's avatar
Damien Leroux committed
403

404
template <typename Ret, typename... Args>
405
struct disk_cache_traits<Oneshot, Ret, Args...> : without_disk_cache_traits<Ret, Args...> {};
406
407

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

410
411
412
413
414
415
416
template <typename Ret, typename... Args>
struct with_mem_cache_traits {
	typedef value<Ret>& return_type;

	template <typename _Maker>
		static
		return_type
417
		create(CachingPolicy _Sync, Ret (&f) (Args...), const clean_value_type<Args>&... x)
418
		{
419
420
            static std::recursive_mutex _;
            std::lock_guard<decltype(_)> lock_guard(_);
421

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

424
425
426
            /*if (ret_in_progress) {*/
                /*return *ret_in_progress;*/
            /*}*/
427

428
429
430
			/*MSG_DEBUG("new value with mem cache");*/
			return_type ret = __get_registry<Ret, Args...>().get(&f, x...);
			if (!ret.valid()) {
431
				ret = new _Maker(_Sync, f, x...);
432
433
434
435
436
437
438
439
440
441
442
443
			}
			return ret;
		}
};

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

	template <typename _Maker>
		static
		return_type
444
		create(CachingPolicy _Sync, Ret (&f) (Args...), const clean_value_type<Args>&... x)
445
		{
446
447
            static std::recursive_mutex _;
            std::lock_guard<decltype(_)> lock_guard(_);
448
            /*value<Ret>* ret_in_progress = __get_in_progress_registry<Ret, Args...>().find(&f, x...);*/
449

450
451
452
            /*if (ret_in_progress) {*/
                /*return *ret_in_progress;*/
            /*}*/
453

454
			/*MSG_DEBUG("new value without mem cache");*/
455
			return_type ret = new _Maker(_Sync, f, x...);
456
457
458
459
460
461
462
463
			return ret;
		}
};

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

template <typename Ret, typename... Args>
464
struct mem_cache_traits<Oneshot, Ret, Args...> : without_mem_cache_traits<Ret, Args...> {};
465
466

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

469
470
template <CachingPolicy _Policy = Oneshot, typename Ret, typename... Args>
typename mem_cache_traits<_Policy & Mem, Ret, Args...>::return_type
471
472
make_value(Ret (&f) (Args...), const clean_value_type<Args>&... x)
{
473
474
475
	typedef mem_cache_traits<_Policy & Mem, Ret, Args...> mem_policy;
	typedef disk_cache_traits<_Policy & Disk, Ret, Args...> disk_policy;
	return mem_policy::template create<typename disk_policy::type>(_Policy & Sync, f, x...);
476
}
Damien Leroux's avatar
Damien Leroux committed
477
478


479
480
template <typename... X> struct tuple;

481
template <CachingPolicy C, typename F, typename R, typename P> struct make_coll_impl;
Damien Leroux's avatar
Damien Leroux committed
482
483
484
485
486
487
488
489
490
491

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;
492
template <> struct type_lists_must_be_identical<tuple<>, tuple<>> {};
Damien Leroux's avatar
Damien Leroux committed
493
494

template <typename A0, typename... A, typename B0, typename... B>
495
496
    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
497
498
499
        static_assert(types_must_be_identical<A0, B0>::value, "INVALID PARAMETER TYPE.");
    };

500
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs, typename... ErrArgs>
501
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<>, tuple<ErrArgs...>> {
Damien Leroux's avatar
Damien Leroux committed
502
503
504
505
    void operator () (collection<Ret>& coll,
                      Ret (&f) (FuncArgs...),
                      ErrArgs... errargs)
    {
506
        type_lists_must_be_identical<tuple<FuncArgs...>, tuple<typename ErrArgs::value_type...>>();
507
        coll.push_back(make_value<_Policy>(f, errargs...));
Damien Leroux's avatar
Damien Leroux committed
508
509
510
    }
};

511
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs>
512
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<>, tuple<clean_value_type<FuncArgs>...>> {
Damien Leroux's avatar
Damien Leroux committed
513
514
515
516
    void operator () (collection<Ret>& coll,
                      Ret (&f) (FuncArgs...),
                      const value<typename clean_type<FuncArgs>::type>&... pargs)
    {
517
        coll.push_back(make_value<_Policy>(f, pargs...));
Damien Leroux's avatar
Damien Leroux committed
518
519
520
521
    }
};


522
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs, typename VT, typename... ArgsRemaining, typename... PreviousArgs>
523
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<value<VT>, ArgsRemaining...>, tuple<PreviousArgs...>> {
Damien Leroux's avatar
Damien Leroux committed
524
525
526
527
528
529
530
    void operator () (collection<Ret>& coll,
                      Ret (&f) (FuncArgs...),
                      const value<VT>& car,
                      const ArgsRemaining&... cdr,
                      const PreviousArgs&... pargs)
    {
        make_coll_impl<
531
			_Policy,
Damien Leroux's avatar
Damien Leroux committed
532
            Ret(FuncArgs...),
533
534
            tuple<ArgsRemaining...>,
            tuple<PreviousArgs..., value<VT>>>() (coll, f, cdr..., pargs..., car);
Damien Leroux's avatar
Damien Leroux committed
535
536
537
    }
};

538
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs, typename T, typename... ArgsRemaining, typename... PreviousArgs>
539
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<range<T>, ArgsRemaining...>, tuple<PreviousArgs...>> {
Damien Leroux's avatar
Damien Leroux committed
540
541
542
543
544
545
546
547
548
    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<
549
				_Policy,
Damien Leroux's avatar
Damien Leroux committed
550
                Ret(FuncArgs...),
551
552
                tuple<ArgsRemaining...>,
                tuple<PreviousArgs..., vtype>>() (coll, f, cdr..., pargs..., v);
Damien Leroux's avatar
Damien Leroux committed
553
554
555
556
        }
    }
};

557
template <CachingPolicy _Policy, typename Ret, typename... FuncArgs, typename T, typename... ArgsRemaining, typename... PreviousArgs>
558
struct make_coll_impl<_Policy, Ret(FuncArgs...), tuple<collection<T>, ArgsRemaining...>, tuple<PreviousArgs...>> {
Damien Leroux's avatar
Damien Leroux committed
559
560
561
562
563
564
565
566
567
    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<
568
				_Policy,
Damien Leroux's avatar
Damien Leroux committed
569
                Ret(FuncArgs...),
570
571
                tuple<ArgsRemaining...>,
                tuple<PreviousArgs..., vtype>>() (coll, f, cdr..., pargs..., v);
Damien Leroux's avatar
Damien Leroux committed
572
573
574
575
        }
    }
};

576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
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
595
596


597
template <CachingPolicy _Policy = Oneshot, typename Ret, typename... Args, typename... CollArgs>
Damien Leroux's avatar
Damien Leroux committed
598
599
600
601
collection<Ret>
make_collection(Ret (&f) (Args...), CollArgs... args)
{
    collection<Ret> ret;
602
    make_coll_impl<_Policy, Ret(Args...), tuple<CollArgs...>, tuple<>>() (ret, f, args...);
Damien Leroux's avatar
Damien Leroux committed
603
604
605
606
    return ret;
}


607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646

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 << '}';
}



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
647
648
#endif