libcopp  2.2.0
task_promise.h
Go to the documentation of this file.
1 // Copyright 2023 owent
2 
3 #pragma once
4 
5 #include <libcopp/utils/config/libcopp_build_features.h>
6 
10 #include <libcopp/future/future.h>
14 
15 // clang-format off
16 #include <libcopp/utils/config/stl_include_prefix.h> // NOLINT(build/include_order)
17 // clang-format on
18 #include <assert.h>
19 #include <cstdlib>
20 #include <functional>
21 #include <type_traits>
22 
23 #if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
24 # include <exception>
25 #endif
26 // clang-format off
27 #include <libcopp/utils/config/stl_include_suffix.h> // NOLINT(build/include_order)
28 // clang-format on
29 
30 #if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
31 
32 LIBCOPP_COTASK_NAMESPACE_BEGIN
33 
34 template <class TVALUE>
35 class LIBCOPP_COTASK_API_HEAD_ONLY task_context_base;
36 
37 template <class TVALUE, class TERROR_TRANSFORM, bool RETURN_VOID>
38 class LIBCOPP_COTASK_API_HEAD_ONLY task_context_delegate;
39 
40 template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
41 class LIBCOPP_COTASK_API_HEAD_ONLY task_context;
42 
43 template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
44 class LIBCOPP_COTASK_API_HEAD_ONLY task_future_base;
45 
46 template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
47 class LIBCOPP_COTASK_API_HEAD_ONLY task_future;
48 
49 template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM, bool RETURN_VOID>
50 class LIBCOPP_COTASK_API_HEAD_ONLY task_promise_base;
51 
52 template <class TCONTEXT>
53 class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable_base;
54 
55 template <class TCONTEXT, bool RETURN_VOID>
56 class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable;
57 
58 template <class TVALUE>
59 class LIBCOPP_COTASK_API_HEAD_ONLY task_context_base {
60  public:
61  using value_type = TVALUE;
63  using id_allocator_type = LIBCOPP_COPP_NAMESPACE_ID::util::uint64_id_allocator;
64  using handle_delegate = LIBCOPP_COPP_NAMESPACE_ID::promise_caller_manager::handle_delegate;
65  using task_status_type = LIBCOPP_COPP_NAMESPACE_ID::promise_status;
66  using promise_flag = LIBCOPP_COPP_NAMESPACE_ID::promise_flag;
67 
68  private:
69  task_context_base(const task_context_base&) = delete;
70  task_context_base(task_context_base&&) = delete;
71  task_context_base& operator=(const task_context_base&) = delete;
72  task_context_base& operator=(task_context_base&&) = delete;
73 
74  public:
75  task_context_base() noexcept
76  : current_handle_(nullptr)
77 # if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
78  ,
79  binding_manager_ptr_(nullptr),
80  binding_manager_fn_(nullptr)
81 # endif
82  {
83  id_allocator_type id_allocator;
84  id_ = id_allocator.allocate();
85  }
86 
87  ~task_context_base() noexcept {
88  force_finish();
89  force_destroy();
90  }
91 
92  UTIL_FORCEINLINE bool is_ready() const noexcept {
93  if (nullptr != current_handle_.promise && current_handle_.promise->check_flag(promise_flag::kHasReturned)) {
94  return true;
95  }
96 
97  return data_.is_ready();
98  }
99 
100  UTIL_FORCEINLINE bool is_pending() const noexcept { return data_.is_pending(); }
101 
102  inline task_status_type get_status() const noexcept {
103  if (current_handle_.promise) {
104  return current_handle_.promise->get_status();
105  }
106 
107  return task_status_type::kInvalid;
108  }
109 
110  UTIL_FORCEINLINE id_type get_id() const noexcept { return id_; }
111 
112  UTIL_FORCEINLINE bool has_multiple_callers() const noexcept {
113  if (nullptr != current_handle_.promise) {
114  return current_handle_.promise->has_multiple_callers();
115  }
116 
117  return false;
118  }
119 
120  protected:
121  UTIL_FORCEINLINE void add_caller(handle_delegate handle) noexcept {
122  if (nullptr != current_handle_.promise) {
123  current_handle_.promise->add_caller(handle);
124  }
125  }
126 
127 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
128  template <LIBCOPP_COPP_NAMESPACE_ID::DerivedPromiseBaseType TPROMISE>
129 # else
130  template <class TPROMISE,
131  typename = std::enable_if_t<std::is_base_of<LIBCOPP_COPP_NAMESPACE_ID::promise_base_type, TPROMISE>::value>>
132 # endif
133  UTIL_FORCEINLINE LIBCOPP_COTASK_API_HEAD_ONLY void add_caller(
134  const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE>& handle) noexcept {
135  add_caller(handle_delegate{handle});
136  }
137 
138  UTIL_FORCEINLINE void remove_caller(handle_delegate handle) noexcept {
139  if (nullptr != current_handle_.promise) {
140  current_handle_.promise->remove_caller(handle, false);
141  }
142  }
143 
144 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
145  template <LIBCOPP_COPP_NAMESPACE_ID::DerivedPromiseBaseType TPROMISE>
146 # else
147  template <class TPROMISE,
148  typename = std::enable_if_t<std::is_base_of<LIBCOPP_COPP_NAMESPACE_ID::promise_base_type, TPROMISE>::value>>
149 # endif
150  UTIL_FORCEINLINE LIBCOPP_COTASK_API_HEAD_ONLY void remove_caller(
151  const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE>& handle, bool inherit_status) noexcept {
152  remove_caller(handle_delegate{handle}, inherit_status);
153  }
154 
155 # if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
156  UTIL_FORCEINLINE void unbind_from_manager() {
157  void* manager_ptr = binding_manager_ptr_;
158  void (*manager_fn)(void*, task_context_base<value_type>&) = binding_manager_fn_;
159  binding_manager_ptr_ = nullptr;
160  binding_manager_fn_ = nullptr;
161 
162  // finally, notify manager to cleanup(maybe start or resume with task's API but not task_manager's)
163  if (nullptr != manager_ptr && nullptr != manager_fn) {
164  (*manager_fn)(manager_ptr, *this);
165  }
166  }
167 # endif
168 
169  private:
170  template <class, class, class, bool>
171  friend class LIBCOPP_COTASK_API_HEAD_ONLY task_promise_base;
172 
173  template <class, class, class>
174  friend class LIBCOPP_COTASK_API_HEAD_ONLY task_future_base;
175 
176  template <class, class, class>
177  friend class LIBCOPP_COTASK_API_HEAD_ONLY task_future;
178 
179  template <class TCONTEXT>
180  friend class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable_base;
181 
182  inline void force_finish() noexcept {
183  COPP_LIKELY_IF (nullptr != current_handle_.promise) {
184  if (current_handle_.promise->get_status() < task_status_type::kDone) {
185  current_handle_.promise->set_status(task_status_type::kKilled);
186  }
187  }
188 
189  // Move unhandled_exception
190  while (current_handle_.handle && !current_handle_.handle.done() && current_handle_.promise &&
191  !current_handle_.promise->check_flag(promise_flag::kHasReturned)) {
192  current_handle_.handle.resume();
193  }
194  }
195 
196  inline void force_destroy() noexcept {
197  // Move current_handle_ to stack here to allow recursive call of force_destroy
198  handle_delegate current_handle = current_handle_;
199  current_handle_ = nullptr;
200 
201  if (nullptr != current_handle.promise) {
202  current_handle.promise->set_flag(promise_flag::kDestroying, true);
203  }
204  if (current_handle.handle) {
205  current_handle.handle.destroy();
206  }
207  }
208 
209  UTIL_FORCEINLINE void initialize_handle(handle_delegate handle) noexcept { current_handle_ = handle; }
210 
211  UTIL_FORCEINLINE handle_delegate& get_handle_delegate() noexcept { return current_handle_; }
212  UTIL_FORCEINLINE const handle_delegate& get_handle_delegate() const noexcept { return current_handle_; }
213 
214  protected:
215  LIBCOPP_COPP_NAMESPACE_ID::future::future<TVALUE> data_;
216 
217 # if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
218  public:
219  class LIBCOPP_COTASK_API_HEAD_ONLY task_manager_helper {
220  private:
221  template <class>
222  friend class LIBCOPP_COTASK_API_HEAD_ONLY task_manager;
223  static bool setup_task_manager(task_context_base<value_type>& context, void* manager_ptr,
224  void (*fn)(void*, task_context_base<value_type>&)) {
225  if (context.binding_manager_ptr_ != nullptr) {
226  return false;
227  }
228 
229  context.binding_manager_ptr_ = manager_ptr;
230  context.binding_manager_fn_ = fn;
231  return true;
232  }
233 
234  static bool cleanup_task_manager(task_context_base<value_type>& context, void* manager_ptr) {
235  if (context.binding_manager_ptr_ != manager_ptr) {
236  return false;
237  }
238 
239  context.binding_manager_ptr_ = nullptr;
240  context.binding_manager_fn_ = nullptr;
241  return true;
242  }
243  };
244 # endif
245 
246  private:
247  id_type id_;
248  LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type<
249 # if defined(LIBCOPP_LOCK_DISABLE_MT) && LIBCOPP_LOCK_DISABLE_MT
250  LIBCOPP_COPP_NAMESPACE_ID::util::lock::unsafe_int_type<size_t>
251 # else
252  size_t
253 # endif
254  >
255  future_counter_;
256  LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock internal_operation_lock_;
257  handle_delegate current_handle_;
258 # if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
259  void* binding_manager_ptr_;
260  void (*binding_manager_fn_)(void*, task_context_base<value_type>&);
261 # endif
262 };
263 
264 template <class TVALUE, class TERROR_TRANSFORM>
265 class LIBCOPP_COTASK_API_HEAD_ONLY task_context_delegate<TVALUE, TERROR_TRANSFORM, true>
266  : public task_context_base<TVALUE> {
267  public:
268  using base_type = task_context_base<TVALUE>;
269  using id_type = typename base_type::id_type;
270  using value_type = typename base_type::value_type;
271  using handle_delegate = typename base_type::handle_delegate;
272  using task_status_type = typename base_type::task_status_type;
273  using promise_flag = typename base_type::promise_flag;
274  using error_transform = TERROR_TRANSFORM;
275 
276  public:
277  ~task_context_delegate() {}
278 
279  using base_type::is_pending;
280  using base_type::is_ready;
281 
282  UTIL_FORCEINLINE void set_value() { data_.reset_data(true); }
283 
284  private:
285  template <class TCONTEXT>
286  friend class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable_base;
287 
288  template <class, class, class>
289  friend class LIBCOPP_COTASK_API_HEAD_ONLY task_future;
290 
291  template <class, class, class>
292  friend struct LIBCOPP_COTASK_API_HEAD_ONLY some_delegate_task_action;
293 
294  using base_type::add_caller;
295  using base_type::data_;
296  using base_type::remove_caller;
297 # if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
298  using base_type::unbind_from_manager;
299 # endif
300 };
301 
302 template <class TVALUE, class TERROR_TRANSFORM>
303 class LIBCOPP_COTASK_API_HEAD_ONLY task_context_delegate<TVALUE, TERROR_TRANSFORM, false>
304  : public task_context_base<TVALUE> {
305  public:
306  using base_type = task_context_base<TVALUE>;
307  using id_type = typename base_type::id_type;
308  using value_type = typename base_type::value_type;
309  using handle_delegate = typename base_type::handle_delegate;
310  using task_status_type = typename base_type::task_status_type;
311  using promise_flag = typename base_type::promise_flag;
312  using error_transform = TERROR_TRANSFORM;
313 
314  public:
315  using base_type::is_pending;
316  using base_type::is_ready;
317 
318  ~task_context_delegate() {
319  if (is_pending()) {
320  set_value(error_transform()(task_status_type::kKilled));
321  }
322  }
323 
324  UTIL_FORCEINLINE const value_type* data() const noexcept {
325  if (!is_ready()) {
326  return nullptr;
327  }
328 
329  return data_.data();
330  }
331 
332  UTIL_FORCEINLINE value_type* data() noexcept {
333  if (!is_ready()) {
334  return nullptr;
335  }
336 
337  return data_.data();
338  }
339 
340  template <class U>
341  UTIL_FORCEINLINE void set_value(U&& in) {
342  data_.reset_data(std::forward<U>(in));
343  }
344 
345  private:
346  template <class TCONTEXT>
347  friend class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable_base;
348 
349  template <class, class, class>
350  friend class LIBCOPP_COTASK_API_HEAD_ONLY task_future;
351 
352  template <class, class, class>
353  friend struct LIBCOPP_COTASK_API_HEAD_ONLY some_delegate_task_action;
354 
355  using base_type::add_caller;
356  using base_type::data_;
357  using base_type::remove_caller;
358 # if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
359  using base_type::unbind_from_manager;
360 # endif
361 };
362 
363 template <class TPRIVATE_DATA>
364 class LIBCOPP_COTASK_API_HEAD_ONLY task_private_data {
365  public:
366  inline task_private_data() noexcept : data_(nullptr) {}
367  inline task_private_data(TPRIVATE_DATA* input) noexcept : data_(input) {}
368  inline task_private_data(task_private_data&& other) noexcept = default;
369  inline task_private_data& operator=(task_private_data&&) noexcept = default;
370  inline task_private_data(const task_private_data&) = delete;
371  inline task_private_data& operator=(const task_private_data&) = delete;
372  inline ~task_private_data() {}
373 
374  inline bool await_ready() const noexcept { return true; }
375  inline TPRIVATE_DATA* await_resume() const noexcept { return data_; }
376  inline void await_suspend(LIBCOPP_COPP_NAMESPACE_ID::promise_base_type::type_erased_handle_type) noexcept {}
377 
378  private:
379  template <class, class, class>
380  friend class LIBCOPP_COTASK_API_HEAD_ONLY task_context;
381 
382  template <class, class, class>
383  friend class LIBCOPP_COTASK_API_HEAD_ONLY task_future;
384 
385  TPRIVATE_DATA* data_;
386 };
387 
388 template <class TID>
389 class LIBCOPP_COTASK_API_HEAD_ONLY task_pick_id {
390  public:
391  inline task_pick_id() noexcept : data_(0) {}
392  inline task_pick_id(TID input) noexcept : data_(input) {}
393  inline task_pick_id(task_pick_id&& other) noexcept = default;
394  inline task_pick_id& operator=(task_pick_id&&) noexcept = default;
395  inline task_pick_id(const task_pick_id&) = delete;
396  inline task_pick_id& operator=(const task_pick_id&) = delete;
397  inline ~task_pick_id() {}
398 
399  inline bool await_ready() const noexcept { return true; }
400  inline TID await_resume() const noexcept { return data_; }
401  inline void await_suspend(LIBCOPP_COPP_NAMESPACE_ID::promise_base_type::type_erased_handle_type) noexcept {}
402 
403  private:
404  template <class, class, class>
405  friend class LIBCOPP_COTASK_API_HEAD_ONLY task_context;
406 
407  template <class, class, class>
408  friend class LIBCOPP_COTASK_API_HEAD_ONLY task_future;
409 
410  TID data_;
411 };
412 
413 template <class TVALUE, class TERROR_TRANSFORM>
414 class LIBCOPP_COTASK_API_HEAD_ONLY task_context<TVALUE, void, TERROR_TRANSFORM>
415  : public task_context_delegate<TVALUE, TERROR_TRANSFORM, std::is_void<typename std::decay<TVALUE>::type>::value> {
416  public:
417  using base_type =
418  task_context_delegate<TVALUE, TERROR_TRANSFORM, std::is_void<typename std::decay<TVALUE>::type>::value>;
419  using value_type = typename base_type::value_type;
420  using id_type = typename base_type::id_type;
421  using private_data_type = void;
422  using handle_delegate = typename base_type::handle_delegate;
423  using task_status_type = typename base_type::task_status_type;
424  using promise_flag = typename base_type::promise_flag;
425  using error_transform = typename base_type::error_transform;
426 
427  public:
428  using base_type::is_pending;
429  using base_type::is_ready;
430  using base_type::set_value;
431 
432  template <class... TARGS>
433  task_context(TARGS&&...) {}
434 };
435 
436 template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
437 class LIBCOPP_COTASK_API_HEAD_ONLY task_context
438  : public task_context_delegate<TVALUE, TERROR_TRANSFORM, std::is_void<typename std::decay<TVALUE>::type>::value> {
439  public:
440  using base_type =
441  task_context_delegate<TVALUE, TERROR_TRANSFORM, std::is_void<typename std::decay<TVALUE>::type>::value>;
442  using value_type = typename base_type::value_type;
443  using private_data_type = TPRIVATE_DATA;
444  using handle_delegate = typename base_type::handle_delegate;
445  using task_status_type = typename base_type::task_status_type;
446  using promise_flag = typename base_type::promise_flag;
447  using error_transform = typename base_type::error_transform;
448 
449  public:
450  using base_type::is_pending;
451  using base_type::is_ready;
452  using base_type::set_value;
453 
454  template <class... TARGS>
455  task_context(TARGS&&... args)
456  : private_data_(
457  LIBCOPP_COPP_NAMESPACE_ID::callable_promise_value_constructor<
458  private_data_type,
459  !std::is_constructible<private_data_type, TARGS...>::value>::construct(std::forward<TARGS>(args)...)) {}
460 
461  private_data_type& get_private_data() noexcept { return private_data_; }
462  const private_data_type& get_private_data() const noexcept { return private_data_; }
463 
464  private:
465  private_data_type private_data_;
466 };
467 
468 template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
469 class LIBCOPP_COTASK_API_HEAD_ONLY task_promise_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM, true>
470  : public LIBCOPP_COPP_NAMESPACE_ID::promise_base_type {
471  public:
472  using value_type = TVALUE;
473  using context_type = task_context<value_type, TPRIVATE_DATA, TERROR_TRANSFORM>;
474  using private_data_type = typename context_type::private_data_type;
475  using context_pointer_type = std::shared_ptr<context_type>;
476  using handle_delegate = typename context_type::handle_delegate;
477  using task_status_type = LIBCOPP_COPP_NAMESPACE_ID::promise_status;
478 
479  template <class... TARGS>
480  task_promise_base(TARGS&&... args)
481  : context_strong_ref_(std::make_shared<context_type>(std::forward<TARGS>(args)...)) {}
482 
483  void return_void() noexcept {
484  set_flag(LIBCOPP_COPP_NAMESPACE_ID::promise_flag::kHasReturned, true);
485 
486  if (get_status() < task_status_type::kDone) {
487  set_status(task_status_type::kDone);
488  }
489 
490  COPP_LIKELY_IF (get_context()) {
491  get_context()->set_value();
492  }
493  }
494 
495  protected:
496  UTIL_FORCEINLINE context_pointer_type move_context() noexcept {
497  context_pointer_type ret = std::move(context_strong_ref_);
498  context_strong_ref_.reset();
499  return ret;
500  }
501 
502  UTIL_FORCEINLINE const context_pointer_type& get_context() noexcept { return context_strong_ref_; }
503 
504  template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<
505  task_promise_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM, true>, TPROMISE>::value>>
506  UTIL_FORCEINLINE void initialize_promise(
507  const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE>& origin_handle) noexcept {
508  COPP_LIKELY_IF (get_context()) {
509  get_context()->initialize_handle(handle_delegate{origin_handle});
510  }
511  }
512 
513  private:
514  context_pointer_type context_strong_ref_;
515 };
516 
517 template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
518 class LIBCOPP_COTASK_API_HEAD_ONLY task_promise_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM, false>
519  : public LIBCOPP_COPP_NAMESPACE_ID::promise_base_type {
520  public:
521  using value_type = TVALUE;
522  using context_type = task_context<value_type, TPRIVATE_DATA, TERROR_TRANSFORM>;
523  using private_data_type = typename context_type::private_data_type;
524  using context_pointer_type = std::shared_ptr<context_type>;
525  using task_status_type = LIBCOPP_COPP_NAMESPACE_ID::promise_status;
526 
527  template <class... TARGS>
528  task_promise_base(TARGS&&... args)
529  : context_strong_ref_(std::make_shared<context_type>(std::forward<TARGS>(args)...)) {}
530 
531  void return_value(value_type value) {
532  set_flag(LIBCOPP_COPP_NAMESPACE_ID::promise_flag::kHasReturned, true);
533 
534  if (get_status() < task_status_type::kDone) {
535  set_status(task_status_type::kDone);
536  }
537  COPP_LIKELY_IF (get_context()) {
538  get_context()->set_value(std::move(value));
539  }
540  }
541 
542  UTIL_FORCEINLINE value_type* data() noexcept {
543  COPP_LIKELY_IF (get_context()) {
544  return get_context()->data();
545  }
546  return nullptr;
547  }
548 
549  UTIL_FORCEINLINE const value_type* data() const noexcept {
550  COPP_LIKELY_IF (get_context()) {
551  return get_context()->data();
552  }
553  return nullptr;
554  }
555 
556  protected:
557  UTIL_FORCEINLINE context_pointer_type move_context() noexcept {
558  context_pointer_type ret = std::move(context_strong_ref_);
559  context_strong_ref_.reset();
560  return ret;
561  }
562 
563  UTIL_FORCEINLINE const context_pointer_type& get_context() noexcept { return context_strong_ref_; }
564 
565  template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<
566  task_promise_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM, false>, TPROMISE>::value>>
567  UTIL_FORCEINLINE void initialize_promise(
568  const LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE>& origin_handle) noexcept {
569  COPP_LIKELY_IF (get_context()) {
570  get_context()->initialize_handle(handle_delegate{origin_handle});
571  }
572  }
573 
574  private:
575  context_pointer_type context_strong_ref_;
576 };
577 
578 template <class TCONTEXT>
579 class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable_base : public LIBCOPP_COPP_NAMESPACE_ID::awaitable_base_type {
580  public:
581  using context_type = TCONTEXT;
582  using context_pointer_type = std::shared_ptr<context_type>;
583  using value_type = typename context_type::value_type;
584  using task_status_type = LIBCOPP_COPP_NAMESPACE_ID::promise_status;
585  using promise_flag = LIBCOPP_COPP_NAMESPACE_ID::promise_flag;
586 
587  public:
588  task_awaitable_base(context_type* context) : context_{context} {}
589 
590  inline bool await_ready() noexcept {
591  COPP_UNLIKELY_IF (nullptr == context_) {
592  return true;
593  }
594 
595  if (context_->is_ready()) {
596  return true;
597  }
598 
599  if (nullptr == context_->get_handle_delegate().promise) {
600  return true;
601  }
602 
603  if (context_->get_handle_delegate().promise->get_status() >= task_status_type::kDone) {
604  return true;
605  }
606 
607  return false;
608  }
609 
610 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
611  template <LIBCOPP_COPP_NAMESPACE_ID::DerivedPromiseBaseType TCPROMISE>
612 # else
613  template <class TCPROMISE, typename = std::enable_if_t<
614  std::is_base_of<LIBCOPP_COPP_NAMESPACE_ID::promise_base_type, TCPROMISE>::value>>
615 # endif
616  inline bool await_suspend(LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TCPROMISE> caller) noexcept {
617  if (nullptr != context_ && caller.promise().get_status() < task_status_type::kDone) {
618  set_caller(caller);
619  context_->add_caller(caller);
620 
621  // Allow kill resume to forward error information
622  caller.promise().set_flag(promise_flag::kInternalWaitting, true);
623  return true;
624  } else {
625  // Already done and can not suspend again
626  // caller.resume();
627  return false;
628  }
629  }
630 
631  protected:
632  task_status_type detach() noexcept {
633  task_status_type result_status;
634  COPP_UNLIKELY_IF (nullptr == context_) {
635  result_status = task_status_type::kInvalid;
636  } else if (context_->is_ready()) {
637  result_status = task_status_type::kDone;
638  } else {
639  result_status = task_status_type::kKilled;
640  }
641 
642  // caller maybe null if the callable is already ready when co_await
643  auto caller = get_caller();
644 
645  if (caller) {
646  if (nullptr != caller.promise) {
647  caller.promise->set_flag(promise_flag::kInternalWaitting, false);
648  }
649  COPP_LIKELY_IF (nullptr != context_) {
650  if (!context_->is_ready() && nullptr != caller.promise) {
651  result_status = caller.promise->get_status();
652  }
653 
654  context_->remove_caller(caller);
655  set_caller(nullptr);
656  } else {
657  set_caller(nullptr);
658  }
659  }
660 
661  return result_status;
662  }
663 
670  UTIL_FORCEINLINE context_type* get_context() noexcept { return context_; }
671 
672  private:
673  context_type* context_;
674 };
675 
676 template <class TCONTEXT>
677 class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable<TCONTEXT, true> : public task_awaitable_base<TCONTEXT> {
678  public:
679  using base_type = task_awaitable_base<TCONTEXT>;
680  using value_type = typename base_type::value_type;
681  using context_type = typename base_type::context_type;
682  using context_pointer_type = typename base_type::context_pointer_type;
683  using task_status_type = typename base_type::task_status_type;
684  using promise_flag = typename base_type::promise_flag;
685  using error_transform = typename context_type::error_transform;
686 
687  public:
688  using base_type::await_ready;
689  using base_type::await_suspend;
690  using base_type::get_caller;
691  using base_type::set_caller;
692  task_awaitable(context_type* context) : base_type(context) {}
693 
694  inline void await_resume() { detach(); }
695 
696  private:
697  using base_type::detach;
698  using base_type::get_context;
699 };
700 
701 template <class TCONTEXT>
702 class LIBCOPP_COTASK_API_HEAD_ONLY task_awaitable<TCONTEXT, false> : public task_awaitable_base<TCONTEXT> {
703  public:
704  using base_type = task_awaitable_base<TCONTEXT>;
705  using value_type = typename base_type::value_type;
706  using context_type = typename base_type::context_type;
707  using context_pointer_type = typename base_type::context_pointer_type;
708  using task_status_type = typename base_type::task_status_type;
709  using promise_flag = typename base_type::promise_flag;
710  using error_transform = typename context_type::error_transform;
711 
712  public:
713  using base_type::await_ready;
714  using base_type::await_suspend;
715  using base_type::get_caller;
716  using base_type::set_caller;
717  task_awaitable(context_type* context) : base_type(context) {}
718 
719  inline value_type await_resume() {
720  bool has_multiple_callers;
721  COPP_LIKELY_IF (nullptr != get_context()) {
722  has_multiple_callers = get_context()->has_multiple_callers();
723  } else {
724  has_multiple_callers = false;
725  }
726  task_status_type result_status = detach();
727 
728  if (task_status_type::kDone != result_status) {
729  return error_transform()(result_status);
730  }
731 
732  COPP_LIKELY_IF (nullptr != get_context()) {
733  if (has_multiple_callers) {
734  return *get_context()->data();
735  } else {
736  return LIBCOPP_COPP_NAMESPACE_ID::multiple_callers_constructor<value_type>::return_value(
737  *get_context()->data());
738  }
739  } else {
740  return error_transform()(task_status_type::kInvalid);
741  }
742  }
743 
744  private:
745  using base_type::detach;
746  using base_type::get_context;
747 };
748 
749 template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
750 class LIBCOPP_COTASK_API_HEAD_ONLY task_future_base {
751  public:
752  using value_type = TVALUE;
753  using context_type = task_context<value_type, TPRIVATE_DATA, TERROR_TRANSFORM>;
754  using id_type = typename context_type::id_type;
755  using private_data_type = typename context_type::private_data_type;
756  using context_pointer_type = std::shared_ptr<context_type>;
757  using task_status_type = typename context_type::task_status_type;
758  using promise_flag = typename context_type::promise_flag;
759 
760  public:
761  task_future_base() noexcept = default;
762 
763  task_future_base(context_pointer_type context) noexcept : context_{context} {
764  COPP_LIKELY_IF (context_) {
765  ++context_->future_counter_;
766  }
767  }
768 
769  task_future_base(const task_future_base& other) noexcept : context_{other.context_} {
770  COPP_LIKELY_IF (context_) {
771  ++context_->future_counter_;
772  }
773  }
774 
775  task_future_base(task_future_base&& other) noexcept : context_{std::move(other.context_)} { other.context_.reset(); }
776 
777  task_future_base& operator=(const task_future_base& other) noexcept {
778  assign(other);
779  return *this;
780  }
781 
782  task_future_base& operator=(task_future_base&& other) noexcept {
783  assign(std::move(other));
784  return *this;
785  }
786 
787  ~task_future_base() {
788  // resume callers
789  reset();
790  }
791 
792  inline friend bool operator==(const task_future_base& l, const task_future_base& r) noexcept {
793  return l.context_ == r.context_;
794  }
795 
796  inline friend bool operator!=(const task_future_base& l, const task_future_base& r) noexcept {
797  return l.context_ != r.context_;
798  }
799 
800  inline operator bool() const noexcept { return valid(); }
801 
802  void assign(const task_future_base& other) noexcept {
803  if (this == &other || context_ == other.context_) {
804  return;
805  }
806 
807  reset();
808 
809  COPP_LIKELY_IF (other.context_) {
810  ++other.context_->future_counter_;
811  }
812  context_ = other.context_;
813  }
814 
815  void assign(task_future_base&& other) noexcept {
816  if (this == &other || context_ == other.context_) {
817  return;
818  }
819 
820  reset();
821  context_.swap(other.context_);
822 
823  return;
824  }
825 
826  void reset() {
827  if (context_) {
828  context_pointer_type context;
829  context.swap(context_);
830  size_t future_counter = --context->future_counter_;
831  // Destroy context when future_counter decrease to 0
832  if (0 == future_counter) {
833  context->force_finish();
834  }
835  }
836  }
837 
838  size_t get_ref_future_count() const noexcept {
839  COPP_LIKELY_IF (context_) {
840  return context_->future_counter_.load();
841  }
842 
843  return 0;
844  }
845 
846  inline task_status_type get_status() const noexcept {
847  COPP_UNLIKELY_IF (!context_) {
848  return task_status_type::kInvalid;
849  }
850 
851  return context_->get_status();
852  }
853 
854  UTIL_FORCEINLINE bool is_canceled() const noexcept { return task_status_type::kCancle == get_status(); }
855  inline bool is_completed() const noexcept {
856  if (false == is_exiting()) {
857  return false;
858  }
859 
860  if (!context_) {
861  return true;
862  }
863 
864  auto& handle = context_->get_handle_delegate().handle;
865  COPP_UNLIKELY_IF (!handle) {
866  return true;
867  }
868 
869  if (handle.done()) {
870  return true;
871  }
872 
873  auto promise = context_->get_handle_delegate().promise;
874  COPP_UNLIKELY_IF (nullptr == promise) {
875  return true;
876  }
877 
878  if (promise->check_flag(promise_flag::kHasReturned)) {
879  return true;
880  }
881 
882  return false;
883  }
884 
885  UTIL_FORCEINLINE bool is_faulted() const noexcept { return task_status_type::kKilled <= get_status(); }
886  UTIL_FORCEINLINE bool is_timeout() const noexcept { return task_status_type::kTimeout <= get_status(); }
887  UTIL_FORCEINLINE bool is_exiting() const noexcept {
888  task_status_type status = get_status();
889  return task_status_type::kDone <= status || task_status_type::kInvalid == status;
890  }
891 
892  UTIL_FORCEINLINE static auto yield_status() noexcept {
893  return LIBCOPP_COPP_NAMESPACE_ID::promise_base_type::pick_current_status();
894  }
895 
896  UTIL_FORCEINLINE static auto yield_private_data() noexcept { return task_private_data<TPRIVATE_DATA>{}; }
897 
898  UTIL_FORCEINLINE static auto yield_task_id() noexcept { return task_pick_id<id_type>{}; }
899 
906  bool start() noexcept {
907  COPP_UNLIKELY_IF (!context_) {
908  return false;
909  }
910 
911  LIBCOPP_COPP_NAMESPACE_ID::util::lock::lock_holder<
912  LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock,
913  LIBCOPP_COPP_NAMESPACE_ID::util::lock::detail::default_try_lock_action<
914  LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock>,
915  LIBCOPP_COPP_NAMESPACE_ID::util::lock::detail::default_try_unlock_action<
916  LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock>>
917  lock_holder{context_->internal_operation_lock_};
918 
919  if (!lock_holder.is_available()) {
920  return false;
921  }
922 
923  auto& handle = context_->get_handle_delegate().handle;
924  COPP_UNLIKELY_IF (!handle) {
925  return false;
926  }
927 
928  if (handle.done()) {
929  return false;
930  }
931 
932  auto promise = context_->get_handle_delegate().promise;
933  COPP_UNLIKELY_IF (nullptr == promise) {
934  return false;
935  }
936 
937  task_status_type expect_status = task_status_type::kCreated;
938  if (!promise->set_status(task_status_type::kRunning, &expect_status)) {
939  return false;
940  }
941 
942  lock_holder.reset();
943 
944  if (!promise->check_flag(promise_flag::kHasReturned) && !promise->check_flag(promise_flag::kDestroying)) {
945  // rethrow a exception in c++20 coroutine will crash when using MSVC now(VS2022)
946  // We may enable exception in the future
947 # if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
948  std::exception_ptr unhandled_exception;
949  try {
950 # endif
951  handle.resume();
952  // rethrow a exception in c++20 coroutine will crash when using MSVC now(VS2022)
953  // We may enable exception in the future
954 # if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
955  } catch (...) {
956  unhandled_exception = std::current_exception();
957  }
958 # endif
959  }
960 
961  return true;
962  }
963 
972  bool kill(task_status_type target_status = task_status_type::kKilled, bool force_resume = false) noexcept {
973  if (target_status < task_status_type::kDone) {
974  return false;
975  }
976 
977  COPP_UNLIKELY_IF (!context_) {
978  return false;
979  }
980 
981  LIBCOPP_COPP_NAMESPACE_ID::util::lock::lock_holder<
982  LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock,
983  LIBCOPP_COPP_NAMESPACE_ID::util::lock::detail::default_try_lock_action<
984  LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock>,
985  LIBCOPP_COPP_NAMESPACE_ID::util::lock::detail::default_try_unlock_action<
986  LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock>>
987  lock_holder{context_->internal_operation_lock_};
988 
989  if (!lock_holder.is_available()) {
990  return false;
991  }
992 
993  auto& handle = context_->get_handle_delegate().handle;
994  COPP_UNLIKELY_IF (!handle) {
995  return false;
996  }
997 
998  bool ret = true;
999  while (context_) {
1000  COPP_UNLIKELY_IF (!handle) {
1001  ret = false;
1002  break;
1003  }
1004 
1005  if (handle.done()) {
1006  ret = false;
1007  break;
1008  }
1009 
1010  task_status_type current_status = get_status();
1011  if (current_status >= task_status_type::kDone) {
1012  ret = false;
1013  break;
1014  }
1015 
1016  auto promise = context_->get_handle_delegate().promise;
1017  COPP_UNLIKELY_IF (nullptr == promise) {
1018  return false;
1019  }
1020 
1021  if (!promise->set_status(target_status, &current_status)) {
1022  continue;
1023  }
1024 
1025  if ((force_resume || promise->is_waiting()) && !promise->check_flag(promise_flag::kHasReturned) &&
1026  !promise->check_flag(promise_flag::kDestroying)) {
1027  // rethrow a exception in c++20 coroutine will crash when using MSVC now(VS2022)
1028  // We may enable exception in the future
1029 # if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
1030  std::exception_ptr unhandled_exception;
1031  try {
1032 # endif
1033  handle.resume();
1034  // rethrow a exception in c++20 coroutine will crash when using MSVC now(VS2022)
1035  // We may enable exception in the future
1036 # if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
1037  }
1038  catch (...) {
1039  unhandled_exception = std::current_exception();
1040  }
1041 # endif
1042  }
1043  break;
1044  }
1045 
1046  return ret;
1047  }
1048 
1049  UTIL_FORCEINLINE bool kill(bool force_resume) { return kill(task_status_type::kKilled, force_resume); }
1050 
1051  UTIL_FORCEINLINE bool cancel(bool force_resume = false) { return kill(task_status_type::kCancle, force_resume); }
1052 
1053  UTIL_FORCEINLINE const context_pointer_type& get_context() const noexcept { return context_; }
1054 
1055  UTIL_FORCEINLINE context_pointer_type& get_context() noexcept { return context_; }
1056 
1057  inline id_type get_id() const noexcept {
1058  COPP_UNLIKELY_IF (!context_) {
1059  return 0;
1060  }
1061 
1062  return context_->get_id();
1063  }
1064 
1065  UTIL_FORCEINLINE bool valid() const noexcept { return !!context_; }
1066 
1067  private:
1068  context_pointer_type context_;
1069 };
1070 
1071 template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM, bool NO_PRIVATE_DATA>
1072 class LIBCOPP_COTASK_API_HEAD_ONLY task_future_delegate;
1073 
1074 template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
1075 class LIBCOPP_COTASK_API_HEAD_ONLY task_future_delegate<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM, false>
1076  : public task_future_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM> {
1077  public:
1078  using base_type = task_future_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>;
1079  using value_type = typename base_type::value_type;
1080  using context_type = typename base_type::context_type;
1081  using id_type = typename base_type::id_type;
1082  using private_data_type = typename base_type::private_data_type;
1083  using context_pointer_type = typename base_type::context_pointer_type;
1084  using task_status_type = typename base_type::task_status_type;
1085  using promise_flag = typename base_type::promise_flag;
1086 
1087  public:
1088  task_future_delegate() noexcept = default;
1089  task_future_delegate(context_pointer_type context) noexcept : base_type{context} {}
1090  task_future_delegate(const task_future_delegate& other) noexcept : base_type{other} {}
1091  task_future_delegate(task_future_delegate&& other) noexcept : base_type{std::move(other)} {}
1092  task_future_delegate& operator=(const task_future_delegate& other) noexcept {
1093  assign(other);
1094  return *this;
1095  }
1096 
1097  task_future_delegate& operator=(task_future_delegate&& other) noexcept {
1098  assign(std::move(other));
1099  return *this;
1100  }
1101 
1102  using base_type::assign;
1103  using base_type::get_context;
1104 
1105  inline private_data_type* get_private_data() noexcept {
1106  COPP_UNLIKELY_IF (!get_context()) {
1107  return nullptr;
1108  }
1109 
1110  return &get_context()->get_private_data();
1111  }
1112 
1113  inline const private_data_type* get_private_data() const noexcept {
1114  COPP_UNLIKELY_IF (!get_context()) {
1115  return nullptr;
1116  }
1117 
1118  return &get_context()->get_private_data();
1119  }
1120 };
1121 
1122 template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
1123 class LIBCOPP_COTASK_API_HEAD_ONLY task_future_delegate<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM, true>
1124  : public task_future_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM> {
1125  public:
1126  using base_type = task_future_base<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>;
1127  using value_type = typename base_type::value_type;
1128  using context_type = typename base_type::context_type;
1129  using id_type = typename base_type::id_type;
1130  using private_data_type = typename base_type::private_data_type;
1131  using context_pointer_type = typename base_type::context_pointer_type;
1132  using task_status_type = typename base_type::task_status_type;
1133  using promise_flag = typename base_type::promise_flag;
1134 
1135  public:
1136  task_future_delegate() noexcept = default;
1137  task_future_delegate(context_pointer_type context) noexcept : base_type{context} {}
1138  task_future_delegate(const task_future_delegate& other) noexcept : base_type{other} {}
1139  task_future_delegate(task_future_delegate&& other) noexcept : base_type{std::move(other)} {}
1140  task_future_delegate& operator=(const task_future_delegate& other) noexcept {
1141  assign(other);
1142  return *this;
1143  }
1144 
1145  task_future_delegate& operator=(task_future_delegate&& other) noexcept {
1146  assign(std::move(other));
1147  return *this;
1148  }
1149 
1150  using base_type::assign;
1151  using base_type::get_context;
1152 };
1153 
1154 template <class TVALUE, class TPRIVATE_DATA,
1155  class TERROR_TRANSFORM = LIBCOPP_COPP_NAMESPACE_ID::promise_error_transform<TVALUE>>
1156 class LIBCOPP_COTASK_API_HEAD_ONLY task_future
1157  : public task_future_delegate<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM, std::is_same<TPRIVATE_DATA, void>::value> {
1158  public:
1159  using error_transform = TERROR_TRANSFORM;
1160  using self_type = task_future<TVALUE, TPRIVATE_DATA, error_transform>;
1161  using base_type =
1162  task_future_delegate<TVALUE, TPRIVATE_DATA, error_transform, std::is_same<TPRIVATE_DATA, void>::value>;
1163  using value_type = typename base_type::value_type;
1164  using context_type = typename base_type::context_type;
1165  using id_type = typename base_type::id_type;
1166  using private_data_type = typename base_type::private_data_type;
1167  using context_pointer_type = typename base_type::context_pointer_type;
1168  using task_status_type = typename base_type::task_status_type;
1169  using promise_flag = typename base_type::promise_flag;
1170 
1171  using promise_base_type = task_promise_base<value_type, private_data_type, error_transform,
1172  std::is_void<typename std::decay<value_type>::type>::value>;
1173  class promise_type : public promise_base_type {
1174  public:
1175 # if defined(__GNUC__) && !defined(__clang__)
1176  template <class... TARGS>
1177  promise_type(TARGS&&... args) : promise_base_type(args...) {}
1178 # else
1179  template <class... TARGS>
1180  promise_type(TARGS&&... args) : promise_base_type(std::forward<TARGS>(args)...) {}
1181 # endif
1182 
1183  using promise_base_type::get_context;
1184  using promise_base_type::move_context;
1185 
1186  auto get_return_object() noexcept { return self_type{get_context()}; }
1187 
1188  struct initial_awaitable {
1189  inline bool await_ready() const noexcept { return false; }
1190 
1191  inline void await_resume() const noexcept {
1192  if (handle.promise().get_status() == task_status_type::kCreated) {
1193  task_status_type excepted = task_status_type::kCreated;
1194  handle.promise().set_status(task_status_type::kRunning, &excepted);
1195  }
1196  }
1197 
1198  inline void await_suspend(LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<promise_type> caller) noexcept {
1199  handle = caller;
1200  caller.promise().initialize_promise(caller);
1201  }
1202 
1203  LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<promise_type> handle;
1204  };
1205  initial_awaitable initial_suspend() noexcept { return {}; }
1206 
1207  // C++20 coroutine
1208  struct LIBCOPP_COTASK_API_HEAD_ONLY final_awaitable
1209  : public LIBCOPP_COPP_NAMESPACE_ID::promise_base_type::final_awaitable {
1210 # if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
1211  template <std::derived_from<promise_base_type> TPROMISE>
1212 # else
1213  template <class TPROMISE, typename = std::enable_if_t<std::is_base_of<promise_base_type, TPROMISE>::value>>
1214 # endif
1215  inline void await_suspend(LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<TPROMISE> self) noexcept {
1216  // Move out context from promise
1217  context_pointer_type context = self.promise().move_context();
1218 
1219 # if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
1220  context->unbind_from_manager();
1221 # endif
1222 
1223  // Notify callers
1224  LIBCOPP_COPP_NAMESPACE_ID::promise_base_type::final_awaitable::template await_suspend(self);
1225 
1226  // At last it may be destroyed after all callers and managers is unbind.
1227  }
1228  };
1229 
1230  final_awaitable final_suspend() noexcept { return {}; }
1231 
1232 # if defined(LIBCOPP_MACRO_ENABLE_EXCEPTION) && LIBCOPP_MACRO_ENABLE_EXCEPTION
1233  void unhandled_exception() {
1234  throw;
1235  // get_context()->last_exception_ = std::current_exception();
1236  }
1237 # elif defined(LIBCOPP_MACRO_HAS_EXCEPTION) && LIBCOPP_MACRO_HAS_EXCEPTION
1238  void unhandled_exception() { throw; }
1239 # else
1240  void unhandled_exception() { std::abort(); }
1241 # endif
1242 
1243  template <class TCONVERT_PRIVATE_DATA>
1244  inline task_private_data<TCONVERT_PRIVATE_DATA> yield_value(
1245  task_private_data<TCONVERT_PRIVATE_DATA>&& input) noexcept {
1246  if (get_context()) {
1247  input.data_ = &get_context()->get_private_data();
1248  } else {
1249  input.data_ = nullptr;
1250  }
1251  return task_private_data<TCONVERT_PRIVATE_DATA>(input.data_);
1252  }
1253 
1254  inline task_pick_id<id_type> yield_value(task_pick_id<id_type>&& input) noexcept {
1255  if (get_context()) {
1256  input.data_ = get_context()->get_id();
1257  } else {
1258  input.data_ = 0;
1259  }
1260  return task_pick_id<id_type>(input.data_);
1261  }
1262 
1263  using promise_base_type::yield_value;
1264  };
1265  using handle_type = LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE coroutine_handle<promise_type>;
1266  using awaitable_type = task_awaitable<context_type, std::is_void<typename std::decay<value_type>::type>::value>;
1267 
1268 # if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
1269  using task_manager_helper = typename context_type::task_manager_helper;
1270 # endif
1271 
1272  public:
1273  task_future() noexcept = default;
1274  task_future(context_pointer_type context) noexcept : base_type{context} {}
1275  task_future(const task_future& other) noexcept : base_type{other} {}
1276  task_future(task_future&& other) noexcept : base_type{std::move(other)} {}
1277  task_future& operator=(const task_future& other) noexcept {
1278  assign(other);
1279  return *this;
1280  }
1281 
1282  task_future& operator=(task_future&& other) noexcept {
1283  assign(std::move(other));
1284  return *this;
1285  }
1286 
1287  using base_type::assign;
1288  using base_type::get_context;
1289 
1290  inline awaitable_type operator co_await() { return awaitable_type{get_context().get()}; }
1291 
1292  private:
1293  template <class TTHENABLE_VALUE>
1294  struct _thenable_return_traits_value_type;
1295 
1296  template <class TCALLABLE_VALUE, class TTASK_ERROR_TRANSFORM>
1297  struct _thenable_return_traits_value_type<
1298  LIBCOPP_COPP_NAMESPACE_ID::callable_future<TCALLABLE_VALUE, TTASK_ERROR_TRANSFORM>> : public std::true_type {
1299  using type =
1301  using error_transform = TTASK_ERROR_TRANSFORM;
1302 
1303  template <class TINPUT>
1304  UTIL_FORCEINLINE static LIBCOPP_COPP_NAMESPACE_ID::callable_future<TCALLABLE_VALUE, TTASK_ERROR_TRANSFORM>
1305  start_thenable(TINPUT&& c) {
1306  return {std::forward<TINPUT>(c)};
1307  }
1308  };
1309 
1310  template <class TTASK_VALUE, class TTASK_PRIVATE_DATA, class TTASK_ERROR_TRANSFORM>
1311  struct _thenable_return_traits_value_type<task_future<TTASK_VALUE, TTASK_PRIVATE_DATA, TTASK_ERROR_TRANSFORM>>
1312  : public std::true_type {
1314  using error_transform = TTASK_ERROR_TRANSFORM;
1315 
1316  template <class TINPUT>
1317  UTIL_FORCEINLINE static task_future<TTASK_VALUE, TTASK_PRIVATE_DATA, TTASK_ERROR_TRANSFORM> start_thenable(
1318  TINPUT&& task) {
1319  task.start();
1320  return {std::forward<TINPUT>(task)};
1321  }
1322  };
1323 
1324  template <class TTHENABLE_VALUE>
1325  struct _thenable_return_traits_value_type : public std::false_type {
1326  using type = TTHENABLE_VALUE;
1327  };
1328 
1329  template <class TTHENABLE, bool TASK_RETURN_VOID>
1330  struct _thenable_return_traits_return_type;
1331 
1332  template <class TTHENABLE>
1333  struct _thenable_return_traits_return_type<TTHENABLE, true>
1334  : public _thenable_return_traits_value_type<typename std::invoke_result<TTHENABLE, context_pointer_type>::type> {
1335  };
1336 
1337  template <class TTHENABLE>
1338  struct _thenable_return_traits_return_type<TTHENABLE, false>
1339  : public _thenable_return_traits_value_type<
1340  typename std::invoke_result<TTHENABLE, context_pointer_type, value_type>::type> {};
1341 
1342  template <class TTHENABLE>
1343  struct thenable_return_traits
1344  : public _thenable_return_traits_return_type<TTHENABLE, std::is_void<value_type>::value> {};
1345 
1346  template <class TTHENABLE, bool THENABLE_RETURN_COROUTINE>
1347  struct _thenable_default_error_transform;
1348 
1349  template <class TTHENABLE>
1350  struct _thenable_default_error_transform<TTHENABLE, true> {
1351  using type = typename thenable_return_traits<TTHENABLE>::error_transform;
1352  };
1353 
1354  template <class TTHENABLE>
1355  struct _thenable_default_error_transform<TTHENABLE, false> {
1356  using type = LIBCOPP_COPP_NAMESPACE_ID::promise_error_transform<typename thenable_return_traits<TTHENABLE>::type>;
1357  };
1358 
1359  template <class TTHENABLE>
1360  struct thenable_error_transform_traits
1361  : public _thenable_default_error_transform<TTHENABLE, thenable_return_traits<TTHENABLE>::value> {};
1362 
1363  template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM, bool THENABLE_RETURN_COROUTINE, bool THENABLE_RETURN_VOID,
1364  bool TASK_RETURN_VOID>
1365  struct thenable_traits;
1366 
1367  template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1368  struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, true, false, false> {
1369  using callable_thenable_type =
1370  LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1371  TTHENABLE_ERROR_TRANSFORM>;
1372 
1373  template <class TTHENABLE_PRIVATE_DATA>
1374  struct task_thenable_type {
1375  using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1376  TTHENABLE_ERROR_TRANSFORM>;
1377  };
1378 
1379  inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1380  co_return (co_await thenable_return_traits<TTHENABLE>::start_thenable(
1381  thenable(context_pointer_type(self.get_context()), co_await self)));
1382  }
1383 
1384  template <class TTHENABLE_PRIVATE_DATA>
1385  inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1386  TTHENABLE thenable) {
1387  co_return (co_await thenable_return_traits<TTHENABLE>::start_thenable(
1388  thenable(context_pointer_type(self.get_context()), co_await self)));
1389  }
1390  };
1391 
1392  template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1393  struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, true, false, true> {
1394  using callable_thenable_type =
1395  LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1396  TTHENABLE_ERROR_TRANSFORM>;
1397 
1398  template <class TTHENABLE_PRIVATE_DATA>
1399  struct task_thenable_type {
1400  using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1401  TTHENABLE_ERROR_TRANSFORM>;
1402  };
1403 
1404  inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1405  co_await self;
1406  co_return (co_await thenable_return_traits<TTHENABLE>::start_thenable(
1407  thenable(context_pointer_type(self.get_context()))));
1408  }
1409 
1410  template <class TTHENABLE_PRIVATE_DATA>
1411  inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1412  TTHENABLE thenable) {
1413  co_await self;
1414  co_return (co_await thenable_return_traits<TTHENABLE>::start_thenable(
1415  thenable(context_pointer_type(self.get_context()))));
1416  }
1417  };
1418 
1419  template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1420  struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, true, true, false> {
1421  using callable_thenable_type =
1422  LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1423  TTHENABLE_ERROR_TRANSFORM>;
1424 
1425  template <class TTHENABLE_PRIVATE_DATA>
1426  struct task_thenable_type {
1427  using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1428  TTHENABLE_ERROR_TRANSFORM>;
1429  };
1430 
1431  inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1432  co_await thenable_return_traits<TTHENABLE>::start_thenable(
1433  thenable(context_pointer_type(self.get_context()), co_await self));
1434  co_return;
1435  }
1436 
1437  template <class TTHENABLE_PRIVATE_DATA>
1438  inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1439  TTHENABLE thenable) {
1440  co_await thenable_return_traits<TTHENABLE>::start_thenable(
1441  thenable(context_pointer_type(self.get_context()), co_await self));
1442  co_return;
1443  }
1444  };
1445 
1446  template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1447  struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, true, true, true> {
1448  using callable_thenable_type =
1449  LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1450  TTHENABLE_ERROR_TRANSFORM>;
1451 
1452  template <class TTHENABLE_PRIVATE_DATA>
1453  struct task_thenable_type {
1454  using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1455  TTHENABLE_ERROR_TRANSFORM>;
1456  };
1457 
1458  inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1459  co_await self;
1460  co_await thenable_return_traits<TTHENABLE>::start_thenable(thenable(context_pointer_type(self.get_context())));
1461  co_return;
1462  }
1463 
1464  template <class TTHENABLE_PRIVATE_DATA>
1465  inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1466  TTHENABLE thenable) {
1467  co_await self;
1468  co_await thenable_return_traits<TTHENABLE>::start_thenable(thenable(context_pointer_type(self.get_context())));
1469  co_return;
1470  }
1471  };
1472 
1473  template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1474  struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, false, true, false> {
1475  using callable_thenable_type =
1476  LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1477  TTHENABLE_ERROR_TRANSFORM>;
1478 
1479  template <class TTHENABLE_PRIVATE_DATA>
1480  struct task_thenable_type {
1481  using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1482  TTHENABLE_ERROR_TRANSFORM>;
1483  };
1484 
1485  inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1486  thenable(context_pointer_type(self.get_context()), co_await self);
1487  co_return;
1488  }
1489 
1490  template <class TTHENABLE_PRIVATE_DATA>
1491  inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1492  TTHENABLE thenable) {
1493  thenable(context_pointer_type(self.get_context()), co_await self);
1494  co_return;
1495  }
1496  };
1497 
1498  template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1499  struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, false, true, true> {
1500  using callable_thenable_type =
1501  LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1502  TTHENABLE_ERROR_TRANSFORM>;
1503 
1504  template <class TTHENABLE_PRIVATE_DATA>
1505  struct task_thenable_type {
1506  using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1507  TTHENABLE_ERROR_TRANSFORM>;
1508  };
1509 
1510  inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1511  co_await self;
1512  thenable(context_pointer_type(self.get_context()));
1513  co_return;
1514  }
1515 
1516  template <class TTHENABLE_PRIVATE_DATA>
1517  inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1518  TTHENABLE thenable) {
1519  co_await self;
1520  thenable(context_pointer_type(self.get_context()));
1521  co_return;
1522  }
1523  };
1524 
1525  template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1526  struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, false, false, false> {
1527  using callable_thenable_type =
1528  LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1529  TTHENABLE_ERROR_TRANSFORM>;
1530 
1531  template <class TTHENABLE_PRIVATE_DATA>
1532  struct task_thenable_type {
1533  using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1534  TTHENABLE_ERROR_TRANSFORM>;
1535  };
1536 
1537  inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1538  co_return thenable(context_pointer_type(self.get_context()), co_await self);
1539  }
1540 
1541  template <class TTHENABLE_PRIVATE_DATA>
1542  inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1543  TTHENABLE thenable) {
1544  co_return thenable(context_pointer_type(self.get_context()), co_await self);
1545  }
1546  };
1547 
1548  template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1549  struct thenable_traits<TTHENABLE, TTHENABLE_ERROR_TRANSFORM, false, false, true> {
1550  using callable_thenable_type =
1551  LIBCOPP_COPP_NAMESPACE_ID::callable_future<typename thenable_return_traits<TTHENABLE>::type,
1552  TTHENABLE_ERROR_TRANSFORM>;
1553 
1554  template <class TTHENABLE_PRIVATE_DATA>
1555  struct task_thenable_type {
1556  using task_type = task_future<typename thenable_return_traits<TTHENABLE>::type, TTHENABLE_PRIVATE_DATA,
1557  TTHENABLE_ERROR_TRANSFORM>;
1558  };
1559 
1560  inline static callable_thenable_type invoke_callable(self_type self, TTHENABLE thenable) {
1561  co_await self;
1562  co_return thenable(context_pointer_type(self.get_context()));
1563  }
1564 
1565  template <class TTHENABLE_PRIVATE_DATA>
1566  inline static typename task_thenable_type<TTHENABLE_PRIVATE_DATA>::task_type invoke_task(self_type self,
1567  TTHENABLE thenable) {
1568  co_await self;
1569  co_return thenable(context_pointer_type(self.get_context()));
1570  }
1571  };
1572 
1573  public:
1574  template <class TTHENABLE, class TTHENABLE_ERROR_TRANSFORM>
1575  struct callable_thenable_trait {
1576  using trait_type = thenable_traits<
1577  typename std::decay<TTHENABLE>::type, TTHENABLE_ERROR_TRANSFORM,
1578  thenable_return_traits<typename std::decay<TTHENABLE>::type>::value,
1579  std::is_same<typename thenable_return_traits<typename std::decay<TTHENABLE>::type>::type, void>::value,
1580  std::is_void<value_type>::value>;
1581 
1582  using callable_thenable_type = typename trait_type::callable_thenable_type;
1583  };
1584 
1585  template <class TTHENABLE, class TTHENABLE_PRIVATE_DATA, class TTHENABLE_ERROR_TRANSFORM>
1586  struct task_thenable_trait {
1587  using trait_type = thenable_traits<
1588  typename std::decay<TTHENABLE>::type, TTHENABLE_ERROR_TRANSFORM,
1589  thenable_return_traits<typename std::decay<TTHENABLE>::type>::value,
1590  std::is_same<typename thenable_return_traits<typename std::decay<TTHENABLE>::type>::type, void>::value,
1591  std::is_void<value_type>::value>;
1592 
1593  using task_thenable_wrapper = typename trait_type::template task_thenable_type<TTHENABLE_PRIVATE_DATA>;
1594  using task_thenable_type = typename task_thenable_wrapper::task_type;
1595  };
1596 
1618  template <class TTHENABLE,
1619  class TTHENABLE_ERROR_TRANSFORM = typename thenable_error_transform_traits<TTHENABLE>::type>
1620  typename callable_thenable_trait<TTHENABLE, TTHENABLE_ERROR_TRANSFORM>::callable_thenable_type then(
1621  TTHENABLE&& thenable) {
1622  using trait_type = typename callable_thenable_trait<TTHENABLE, TTHENABLE_ERROR_TRANSFORM>::trait_type;
1623  return trait_type::invoke_callable(*this, std::forward<TTHENABLE>(thenable));
1624  }
1625 
1652  template <class TTHENABLE, class TTHENABLE_PRIVATE_DATA,
1653  class TTHENABLE_ERROR_TRANSFORM = typename thenable_error_transform_traits<TTHENABLE>::type>
1654  typename task_thenable_trait<TTHENABLE, typename std::decay<TTHENABLE_PRIVATE_DATA>::type,
1655  TTHENABLE_ERROR_TRANSFORM>::task_thenable_type
1656  then(TTHENABLE&& thenable, TTHENABLE_PRIVATE_DATA&& private_data) {
1657  using trait_type = typename task_thenable_trait<TTHENABLE, typename std::decay<TTHENABLE_PRIVATE_DATA>::type,
1658  TTHENABLE_ERROR_TRANSFORM>::trait_type;
1659  auto result = trait_type::template invoke_task<typename std::decay<TTHENABLE_PRIVATE_DATA>::type>(
1660  *this, std::forward<TTHENABLE>(thenable));
1661  *result.get_private_data() = std::forward<TTHENABLE_PRIVATE_DATA>(private_data);
1662  result.start();
1663  return result;
1664  }
1665 
1692  template <class TTHENABLE,
1693  class TTHENABLE_ERROR_TRANSFORM = typename thenable_error_transform_traits<TTHENABLE>::type>
1694  typename task_thenable_trait<TTHENABLE, void, TTHENABLE_ERROR_TRANSFORM>::task_thenable_type then(
1695  TTHENABLE&& thenable, std::nullptr_t) {
1696  using trait_type = typename task_thenable_trait<TTHENABLE, void, TTHENABLE_ERROR_TRANSFORM>::trait_type;
1697  auto result = trait_type::template invoke_task<void>(*this, std::forward<TTHENABLE>(thenable));
1698  result.start();
1699  return result;
1700  }
1701 };
1702 
1703 // some
1704 template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
1705 struct LIBCOPP_COTASK_API_HEAD_ONLY some_delegate_task_action {
1706  using future_type = task_future<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>;
1707  using context_type = LIBCOPP_COPP_NAMESPACE_ID::some_delegate_context<future_type>;
1708 
1709  inline static void suspend_future(const LIBCOPP_COPP_NAMESPACE_ID::promise_caller_manager::handle_delegate& caller,
1710  future_type& task_object) {
1711  if (task_object.get_context()) {
1712  task_object.get_context()->add_caller(caller);
1713  }
1714  }
1715 
1716  inline static void resume_future(const LIBCOPP_COPP_NAMESPACE_ID::promise_caller_manager::handle_delegate& caller,
1717  future_type& task_object) {
1718  if (task_object.get_context()) {
1719  task_object.get_context()->remove_caller(caller);
1720  }
1721  }
1722 
1723  inline static bool is_pending(future_type& future_object) noexcept { return !future_object.is_exiting(); }
1724 };
1725 
1726 LIBCOPP_COTASK_NAMESPACE_END
1727 
1728 LIBCOPP_COPP_NAMESPACE_BEGIN
1729 // some
1730 template <class TVALUE, class TPRIVATE_DATA, class TERROR_TRANSFORM>
1731 class LIBCOPP_COTASK_API_HEAD_ONLY some_delegate<cotask::task_future<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>>
1732  : public some_delegate_base<cotask::task_future<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>,
1733  cotask::some_delegate_task_action<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>> {
1734  public:
1735  using base_type = some_delegate_base<cotask::task_future<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>,
1736  cotask::some_delegate_task_action<TVALUE, TPRIVATE_DATA, TERROR_TRANSFORM>>;
1737  using future_type = typename base_type::future_type;
1738  using value_type = typename base_type::value_type;
1739  using ready_output_type = typename base_type::ready_output_type;
1740  using context_type = typename base_type::context_type;
1741 
1742  using base_type::run;
1743 };
1744 
1745 LIBCOPP_COPP_NAMESPACE_END
1746 
1747 #endif
Definition: task.h:37
int start(void *priv_data, EN_TASK_STATUS expected_status=EN_TS_CREATED) override
Definition: task.h:462
#define UTIL_FORCEINLINE
#define LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE
Definition: coroutine.h:41
#define COPP_UNLIKELY_IF(...)
Definition: features.h:117
#define COPP_LIKELY_IF(...)
Definition: features.h:102
锁管理器 Licensed under the MIT licenses.
auto operator==(const not_null< T > &lhs, const not_null< U > &rhs) noexcept(noexcept(lhs.get()==rhs.get())) -> decltype(lhs.get()==rhs.get())
Definition: not_null.h:116
auto operator!=(const not_null< T > &lhs, const not_null< U > &rhs) noexcept(noexcept(lhs.get() !=rhs.get())) -> decltype(lhs.get() !=rhs.get())
Definition: not_null.h:122
constexpr auto data(TCONTAINER &&container) -> decltype(container.data())
Definition: span.h:54
assign_t< T > assign(T &t)
std::shared_ptr< cli::cmd_option_value > value_type
Definition: cmd_option.h:50
自旋锁 Licensed under the MIT licenses.
class LIBCOPP_COTASK_API_HEAD_ONLY task_manager
Definition: task_manager.h:153