85.11% Lines (40/47)
75.00% Functions (12/16)
| TLA | Baseline | Branch | ||||||
|---|---|---|---|---|---|---|---|---|
| Line | Hits | Code | Line | Hits | Code | |||
| 1 | + | // | ||||||
| 2 | + | // Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com) | ||||||
| 3 | + | // | ||||||
| 4 | + | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||||
| 5 | + | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||||
| 6 | + | // | ||||||
| 7 | + | // Official repository: https://github.com/cppalliance/capy | ||||||
| 8 | + | // | ||||||
| 9 | + | |||||||
| 10 | + | #ifndef BOOST_CAPY_ASIO_CONTINUATION_HPP | ||||||
| 11 | + | #define BOOST_CAPY_ASIO_CONTINUATION_HPP | ||||||
| 12 | + | |||||||
| 13 | + | #include <boost/capy/continuation.hpp> | ||||||
| 14 | + | #include <boost/capy/concept/executor.hpp> | ||||||
| 15 | + | |||||||
| 16 | + | #include <memory> | ||||||
| 17 | + | |||||||
| 18 | + | namespace boost::capy | ||||||
| 19 | + | { | ||||||
| 20 | + | |||||||
| 21 | + | namespace detail | ||||||
| 22 | + | { | ||||||
| 23 | + | |||||||
| 24 | + | template<typename Allocator> | ||||||
| 25 | + | struct continuation_handle_promise_base_ | ||||||
| 26 | + | { | ||||||
| 27 | + | using alloc_t = std::allocator_traits<Allocator> | ||||||
| 28 | + | ::template rebind_alloc<char>; | ||||||
| 29 | + | |||||||
| 30 | + | template<typename Func> | ||||||
| HITGNC | 31 | + | 5 | void * operator new(std::size_t n, Func &, Allocator &allocator_) | ||||
| 32 | + | { | ||||||
| HITGNC | 33 | + | 5 | alloc_t alloc(allocator_); | ||||
| HITGNC | 34 | + | 5 | std::size_t m = n; | ||||
| HITGNC | 35 | + | 5 | if (n % alignof(alloc_t) > 0) | ||||
| MISUNC | 36 | + | ✗ | m += alignof(alloc_t) - (n % alignof(alloc_t)); | ||||
| 37 | + | |||||||
| HITGNC | 38 | + | 5 | char * mem = alloc.allocate(m + sizeof(alloc)); | ||||
| 39 | + | |||||||
| HITGNC | 40 | + | 5 | new (mem + m) alloc_t(std::move(alloc)); | ||||
| HITGNC | 41 | + | 5 | return mem; | ||||
| 42 | + | } | ||||||
| 43 | + | |||||||
| HITGNC | 44 | + | 5 | void operator delete(void * p, std::size_t n) | ||||
| 45 | + | { | ||||||
| HITGNC | 46 | + | 5 | std::size_t m = n; | ||||
| HITGNC | 47 | + | 5 | if (n % alignof(alloc_t) > 0) | ||||
| MISUNC | 48 | + | ✗ | m += alignof(alloc_t) - (n % alignof(alloc_t)); | ||||
| 49 | + | |||||||
| HITGNC | 50 | + | 5 | auto * a = reinterpret_cast<alloc_t*>(static_cast<char*>(p) + m); | ||||
| 51 | + | |||||||
| HITGNC | 52 | + | 5 | alloc_t alloc(std::move(*a)); | ||||
| HITGNC | 53 | + | 5 | a->~alloc_t(); | ||||
| 54 | + | |||||||
| HITGNC | 55 | + | 5 | alloc.deallocate(static_cast<char*>(p), n); | ||||
| HITGNC | 56 | + | 5 | } | ||||
| 57 | + | }; | ||||||
| 58 | + | |||||||
| 59 | + | |||||||
| 60 | + | template<> | ||||||
| 61 | + | struct continuation_handle_promise_base_<std::allocator<void>> | ||||||
| 62 | + | { | ||||||
| 63 | + | }; | ||||||
| 64 | + | |||||||
| 65 | + | template<typename Allocator> | ||||||
| 66 | + | struct continuation_handle_promise_type | ||||||
| 67 | + | : continuation_handle_promise_base_<Allocator> | ||||||
| 68 | + | { | ||||||
| 69 | + | |||||||
| 70 | + | struct initial_aw_t | ||||||
| 71 | + | { | ||||||
| HITGNC | 72 | + | 11 | bool await_ready() const {return false;} | ||||
| HITGNC | 73 | + | 11 | void await_suspend( | ||||
| 74 | + | std::coroutine_handle<continuation_handle_promise_type<Allocator>> h) | ||||||
| 75 | + | { | ||||||
| HITGNC | 76 | + | 11 | auto & c = h.promise().cont; | ||||
| HITGNC | 77 | + | 11 | c.h = h; | ||||
| HITGNC | 78 | + | 11 | c.next = nullptr; | ||||
| HITGNC | 79 | + | 11 | } | ||||
| HITGNC | 80 | + | 11 | void await_resume() {} | ||||
| 81 | + | }; | ||||||
| 82 | + | |||||||
| HITGNC | 83 | + | 11 | initial_aw_t initial_suspend() const noexcept | ||||
| 84 | + | { | ||||||
| HITGNC | 85 | + | 11 | return initial_aw_t{}; | ||||
| 86 | + | } | ||||||
| MISUNC | 87 | + | ✗ | std::suspend_never final_suspend() const noexcept {return {};} | ||||
| 88 | + | |||||||
| 89 | + | template<typename Function> | ||||||
| HITGNC | 90 | + | 11 | auto yield_value(Function & func) | ||||
| 91 | + | { | ||||||
| 92 | + | struct yielder | ||||||
| 93 | + | { | ||||||
| 94 | + | Function func; | ||||||
| 95 | + | |||||||
| HITGNC | 96 | + | 11 | bool await_ready() const {return false;} | ||||
| HITGNC | 97 | + | 11 | void await_suspend(std::coroutine_handle<> h) | ||||
| 98 | + | { | ||||||
| HITGNC | 99 | + | 11 | auto f = std::move(func); | ||||
| HITGNC | 100 | + | 11 | h.destroy(); | ||||
| 101 | + | |||||||
| 102 | + | #if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ <= 14) | ||||||
| 103 | + | #pragma GCC diagnostic push | ||||||
| 104 | + | #pragma GCC diagnostic ignored "-Warray-bounds" | ||||||
| 105 | + | #endif | ||||||
| 106 | + | |||||||
| HITGNC | 107 | + | 11 | std::move(f)(); | ||||
| 108 | + | |||||||
| 109 | + | #if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ <= 14) | ||||||
| 110 | + | #pragma GCC diagnostic pop | ||||||
| 111 | + | #endif | ||||||
| 112 | + | |||||||
| HITGNC | 113 | + | 11 | } | ||||
| MISUNC | 114 | + | ✗ | void await_resume() {} | ||||
| 115 | + | }; | ||||||
| 116 | + | |||||||
| HITGNC | 117 | + | 11 | return yielder{std::move(func)}; | ||||
| 118 | + | } | ||||||
| 119 | + | |||||||
| MISUNC | 120 | + | ✗ | void unhandled_exception() { throw; } | ||||
| MISUNC | 121 | + | ✗ | void return_void() {} | ||||
| 122 | + | |||||||
| 123 | + | continuation cont; | ||||||
| 124 | + | |||||||
| 125 | + | struct helper | ||||||
| 126 | + | { | ||||||
| 127 | + | continuation * cont; | ||||||
| 128 | + | using promise_type = continuation_handle_promise_type; | ||||||
| 129 | + | }; | ||||||
| 130 | + | |||||||
| HITGNC | 131 | + | 11 | helper get_return_object() | ||||
| 132 | + | { | ||||||
| HITGNC | 133 | + | 11 | return helper{&cont}; | ||||
| 134 | + | } | ||||||
| 135 | + | }; | ||||||
| 136 | + | |||||||
| 137 | + | #if defined(__GNUC__) && !defined(__clang__) | ||||||
| 138 | + | #pragma GCC diagnostic push | ||||||
| 139 | + | #pragma GCC diagnostic ignored "-Wmismatched-new-delete" | ||||||
| 140 | + | #endif | ||||||
| 141 | + | |||||||
| 142 | + | template<std::invocable<> Function, typename Allocator> | ||||||
| HITGNC | 143 | + | 11 | auto make_continuation_helper( | ||||
| 144 | + | Function func, | ||||||
| 145 | + | Allocator) | ||||||
| 146 | + | -> continuation_handle_promise_type<Allocator>::helper | ||||||
| 147 | + | { | ||||||
| 148 | + | co_yield func; | ||||||
| HITGNC | 149 | + | 22 | } | ||||
| 150 | + | |||||||
| 151 | + | #if defined(__GNUC__) && !defined(__clang__) | ||||||
| 152 | + | #pragma GCC diagnostic pop | ||||||
| 153 | + | #endif | ||||||
| 154 | + | |||||||
| 155 | + | template<std::invocable<> Function, typename Allocator> | ||||||
| HITGNC | 156 | + | 11 | continuation & make_continuation( | ||||
| 157 | + | Function && func, | ||||||
| 158 | + | Allocator && alloc) | ||||||
| 159 | + | { | ||||||
| HITGNC | 160 | + | 11 | continuation * c = detail::make_continuation_helper( | ||||
| MISUNC | 161 | + | ✗ | std::forward<Function>(func), | ||||
| HITGNC | 162 | + | 11 | std::forward<Allocator>(alloc)).cont; | ||||
| HITGNC | 163 | + | 11 | return *c; | ||||
| 164 | + | } | ||||||
| 165 | + | |||||||
| 166 | + | } | ||||||
| 167 | + | |||||||
| 168 | + | |||||||
| 169 | + | } | ||||||
| 170 | + | |||||||
| 171 | + | #endif | ||||||
| 172 | + | |||||||