libcoro  1.0
Coroutine support library for C++20
future_variant.h
1 #pragma once
2 #include "future.h"
3 #include <variant>
4 
5 namespace coro {
6 
7 namespace _details {
8  template<typename FutType, typename FutVariant>
9  struct future_variant_getter {
10  FutVariant *owner;
11  using RetVal = decltype(get<FutType>(*owner).get());
12  operator RetVal() {
13  auto &ft = get<FutType>(*owner);
14  return ft.get();
15  }
16  };
17 
18  template<typename FutVariant>
19  struct future_variant_getter<void, FutVariant> {
20  FutVariant *owner;
21  template<typename T>
22  operator T &&() {
23  if (holds_alternative<deferred_future<T> >(*owner)) {
24  return get<deferred_future<T> >(*owner).get();
25  } else {
26  return get<future<T> >(*owner).get();
27  }
28  }
29  };
30 
31 
32  class future_variant_interface {
33  public:
34  struct awaiter {
35  void *ptr;
36  std::coroutine_handle<> (*on_suspend)(void *ptr, std::coroutine_handle<> h);
37  bool await_ready() const {return ptr == nullptr;}
38  std::coroutine_handle<> await_suspend(std::coroutine_handle<> h) {
39  return on_suspend(ptr, h);
40  }
41  void await_resume() noexcept {}
42  };
43 
44  constexpr virtual ~future_variant_interface() = default;
45  virtual void destroy_at(void *ptr) const = 0;
46  virtual awaiter on_await(void *ptr) const = 0;
47  virtual void on_wait(void *ptr) const = 0;
48  };
49 
50  template<typename Fut>
51  class future_variant_impl : public future_variant_interface{
52  public:
53  virtual void destroy_at(void *ptr) const override {
54  std::destroy_at(reinterpret_cast<Fut *>(ptr));
55  }
56  virtual awaiter on_await(void *ptr) const override{
57  return {ptr, [](void *ptr, std::coroutine_handle<> h){
58  return reinterpret_cast<Fut *>(ptr)->await_suspend(h);
59  }};
60  }
61  virtual void on_wait(void *ptr) const override{
62  reinterpret_cast<Fut *>(ptr)->wait();
63  }
64  };
65 
66  template<>
67  class future_variant_impl<std::nullptr_t> : public future_variant_interface{
68  public:
69  virtual void destroy_at(void *) const override{}
70  virtual awaiter on_await(void *) const override{return {}; }
71  virtual void on_wait(void *) const override{}
72  };
73 
74  template<typename Fut>
75  inline constexpr future_variant_impl<Fut> future_variant_control = {};
76 }
77 
79 
105 template<typename ... Types>
107 public:
108 
109  future_variant() = default;
110  future_variant(const future_variant &) = delete;
111  future_variant &operator=(const future_variant &) = delete;
112  ~future_variant() {
113  control->destroy_at(buffer);
114  }
115 
117 
123  template<std::invocable<> Fn>
124  auto &operator<<(Fn &&fn) {
125  control->destroy_at(buffer);
126  using fut_type = std::invoke_result_t<Fn>;
127  static_assert(sizeof(fut_type) <= buffer_size, "Returned future is not expected");
128  fut_type *ptr = new(buffer) fut_type(fn());
129  control = &_details::future_variant_control<fut_type>;
130  return *ptr;
131  }
132 
134  void reset() {
135  control->destroy_at(buffer);
136  control = &_details::future_variant_control<std::nullptr_t>;
137  }
138 
140 
144  template<typename promise_type>
145  auto &get_promise(promise_type &p) {
146  using fut_type = typename promise_type::FutureType;
147  static_assert(sizeof(fut_type) <= buffer_size, "Future type is not expected");
148  fut_type *ptr = new(buffer) fut_type;
149  p = ptr->get_promise();
150  control = &_details::future_variant_control<fut_type>;
151  return *ptr;
152  }
153 
155 
160  template<typename fut_type, typename ... X>
161  friend fut_type &get(future_variant<X...> &me);
162 
164 
169  template<typename fut_type, typename ... X>
170  friend const fut_type &get(const future_variant<X...> &me);
171 
172 
174 
181  template<typename fut_type, typename ... X>
183 
184  template<typename FutType, typename FutVariant>
185  friend struct future_variant_getter;
186 
188 
196  template<typename fut_type = void>
197  _details::future_variant_getter<fut_type, future_variant> get() {
198  return {this};
199  }
200 
201  using awaiter = _details::future_variant_interface::awaiter;
202 
204 
211  awaiter operator co_await() {
212  return control->on_await(buffer);
213  }
214 
216  void wait() {
217  return control->on_wait(buffer);
218  }
219 
220 
221 protected:
222  static constexpr auto buffer_size = std::max({sizeof(future<Types>)...});
223  const _details::future_variant_interface *control = &_details::future_variant_control<std::nullptr_t>;
224  char buffer[buffer_size];
225 };
226 
227 template<typename fut_type, typename ... Types>
228 const fut_type &get(const future_variant<Types...> &me) {
229  if (me.control != &_details::future_variant_control<fut_type>) {
230  throw std::bad_variant_access();
231  }
232  return *reinterpret_cast<const fut_type *>(me.buffer);
233 }
234 
235 template<typename fut_type, typename ... Types>
236  fut_type &get( future_variant<Types...> &me) {
237  if (me.control != &_details::future_variant_control<fut_type>) {
238  throw std::bad_variant_access();
239  }
240  return *reinterpret_cast<fut_type *>(me.buffer);
241 }
242 
243 template<typename fut_type, typename ... Types>
244 bool holds_alternative(future_variant<Types...> &me) {
245  return (me.control == &_details::future_variant_control<fut_type>);
246 }
247 
248 
249 }
auto & operator<<(Fn &&fn)
Redirect return value to future object.
auto & get_promise(promise_type &p)
Initialize underlying future and retrieves promise.
void wait()
Helps to wait on future regardless on which variant is active.
friend fut_type & get(future_variant< X... > &me)
Retrieve reference to future - if it is current variant.
friend bool holds_alternative(future_variant< X... > &me)
tests whether holds given variant
_details::future_variant_getter< fut_type, future_variant > get()
Retrieve result of the future.
void reset()
Delete any underlying future and return object into uninitalized state.
friend const fut_type & get(const future_variant< X... > &me)
Retrieve reference to future - if it is current variant.
makes a variant future - multiple futures shares single space
Contains future value of T, can be co_awaited in coroutine.
Definition: future.h:417
main namespace
Definition: aggregator.h:8