libzypp  17.35.14
statemachine.h
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \----------------------------------------------------------------------/
9 *
10 * This file contains private API, this might break at any time between releases.
11 * You have been warned!
12 *
13 */
14 #ifndef ZYPP_NG_BASE_STATEMACHINE_INCLUDED_H
15 #define ZYPP_NG_BASE_STATEMACHINE_INCLUDED_H
16 
18 #include <zypp-core/zyppng/base/Base>
19 
20 #include <variant>
21 #include <tuple>
22 #include <functional>
23 #include <memory>
24 #include <optional>
25 
26 namespace zyppng {
27 
28  namespace detail {
29 
30  template <typename T>
31  using EventSource = SignalProxy<void()> (T::*)();
32 
38  template < class State, class Transitions >
40  using StateType = State;
41  Transitions _transitions;
42 
43  template< typename StateMachine >
44  StateWithTransitions ( StateMachine &sm ) : _ptr ( std::make_shared<State>( sm )) { }
45  StateWithTransitions ( std::shared_ptr<State> &&s ) : _ptr ( std::move(s) ) {}
46 
47  // move construction is ok
48  StateWithTransitions ( StateWithTransitions &&other ) = default;
50 
51  // no copy construction
52  StateWithTransitions ( const StateWithTransitions &other ) = delete;
53  StateWithTransitions &operator= ( const StateWithTransitions &other ) = delete;
54 
55  static constexpr auto stateId = State::stateId;
56  static constexpr bool isFinal = State::isFinal;
57 
58  void enter( ) {
59  // keep the pointer around, for we might transition to the next state immediately
60  auto keepAlive = _ptr;
61  return keepAlive->enter( );
62  }
63 
64  void exit( ) {
65  // keep the pointer around, for we might transition to the next state immediately
66  auto keepAlive = _ptr;
67  return keepAlive->exit( );
68  }
69 
70  std::shared_ptr<State> wrappedState () {
71  return _ptr;
72  }
73 
74  const std::shared_ptr<State> wrappedState () const {
75  return _ptr;
76  }
77 
78  private:
79  // we need to use a std::shared_ptr here so we can correctly reference the object during signal emission
80  std::shared_ptr<State> _ptr;
81  };
82 
83 
87  template < template<typename...> typename Templ , typename NewType, typename TupleType, bool condition >
89 
90  template < template<typename...> typename Templ, typename NewType, typename ...Types >
91  struct add_type_to_collection< Templ, NewType, Templ<Types...>, true > {
92  using Type = Templ<Types..., NewType>;
93  };
94 
95  template < template<typename...> typename Templ, typename NewType, typename ...Types >
96  struct add_type_to_collection< Templ, NewType, Templ<Types...>, false > {
97  using Type = Templ<Types...>;
98  };
99 
104  template < typename Variant, typename Type, template<typename, typename> typename Compare = std::is_same, size_t I = 0 >
105  constexpr bool VariantHasType () {
106  // cancel the evaluation if we entered the last type in the variant
107  if constexpr ( I >= std::variant_size_v<Variant> ) {
108  return false;
109  } else {
110  // if the current type in the variant is the same as the one we are looking for evaluate to true
111  if ( Compare< std::variant_alternative_t< I, Variant>, Type >::value )
112  return true;
113 
114  // otherwise call the next iteration with I+1
115  return VariantHasType<Variant, Type, Compare, I+1>();
116  }
117  }
118 
122  template< class State, class TupleSoFar, class Head, class ...Transitions >
125  using Type = typename collect_transitions_helper<State, NewTuple, Transitions...>::Type;
126  };
127 
128  template< class State, class TupleSoFar, class Head >
129  struct collect_transitions_helper<State, TupleSoFar, Head > {
131  };
132 
133  template< class State, class ...Transitions >
136  };
137 
141  template <typename VariantSoFar, typename Head, typename ...Transitions>
145  using Type = typename make_state_set_helper<WithTarget, Transitions...>::Type;
146  };
147 
148  template <typename VariantSoFar, typename Head>
149  struct make_state_set_helper< VariantSoFar, Head > {
152  };
153 
154  template <typename Head, typename ...Transitions>
155  struct make_state_set {
156  using InitialVariant = std::variant<typename Head::SourceType>;
158  using Type = typename make_state_set_helper< VariantSoFar, Transitions...>::Type;
159  };
160 
161 
165  template <typename A, typename B>
166  struct is_same_state : public std::is_same< typename A::StateType, typename B::StateType> {};
167 
168 
172  template <typename State, typename ...Transitions>
174  using Type = StateWithTransitions<State, typename collect_transitions<State, Transitions...>::Type>;
175  };
176 
181  template <typename VariantSoFar, typename StateVariant, typename ...Transitions>
183 
184  template <typename VariantSoFar, typename HeadState, typename ...State, typename ...Transitions>
185  struct make_statewithtransition_set_helper< VariantSoFar, std::variant<HeadState, State...>, Transitions... > {
186  using FullStateType = typename make_statewithtransition<HeadState, Transitions...>::Type;
187  using NewVariant = typename add_type_to_collection< std::variant, FullStateType, VariantSoFar, !VariantHasType<VariantSoFar, FullStateType/*, is_same_state */>()>::Type;
188  using Type = typename make_statewithtransition_set_helper< NewVariant, std::variant<State...>, Transitions...>::Type;
189  };
190 
191  template <typename VariantSoFar, typename HeadState, typename ...Transitions >
192  struct make_statewithtransition_set_helper< VariantSoFar, std::variant<HeadState>, Transitions... > {
193  using FullStateType = typename make_statewithtransition<HeadState, Transitions...>::Type;
194  using Type = typename add_type_to_collection< std::variant, FullStateType, VariantSoFar, !VariantHasType<VariantSoFar, FullStateType /*, is_same_state */>()>::Type;
195  };
196 
197  template <typename NoState, typename StateVariant, typename ...Transitions>
199 
200  template <typename NoState, typename HeadState, typename ...States, typename ...Transitions>
201  struct make_statewithtransition_set< NoState, std::variant<HeadState, States...>, Transitions...>{
202  using FirstState = typename make_statewithtransition< HeadState, Transitions...>::Type;
203  using Type = typename make_statewithtransition_set_helper< std::variant<NoState, FirstState>, std::variant<States...>, Transitions...>::Type;
204  };
205  }
206 
207  constexpr bool DefaultStateCondition(true);
208  constexpr std::nullptr_t DefaultStateTransition(nullptr);
209 
231  template <
232  typename Source,
234  typename Target,
235  auto Cond = DefaultStateCondition,
236  auto Op = DefaultStateTransition >
237  struct Transition {
238 
239  using SourceType = Source;
241 
242 
243  template< typename Statemachine >
244  std::shared_ptr<Target> operator() ( Statemachine &sm, Source &oldState ) {
245  using OpType = std::decay_t<decltype ( Op )>;
246  // check if we have a member function pointer
247  if constexpr ( std::is_member_function_pointer_v<OpType> ) {
248  return std::invoke( Op, &oldState );
249  } else if constexpr ( std::is_null_pointer_v<OpType> ) {
250  return std::make_shared<Target>(sm);
251  } else {
252  return std::invoke( Op, sm, oldState );
253  }
254  }
255 
256  bool checkCondition ( Source &currentState ) {
257  using CondType = std::decay_t<decltype ( Cond )>;
258  if constexpr ( std::is_same_v<bool, CondType> ) {
259  return Cond;
260  } else if constexpr ( std::is_member_function_pointer_v<CondType> ) {
261  return std::invoke( Cond, &currentState );
262  } else {
263  return std::invoke( Cond, currentState );
264  }
265  }
266 
268  return std::invoke( ev, st );
269  }
270 
271  auto eventAccessor () const {
272  return ev;
273  }
274 
275  };
276 
363  template < typename Derived, typename StateId, typename ...Transitions >
364  class Statemachine {
365 
366  struct _InitialState{};
367 
368  public:
369 
370  using AllStates = typename detail::make_state_set< Transitions... >::Type;
372  using FState = typename StateSetHelper::FirstState;
373  using StateSet = typename StateSetHelper::Type;
374 
375  using StatemachineType = Statemachine< Derived, StateId, Transitions...>;
376 
377  public:
379  virtual ~Statemachine() {}
380 
384  void start () {
385  if ( _state.index() == 0 || _isInFinalState ) {
386  _previousState.reset();
387  _isInFinalState = false;
388  _emittedFinalSig = false;
389  enterState( FState( static_cast<Derived &>(*this) ) );
390  }
391  }
392 
393  template <typename Func>
394  auto visitState ( Func && f ) {
395  return std::visit( [ func = std::forward<Func>(f) ] ( auto &s ) {
396  using T = std::decay_t<decltype (s)>;
397  if constexpr ( std::is_same_v< T, _InitialState > ) {
398  throw std::exception();
399  } else {
400  auto lock = s.wrappedState();
401  return ( func( *lock ) );
402  }
403  }, _state );
404  }
405 
410  std::optional<StateId> currentState () const {
411  return std::visit( []( const auto &s ) -> std::optional<StateId> {
412  using T = std::decay_t<decltype (s)>;
413  if constexpr ( std::is_same_v< T, _InitialState > ) {
414  return {};
415  } else {
416  return T::stateId;
417  }
418  }, _state );
419  }
420 
425  std::optional<StateId> previousState () const {
426  return _previousState;
427  }
428 
433  template<typename T>
434  std::shared_ptr<T> state () {
435  using WrappedEventType = typename detail::make_statewithtransition< std::decay_t<T>, Transitions...>::Type;
436  return std::get<WrappedEventType>( _state ).wrappedState();
437  }
438 
443  template<typename T>
444  const std::shared_ptr<T> state () const {
445  using WrappedEventType = typename detail::make_statewithtransition< std::decay_t<T>, Transitions...>::Type;
446  return std::get<WrappedEventType>( _state ).wrappedState();
447  }
448 
453  template <typename NewState >
454  void forceState ( std::unique_ptr<NewState> &&nS ) {
455  using WrappedSType = typename detail::make_statewithtransition< std::decay_t<NewState>, Transitions...>::Type;
456  std::visit( [this, &nS]( auto &currState ) {
458  if constexpr ( std::is_same_v< T, WrappedSType > ) {
459  return;
460  } else if constexpr ( std::is_same_v< T, _InitialState > ) {
461  enterState ( WrappedSType( std::move(nS) ) );
462  } else {
463  enterState ( currState, WrappedSType( std::move(nS) ) );
464  }
465  }, _state );
466  }
467 
472  return _sigFinished;
473  }
474 
482  return _sigStateChanged;
483  }
484 
485  protected:
486 
487  template <typename OldState, typename NewState>
488  void enterState ( OldState &os, NewState &&nS ) {
489  // disconnect all signals from the current state
491  std::forward<OldState>(os).exit();
492  _previousState = OldState::stateId;
493  enterState( std::forward<NewState>(nS) );
494  }
495 
496  template <typename NewState>
497  void enterState ( NewState &&nS ) {
498 
499  if constexpr ( !NewState::isFinal ) {
500  connectAllTransitions<0>( nS, nS._transitions );
501  }
502 
503  _state.template emplace<NewState>( std::forward<NewState>(nS) );
504 
505  // handle final state things
506  if constexpr ( NewState::isFinal ) {
507  _isInFinalState = true;
508  _emittedFinalSig = false;
509  }
510 
511  // let the outside world know whats going on
512  _sigStateChanged.emit( NewState::stateId );
513 
514  // call enter on the state as the last thing to do, it might emit a transition event right away
515  std::get< std::decay_t<NewState> >( _state ).enter();
516 
517  // emit the final signal, but only if it was not already emitted by a subsequent transition
518  if ( _isInFinalState && !_emittedFinalSig ) {
519  _emittedFinalSig = true;
520  _sigFinished.emit();
521  }
522 
523  }
524 
525  template <typename State, typename Transition>
526  auto makeEventCallback ( Transition &transition ) {
527  using WrappedEventType = typename detail::make_statewithtransition< typename Transition::TargetType, Transitions...>::Type;
528  return [ mytrans = &transition, this]() mutable {
529  auto stateLock = std::get< std::decay_t<State> >(_state).wrappedState();
530  if ( mytrans->checkCondition( *stateLock ) ) {
531  auto &st = std::get< std::decay_t<State> >(_state);
532  enterState( st , WrappedEventType( (*mytrans)( static_cast<Derived &>(*this), *stateLock ) ) );
533  }
534  };
535  }
536 
537  template< std::size_t I = 0, typename State, typename ...StateTrans>
538  void connectAllTransitions( State &&nS, std::tuple<StateTrans...> &transitions ) {
539  if constexpr (I >= sizeof...(StateTrans)) {
540  return;
541  } else {
542  auto &transition = std::get<I>( transitions );
543  //_currentStateConnections.push_back( transition.eventSource ( std::forward<State>(nS).wrappedState().get() ).connect( makeEventCallback< std::decay_t<State> >(transition)) );
544  _currentStateConnections.push_back( std::forward<State>(nS).wrappedState()->Base::connectFunc( transition.eventAccessor(), makeEventCallback< std::decay_t<State> >(transition), *static_cast<Derived*>(this) ) );
545  connectAllTransitions<I+1>( std::forward<State>(nS), transitions );
546  }
547  }
548 
550  for ( auto &c : _currentStateConnections )
551  c.disconnect();
552  _currentStateConnections.clear();
553  }
554 
555  private:
556  bool _isInFinalState = false;
557  bool _emittedFinalSig = false; //< Flag to make sure the finished signals is only emitted once
561  std::optional<StateId> _previousState;
562  std::vector<sigc::connection> _currentStateConnections;
563  };
564 
569  template < typename StatemachineType, bool isFin >
570  class BasicState : public Base {
571  public:
572 
573  static constexpr bool isFinal = isFin;
574 
575  BasicState( StatemachineType &sm ) : _sm( sm ){}
576  ~BasicState() override {}
577 
578  BasicState( BasicState && ) noexcept = default;
579  BasicState &operator= ( BasicState && ) noexcept = default;
580 
581  StatemachineType &stateMachine () {
582  return _sm;
583  }
584 
585  const StatemachineType &stateMachine () const {
586  return _sm;
587  }
588 
589  private:
590  StatemachineType &_sm;
591 
592  };
593 
599  template < typename StatemachineType, auto sId, bool isFin >
600  class SimpleState : public BasicState<StatemachineType, isFin> {
601  public:
602  static constexpr auto stateId = sId;
604  };
605 
606 }
607 
608 #endif // ZYPP_NG_BASE_STATEMACHINE_INCLUDED_H
Iterates over the list of Transitions and collects them all in a std::variant<State1, State2, ...> type.
Definition: statemachine.h:142
StateWithTransitions & operator=(StateWithTransitions &&other)=default
constexpr bool DefaultStateCondition(true)
std::shared_ptr< State > _ptr
Definition: statemachine.h:80
typename detail::make_state_set< Transitions... >::Type AllStates
Definition: statemachine.h:370
static constexpr bool isFinal
Definition: statemachine.h:573
Iterates over each State in the StateVariant argument, collects the corresponding Transitions and com...
Definition: statemachine.h:182
typename collect_transitions_helper< State, NewTuple, Transitions... >::Type Type
Definition: statemachine.h:125
std::shared_ptr< Target > operator()(Statemachine &sm, Source &oldState)
Definition: statemachine.h:244
BasicState(StatemachineType &sm)
Definition: statemachine.h:575
SignalProxy< void()>(T::*)() EventSource
Definition: statemachine.h:31
std::optional< StateId > _previousState
Definition: statemachine.h:561
typename StateSetHelper::FirstState FState
Definition: statemachine.h:372
Signal< void(StateId)> _sigStateChanged
Definition: statemachine.h:558
SignalProxy< void(StateId)> sigStateChanged()
Definition: statemachine.h:481
Definition: Arch.h:363
void enterState(NewState &&nS)
Definition: statemachine.h:497
constexpr std::nullptr_t DefaultStateTransition(nullptr)
typename add_type_to_collection< std::variant, typename Head::TargetType, InitialVariant, !VariantHasType< InitialVariant, typename Head::TargetType >() >::Type VariantSoFar
Definition: statemachine.h:157
typename make_state_set_helper< WithTarget, Transitions... >::Type Type
Definition: statemachine.h:145
StatemachineType & stateMachine()
Definition: statemachine.h:581
auto makeEventCallback(Transition &transition)
Definition: statemachine.h:526
std::enable_if< std::is_member_pointer< typename std::decay< Functor >::type >::value, typename std::result_of< Functor &&(Args &&...)>::type >::type invoke(Functor &&f, Args &&... args)
Definition: functional.h:32
typename add_type_to_collection< std::tuple, Head, TupleSoFar, std::is_same_v< State, typename Head::SourceType > >::Type NewTuple
Definition: statemachine.h:124
const std::unordered_map< ParserState, std::vector< transition > > & transitions()
typename make_statewithtransition_set_helper< NewVariant, std::variant< State... >, Transitions... >::Type Type
Definition: statemachine.h:188
void forceState(std::unique_ptr< NewState > &&nS)
Definition: statemachine.h:454
static constexpr auto stateId
Definition: statemachine.h:602
collect all transitions that have the same SourceState as the first type argument ...
Definition: statemachine.h:123
typename StateSetHelper::Type StateSet
Definition: statemachine.h:373
void enterState(OldState &os, NewState &&nS)
Definition: statemachine.h:488
typename add_type_to_collection< std::variant, FullStateType, VariantSoFar, !VariantHasType< VariantSoFar, FullStateType >()>::Type Type
Definition: statemachine.h:194
std::vector< sigc::connection > _currentStateConnections
Definition: statemachine.h:562
bool checkCondition(Source &currentState)
Definition: statemachine.h:256
StatemachineType & _sm
Definition: statemachine.h:590
std::variant< typename Head::SourceType > InitialVariant
Definition: statemachine.h:156
const StatemachineType & stateMachine() const
Definition: statemachine.h:585
typename make_state_set_helper< VariantSoFar, Transitions... >::Type Type
Definition: statemachine.h:158
auto visitState(Func &&f)
Definition: statemachine.h:394
std::shared_ptr< T > state()
Definition: statemachine.h:434
Signal< void()> _sigFinished
Definition: statemachine.h:559
typename add_type_to_collection< std::tuple, Head, TupleSoFar, std::is_same_v< State, typename Head::SourceType > >::Type Type
Definition: statemachine.h:130
typename add_type_to_collection< std::variant, FullStateType, VariantSoFar, !VariantHasType< VariantSoFar, FullStateType >()>::Type NewVariant
Definition: statemachine.h:187
typename add_type_to_collection< std::variant, typename Head::TargetType, WithSource, !VariantHasType< WithSource, typename Head::TargetType >() >::Type WithTarget
Definition: statemachine.h:144
~BasicState() override
Definition: statemachine.h:576
SignalProxy< void()> sigFinished()
Definition: statemachine.h:471
typename add_type_to_collection< std::variant, typename Head::SourceType, VariantSoFar, !VariantHasType< VariantSoFar, typename Head::SourceType >() >::Type WithSource
Definition: statemachine.h:143
std::optional< StateId > previousState() const
Definition: statemachine.h:425
General compare functor returning -1, 0, 1.
Definition: RelCompare.h:86
std::shared_ptr< State > wrappedState()
Definition: statemachine.h:70
SignalProxy< void() > eventSource(Source *st)
Definition: statemachine.h:267
Turns a State type into its StateWithTransitions counterpart.
Definition: statemachine.h:173
this adds the type NewType to the collection if the condition is true
Definition: statemachine.h:88
void connectAllTransitions(State &&nS, std::tuple< StateTrans... > &transitions)
Definition: statemachine.h:538
static auto connectFunc(typename internal::MemberFunction< SenderFunc >::ClassType &s, SenderFunc &&sFun, ReceiverFunc &&rFunc, const Tracker &...trackers)
Definition: base.h:163
const std::shared_ptr< State > wrappedState() const
Definition: statemachine.h:74
std::optional< StateId > currentState() const
Definition: statemachine.h:410
typename detail::make_statewithtransition_set< _InitialState, AllStates, Transitions... > StateSetHelper
Definition: statemachine.h:371
typename add_type_to_collection< std::variant, typename Head::SourceType, VariantSoFar, !VariantHasType< VariantSoFar, typename Head::SourceType >() >::Type WithSource
Definition: statemachine.h:150
typename make_statewithtransition_set_helper< std::variant< NoState, FirstState >, std::variant< States... >, Transitions... >::Type Type
Definition: statemachine.h:203
This defines the actual StateMachine.
Definition: statemachine.h:364
typename decay< T >::type decay_t
Definition: TypeTraits.h:42
auto eventAccessor() const
Definition: statemachine.h:271
typename collect_transitions_helper< State, std::tuple<>, Transitions... >::Type Type
Definition: statemachine.h:135
StateWithTransitions(StateMachine &sm)
Definition: statemachine.h:44
StateWithTransitions(std::shared_ptr< State > &&s)
Definition: statemachine.h:45
const std::shared_ptr< T > state() const
Definition: statemachine.h:444
constexpr bool VariantHasType()
Constexpr function that evaluates to true if a variant type Variant already contains the type Type...
Definition: statemachine.h:105
Evaluates to true if type A and type B wrap the same State type.
Definition: statemachine.h:166
typename add_type_to_collection< std::variant, typename Head::TargetType, WithSource, !VariantHasType< WithSource, typename Head::TargetType >() >::Type Type
Definition: statemachine.h:151