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