SObjectizer-5 Extra
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 
22 namespace so_5 {
23 
24 namespace extra {
25 
26 namespace async_op {
27 
28 namespace time_unlimited {
29 
30 //! Enumeration for status of operation.
31 enum 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.
39  activated,
40  //! Operation is completed.
41  completed,
42  //! Operation is cancelled.
43  cancelled
44  };
45 
46 // Forward declarations.
47 // Necessary to declare friends for details::op_data_t.
48 
49 template< typename Operation_Data >
51 
52 template< typename Operation_Data >
54 
55 namespace 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  */
82 class op_data_t : protected ::so_5::atomic_refcounted_t
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 )
125  , m_handler( std::move(handler) )
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 
206  [self = std::move(actual_data),
208  ::so_5::message_ref_t & msg )
209  {
210  self->completed();
211  user_handler( msg );
212  };
213 
215  mbox,
216  state,
218  std::move(actual_handler) );
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(
241  ::so_5::extra::async_op::errors::rc_no_completion_handler,
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  }
272  else if( status_t::not_activated == m_status )
273  {
274  m_subscriptions.clear();
275  }
276  }
277 
278  //! Get the current status of the operation.
279  [[nodiscard]] status_t
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  {
297  if( status_t::activated == m_status )
298  SO_5_THROW_EXCEPTION(
299  ::so_5::extra::async_op::errors::rc_async_op_activated,
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
312  completed() noexcept
313  {
316  }
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  */
388 template< 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  */
431 template< 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 :
455  cancellation_point_t() = default;
456 
457  cancellation_point_t( const cancellation_point_t & ) = delete;
459 
461  operator=( const cancellation_point_t & ) = delete;
462 
464  operator=( cancellation_point_t && ) = default;
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  */
474  [[nodiscard]] status_t
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  */
661 template<
662  typename Operation_Data = details::op_data_t >
663 class definition_point_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 
701  definition_point_t( const definition_point_t & ) = delete;
703  operator=( const definition_point_t & ) = delete;
704 
705  definition_point_t( definition_point_t && ) = default;
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 
732  m_op->reserve( capacity );
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 */
auto activate(Args &&...args) &&
Just a proxy for actual activate() methods.
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.
A main class for implementation of time-unlimited asynchronous one-time operation.
details::op_shptr_t< Operation_Data > m_op
Actual operation data.
bool is_activable() const noexcept
Checks if the async operation can be activated.
Status of operation is unknown because the operation data has been moved to another proxy-object...
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.
cancellation_point_t< Operation_Data > activate() &
Activate async operation.
definition_point_t< details::op_data_t > make(::so_5::agent_t &owner)
Helper function for creation an instance of async operation.
Ranges for error codes of each submodules.
Definition: details.hpp:13
definition_point_t && completed_on(Args &&...args) &&
Just a proxy for the main version of completed_on.
details::op_shptr_t< Operation_Data > m_op
Actual data for async op.
definition_point_t & operator=(definition_point_t &&)=default
cancellation_point_t & operator=(const cancellation_point_t &)=delete
void create_subscriptions()
Subscribe agent for all subscriptions in the subscriptions&#39; container.
void completed() noexcept
Perform operation completion procedure.
definition_point_t & operator=(const definition_point_t &)=delete
definition_point_t(::so_5::outliving_reference_t< ::so_5::agent_t > owner)
Initializing constructor.
::so_5::outliving_reference_t<::so_5::agent_t > m_owner
Owner of async operation.
definition_point_t & reserve_completion_handlers_capacity(std::size_t capacity) &
Reserve a space for storage of completion handlers.
void cleanup() noexcept
Throw out a reference to the async operation data.
cancellation_point_t & operator=(cancellation_point_t &&)=default
void cancel() noexcept
An attempt to cancel the async operation.
void ensure_not_activated()
Check if operation is activated and throw an exception if it is.
void destroy_and_clear_subscriptions() noexcept
Destroy all subscriptions and clean subscriptions&#39; container.
void ensure_not_empty() const
Checks that the definition_point owns async operation data.
status_t current_status() const noexcept
Get the current status of the operation.
bool is_cancellable() const noexcept
Can the async operation be cancelled via this cancellation point?
void activate()
Performs all necessary activation actions.
friend class ::so_5::extra::async_op::time_unlimited::cancellation_point_t
cancellation_point_t< Operation_Data > activate(Activation_Action &&action) &
Activate async operation with addition starting action.
status_t m_status
The status of the async operation.
definition_point_t(const definition_point_t &)=delete
void cancel() noexcept
Cancel async operation.
cancellation_point_t(details::op_shptr_t< Operation_Data > op)
Initializing constructor to be used by definition_point.
void destroy_subscriptions_up_to(const std::size_t n) noexcept
Destroy subscriptions in range [0..n).
bool has_completion_handlers() const noexcept
Is there any completion handler?
const ::so_5::state_t * m_state
State for that a subscription should be created.
status_t status() const noexcept
Get the status of the operation.
auto reserve_completion_handlers_capacity(Args &&...args) &&
Just a proxy for actual version of reserve_completion_handlers_capacity.
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.
void reserve(std::size_t capacity)
Reserve a capacity for vector with subscriptions&#39; data.
std::vector< subscription_data_t > m_subscriptions
Subscriptions which should be created on activation.
op_data_t(::so_5::outliving_reference_t<::so_5::agent_t > owner)
Initializing constructor.
cancellation_point_t(const cancellation_point_t &)=delete
status_t
Enumeration for status of operation.