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