Implement Fallbacks behavior for children of type Connecting.
All other connect-like children are currently infeasible to handle,
because we cannot forward a single job, i.e. a pair (from, to)
to the next child, but only individual states.
However, passing states, will cause creation of undesired state pairs
as jobs in subsequent children.
Let's consider the following simple situation, where generators produce solutions in the given order.
GEN 1 3
Fallbacks |X
GEN 2 4
When passing state 4 to the Fallbacks' connector, it forms pending pairs with both 1 and 3.
Thus, the container needs to check whether 1-4 or 3-4 was processed when receiving a success or failure,
to correctly forward the failed one to the next child.
- always provide eef markers (also in case of success)
- tint failures in red
- use different names for "ik frame" and "target frame" markers
- reduce code duplication
Further factorize and simplify FallbacksPrivate classes employing ideas from @v4hn.
The key difference between the variants his how they advance to the next job.
Thus, the only virtual method required is nextJob().
- Enable moving/swapping of other container impls (e.g. Fallbacks)
- Clarify (via move semantics) that content of source impl will be lost
- Get rid of friend declarations
Adapt test results FallbacksFixturePropagate.computeFirstSuccessfulStagePerSolutionOnly
due to 2e63c154aa:
The order of computations has changed, because we lock the processed state
as soon as it is forwarded to the first fallback child.
In this case, after processing GEN1 und FWD1 once, we have the two states with costs 2, 4 in the queue.
The first one, i.e. with cost 2 is forwarded to the child FWD2, which fails.
In the next cycle, although we have new states in the queue (1, 2, 3, 4), we stick with state "2"
and forward it two FWD3, which adds costs 210, resulting in 212.
With previous code, the Fallback container switched to state "1", forwarded to FWD2.
- Drop variable current_external_state_
- Instead encode the info that the external state wasn't yet forwarded to any child via stage = children().cend()
- If all children have exhausted their solutions for this state, it is removed from the pending list
Not only propagate updates along solution paths, but also bridge
the gap of a `Connecting` stage.
- If a state becomes enabled, re-enable opposite `ARMED` states as well.
- If a state becomes pruned, also prune opposite states if they don't have alternatives.
- Make sure that we don't run into a recursive update loop by disabling notify() callbacks.
This also requires to drop the assertion in SerialContainer::onNewSolution()
that new solutions will have enabled start+end states (a CONNECT stage's solution might not).