libzypp 17.37.17
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
26namespace zyppng {
27
28 namespace detail {
29
30 template <typename 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
50
51 // no copy construction
52 StateWithTransitions ( 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
116 }
117 }
118
122 template< class State, class TupleSoFar, class Head, class ...Transitions >
127
128 template< class State, class TupleSoFar, class Head >
132
133 template< class State, class ...Transitions >
137
141 template <typename VariantSoFar, typename Head, typename ...Transitions>
147
148 template <typename VariantSoFar, typename Head>
153
154 template <typename Head, typename ...Transitions>
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
267 SignalProxy< void() > eventSource ( Source *st ) {
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 >
365
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 ) {
457 using T = std::decay_t<decltype (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
481 SignalProxy<void ( StateId )> sigStateChanged () {
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
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();
553 }
554
555 private:
556 bool _isInFinalState = false;
557 bool _emittedFinalSig = false; //< Flag to make sure the finished signals is only emitted once
558 Signal <void ( StateId )> _sigStateChanged;
560 StateSet _state = _InitialState();
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;
603 using BasicState<StatemachineType, isFin>::BasicState;
604 };
605
606}
607
608#endif // ZYPP_NG_BASE_STATEMACHINE_INCLUDED_H
static auto connectFunc(typename internal::MemberFunction< SenderFunc >::ClassType &s, SenderFunc &&sFun, ReceiverFunc &&rFunc, const Tracker &...trackers)
Definition base.h:163
~BasicState() override
StatemachineType & stateMachine()
BasicState(BasicState &&) noexcept=default
StatemachineType & _sm
static constexpr bool isFinal
BasicState(StatemachineType &sm)
const StatemachineType & stateMachine() const
static constexpr auto stateId
This defines the actual StateMachine.
std::optional< StateId > previousState() const
typename detail::make_statewithtransition_set< _InitialState, AllStates, Transitions... > StateSetHelper
const std::shared_ptr< T > state() const
SignalProxy< void()> sigFinished()
auto makeEventCallback(Transition &transition)
void enterState(NewState &&nS)
Statemachine< Derived, StateId, Transitions... > StatemachineType
std::optional< StateId > currentState() const
void connectAllTransitions(State &&nS, std::tuple< StateTrans... > &transitions)
void forceState(std::unique_ptr< NewState > &&nS)
SignalProxy< void(StateId)> sigStateChanged()
std::vector< sigc::connection > _currentStateConnections
typename detail::make_state_set< Transitions... >::Type AllStates
typename StateSetHelper::FirstState FState
auto visitState(Func &&f)
void enterState(OldState &os, NewState &&nS)
std::shared_ptr< T > state()
typename StateSetHelper::Type StateSet
Definition Arch.h:364
typename decay< T >::type decay_t
Definition TypeTraits.h:42
std::enable_if< std::is_member_pointer< typenamestd::decay< Functor >::type >::value, typenamestd::result_of< Functor &&(Args &&...)>::type >::type invoke(Functor &&f, Args &&... args)
Definition functional.h:32
constexpr bool VariantHasType()
Constexpr function that evaluates to true if a variant type Variant already contains the type Type.
SignalProxy< void()>(T::*)() EventSource
constexpr std::nullptr_t DefaultStateTransition(nullptr)
constexpr bool DefaultStateCondition(true)
General compare functor returning -1, 0, 1.
Definition RelCompare.h:87
SignalProxy< void() > eventSource(Source *st)
bool checkCondition(Source &currentState)
auto eventAccessor() const
std::shared_ptr< Target > operator()(Statemachine &sm, Source &oldState)
StateWithTransitions & operator=(StateWithTransitions &&other)=default
StateWithTransitions(std::shared_ptr< State > &&s)
std::shared_ptr< State > wrappedState()
StateWithTransitions(const StateWithTransitions &other)=delete
const std::shared_ptr< State > wrappedState() const
StateWithTransitions(StateWithTransitions &&other)=default
this adds the type NewType to the collection if the condition is true
typename add_type_to_collection< std::tuple, Head, TupleSoFar, std::is_same_v< State, typename Head::SourceType > >::Type Type
collect all transitions that have the same SourceState as the first type argument
typename add_type_to_collection< std::tuple, Head, TupleSoFar, std::is_same_v< State, typename Head::SourceType > >::Type NewTuple
typename collect_transitions_helper< State, NewTuple, Transitions... >::Type Type
typename collect_transitions_helper< State, std::tuple<>, Transitions... >::Type Type
Evaluates to true if type A and type B wrap the same State type.
typename add_type_to_collection< std::variant, typename Head::TargetType, WithSource, !VariantHasType< WithSource, typename Head::TargetType >() >::Type Type
typename add_type_to_collection< std::variant, typename Head::SourceType, VariantSoFar, !VariantHasType< VariantSoFar, typename Head::SourceType >() >::Type WithSource
Iterates over the list of Transitions and collects them all in a std::variant<State1,...
typename make_state_set_helper< WithTarget, Transitions... >::Type Type
typename add_type_to_collection< std::variant, typename Head::SourceType, VariantSoFar, !VariantHasType< VariantSoFar, typename Head::SourceType >() >::Type WithSource
typename add_type_to_collection< std::variant, typename Head::TargetType, WithSource, !VariantHasType< WithSource, typename Head::TargetType >() >::Type WithTarget
typename make_state_set_helper< VariantSoFar, Transitions... >::Type Type
typename add_type_to_collection< std::variant, typename Head::TargetType, InitialVariant, !VariantHasType< InitialVariant, typename Head::TargetType >() >::Type VariantSoFar
std::variant< typename Head::SourceType > InitialVariant
typename make_statewithtransition_set_helper< std::variant< NoState, FirstState >, std::variant< States... >, Transitions... >::Type Type
typename make_statewithtransition_set_helper< NewVariant, std::variant< State... >, Transitions... >::Type Type
typename add_type_to_collection< std::variant, FullStateType, VariantSoFar, !VariantHasType< VariantSoFar, FullStateType >()>::Type NewVariant
typename add_type_to_collection< std::variant, FullStateType, VariantSoFar, !VariantHasType< VariantSoFar, FullStateType >()>::Type Type
Iterates over each State in the StateVariant argument, collects the corresponding Transitions and com...
Turns a State type into its StateWithTransitions counterpart.
StateWithTransitions< State, typename collect_transitions< State, Transitions... >::Type > Type