QStateMachine: cache expensive calculations.
As nothing changes in the state machine when selecting transitions for events and then calculating the exit- and entry-sets, some calculations can be cached. The exit set for a transition was calculated multiple times. First in removeConflictingTransitions, where the two loops would each calculate them multiple times. Then secondly in microstep(), which would calculate the exit set for all transitions. Transition selection, exit set calculation, and entry set calculation all calculate the transition domain and effective target states for transitions. Change-Id: I217328a73db2f71e371eb5f60a0c7b222303f0ca Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@theqtcompany.com>
This commit is contained in:
parent
e445f3c47b
commit
bd15b23987
@ -177,6 +177,100 @@ QT_BEGIN_NAMESPACE
|
||||
// #define QSTATEMACHINE_DEBUG
|
||||
// #define QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
|
||||
|
||||
struct CalculationCache {
|
||||
struct TransitionInfo {
|
||||
QList<QAbstractState*> effectiveTargetStates;
|
||||
QSet<QAbstractState*> exitSet;
|
||||
QAbstractState *transitionDomain;
|
||||
|
||||
bool effectiveTargetStatesIsKnown: 1;
|
||||
bool exitSetIsKnown : 1;
|
||||
bool transitionDomainIsKnown : 1;
|
||||
|
||||
TransitionInfo()
|
||||
: transitionDomain(0)
|
||||
, effectiveTargetStatesIsKnown(false)
|
||||
, exitSetIsKnown(false)
|
||||
, transitionDomainIsKnown(false)
|
||||
{}
|
||||
};
|
||||
|
||||
typedef QHash<QAbstractTransition *, TransitionInfo> TransitionInfoCache;
|
||||
TransitionInfoCache cache;
|
||||
|
||||
bool effectiveTargetStates(QAbstractTransition *t, QList<QAbstractState *> *targets) const
|
||||
{
|
||||
Q_ASSERT(targets);
|
||||
|
||||
TransitionInfoCache::const_iterator cacheIt = cache.find(t);
|
||||
if (cacheIt == cache.end() || !cacheIt->effectiveTargetStatesIsKnown)
|
||||
return false;
|
||||
|
||||
*targets = cacheIt->effectiveTargetStates;
|
||||
return true;
|
||||
}
|
||||
|
||||
void insert(QAbstractTransition *t, const QList<QAbstractState *> &targets)
|
||||
{
|
||||
TransitionInfoCache::iterator cacheIt = cache.find(t);
|
||||
TransitionInfo &ti = cacheIt == cache.end()
|
||||
? *cache.insert(t, TransitionInfo())
|
||||
: *cacheIt;
|
||||
|
||||
Q_ASSERT(!ti.effectiveTargetStatesIsKnown);
|
||||
ti.effectiveTargetStates = targets;
|
||||
ti.effectiveTargetStatesIsKnown = true;
|
||||
}
|
||||
|
||||
bool exitSet(QAbstractTransition *t, QSet<QAbstractState *> *exits) const
|
||||
{
|
||||
Q_ASSERT(exits);
|
||||
|
||||
TransitionInfoCache::const_iterator cacheIt = cache.find(t);
|
||||
if (cacheIt == cache.end() || !cacheIt->exitSetIsKnown)
|
||||
return false;
|
||||
|
||||
*exits = cacheIt->exitSet;
|
||||
return true;
|
||||
}
|
||||
|
||||
void insert(QAbstractTransition *t, const QSet<QAbstractState *> &exits)
|
||||
{
|
||||
TransitionInfoCache::iterator cacheIt = cache.find(t);
|
||||
TransitionInfo &ti = cacheIt == cache.end()
|
||||
? *cache.insert(t, TransitionInfo())
|
||||
: *cacheIt;
|
||||
|
||||
Q_ASSERT(!ti.exitSetIsKnown);
|
||||
ti.exitSet = exits;
|
||||
ti.exitSetIsKnown = true;
|
||||
}
|
||||
|
||||
bool transitionDomain(QAbstractTransition *t, QAbstractState **domain) const
|
||||
{
|
||||
Q_ASSERT(domain);
|
||||
|
||||
TransitionInfoCache::const_iterator cacheIt = cache.find(t);
|
||||
if (cacheIt == cache.end() || !cacheIt->transitionDomainIsKnown)
|
||||
return false;
|
||||
|
||||
*domain = cacheIt->transitionDomain;
|
||||
return true;
|
||||
}
|
||||
|
||||
void insert(QAbstractTransition *t, QAbstractState *domain)
|
||||
{
|
||||
TransitionInfoCache::iterator cacheIt = cache.find(t);
|
||||
TransitionInfo &ti = cacheIt == cache.end()
|
||||
? *cache.insert(t, TransitionInfo())
|
||||
: *cacheIt;
|
||||
|
||||
Q_ASSERT(!ti.transitionDomainIsKnown);
|
||||
ti.transitionDomain = domain;
|
||||
ti.transitionDomainIsKnown = true;
|
||||
}
|
||||
};
|
||||
|
||||
/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
|
||||
|
||||
function isDescendant(state1, state2)
|
||||
@ -245,8 +339,14 @@ function getEffectiveTargetStates(transition)
|
||||
targets.add(s)
|
||||
return targets
|
||||
*/
|
||||
static QSet<QAbstractState *> getEffectiveTargetStates(QAbstractTransition *transition)
|
||||
static QList<QAbstractState *> getEffectiveTargetStates(QAbstractTransition *transition, CalculationCache *cache)
|
||||
{
|
||||
Q_ASSERT(cache);
|
||||
|
||||
QList<QAbstractState *> targetsList;
|
||||
if (cache->effectiveTargetStates(transition, &targetsList))
|
||||
return targetsList;
|
||||
|
||||
QSet<QAbstractState *> targets;
|
||||
foreach (QAbstractState *s, transition->targetStates()) {
|
||||
if (QHistoryState *historyState = QStateMachinePrivate::toHistoryState(s)) {
|
||||
@ -266,7 +366,10 @@ static QSet<QAbstractState *> getEffectiveTargetStates(QAbstractTransition *tran
|
||||
targets.insert(s);
|
||||
}
|
||||
}
|
||||
return targets;
|
||||
|
||||
targetsList = targets.toList();
|
||||
cache->insert(transition, targetsList);
|
||||
return targetsList;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@ -417,8 +520,9 @@ QState *QStateMachinePrivate::findLCCA(const QList<QAbstractState*> &states) con
|
||||
return findLCA(states, true);
|
||||
}
|
||||
|
||||
QList<QAbstractTransition*> QStateMachinePrivate::selectTransitions(QEvent *event)
|
||||
QList<QAbstractTransition*> QStateMachinePrivate::selectTransitions(QEvent *event, CalculationCache *cache)
|
||||
{
|
||||
Q_ASSERT(cache);
|
||||
Q_Q(const QStateMachine);
|
||||
|
||||
QVarLengthArray<QAbstractState *> configuration_sorted;
|
||||
@ -453,7 +557,7 @@ QList<QAbstractTransition*> QStateMachinePrivate::selectTransitions(QEvent *even
|
||||
}
|
||||
|
||||
if (!enabledTransitions.isEmpty()) {
|
||||
removeConflictingTransitions(enabledTransitions);
|
||||
removeConflictingTransitions(enabledTransitions, cache);
|
||||
#ifdef QSTATEMACHINE_DEBUG
|
||||
qDebug() << q << ": enabled transitions after removing conflicts:" << enabledTransitions;
|
||||
#endif
|
||||
@ -486,15 +590,20 @@ function removeConflictingTransitions(enabledTransitions):
|
||||
|
||||
Note: the implementation below does not build the transitionsToRemove, but removes them in-place.
|
||||
*/
|
||||
void QStateMachinePrivate::removeConflictingTransitions(QList<QAbstractTransition*> &enabledTransitions)
|
||||
void QStateMachinePrivate::removeConflictingTransitions(QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache)
|
||||
{
|
||||
Q_ASSERT(cache);
|
||||
|
||||
if (enabledTransitions.size() == 1)
|
||||
return; // There is no transition to conflict with.
|
||||
|
||||
QList<QAbstractTransition*> filteredTransitions;
|
||||
filteredTransitions.reserve(enabledTransitions.size());
|
||||
std::sort(enabledTransitions.begin(), enabledTransitions.end(), transitionStateEntryLessThan);
|
||||
|
||||
foreach (QAbstractTransition *t1, enabledTransitions) {
|
||||
bool t1Preempted = false;
|
||||
QSet<QAbstractState*> exitSetT1 = computeExitSet_Unordered(QList<QAbstractTransition*>() << t1);
|
||||
QSet<QAbstractState*> exitSetT1 = computeExitSet_Unordered(t1, cache);
|
||||
QList<QAbstractTransition*>::iterator t2It = filteredTransitions.begin();
|
||||
while (t2It != filteredTransitions.end()) {
|
||||
QAbstractTransition *t2 = *t2It;
|
||||
@ -505,7 +614,7 @@ void QStateMachinePrivate::removeConflictingTransitions(QList<QAbstractTransitio
|
||||
break;
|
||||
}
|
||||
|
||||
QSet<QAbstractState*> exitSetT2 = computeExitSet_Unordered(QList<QAbstractTransition*>() << t2);
|
||||
QSet<QAbstractState*> exitSetT2 = computeExitSet_Unordered(t2, cache);
|
||||
if (exitSetT1.intersect(exitSetT2).isEmpty()) {
|
||||
// No conflict, no cry. Next patient please.
|
||||
++t2It;
|
||||
@ -529,17 +638,20 @@ void QStateMachinePrivate::removeConflictingTransitions(QList<QAbstractTransitio
|
||||
enabledTransitions = filteredTransitions;
|
||||
}
|
||||
|
||||
void QStateMachinePrivate::microstep(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions)
|
||||
void QStateMachinePrivate::microstep(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions,
|
||||
CalculationCache *cache)
|
||||
{
|
||||
Q_ASSERT(cache);
|
||||
|
||||
#ifdef QSTATEMACHINE_DEBUG
|
||||
qDebug() << q_func() << ": begin microstep( enabledTransitions:" << enabledTransitions << ')';
|
||||
qDebug() << q_func() << ": configuration before exiting states:" << configuration;
|
||||
#endif
|
||||
QList<QAbstractState*> exitedStates = computeExitSet(enabledTransitions);
|
||||
QList<QAbstractState*> exitedStates = computeExitSet(enabledTransitions, cache);
|
||||
QHash<RestorableId, QVariant> pendingRestorables = computePendingRestorables(exitedStates);
|
||||
|
||||
QSet<QAbstractState*> statesForDefaultEntry;
|
||||
QList<QAbstractState*> enteredStates = computeEntrySet(enabledTransitions, statesForDefaultEntry);
|
||||
QList<QAbstractState*> enteredStates = computeEntrySet(enabledTransitions, statesForDefaultEntry, cache);
|
||||
|
||||
#ifdef QSTATEMACHINE_DEBUG
|
||||
qDebug() << q_func() << ": computed exit set:" << exitedStates;
|
||||
@ -598,42 +710,61 @@ function computeExitSet(transitions)
|
||||
statesToExit.add(s)
|
||||
return statesToExit
|
||||
*/
|
||||
QList<QAbstractState*> QStateMachinePrivate::computeExitSet(const QList<QAbstractTransition*> &enabledTransitions)
|
||||
QList<QAbstractState*> QStateMachinePrivate::computeExitSet(const QList<QAbstractTransition*> &enabledTransitions,
|
||||
CalculationCache *cache)
|
||||
{
|
||||
QList<QAbstractState*> statesToExit_sorted = computeExitSet_Unordered(enabledTransitions).toList();
|
||||
Q_ASSERT(cache);
|
||||
|
||||
QList<QAbstractState*> statesToExit_sorted = computeExitSet_Unordered(enabledTransitions, cache).toList();
|
||||
std::sort(statesToExit_sorted.begin(), statesToExit_sorted.end(), stateExitLessThan);
|
||||
return statesToExit_sorted;
|
||||
}
|
||||
|
||||
QSet<QAbstractState*> QStateMachinePrivate::computeExitSet_Unordered(const QList<QAbstractTransition*> &enabledTransitions)
|
||||
QSet<QAbstractState*> QStateMachinePrivate::computeExitSet_Unordered(const QList<QAbstractTransition*> &enabledTransitions,
|
||||
CalculationCache *cache)
|
||||
{
|
||||
Q_ASSERT(cache);
|
||||
|
||||
QSet<QAbstractState*> statesToExit;
|
||||
for (int i = 0; i < enabledTransitions.size(); ++i) {
|
||||
QAbstractTransition *t = enabledTransitions.at(i);
|
||||
QList<QAbstractState *> effectiveTargetStates = getEffectiveTargetStates(t).toList();
|
||||
QAbstractState *domain = getTransitionDomain(t, effectiveTargetStates);
|
||||
if (domain == Q_NULLPTR && !t->targetStates().isEmpty()) {
|
||||
// So we didn't find the least common ancestor for the source and target states of the
|
||||
// transition. If there were not target states, that would be fine: then the transition
|
||||
// will fire any events or signals, but not exit the state.
|
||||
//
|
||||
// However, there are target states, so it's either a node without a parent (or parent's
|
||||
// parent, etc), or the state belongs to a different state machine. Either way, this
|
||||
// makes the state machine invalid.
|
||||
if (error == QStateMachine::NoError)
|
||||
setError(QStateMachine::NoCommonAncestorForTransitionError, t->sourceState());
|
||||
QList<QAbstractState *> lst = pendingErrorStates.toList();
|
||||
lst.prepend(t->sourceState());
|
||||
foreach (QAbstractTransition *t, enabledTransitions)
|
||||
statesToExit.unite(computeExitSet_Unordered(t, cache));
|
||||
return statesToExit;
|
||||
}
|
||||
|
||||
domain = findLCCA(lst);
|
||||
Q_ASSERT(domain != 0);
|
||||
}
|
||||
QSet<QAbstractState*> QStateMachinePrivate::computeExitSet_Unordered(QAbstractTransition *t,
|
||||
CalculationCache *cache)
|
||||
{
|
||||
Q_ASSERT(cache);
|
||||
|
||||
foreach (QAbstractState* s, configuration) {
|
||||
if (isDescendant(s, domain))
|
||||
statesToExit.insert(s);
|
||||
}
|
||||
QSet<QAbstractState*> statesToExit;
|
||||
if (cache->exitSet(t, &statesToExit))
|
||||
return statesToExit;
|
||||
|
||||
QList<QAbstractState *> effectiveTargetStates = getEffectiveTargetStates(t, cache);
|
||||
QAbstractState *domain = getTransitionDomain(t, effectiveTargetStates, cache);
|
||||
if (domain == Q_NULLPTR && !t->targetStates().isEmpty()) {
|
||||
// So we didn't find the least common ancestor for the source and target states of the
|
||||
// transition. If there were not target states, that would be fine: then the transition
|
||||
// will fire any events or signals, but not exit the state.
|
||||
//
|
||||
// However, there are target states, so it's either a node without a parent (or parent's
|
||||
// parent, etc), or the state belongs to a different state machine. Either way, this
|
||||
// makes the state machine invalid.
|
||||
if (error == QStateMachine::NoError)
|
||||
setError(QStateMachine::NoCommonAncestorForTransitionError, t->sourceState());
|
||||
QList<QAbstractState *> lst = pendingErrorStates.toList();
|
||||
lst.prepend(t->sourceState());
|
||||
|
||||
domain = findLCCA(lst);
|
||||
Q_ASSERT(domain != 0);
|
||||
}
|
||||
|
||||
foreach (QAbstractState* s, configuration) {
|
||||
if (isDescendant(s, domain))
|
||||
statesToExit.insert(s);
|
||||
}
|
||||
|
||||
cache->insert(t, statesToExit);
|
||||
return statesToExit;
|
||||
}
|
||||
|
||||
@ -695,8 +826,11 @@ void QStateMachinePrivate::executeTransitionContent(QEvent *event, const QList<Q
|
||||
}
|
||||
|
||||
QList<QAbstractState*> QStateMachinePrivate::computeEntrySet(const QList<QAbstractTransition *> &enabledTransitions,
|
||||
QSet<QAbstractState *> &statesForDefaultEntry)
|
||||
QSet<QAbstractState *> &statesForDefaultEntry,
|
||||
CalculationCache *cache)
|
||||
{
|
||||
Q_ASSERT(cache);
|
||||
|
||||
QSet<QAbstractState*> statesToEnter;
|
||||
if (pendingErrorStates.isEmpty()) {
|
||||
foreach (QAbstractTransition *t, enabledTransitions) {
|
||||
@ -704,8 +838,8 @@ QList<QAbstractState*> QStateMachinePrivate::computeEntrySet(const QList<QAbstra
|
||||
addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry);
|
||||
}
|
||||
|
||||
QList<QAbstractState *> effectiveTargetStates = getEffectiveTargetStates(t).toList();
|
||||
QAbstractState *ancestor = getTransitionDomain(t, effectiveTargetStates);
|
||||
QList<QAbstractState *> effectiveTargetStates = getEffectiveTargetStates(t, cache);
|
||||
QAbstractState *ancestor = getTransitionDomain(t, effectiveTargetStates, cache);
|
||||
foreach (QAbstractState *s, effectiveTargetStates) {
|
||||
addAncestorStatesToEnter(s, ancestor, statesToEnter, statesForDefaultEntry);
|
||||
}
|
||||
@ -742,11 +876,19 @@ function getTransitionDomain(t)
|
||||
else:
|
||||
return findLCCA([t.source].append(tstates))
|
||||
*/
|
||||
QAbstractState *QStateMachinePrivate::getTransitionDomain(QAbstractTransition *t, const QList<QAbstractState *> &effectiveTargetStates) const
|
||||
QAbstractState *QStateMachinePrivate::getTransitionDomain(QAbstractTransition *t,
|
||||
const QList<QAbstractState *> &effectiveTargetStates,
|
||||
CalculationCache *cache) const
|
||||
{
|
||||
Q_ASSERT(cache);
|
||||
|
||||
if (effectiveTargetStates.isEmpty())
|
||||
return 0;
|
||||
|
||||
QAbstractState *domain = Q_NULLPTR;
|
||||
if (cache->transitionDomain(t, &domain))
|
||||
return domain;
|
||||
|
||||
#if 0
|
||||
// Qt only has external transitions, so skip the special case for the internal transitions
|
||||
if (QState *tSource = t->sourceState()) {
|
||||
@ -768,7 +910,9 @@ QAbstractState *QStateMachinePrivate::getTransitionDomain(QAbstractTransition *t
|
||||
QList<QAbstractState *> states(effectiveTargetStates);
|
||||
if (QAbstractState *src = t->sourceState())
|
||||
states.prepend(src);
|
||||
return findLCCA(states);
|
||||
domain = findLCCA(states);
|
||||
cache->insert(t, domain);
|
||||
return domain;
|
||||
}
|
||||
|
||||
void QStateMachinePrivate::enterStates(QEvent *event, const QList<QAbstractState*> &exitedStates_sorted,
|
||||
@ -1683,6 +1827,7 @@ void QStateMachinePrivate::_q_start()
|
||||
processingScheduled = true; // we call _q_process() below
|
||||
|
||||
QList<QAbstractTransition*> transitions;
|
||||
CalculationCache calculationCache;
|
||||
QAbstractTransition *initialTransition = createInitialTransition();
|
||||
transitions.append(initialTransition);
|
||||
|
||||
@ -1690,7 +1835,7 @@ void QStateMachinePrivate::_q_start()
|
||||
executeTransitionContent(&nullEvent, transitions);
|
||||
QList<QAbstractState*> exitedStates = QList<QAbstractState*>();
|
||||
QSet<QAbstractState*> statesForDefaultEntry;
|
||||
QList<QAbstractState*> enteredStates = computeEntrySet(transitions, statesForDefaultEntry);
|
||||
QList<QAbstractState*> enteredStates = computeEntrySet(transitions, statesForDefaultEntry, &calculationCache);
|
||||
QHash<RestorableId, QVariant> pendingRestorables;
|
||||
QHash<QAbstractState*, QList<QPropertyAssignment> > assignmentsForEnteredStates =
|
||||
computePropertyAssignments(enteredStates, pendingRestorables);
|
||||
@ -1743,8 +1888,10 @@ void QStateMachinePrivate::_q_process()
|
||||
break;
|
||||
}
|
||||
QList<QAbstractTransition*> enabledTransitions;
|
||||
CalculationCache calculationCache;
|
||||
|
||||
QEvent *e = new QEvent(QEvent::None);
|
||||
enabledTransitions = selectTransitions(e);
|
||||
enabledTransitions = selectTransitions(e, &calculationCache);
|
||||
if (enabledTransitions.isEmpty()) {
|
||||
delete e;
|
||||
e = 0;
|
||||
@ -1753,7 +1900,7 @@ void QStateMachinePrivate::_q_process()
|
||||
#ifdef QSTATEMACHINE_DEBUG
|
||||
qDebug() << q << ": dequeued internal event" << e << "of type" << e->type();
|
||||
#endif
|
||||
enabledTransitions = selectTransitions(e);
|
||||
enabledTransitions = selectTransitions(e, &calculationCache);
|
||||
if (enabledTransitions.isEmpty()) {
|
||||
delete e;
|
||||
e = 0;
|
||||
@ -1764,7 +1911,7 @@ void QStateMachinePrivate::_q_process()
|
||||
#ifdef QSTATEMACHINE_DEBUG
|
||||
qDebug() << q << ": dequeued external event" << e << "of type" << e->type();
|
||||
#endif
|
||||
enabledTransitions = selectTransitions(e);
|
||||
enabledTransitions = selectTransitions(e, &calculationCache);
|
||||
if (enabledTransitions.isEmpty()) {
|
||||
delete e;
|
||||
e = 0;
|
||||
@ -1778,7 +1925,7 @@ void QStateMachinePrivate::_q_process()
|
||||
}
|
||||
if (!enabledTransitions.isEmpty()) {
|
||||
q->beginMicrostep(e);
|
||||
microstep(e, enabledTransitions);
|
||||
microstep(e, enabledTransitions, &calculationCache);
|
||||
q->endMicrostep(e);
|
||||
}
|
||||
#ifdef QSTATEMACHINE_DEBUG
|
||||
|
@ -75,6 +75,7 @@ class QState;
|
||||
class QAbstractAnimation;
|
||||
#endif
|
||||
|
||||
struct CalculationCache;
|
||||
class QStateMachine;
|
||||
class Q_CORE_EXPORT QStateMachinePrivate : public QStatePrivate
|
||||
{
|
||||
@ -124,13 +125,14 @@ public:
|
||||
void clearHistory();
|
||||
QAbstractTransition *createInitialTransition() const;
|
||||
|
||||
void removeConflictingTransitions(QList<QAbstractTransition*> &enabledTransitions);
|
||||
void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList);
|
||||
QList<QAbstractTransition *> selectTransitions(QEvent *event);
|
||||
void removeConflictingTransitions(QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache);
|
||||
void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList, CalculationCache *cache);
|
||||
QList<QAbstractTransition *> selectTransitions(QEvent *event, CalculationCache *cache);
|
||||
void exitStates(QEvent *event, const QList<QAbstractState *> &statesToExit_sorted,
|
||||
const QHash<QAbstractState*, QList<QPropertyAssignment> > &assignmentsForEnteredStates);
|
||||
QList<QAbstractState*> computeExitSet(const QList<QAbstractTransition*> &enabledTransitions);
|
||||
QSet<QAbstractState*> computeExitSet_Unordered(const QList<QAbstractTransition*> &enabledTransitions);
|
||||
QList<QAbstractState*> computeExitSet(const QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache);
|
||||
QSet<QAbstractState*> computeExitSet_Unordered(const QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache);
|
||||
QSet<QAbstractState*> computeExitSet_Unordered(QAbstractTransition *t, CalculationCache *cache);
|
||||
void executeTransitionContent(QEvent *event, const QList<QAbstractTransition*> &transitionList);
|
||||
void enterStates(QEvent *event, const QList<QAbstractState*> &exitedStates_sorted,
|
||||
const QList<QAbstractState*> &statesToEnter_sorted,
|
||||
@ -141,9 +143,10 @@ public:
|
||||
#endif
|
||||
);
|
||||
QList<QAbstractState*> computeEntrySet(const QList<QAbstractTransition*> &enabledTransitions,
|
||||
QSet<QAbstractState*> &statesForDefaultEntry);
|
||||
QSet<QAbstractState*> &statesForDefaultEntry, CalculationCache *cache);
|
||||
QAbstractState *getTransitionDomain(QAbstractTransition *t,
|
||||
const QList<QAbstractState *> &effectiveTargetStates) const;
|
||||
const QList<QAbstractState *> &effectiveTargetStates,
|
||||
CalculationCache *cache) const;
|
||||
void addDescendantStatesToEnter(QAbstractState *state,
|
||||
QSet<QAbstractState*> &statesToEnter,
|
||||
QSet<QAbstractState*> &statesForDefaultEntry);
|
||||
|
@ -256,10 +256,12 @@ public:
|
||||
Entry,
|
||||
Exit
|
||||
};
|
||||
TestState(QState *parent)
|
||||
: QState(parent) {}
|
||||
TestState(ChildMode mode)
|
||||
: QState(mode) {}
|
||||
TestState(QState *parent, const QString &objectName = QString())
|
||||
: QState(parent)
|
||||
{ setObjectName(objectName); }
|
||||
TestState(ChildMode mode, const QString &objectName = QString())
|
||||
: QState(mode)
|
||||
{ setObjectName(objectName); }
|
||||
QList<QPair<int, Event> > events;
|
||||
protected:
|
||||
virtual void onEntry(QEvent *) {
|
||||
@ -273,9 +275,9 @@ protected:
|
||||
class TestTransition : public QAbstractTransition
|
||||
{
|
||||
public:
|
||||
TestTransition(QAbstractState *target)
|
||||
TestTransition(QAbstractState *target, const QString &objectName = QString())
|
||||
: QAbstractTransition()
|
||||
{ setTargetState(target); }
|
||||
{ setTargetState(target); setObjectName(objectName); }
|
||||
QList<int> triggers;
|
||||
protected:
|
||||
virtual bool eventTest(QEvent *) {
|
||||
@ -1352,15 +1354,16 @@ void tst_QStateMachine::stateEntryAndExit()
|
||||
{
|
||||
QStateMachine machine;
|
||||
|
||||
TestState *s1 = new TestState(&machine);
|
||||
TestState *s11 = new TestState(s1);
|
||||
TestState *s12 = new TestState(s1);
|
||||
TestState *s2 = new TestState(&machine);
|
||||
TestState *s1 = new TestState(&machine, "s1");
|
||||
TestState *s11 = new TestState(s1, "s11");
|
||||
TestState *s12 = new TestState(s1, "s12");
|
||||
TestState *s2 = new TestState(&machine, "s2");
|
||||
QFinalState *s3 = new QFinalState(&machine);
|
||||
s3->setObjectName("s3");
|
||||
s1->setInitialState(s11);
|
||||
TestTransition *t1 = new TestTransition(s12);
|
||||
TestTransition *t1 = new TestTransition(s12, "t1");
|
||||
s11->addTransition(t1);
|
||||
TestTransition *t2 = new TestTransition(s2);
|
||||
TestTransition *t2 = new TestTransition(s2, "t2");
|
||||
s12->addTransition(t2);
|
||||
s2->addTransition(s3);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user