SObjectizer-5 Extra
Loading...
Searching...
No Matches
time_unlimited.hpp
Go to the documentation of this file.
1/*!
2 * \file
3 * \brief Implementation of time-unlimited asynchronous one-time operation.
4 *
5 * \since
6 * v.1.0.4
7 */
8
9#pragma once
10
11#include <so_5_extra/async_op/details.hpp>
12#include <so_5_extra/async_op/errors.hpp>
13
14#include <so_5/details/invoke_noexcept_code.hpp>
15
16#include <so_5/agent.hpp>
17
18#include <so_5/outliving.hpp>
19
20#include <vector>
21
22namespace so_5 {
23
24namespace extra {
25
26namespace async_op {
27
28namespace time_unlimited {
29
30//! Enumeration for status of operation.
31enum class status_t
32 {
33 //! Status of operation is unknown because the
34 //! operation data has been moved to another proxy-object.
36 //! Operation is not activated yet.
38 //! Operation is activated.
40 //! Operation is completed.
42 //! Operation is cancelled.
44 };
45
46// Forward declarations.
47// Necessary to declare friends for details::op_data_t.
48
49template< typename Operation_Data >
51
52template< typename Operation_Data >
54
55namespace details
56{
57
58/*!
59 * \brief A main class for implementation of time-unlimited
60 * asynchronous one-time operation.
61 *
62 * This class contains an information about completion handlers for
63 * async operation.
64 *
65 * Do not create objects of this class directly (unless you really know
66 * what you are doing).
67 * Use so_5::extra::async_op::time_unlimited::make() helper function for that.
68 *
69 * \note
70 * Instances of that class should be created only as dynamically allocated
71 * objects. It is because smart pointers are created inside the instance
72 * (for example completed_on() creates intrusive_ptr_t for `this`). Because
73 * of that this class has a protected destructor.
74 *
75 * \attention
76 * This is not a thread-safe type. It is beter and safer to work with
77 * an object of that type inside an agent for which that object is created.
78 *
79 * \since
80 * v.1.0.4
81 */
83 {
84 friend class ::so_5::intrusive_ptr_t<op_data_t>;
85
86 template< typename Operation_Data >
88 template< typename Operation_Data >
90
91 private :
92 //! Description of one subscription.
94 {
95 //! Mbox from that a message is expected.
97
98 //! State for that a subscription should be created.
99 /*!
100 * \attention
101 * Can't be nullptr.
102 */
103 const ::so_5::state_t * m_state;
104
105 //! Subscription type.
106 /*!
107 * \note
108 * This is a subscription type. Not a type which will
109 * be passed to the event handler.
110 */
112
113 //! Event handler.
115
116 //! Initializing constructor.
118 so_5::mbox_t mbox,
119 const so_5::state_t & state,
120 std::type_index subscription_type,
121 so_5::event_handler_method_t handler )
122 : m_mbox( std::move(mbox) )
123 , m_state( &state )
126 {}
127 };
128
129 //! Owner of async operation.
131
132 //! The status of the async operation.
134
135 //! Subscriptions which should be created on activation.
137
138 protected :
139 // NOTE: constructor and destructor will be available only
140 // for friends and for derived classes.
141
142 //! Initializing constructor.
144 //! An agent which owns async operation.
145 ::so_5::outliving_reference_t<::so_5::agent_t> owner )
146 : m_owner(owner)
147 {}
148
149 ~op_data_t() noexcept
150 {}
151
152 //! Reserve a capacity for vector with subscriptions' data.
153 void
154 reserve( std::size_t capacity )
155 {
156 m_subscriptions.reserve( capacity );
157 }
158
159 //! Add an operation completion handler.
160 /*!
161 * This method stores description of a competion handler. This
162 * description will be used later in activate() method for subscription
163 * to a completion message/signal.
164 *
165 * \tparam Operation_Data An actual type of operation data object.
166 * In the most cases it will be op_data_t itself. But for debugging or
167 * testing purposes it can also be a derived class. This type is
168 * necessary to store the right smart pointer to actual operation
169 * data object in event handler wrapper.
170 *
171 * \tparam Msg_Target A type of destination for message/signal about
172 * the completion of the async operation.
173 * It can be a const reference to so_5::mbox_t, so_5::agent_t,
174 * so_5::adhoc_agent_definition_proxy_t.
175 *
176 * \tparam Event_Handler A type of handler for message/signal about
177 * the completion of the async operation.
178 */
179 template<
180 typename Operation_Data,
181 typename Msg_Target,
182 typename Event_Handler >
183 void
185 //! A smart pointer to the actual instance of operation data.
186 ::so_5::intrusive_ptr_t< Operation_Data > actual_data,
187 //! A destination for message about operation completion.
188 Msg_Target && msg_target,
189 //! A state in which message should be handled.
190 const ::so_5::state_t & state,
191 //! A message handler.
192 Event_Handler && evt_handler )
193 {
195
196 const auto mbox = ::so_5::extra::async_op::details::target_to_mbox(
197 msg_target );
198
199 auto evt_handler_info =
201 mbox,
202 m_owner.get(),
204
208 ::so_5::message_ref_t & msg )
209 {
210 self->completed();
211 user_handler( msg );
212 };
213
215 mbox,
216 state,
219 }
220
221 /*!
222 * \brief Performs all necessary activation actions.
223 *
224 * \note
225 * It throws if:
226 * - the operation is already activated;
227 * - there is no defined completion handlers.
228 */
229 void
231 {
233
234 if( !m_subscriptions.empty() )
235 {
238 }
239 else
240 SO_5_THROW_EXCEPTION(
242 "Operation can't be activated without any completion "
243 "handler" );
244 }
245
246 //! Cancel async operation.
247 /*!
248 * If an async operation is in progress then all subscriptions
249 * will be destroyed and all information about completion handlers
250 * will be erased.
251 *
252 * \note
253 * It is safe to cancel an operation which wasn't activacted or
254 * was already finished.
255 * If cancel() is called before activate() then all information
256 * about completion handlers created by previous calls to
257 * add_completion_handler() will be lost.
258 *
259 * \attention
260 * This method is marked as noexcept because event unsubscription
261 * operations shouldn't throw. But if such operation throws then
262 * there is no way to recover.
263 */
264 void
265 cancel() noexcept
266 {
268 {
271 }
273 {
274 m_subscriptions.clear();
275 }
276 }
277
278 //! Get the current status of the operation.
280 current_status() const noexcept
281 {
282 return m_status;
283 }
284
285 //! Is there any completion handler?
286 [[nodiscard]] bool
287 has_completion_handlers() const noexcept
288 {
289 return !m_subscriptions.empty();
290 }
291
292 private :
293 //! Check if operation is activated and throw an exception if it is.
294 void
296 {
298 SO_5_THROW_EXCEPTION(
300 "Operation can't be performed when async_op is already "
301 "activated" );
302 }
303
304 //! Perform operation completion procedure.
305 /*!
306 * All subscriptions will be destroyed. All information about
307 * subscriptions will be deleted.
308 *
309 * Status will be changed to status_t::completed.
310 */
311 void
317
318 //! Subscribe agent for all subscriptions in the subscriptions' container.
319 /*!
320 * \note
321 * If an exception is thrown during subscription then all previously
322 * created subscriptions will be destroyed.
323 */
324 void
326 {
327 // All subscriptions must be destroyed if an exception
328 // is thrown.
329 std::size_t current_index = 0;
330 try
331 {
332 for(; current_index != m_subscriptions.size(); ++current_index )
333 {
334 auto & sd = m_subscriptions[ current_index ];
335 m_owner.get().so_create_event_subscription(
336 sd.m_mbox,
337 sd.m_subscription_type,
338 *(sd.m_state),
339 sd.m_handler,
340 ::so_5::thread_safety_t::unsafe,
341 ::so_5::event_handler_kind_t::final_handler );
342 }
343 }
344 catch(...)
345 {
346 // All created subscriptions should be dropped.
347 destroy_subscriptions_up_to( current_index );
348
349 throw;
350 }
351 }
352
353 //! Destroy all subscriptions and clean subscriptions' container.
354 void
356 {
357 destroy_subscriptions_up_to( m_subscriptions.size() );
358 m_subscriptions.clear();
359 }
360
361 //! Destroy subscriptions in range [0..n).
362 void
364 //! Last index of subscription in m_subscriptions container
365 //! which shouldn't be included.
366 const std::size_t n ) noexcept
367 {
368 for( std::size_t i = 0; i != n; ++i )
369 {
370 const auto & sd = m_subscriptions[ i ];
371 m_owner.get().so_destroy_event_subscription(
372 sd.m_mbox,
373 sd.m_subscription_type,
374 *(sd.m_state) );
375 }
376 }
377 };
378
379//
380// op_shptr_t
381//
382/*!
383 * \brief An alias for smart pointer to operation data.
384 *
385 * \since
386 * v.1.0.4
387 */
388template< typename Operation_Data >
390
391} /* namespace details */
392
393/*!
394 * \brief An object that allows to cancel async operation.
395 *
396 * Usage example:
397 * \code
398 * namespace asyncop = so_5::extra::async_op::time_unlimited;
399 * class demo : public so_5::agent_t {
400 * asyncop::cancellation_point_t<> cp_;
401 * ...
402 * void initiate_async_op() {
403 * auto op = asyncop::make<timeout>(*this);
404 * op.completed_on(...);
405 * cp_ = op.activate(...);
406 * }
407 * void on_interruption_signal(mhood_t<interrupt_activity> cmd) {
408 * // Operation should be cancelled.
409 * cp_.cancel();
410 * ...
411 * }
412 * };
413 * \endcode
414 *
415 * \note
416 * This class is DefaultConstructible and Moveable, but not Copyable
417 * and not CopyConstructible.
418 *
419 * \attention
420 * Objects of this class are not thread safe. It means that cancellation
421 * point should be used only by agent which created it. And the cancellation
422 * point can't be used inside thread-safe event handlers of that agent.
423 *
424 * \tparam Operation_Data Type of actual operation data representation.
425 * Please note that this template parameter is indended to be used for
426 * debugging and testing purposes only.
427 *
428 * \since
429 * v.1.0.4
430 */
431template< typename Operation_Data = details::op_data_t >
433 {
434 private :
435 template<typename Op_Data> friend class definition_point_t;
436
437 //! Actual data for async op.
438 /*!
439 * \note
440 * This can be a nullptr if the default constructor was used,
441 * or if operation is already cancelled, or if the content of
442 * the cancellation_point was moved to another object.
443 */
445
446 //! Initializing constructor to be used by definition_point.
448 //! Actual data for async operation.
449 //! Can't be null.
450 details::op_shptr_t< Operation_Data > op )
451 : m_op( std::move(op) )
452 {}
453
454 public :
456
459
461 operator=( const cancellation_point_t & ) = delete;
462
465
466 //! Get the status of the operation.
467 /*!
468 * \note
469 * The value status_t::unknown_moved_away can be returned if
470 * the actual data of the async operation was moved to another object
471 * (like another cancellation_point_t). Or after a call to
472 * cleanup() method.
473 */
475 status() const noexcept
476 {
477 if( m_op)
478 return m_op->current_status();
480 }
481
482 //! Can the async operation be cancelled via this cancellation point?
483 /*!
484 * \return true if the cancellation_point holds actual async operation's
485 * data and this async operation is not completed yet.
486 */
487 [[nodiscard]] bool
488 is_cancellable() const noexcept
489 {
490 return m_op && status_t::activated == m_op->current_status();
491 }
492
493 //! An attempt to cancel the async operation.
494 /*!
495 * \note
496 * Operation will be cancelled only if (true == is_cancellable()).
497 *
498 * It is safe to call cancel() if the operation is already
499 * cancelled or completed. In that case the call to
500 * cancel() will have no effect.
501 */
502 void
503 cancel() noexcept
504 {
505 if( is_cancellable() )
506 {
507 m_op->cancel();
508 }
509 }
510
511 //! Throw out a reference to the async operation data.
512 /*!
513 * A cancellation_point holds a reference to the async operation
514 * data. It means that the async operation data will be destroyed
515 * only when the cancellation_point will be destroyed. For example,
516 * in that case:
517 * \code
518 * namespace asyncop = so_5::extra::async_op::time_unlimited;
519 * class demo : public so_5::agent_t {
520 * ...
521 * asyncop::cancellation_point_t<> cp_;
522 * ...
523 * void initiate_async_op() {
524 * cp_ = asyncop::make<timeout_msg>(*this)
525 * ...
526 * .activate(...);
527 * ...
528 * }
529 * ...
530 * void on_some_interruption() {
531 * // Cancel asyncop.
532 * cp_.cancel();
533 * // Async operation is cancelled, but the async operation
534 * // data is still in memory. The data will be deallocated
535 * // only when cp_ receives new value or when cp_ will be
536 * // destroyed (e.g. after destruction of demo agent).
537 * }
538 * \endcode
539 *
540 * A call to cleanup() method removes the reference to the async
541 * operation data. It means that if the operation is already
542 * completed or cancelled, then the operation data
543 * fill be deallocated.
544 *
545 * \note
546 * If the operation is still in progress then a call to cleanup()
547 * doesn't break the operation. You need to call cancel() manually
548 * before calling cleanup() to cancel the operation.
549 */
550 void
551 cleanup() noexcept
552 {
553 m_op.reset();
554 }
555 };
556
557/*!
558 * \brief An interface for definition of async operation.
559 *
560 * Object of this type is usually created by make() function and
561 * is used for definition of async operation. Completion and timeout
562 * handlers are set for async operation by using definition_point object.
563 *
564 * Then an user calls activate() method and the definition_point transfers
565 * the async operation data into cancellation_point object. It means that
566 * after a call to activate() method the definition_point object should
567 * not be used. Because it doesn't hold any async operation anymore.
568 *
569 * A simple usage without storing the cancellation_point:
570 * \code
571 * namespace asyncop = so_5::extra::async_op::time_unlimited;
572 * class demo : public so_5::agent_t {
573 * ...
574 * void initiate_async_op() {
575 * // Create a definition_point for a new async operation...
576 * asyncop::make(*this)
577 * // ...then set up completion handler(s)...
578 * .completed_on(
579 * *this,
580 * so_default_state(),
581 * &demo::on_first_completion_msg )
582 * .completed_on(
583 * some_external_mbox_,
584 * some_user_defined_state_,
585 * [this](mhood_t<another_completion_msg> cmd) {...})
586 * // ...and now we can activate the operation.
587 * .activate();
588 * ...
589 * }
590 * };
591 * \endcode
592 * \note
593 * There is no need to hold definition_point object after activation
594 * of the async operation. This object can be safely discarded.
595 *
596 * A more complex example using cancellation_point for
597 * cancelling the operation.
598 * \code
599 * namespace asyncop = so_5::extra::async_op::time_unlimited;
600 * class demo : public so_5::agent_t {
601 * ...
602 * // Cancellation point for the async operation.
603 * asyncop::cancellation_point_t<> cp_;
604 * ...
605 * void initiate_async_op() {
606 * // Create a definition_point for a new async operation
607 * // and store the cancellation point after activation.
608 * cp_ = asyncop::make(*this)
609 * // ...then set up completion handler(s)...
610 * .completed_on(
611 * *this,
612 * so_default_state(),
613 * &demo::on_first_completion_msg )
614 * .completed_on(
615 * some_external_mbox_,
616 * some_user_defined_state_,
617 * [this](mhood_t<another_completion_msg> cmd) {...})
618 * // ...and now we can activate the operation.
619 * .activate();
620 * ...
621 * }
622 * ...
623 * void on_abortion_signal(mhood_t<abort_signal>) {
624 * // The current async operation should be cancelled.
625 * cp_.cancel();
626 * }
627 * };
628 * \endcode
629 *
630 * \note
631 * There are two forms of activate() method. The first one doesn't receive
632 * any arguments. It was shown in the examples above. The second one receives
633 * the lambda-function as argument. It can be used when some addtional
634 * actions should be performed during the activation of the async operation.
635 * For example:
636 * \code
637 * void initiate_async_op() {
638 * asyncop::make(*this)
639 * .completed_on(...)
640 * .completed_on(...)
641 * .activate([this] {
642 * // Several messages must be sent at the start of async op.
643 * so_5::send<first_initial_msg>(some_target, ...);
644 * so_5::send<second_initial_msg>(some_target, ...);
645 * ...
646 * });
647 * }
648 * \endcode
649 *
650 * \note
651 * This class is Moveable, but not DefaultConstructible nor Copyable.
652 *
653 * \attention
654 * Objects of this class are not thread safe. It means that a definition
655 * point should be used only by agent which created it. And the definition
656 * point can't be used inside thread-safe event handlers of that agent.
657 *
658 * \since
659 * v.1.0.4
660 */
661template<
662 typename Operation_Data = details::op_data_t >
664 {
665 //! Actual operation data.
666 /*!
667 * \note
668 * This pointer can be nullptr after activation or after the
669 * content of the object is moved away.
670 */
672
673 //! Checks that the definition_point owns async operation data.
674 void
676 {
677 if( !m_op )
680 "an attempt to use empty definition_point object" );
681 }
682
683 public :
684 //! Initializing constructor.
686 //! The owner of the async operation.
687 ::so_5::outliving_reference_t< ::so_5::agent_t > owner )
688 : m_op( new Operation_Data( owner ) )
689 {}
690
692 {
693 // If operation data is still here then it means that
694 // there wasn't call to `activate()` and we should cancel
695 // all described handlers.
696 // This will lead to deallocation of operation data.
697 if( this->m_op )
698 this->m_op->cancel();
699 }
700
703 operator=( const definition_point_t & ) = delete;
704
707 operator=( definition_point_t && ) = default;
708
709 /*!
710 * \brief Reserve a space for storage of completion handlers.
711 *
712 * Usage example:
713 * \code
714 * namespace asyncop = so_5::extra::async_op::time_unlimited;
715 * auto op = asyncop::make(some_agent);
716 * // Reserve space for four completion handlers.
717 * op.reserve_completion_handlers_capacity(4);
718 * op.completed_on(...);
719 * op.completed_on(...);
720 * op.completed_on(...);
721 * op.completed_on(...);
722 * op.activate();
723 * \endcode
724 */
727 //! A required capacity.
728 std::size_t capacity ) &
729 {
731
733
734 return *this;
735 }
736
737 //! Just a proxy for actual version of %reserve_completion_handlers_capacity.
738 template< typename... Args >
739 auto
741 {
742 return std::move(this->reserve_completion_handlers_capacity(
743 std::forward<Args>(args)... ));
744 }
745
746 /*!
747 * \brief Checks if the async operation can be activated.
748 *
749 * The operation can be activated if the definition_point still
750 * holds the operation data (e.g. operation is not activated yet) and
751 * there is at least one completion handler for the operation.
752 */
753 [[nodiscard]] bool
754 is_activable() const noexcept
755 {
756 // Operation is activable if we still hold the operation data.
757 return m_op && m_op->has_completion_handlers();
758 }
759
760 /*!
761 * \brief Add a completion handler for the async operation.
762 *
763 * Usage example:
764 * \code
765 * namespace asyncop = so_5::extra::async_op::time_unlimited;
766 * class demo : public so_5::agent_t {
767 * ...
768 * void initiate_async_op() {
769 * asyncop::make<timeout>(*this)
770 * .completed_on(
771 * *this,
772 * so_default_state(),
773 * &demo::some_event )
774 * .completed_on(
775 * some_mbox_,
776 * some_agent_state_,
777 * [this](mhood_t<some_msg> cmd) {...})
778 * ...
779 * .activate(...);
780 * }
781 * };
782 * \endcode
783 *
784 * \note
785 * The completion handler will be stored inside async operation
786 * data. Actual subscription for it will be made during activation
787 * of the async operation.
788 *
789 * \tparam Msg_Target It can be a mbox, or a reference to an agent.
790 * In the case if Msg_Target if a reference to an agent the agent's
791 * direct mbox will be used as message source.
792 *
793 * \tparam Event_Handler Type of actual handler for message/signal.
794 * It can be a pointer to agent's method or lambda (or another
795 * type of functional object).
796 */
797 template<
798 typename Msg_Target,
799 typename Event_Handler >
802 //! A source from which a completion message is expected.
803 //! It \a msg_target is a reference to an agent then
804 //! the agent's direct mbox will be used.
805 Msg_Target && msg_target,
806 //! A state for which that completion handler will be subscribed.
807 const ::so_5::state_t & state,
808 //! The completion handler itself.
809 Event_Handler && evt_handler ) &
810 {
812
814 this->m_op,
816 state,
818
819 return *this;
820 }
821
822 //! Just a proxy for the main version of %completed_on.
823 template< typename... Args >
825 completed_on( Args && ...args ) &&
826 {
827 return std::move(this->completed_on(std::forward<Args>(args)...));
828 }
829
830 //! Activate async operation with addition starting action.
831 /*!
832 * This method performs two steps:
833 *
834 * 1. Activates the async operation.
835 * 2. Calls \a action lambda-function (or functional object).
836 *
837 * It an exception is thrown from \a action then the activated
838 * async operation will be cancelled automatically.
839 *
840 * Usage example:
841 * \code
842 * namespace asyncop = so_5::extra::async_op::time_unlimited;
843 * class demo : public so_5::agent_t {
844 * public:
845 * ...
846 * virtual void so_evt_start() override {
847 * // Set up operation completion handlers...
848 * asyncop::make(*this)
849 * .completed_on(...)
850 * .completed_on(...)
851 * .completed_on(...)
852 * // And now the operation can be activated.
853 * .activate([this] {
854 * ... // Some initial actions like sending a message...
855 * });
856 * ...
857 * }
858 * };
859 * \endcode
860 *
861 * \attention
862 * It throws if `!is_activable()`.
863 *
864 * \attention
865 * If an exception is thrown during the activation procedure then
866 * the definition_point will become empty. It means that after an
867 * exception from activate() the definition_point object should not
868 * be used.
869 *
870 * \tparam Activation_Action A type of lambda-function or functional
871 * object to be excecuted on activation of operation.
872 */
873 template< typename Activation_Action >
874 cancellation_point_t< Operation_Data >
876 //! A lambda-function or functional object which will be called
877 //! after creation of all necessary subscriptions and switching
878 //! to activated status.
879 Activation_Action && action ) &
880 {
881 if( !this->is_activable() )
884 "definition_point_t doesn't hold operation data anymore." );
885 auto op = std::move(m_op);
886
887 op->activate();
888
890 [&] { action(); },
891 [&] { op->cancel(); } );
892
893 return { std::move(op) };
894 }
895
896 //! Activate async operation.
897 /*!
898 * Usage example:
899 * \code
900 * namespace asyncop = so_5::extra::async_op::time_unlimited;
901 * class demo : public so_5::agent_t {
902 * public:
903 * ...
904 * virtual void so_evt_start() override {
905 * // Create an async operation...
906 * asyncop::make(*this)
907 * // Then set up completion handlers...
908 * ->completed_on(...)
909 * .completed_on(...)
910 * .completed_on(...)
911 * // And now the operation can be activated.
912 * .activate();
913 * ...
914 * }
915 * };
916 * \endcode
917 *
918 * \attention
919 * It throws if `!is_activable()`.
920 *
921 * \attention
922 * If an exception is thrown during the activation procedure then
923 * the definition_point will become empty. It means that after an
924 * exception from activate() the definition_point object should not
925 * be used.
926 */
927 cancellation_point_t< Operation_Data >
929 {
930 return this->activate( []{/* Nothing to do*/} );
931 }
932
933 //! Just a proxy for actual %activate() methods.
934 template< typename... Args >
935 auto
936 activate( Args && ...args ) &&
937 {
938 return this->activate( std::forward<Args>(args)... );
939 }
940 };
941
942//
943// make
944//
945/*!
946 * \brief Helper function for creation an instance of async operation.
947 *
948 * Instead of creation of op_data_t's instances directly by hand this
949 * factory function should be used:
950 * \code
951 * namespace asyncop = so_5::extra::async_op::time_unlimited;
952 * class demo : public so_5::agent_t {
953 * public:
954 * ...
955 * virtual void so_evt_start() override {
956 * // Create an async operation...
957 * asyncop::make(*this)
958 * // ...set up operation completion handlers...
959 * .completed_on(...)
960 * .completed_on(...)
961 * .completed_on(...)
962 * // And now the operation can be activated.
963 * .activate();
964 * ...
965 * }
966 * };
967 * \endcode
968 *
969 * \since
970 * v.1.0.4
971 */
974 //! Agent for that this async operation will be created.
975 ::so_5::agent_t & owner )
976 {
977 return { ::so_5::outliving_mutable(owner) };
978 }
979
980} /* namespace time_unlimited */
981
982} /* namespace async_op */
983
984} /* namespace extra */
985
986} /* namespace so_5 */
An object that allows to cancel async operation.
cancellation_point_t(details::op_shptr_t< Operation_Data > op)
Initializing constructor to be used by definition_point.
details::op_shptr_t< Operation_Data > m_op
Actual data for async op.
void cleanup() noexcept
Throw out a reference to the async operation data.
void cancel() noexcept
An attempt to cancel the async operation.
bool is_cancellable() const noexcept
Can the async operation be cancelled via this cancellation point?
cancellation_point_t & operator=(const cancellation_point_t &)=delete
cancellation_point_t & operator=(cancellation_point_t &&)=default
status_t status() const noexcept
Get the status of the operation.
cancellation_point_t(const cancellation_point_t &)=delete
An interface for definition of async operation.
definition_point_t & operator=(const definition_point_t &)=delete
details::op_shptr_t< Operation_Data > m_op
Actual operation data.
definition_point_t & reserve_completion_handlers_capacity(std::size_t capacity) &
Reserve a space for storage of completion handlers.
void ensure_not_empty() const
Checks that the definition_point owns async operation data.
auto activate(Args &&...args) &&
Just a proxy for actual activate() methods.
cancellation_point_t< Operation_Data > activate() &
Activate async operation.
auto reserve_completion_handlers_capacity(Args &&...args) &&
Just a proxy for actual version of reserve_completion_handlers_capacity.
definition_point_t(const definition_point_t &)=delete
definition_point_t(::so_5::outliving_reference_t< ::so_5::agent_t > owner)
Initializing constructor.
definition_point_t & operator=(definition_point_t &&)=default
cancellation_point_t< Operation_Data > activate(Activation_Action &&action) &
Activate async operation with addition starting action.
bool is_activable() const noexcept
Checks if the async operation can be activated.
definition_point_t & completed_on(Msg_Target &&msg_target, const ::so_5::state_t &state, Event_Handler &&evt_handler) &
Add a completion handler for the async operation.
definition_point_t && completed_on(Args &&...args) &&
Just a proxy for the main version of completed_on.
A main class for implementation of time-unlimited asynchronous one-time operation.
void ensure_not_activated()
Check if operation is activated and throw an exception if it is.
std::vector< subscription_data_t > m_subscriptions
Subscriptions which should be created on activation.
void create_subscriptions()
Subscribe agent for all subscriptions in the subscriptions' container.
void destroy_subscriptions_up_to(const std::size_t n) noexcept
Destroy subscriptions in range [0..n).
void activate()
Performs all necessary activation actions.
void reserve(std::size_t capacity)
Reserve a capacity for vector with subscriptions' data.
void destroy_and_clear_subscriptions() noexcept
Destroy all subscriptions and clean subscriptions' container.
void completed() noexcept
Perform operation completion procedure.
status_t current_status() const noexcept
Get the current status of the operation.
status_t m_status
The status of the async operation.
op_data_t(::so_5::outliving_reference_t<::so_5::agent_t > owner)
Initializing constructor.
bool has_completion_handlers() const noexcept
Is there any completion handler?
::so_5::outliving_reference_t<::so_5::agent_t > m_owner
Owner of async operation.
void add_completion_handler(::so_5::intrusive_ptr_t< Operation_Data > actual_data, Msg_Target &&msg_target, const ::so_5::state_t &state, Event_Handler &&evt_handler)
Add an operation completion handler.
const int rc_async_op_activated
An attempt to perform some action which can't be done when async operation is activated.
Definition errors.hpp:28
const int rc_no_completion_handler
An attempt to activate async operation without defined completion handlers.
Definition errors.hpp:38
definition_point_t< details::op_data_t > make(::so_5::agent_t &owner)
Helper function for creation an instance of async operation.
status_t
Enumeration for status of operation.
@ not_activated
Operation is not activated yet.
@ unknown_moved_away
Status of operation is unknown because the operation data has been moved to another proxy-object.
Ranges for error codes of each submodules.
Definition details.hpp:13
const ::so_5::state_t * m_state
State for that a subscription should be created.
subscription_data_t(so_5::mbox_t mbox, const so_5::state_t &state, std::type_index subscription_type, so_5::event_handler_method_t handler)
Initializing constructor.