![]() |
|
|||
File indexing completed on 2025-07-02 08:07:13
0001 // 0002 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) 0003 // 0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying 0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 0006 // 0007 // Official repository: https://github.com/boostorg/beast 0008 // 0009 0010 #ifndef BOOST_BEAST_CORE_ASYNC_BASE_HPP 0011 #define BOOST_BEAST_CORE_ASYNC_BASE_HPP 0012 0013 #include <boost/beast/core/detail/config.hpp> 0014 #include <boost/beast/core/detail/allocator.hpp> 0015 #include <boost/beast/core/detail/async_base.hpp> 0016 #include <boost/beast/core/detail/filtering_cancellation_slot.hpp> 0017 #include <boost/beast/core/detail/work_guard.hpp> 0018 #include <boost/asio/append.hpp> 0019 #include <boost/asio/associated_allocator.hpp> 0020 #include <boost/asio/associated_cancellation_slot.hpp> 0021 #include <boost/asio/associated_executor.hpp> 0022 #include <boost/asio/associated_immediate_executor.hpp> 0023 #include <boost/asio/bind_executor.hpp> 0024 #include <boost/asio/dispatch.hpp> 0025 #include <boost/asio/handler_continuation_hook.hpp> 0026 #include <boost/asio/post.hpp> 0027 #include <boost/core/exchange.hpp> 0028 #include <boost/core/empty_value.hpp> 0029 #include <utility> 0030 0031 namespace boost { 0032 namespace beast { 0033 0034 0035 /** Base class to assist writing composed operations. 0036 0037 A function object submitted to intermediate initiating functions during 0038 a composed operation may derive from this type to inherit all of the 0039 boilerplate to forward the executor, allocator, and legacy customization 0040 points associated with the completion handler invoked at the end of the 0041 composed operation. 0042 0043 The composed operation must be typical; that is, associated with one 0044 executor of an I/O object, and invoking a caller-provided completion 0045 handler when the operation is finished. Classes derived from 0046 @ref async_base will acquire these properties: 0047 0048 @li Ownership of the final completion handler provided upon construction. 0049 0050 @li If the final handler has an associated allocator, this allocator will 0051 be propagated to the composed operation subclass. Otherwise, the 0052 associated allocator will be the type specified in the allocator 0053 template parameter, or the default of `std::allocator<void>` if the 0054 parameter is omitted. 0055 0056 @li If the final handler has an associated executor, then it will be used 0057 as the executor associated with the composed operation. Otherwise, 0058 the specified `Executor1` will be the type of executor associated 0059 with the composed operation. 0060 0061 @li An instance of `net::executor_work_guard` for the instance of `Executor1` 0062 shall be maintained until either the final handler is invoked, or the 0063 operation base is destroyed, whichever comes first. 0064 0065 @li Calls to the legacy customization point `asio_handler_is_continuation` 0066 which use argument-dependent lookup, will be forwarded to the 0067 legacy customization points associated with the handler. 0068 0069 @par Example 0070 0071 The following code demonstrates how @ref async_base may be be used to 0072 assist authoring an asynchronous initiating function, by providing all of 0073 the boilerplate to manage the final completion handler in a way that 0074 maintains the allocator and executor associations: 0075 0076 @code 0077 0078 // Asynchronously read into a buffer until the buffer is full, or an error occurs 0079 template<class AsyncReadStream, class ReadHandler> 0080 typename net::async_result<ReadHandler, void(error_code, std::size_t)>::return_type 0081 async_read(AsyncReadStream& stream, net::mutable_buffer buffer, ReadHandler&& handler) 0082 { 0083 using handler_type = BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t)); 0084 using base_type = async_base<handler_type, typename AsyncReadStream::executor_type>; 0085 0086 struct op : base_type 0087 { 0088 AsyncReadStream& stream_; 0089 net::mutable_buffer buffer_; 0090 std::size_t total_bytes_transferred_; 0091 0092 op( 0093 AsyncReadStream& stream, 0094 net::mutable_buffer buffer, 0095 handler_type& handler) 0096 : base_type(std::move(handler), stream.get_executor()) 0097 , stream_(stream) 0098 , buffer_(buffer) 0099 , total_bytes_transferred_(0) 0100 { 0101 (*this)({}, 0, false); // start the operation 0102 } 0103 0104 void operator()(error_code ec, std::size_t bytes_transferred, bool is_continuation = true) 0105 { 0106 // Adjust the count of bytes and advance our buffer 0107 total_bytes_transferred_ += bytes_transferred; 0108 buffer_ = buffer_ + bytes_transferred; 0109 0110 // Keep reading until buffer is full or an error occurs 0111 if(! ec && buffer_.size() > 0) 0112 return stream_.async_read_some(buffer_, std::move(*this)); 0113 0114 // Call the completion handler with the result. If `is_continuation` is 0115 // false, which happens on the first time through this function, then 0116 // `net::post` will be used to call the completion handler, otherwise 0117 // the completion handler will be invoked directly. 0118 0119 this->complete(is_continuation, ec, total_bytes_transferred_); 0120 } 0121 }; 0122 0123 net::async_completion<ReadHandler, void(error_code, std::size_t)> init{handler}; 0124 op(stream, buffer, init.completion_handler); 0125 return init.result.get(); 0126 } 0127 0128 @endcode 0129 0130 Data members of composed operations implemented as completion handlers 0131 do not have stable addresses, as the composed operation object is move 0132 constructed upon each call to an initiating function. For most operations 0133 this is not a problem. For complex operations requiring stable temporary 0134 storage, the class @ref stable_async_base is provided which offers 0135 additional functionality: 0136 0137 @li The free function @ref allocate_stable may be used to allocate 0138 one or more temporary objects associated with the composed operation. 0139 0140 @li Memory for stable temporary objects is allocated using the allocator 0141 associated with the composed operation. 0142 0143 @li Stable temporary objects are automatically destroyed, and the memory 0144 freed using the associated allocator, either before the final completion 0145 handler is invoked (a Networking requirement) or when the composed operation 0146 is destroyed, whichever occurs first. 0147 0148 @par Temporary Storage Example 0149 0150 The following example demonstrates how a composed operation may store a 0151 temporary object. 0152 0153 @code 0154 0155 @endcode 0156 0157 @tparam Handler The type of the completion handler to store. 0158 This type must meet the requirements of <em>CompletionHandler</em>. 0159 0160 @tparam Executor1 The type of the executor used when the handler has no 0161 associated executor. An instance of this type must be provided upon 0162 construction. The implementation will maintain an executor work guard 0163 and a copy of this instance. 0164 0165 @tparam Allocator The allocator type to use if the handler does not 0166 have an associated allocator. If this parameter is omitted, then 0167 `std::allocator<void>` will be used. If the specified allocator is 0168 not default constructible, an instance of the type must be provided 0169 upon construction. 0170 0171 @see stable_async_base 0172 */ 0173 template< 0174 class Handler, 0175 class Executor1, 0176 class Allocator = std::allocator<void> 0177 > 0178 class async_base 0179 #if ! BOOST_BEAST_DOXYGEN 0180 : private boost::empty_value<Allocator> 0181 #endif 0182 { 0183 static_assert( 0184 net::is_executor<Executor1>::value || net::execution::is_executor<Executor1>::value, 0185 "Executor type requirements not met"); 0186 0187 Handler h_; 0188 detail::select_work_guard_t<Executor1> wg1_; 0189 net::cancellation_type act_{net::cancellation_type::terminal}; 0190 public: 0191 /** The type of executor associated with this object. 0192 0193 If a class derived from @ref boost::beast::async_base is a completion 0194 handler, then the associated executor of the derived class will 0195 be this type. 0196 */ 0197 using executor_type = 0198 #if BOOST_BEAST_DOXYGEN 0199 __implementation_defined__; 0200 #else 0201 typename 0202 net::associated_executor< 0203 Handler, 0204 typename detail::select_work_guard_t<Executor1>::executor_type 0205 >::type; 0206 #endif 0207 0208 /** The type of the immediate executor associated with this object. 0209 0210 If a class derived from @ref boost::beast::async_base is a completion 0211 handler, then the associated immediage executor of the derived class will 0212 be this type. 0213 */ 0214 using immediate_executor_type = 0215 #if BOOST_BEAST_DOXYGEN 0216 __implementation_defined__; 0217 #else 0218 typename 0219 net::associated_immediate_executor< 0220 Handler, 0221 typename detail::select_work_guard_t<Executor1>::executor_type 0222 >::type; 0223 #endif 0224 0225 0226 private: 0227 0228 virtual 0229 void 0230 before_invoke_hook() 0231 { 0232 } 0233 0234 public: 0235 /** Constructor 0236 0237 @param handler The final completion handler. 0238 The type of this object must meet the requirements of <em>CompletionHandler</em>. 0239 The implementation takes ownership of the handler by performing a decay-copy. 0240 0241 @param ex1 The executor associated with the implied I/O object 0242 target of the operation. The implementation shall maintain an 0243 executor work guard for the lifetime of the operation, or until 0244 the final completion handler is invoked, whichever is shorter. 0245 0246 @param alloc The allocator to be associated with objects 0247 derived from this class. If `Allocator` is default-constructible, 0248 this parameter is optional and may be omitted. 0249 */ 0250 #if BOOST_BEAST_DOXYGEN 0251 template<class Handler_> 0252 async_base( 0253 Handler&& handler, 0254 Executor1 const& ex1, 0255 Allocator const& alloc = Allocator()); 0256 #else 0257 template< 0258 class Handler_, 0259 class = typename std::enable_if< 0260 ! std::is_same<typename 0261 std::decay<Handler_>::type, 0262 async_base 0263 >::value>::type 0264 > 0265 async_base( 0266 Handler_&& handler, 0267 Executor1 const& ex1) 0268 : h_(std::forward<Handler_>(handler)) 0269 , wg1_(detail::make_work_guard(ex1)) 0270 { 0271 } 0272 0273 template<class Handler_> 0274 async_base( 0275 Handler_&& handler, 0276 Executor1 const& ex1, 0277 Allocator const& alloc) 0278 : boost::empty_value<Allocator>( 0279 boost::empty_init_t{}, alloc) 0280 , h_(std::forward<Handler_>(handler)) 0281 , wg1_(ex1) 0282 { 0283 } 0284 #endif 0285 0286 /// Move Constructor 0287 async_base(async_base&& other) = default; 0288 0289 virtual ~async_base() = default; 0290 async_base(async_base const&) = delete; 0291 async_base& operator=(async_base const&) = delete; 0292 0293 /** The type of allocator associated with this object. 0294 0295 If a class derived from @ref boost::beast::async_base is a completion 0296 handler, then the associated allocator of the derived class will 0297 be this type. 0298 */ 0299 using allocator_type = 0300 net::associated_allocator_t<Handler, Allocator>; 0301 0302 /** Returns the allocator associated with this object. 0303 0304 If a class derived from @ref boost::beast::async_base is a completion 0305 handler, then the object returned from this function will be used 0306 as the associated allocator of the derived class. 0307 */ 0308 allocator_type 0309 get_allocator() const noexcept 0310 { 0311 return net::get_associated_allocator(h_, 0312 boost::empty_value<Allocator>::get()); 0313 } 0314 0315 /** Returns the executor associated with this object. 0316 0317 If a class derived from @ref boost::beast::async_base is a completion 0318 handler, then the object returned from this function will be used 0319 as the associated executor of the derived class. 0320 */ 0321 executor_type 0322 get_executor() const noexcept 0323 { 0324 return net::get_associated_executor( 0325 h_, wg1_.get_executor()); 0326 } 0327 0328 /** Returns the immediate executor associated with this handler. 0329 If the handler has none it returns asios default immediate 0330 executor based on the executor of the object. 0331 0332 If a class derived from @ref boost::beast::async_base is a completion 0333 handler, then the object returned from this function will be used 0334 as the associated immediate executor of the derived class. 0335 */ 0336 immediate_executor_type 0337 get_immediate_executor() const noexcept 0338 { 0339 return net::get_associated_immediate_executor( 0340 h_, wg1_.get_executor()); 0341 } 0342 0343 0344 /** The type of cancellation_slot associated with this object. 0345 0346 If a class derived from @ref async_base is a completion 0347 handler, then the associated cancellation_slot of the 0348 derived class will be this type. 0349 0350 The default type is a filtering cancellation slot, 0351 that only allows terminal cancellation. 0352 */ 0353 using cancellation_slot_type = 0354 beast::detail::filtering_cancellation_slot<net::associated_cancellation_slot_t<Handler>>; 0355 0356 /** Returns the cancellation_slot associated with this object. 0357 0358 If a class derived from @ref async_base is a completion 0359 handler, then the object returned from this function will be used 0360 as the associated cancellation_slot of the derived class. 0361 */ 0362 cancellation_slot_type 0363 get_cancellation_slot() const noexcept 0364 { 0365 return cancellation_slot_type(act_, net::get_associated_cancellation_slot(h_, 0366 net::cancellation_slot())); 0367 } 0368 0369 /// Set the allowed cancellation types, default is `terminal`. 0370 void set_allowed_cancellation( 0371 net::cancellation_type allowed_cancellation_types = net::cancellation_type::terminal) 0372 { 0373 act_ = allowed_cancellation_types; 0374 } 0375 0376 /// Returns the handler associated with this object 0377 Handler const& 0378 handler() const noexcept 0379 { 0380 return h_; 0381 } 0382 0383 /** Returns ownership of the handler associated with this object 0384 0385 This function is used to transfer ownership of the handler to 0386 the caller, by move-construction. After the move, the only 0387 valid operations on the base object are move construction and 0388 destruction. 0389 */ 0390 Handler 0391 release_handler() 0392 { 0393 return std::move(h_); 0394 } 0395 0396 /** Invoke the final completion handler, maybe using post. 0397 0398 This invokes the final completion handler with the specified 0399 arguments forwarded. It is undefined to call either of 0400 @ref boost::beast::async_base::complete or 0401 @ref boost::beast::async_base::complete_now more than once. 0402 0403 Any temporary objects allocated with @ref boost::beast::allocate_stable will 0404 be automatically destroyed before the final completion handler 0405 is invoked. 0406 0407 @param is_continuation If this value is `false`, then the 0408 handler will be submitted to the to the immediate executor using 0409 `net::dispatch`. If the handler has no immediate executor, 0410 this will submit to the executor via `net::post`. 0411 Otherwise the handler will be invoked as if by calling 0412 @ref boost::beast::async_base::complete_now. 0413 0414 @param args A list of optional parameters to invoke the handler 0415 with. The completion handler must be invocable with the parameter 0416 list, or else a compilation error will result. 0417 */ 0418 template<class... Args> 0419 void 0420 complete(bool is_continuation, Args&&... args) 0421 { 0422 this->before_invoke_hook(); 0423 if(! is_continuation) 0424 { 0425 auto const ex = this->get_immediate_executor(); 0426 net::dispatch( 0427 ex, 0428 net::append(std::move(h_), std::forward<Args>(args)...)); 0429 wg1_.reset(); 0430 } 0431 else 0432 { 0433 wg1_.reset(); 0434 h_(std::forward<Args>(args)...); 0435 } 0436 } 0437 0438 /** Invoke the final completion handler. 0439 0440 This invokes the final completion handler with the specified 0441 arguments forwarded. It is undefined to call either of 0442 @ref boost::beast::async_base::complete or @ref boost::beast::async_base::complete_now more than once. 0443 0444 Any temporary objects allocated with @ref boost::beast::allocate_stable will 0445 be automatically destroyed before the final completion handler 0446 is invoked. 0447 0448 @param args A list of optional parameters to invoke the handler 0449 with. The completion handler must be invocable with the parameter 0450 list, or else a compilation error will result. 0451 */ 0452 template<class... Args> 0453 void 0454 complete_now(Args&&... args) 0455 { 0456 this->before_invoke_hook(); 0457 wg1_.reset(); 0458 h_(std::forward<Args>(args)...); 0459 } 0460 0461 #if ! BOOST_BEAST_DOXYGEN 0462 Handler* 0463 get_legacy_handler_pointer() noexcept 0464 { 0465 return std::addressof(h_); 0466 } 0467 #endif 0468 }; 0469 0470 //------------------------------------------------------------------------------ 0471 0472 /** Base class to provide completion handler boilerplate for composed operations. 0473 0474 A function object submitted to intermediate initiating functions during 0475 a composed operation may derive from this type to inherit all of the 0476 boilerplate to forward the executor, allocator, and legacy customization 0477 points associated with the completion handler invoked at the end of the 0478 composed operation. 0479 0480 The composed operation must be typical; that is, associated with one 0481 executor of an I/O object, and invoking a caller-provided completion 0482 handler when the operation is finished. Classes derived from 0483 @ref async_base will acquire these properties: 0484 0485 @li Ownership of the final completion handler provided upon construction. 0486 0487 @li If the final handler has an associated allocator, this allocator will 0488 be propagated to the composed operation subclass. Otherwise, the 0489 associated allocator will be the type specified in the allocator 0490 template parameter, or the default of `std::allocator<void>` if the 0491 parameter is omitted. 0492 0493 @li If the final handler has an associated executor, then it will be used 0494 as the executor associated with the composed operation. Otherwise, 0495 the specified `Executor1` will be the type of executor associated 0496 with the composed operation. 0497 0498 @li An instance of `net::executor_work_guard` for the instance of `Executor1` 0499 shall be maintained until either the final handler is invoked, or the 0500 operation base is destroyed, whichever comes first. 0501 0502 0503 Data members of composed operations implemented as completion handlers 0504 do not have stable addresses, as the composed operation object is move 0505 constructed upon each call to an initiating function. For most operations 0506 this is not a problem. For complex operations requiring stable temporary 0507 storage, the class @ref stable_async_base is provided which offers 0508 additional functionality: 0509 0510 @li The free function @ref beast::allocate_stable may be used to allocate 0511 one or more temporary objects associated with the composed operation. 0512 0513 @li Memory for stable temporary objects is allocated using the allocator 0514 associated with the composed operation. 0515 0516 @li Stable temporary objects are automatically destroyed, and the memory 0517 freed using the associated allocator, either before the final completion 0518 handler is invoked (a Networking requirement) or when the composed operation 0519 is destroyed, whichever occurs first. 0520 0521 @par Example 0522 0523 The following code demonstrates how @ref stable_async_base may be be used to 0524 assist authoring an asynchronous initiating function, by providing all of 0525 the boilerplate to manage the final completion handler in a way that maintains 0526 the allocator and executor associations. Furthermore, the operation shown 0527 allocates temporary memory using @ref beast::allocate_stable for the timer and 0528 message, whose addresses must not change between intermediate operations: 0529 0530 @code 0531 0532 // Asynchronously send a message multiple times, once per second 0533 template <class AsyncWriteStream, class T, class WriteHandler> 0534 auto async_write_messages( 0535 AsyncWriteStream& stream, 0536 T const& message, 0537 std::size_t repeat_count, 0538 WriteHandler&& handler) -> 0539 typename net::async_result< 0540 typename std::decay<WriteHandler>::type, 0541 void(error_code)>::return_type 0542 { 0543 using handler_type = typename net::async_completion<WriteHandler, void(error_code)>::completion_handler_type; 0544 using base_type = stable_async_base<handler_type, typename AsyncWriteStream::executor_type>; 0545 0546 struct op : base_type, boost::asio::coroutine 0547 { 0548 // This object must have a stable address 0549 struct temporary_data 0550 { 0551 // Although std::string is in theory movable, most implementations 0552 // use a "small buffer optimization" which means that we might 0553 // be submitting a buffer to the write operation and then 0554 // moving the string, invalidating the buffer. To prevent 0555 // undefined behavior we store the string object itself at 0556 // a stable location. 0557 std::string const message; 0558 0559 net::steady_timer timer; 0560 0561 temporary_data(std::string message_, net::io_context& ctx) 0562 : message(std::move(message_)) 0563 , timer(ctx) 0564 { 0565 } 0566 }; 0567 0568 AsyncWriteStream& stream_; 0569 std::size_t repeats_; 0570 temporary_data& data_; 0571 0572 op(AsyncWriteStream& stream, std::size_t repeats, std::string message, handler_type& handler) 0573 : base_type(std::move(handler), stream.get_executor()) 0574 , stream_(stream) 0575 , repeats_(repeats) 0576 , data_(allocate_stable<temporary_data>(*this, std::move(message), stream.get_executor().context())) 0577 { 0578 (*this)(); // start the operation 0579 } 0580 0581 // Including this file provides the keywords for macro-based coroutines 0582 #include <boost/asio/yield.hpp> 0583 0584 void operator()(error_code ec = {}, std::size_t = 0) 0585 { 0586 reenter(*this) 0587 { 0588 // If repeats starts at 0 then we must complete immediately. But 0589 // we can't call the final handler from inside the initiating 0590 // function, so we post our intermediate handler first. We use 0591 // net::async_write with an empty buffer instead of calling 0592 // net::post to avoid an extra function template instantiation, to 0593 // keep compile times lower and make the resulting executable smaller. 0594 yield net::async_write(stream_, net::const_buffer{}, std::move(*this)); 0595 while(! ec && repeats_-- > 0) 0596 { 0597 // Send the string. We construct a `const_buffer` here to guarantee 0598 // that we do not create an additional function template instantation 0599 // of net::async_write, since we already instantiated it above for 0600 // net::const_buffer. 0601 0602 yield net::async_write(stream_, 0603 net::const_buffer(net::buffer(data_.message)), std::move(*this)); 0604 if(ec) 0605 break; 0606 0607 // Set the timer and wait 0608 data_.timer.expires_after(std::chrono::seconds(1)); 0609 yield data_.timer.async_wait(std::move(*this)); 0610 } 0611 } 0612 0613 // The base class destroys the temporary data automatically, 0614 // before invoking the final completion handler 0615 this->complete_now(ec); 0616 } 0617 0618 // Including this file undefines the macros for the coroutines 0619 #include <boost/asio/unyield.hpp> 0620 }; 0621 0622 net::async_completion<WriteHandler, void(error_code)> completion(handler); 0623 std::ostringstream os; 0624 os << message; 0625 op(stream, repeat_count, os.str(), completion.completion_handler); 0626 return completion.result.get(); 0627 } 0628 0629 @endcode 0630 0631 @tparam Handler The type of the completion handler to store. 0632 This type must meet the requirements of <em>CompletionHandler</em>. 0633 0634 @tparam Executor1 The type of the executor used when the handler has no 0635 associated executor. An instance of this type must be provided upon 0636 construction. The implementation will maintain an executor work guard 0637 and a copy of this instance. 0638 0639 @tparam Allocator The allocator type to use if the handler does not 0640 have an associated allocator. If this parameter is omitted, then 0641 `std::allocator<void>` will be used. If the specified allocator is 0642 not default constructible, an instance of the type must be provided 0643 upon construction. 0644 0645 @see allocate_stable, async_base 0646 */ 0647 template< 0648 class Handler, 0649 class Executor1, 0650 class Allocator = std::allocator<void> 0651 > 0652 class stable_async_base 0653 : public async_base< 0654 Handler, Executor1, Allocator> 0655 { 0656 detail::stable_base* list_ = nullptr; 0657 0658 void 0659 before_invoke_hook() override 0660 { 0661 detail::stable_base::destroy_list(list_); 0662 } 0663 0664 public: 0665 /** Constructor 0666 0667 @param handler The final completion handler. 0668 The type of this object must meet the requirements of <em>CompletionHandler</em>. 0669 The implementation takes ownership of the handler by performing a decay-copy. 0670 0671 @param ex1 The executor associated with the implied I/O object 0672 target of the operation. The implementation shall maintain an 0673 executor work guard for the lifetime of the operation, or until 0674 the final completion handler is invoked, whichever is shorter. 0675 0676 @param alloc The allocator to be associated with objects 0677 derived from this class. If `Allocator` is default-constructible, 0678 this parameter is optional and may be omitted. 0679 */ 0680 #if BOOST_BEAST_DOXYGEN 0681 template<class Handler> 0682 stable_async_base( 0683 Handler&& handler, 0684 Executor1 const& ex1, 0685 Allocator const& alloc = Allocator()); 0686 #else 0687 template< 0688 class Handler_, 0689 class = typename std::enable_if< 0690 ! std::is_same<typename 0691 std::decay<Handler_>::type, 0692 stable_async_base 0693 >::value>::type 0694 > 0695 stable_async_base( 0696 Handler_&& handler, 0697 Executor1 const& ex1) 0698 : async_base< 0699 Handler, Executor1, Allocator>( 0700 std::forward<Handler_>(handler), ex1) 0701 { 0702 } 0703 0704 template<class Handler_> 0705 stable_async_base( 0706 Handler_&& handler, 0707 Executor1 const& ex1, 0708 Allocator const& alloc) 0709 : async_base< 0710 Handler, Executor1, Allocator>( 0711 std::forward<Handler_>(handler), ex1, alloc) 0712 { 0713 } 0714 #endif 0715 0716 /// Move Constructor 0717 stable_async_base(stable_async_base&& other) 0718 : async_base<Handler, Executor1, Allocator>( 0719 std::move(other)) 0720 , list_(boost::exchange(other.list_, nullptr)) 0721 { 0722 } 0723 0724 /** Destructor 0725 0726 If the completion handler was not invoked, then any 0727 state objects allocated with @ref allocate_stable will 0728 be destroyed here. 0729 */ 0730 ~stable_async_base() 0731 { 0732 detail::stable_base::destroy_list(list_); 0733 } 0734 0735 /** Allocate a temporary object to hold operation state. 0736 0737 The object will be destroyed just before the completion 0738 handler is invoked, or when the operation base is destroyed. 0739 */ 0740 template< 0741 class State, 0742 class Handler_, 0743 class Executor1_, 0744 class Allocator_, 0745 class... Args> 0746 friend 0747 State& 0748 allocate_stable( 0749 stable_async_base< 0750 Handler_, Executor1_, Allocator_>& base, 0751 Args&&... args); 0752 }; 0753 0754 /** Allocate a temporary object to hold stable asynchronous operation state. 0755 0756 The object will be destroyed just before the completion 0757 handler is invoked, or when the base is destroyed. 0758 0759 @tparam State The type of object to allocate. 0760 0761 @param base The helper to allocate from. 0762 0763 @param args An optional list of parameters to forward to the 0764 constructor of the object being allocated. 0765 0766 @see stable_async_base 0767 */ 0768 template< 0769 class State, 0770 class Handler, 0771 class Executor1, 0772 class Allocator, 0773 class... Args> 0774 State& 0775 allocate_stable( 0776 stable_async_base< 0777 Handler, Executor1, Allocator>& base, 0778 Args&&... args); 0779 0780 } // beast 0781 } // boost 0782 0783 #include <boost/beast/core/impl/async_base.hpp> 0784 0785 #endif
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |