Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
f37b9dd0d7c7126bc1c3a7e327f20cc312ce6808
[simgrid.git] / include / xbt / functional.hpp
1 /* Copyright (c) 2015-2016. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #ifndef XBT_FUNCTIONAL_HPP
8 #define XBT_FUNCTIONAL_HPP
9
10 #include <cstddef>
11 #include <cstdlib>
12
13 #include <exception>
14 #include <functional>
15 #include <memory>
16 #include <string>
17 #include <tuple>
18 #include <utility>
19 #include <vector>
20
21 #include <xbt/sysdep.h>
22 #include <xbt/utility.hpp>
23
24 namespace simgrid {
25 namespace xbt {
26
27 template<class F>
28 class MainFunction {
29 private:
30   F code_;
31   std::shared_ptr<const std::vector<std::string>> args_;
32 public:
33   MainFunction(F code, std::vector<std::string> args) :
34     code_(std::move(code)),
35     args_(std::make_shared<const std::vector<std::string>>(std::move(args)))
36   {}
37   int operator()() const
38   {
39     const int argc = args_->size();
40     std::vector<std::string> args = *args_;
41     std::unique_ptr<char*[]> argv(new char*[argc + 1]);
42     for (int i = 0; i != argc; ++i)
43       argv[i] = args[i].empty() ? const_cast<char*>(""): &args[i].front();
44     argv[argc] = nullptr;
45     return code_(argc, argv.get());
46   }
47 };
48
49 template<class F> inline
50 std::function<void()> wrapMain(F code, std::vector<std::string> args)
51 {
52   return MainFunction<F>(std::move(code), std::move(args));
53 }
54
55 template<class F> inline
56 std::function<void()> wrapMain(F code, int argc, const char*const argv[])
57 {
58   std::vector<std::string> args(argv, argv + argc);
59   return MainFunction<F>(std::move(code), std::move(args));
60 }
61
62 namespace bits {
63 template <class F, class Tuple, std::size_t... I>
64 constexpr auto apply(F&& f, Tuple&& t, simgrid::xbt::index_sequence<I...>)
65   -> decltype(std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...))
66 {
67   return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
68 }
69 }
70
71 /** Call a functional object with the values in the given tuple (from C++17)
72  *
73  *  @code{.cpp}
74  *  int foo(int a, bool b);
75  *
76  *  auto args = std::make_tuple(1, false);
77  *  int res = apply(foo, args);
78  *  @encode
79  **/
80 template <class F, class Tuple>
81 constexpr auto apply(F&& f, Tuple&& t)
82   -> decltype(simgrid::xbt::bits::apply(
83     std::forward<F>(f),
84     std::forward<Tuple>(t),
85     simgrid::xbt::make_index_sequence<
86       std::tuple_size<typename std::decay<Tuple>::type>::value
87     >()))
88 {
89   return simgrid::xbt::bits::apply(
90     std::forward<F>(f),
91     std::forward<Tuple>(t),
92     simgrid::xbt::make_index_sequence<
93       std::tuple_size<typename std::decay<Tuple>::type>::value
94     >());
95 }
96
97 template<class T> class Task;
98
99 /** Type-erased run-once task
100  *
101  *  * Like std::function but callable only once.
102  *    However, it works with move-only types.
103  *
104  *  * Like std::packaged_task<> but without the shared state.
105  */
106 template<class R, class... Args>
107 class Task<R(Args...)> {
108 private:
109   // Type-erasure for the code:
110   class Base {
111   public:
112     virtual ~Base() {}
113     virtual R operator()(Args...) = 0;
114   };
115   template<class F>
116   class Impl : public Base {
117   public:
118     Impl(F&& code) : code_(std::move(code)) {}
119     Impl(F const& code) : code_(code) {}
120     ~Impl() override {}
121     R operator()(Args... args) override
122     {
123       return code_(std::forward<Args>(args)...);
124     }
125   private:
126     F code_;
127   };
128   std::unique_ptr<Base> code_;
129 public:
130   Task() {}
131   Task(std::nullptr_t) {}
132
133   template<class F>
134   Task(F&& code) :
135     code_(new Impl<F>(std::forward<F>(code))) {}
136
137   operator bool() const { return code_ != nullptr; }
138   bool operator!() const { return code_ == nullptr; }
139
140   template<class... OtherArgs>
141   R operator()(OtherArgs&&... args)
142   {
143     std::unique_ptr<Base> code = std::move(code_);
144     return (*code)(std::forward<OtherArgs>(args)...);
145   }
146 };
147
148 template<class F, class... Args>
149 class TaskImpl {
150 private:
151   F code_;
152   std::tuple<Args...> args_;
153   typedef decltype(simgrid::xbt::apply(std::move(code_), std::move(args_))) result_type;
154 public:
155   TaskImpl(F code, std::tuple<Args...> args) :
156     code_(std::move(code)),
157     args_(std::move(args))
158   {}
159   result_type operator()()
160   {
161     return simgrid::xbt::apply(std::move(code_), std::move(args_));
162   }
163 };
164
165 template<class F, class... Args>
166 auto makeTask(F code, Args... args)
167 -> Task< decltype(code(std::move(args)...))() >
168 {
169   TaskImpl<F, Args...> task(std::move(code), std::make_tuple(std::move(args)...));
170   return std::move(task);
171 }
172
173 }
174 }
175
176 #endif