target= just_getmovpos(d,&tac);
if (d->i->invertible) {
- Segment *interferer= segment_interferes(&tac,d);
+ Segment *interferer= segment_interferes_simple(&tac,d);
if (interferer) {
actual_inversions_start();
d->seg_inverted= interferer->seg_inverted
static int nose_nextseg(TrackLocation *t, TrackAdvanceContext *c,
MovPosComb *mpc_io, const TrackLocation *before) {
PredictUserContext *u= c->u;
- Segment *interferer;
MovPosComb route_plan;
TimeInterval max_ms;
ErrorCode ec;
return predict_problem(u, t->seg, "will collide with itself!");
if (!u->optimistic) {
- interferer= segment_interferes(c,t->seg);
- if (interferer) {
- if (interferer->owner && interferer->owner != u->train)
- return predict_problem(u, t->seg, "impeded by %s at %s",
- interferer->owner->pname, interferer->i->pname);
- if (interferer->pred_present)
- return predict_problem(u, t->seg, "will collide with itself at %s!",
- interferer->i->pname);
+ Segment *interferer= segment_interferer(t->seg);
+ /* We want to avoid calling segment_interferer_does unless we have
+ * to, as it uses getmovpos which, if the movposcomb is unknown,
+ * will predict_problem even if the interferer is empty. */
+ if (interferer &&
+ (interferer->owner || interferer->pred_present)) {
+ int does;
+ ec= segment_interferer_does(c,t->seg,interferer, &does);
+ if (!ec) return ec;
+
+ if (does) {
+ if (interferer->owner && interferer->owner != u->train)
+ return predict_problem(u, t->seg, "impeded by %s at %s",
+ interferer->owner->pname, interferer->i->pname);
+ if (interferer->pred_present)
+ return predict_problem(u, t->seg, "will collide with itself at %s!",
+ interferer->i->pname);
+ }
}
}
seg->seg_inverted= seg->tr_backwards ^ u.train_polarity_inverted;
if (seg->i->invertible) {
actual_inversions_segment(seg);
- Segment *interferer= segment_interferes(0,seg);
+ Segment *interferer= segment_interferes_simple(0,seg);
if (interferer && !interferer->will_polarise &&
interferer->i->invertible) {
interferer->seg_inverted= seg->seg_inverted
void safety_notify_detection(Segment *seg) {
Train *tra;
ErrorCode ec;
- Segment *interferer;
int maxinto;
struct timeval tnow;
SpeedInfo speed_info;
debug_count_event("detection");
if (!seg->det_expected) {
- interferer= segment_interferes(0,seg);
+ Segment *interferer= segment_interferes_simple(0,seg);
if (!interferer) safety_panic(0,seg, "unexpected detection");
if (interferer->det_ignore) return;
if (!interferer->det_expected)
/* Of c, only c->getmovpos is used. t->remain is not used.
* c may be 0 which works just like c->getmovpos==0. */
-Segment *segment_interferes(TrackAdvanceContext *c, Segment *base);
- /* 0 means we know there is no interference; if we can't determine
- * the relevant movposcombs we return the interfering segment.
- * c is used as for trackloc_getlink. */
+Segment *segment_interferer(Segment *base);
+ /* Returns the segment which may interfere with base, if any. */
+
+ErrorCode segment_interferer_does(TrackAdvanceContext *c, Segment *base,
+ Segment *interferer, int *does_r);
+ /* Checks whether it interferes with base.
+ * Return is 0 or the error value from c->getmovpos.
+ * *does_r is set (only) on successful return,
+ * c is used as for trackloc_getlink. If c->getmovpos is 0
+ * the segments are taken to interfere if they would in any movposcomb.
+ * interferer may be 0 in which case succeeds, setting *does_r=0.
+ */
+
+Segment *segment_interferes_simple(TrackAdvanceContext *c, Segment *base);
+ /* Combines segment_interferer and segment_interferer_does.
+ * c->getmovpos MUST NOT return errors; we abort if it does. */
int trackloc_advance(TrackLocation *t, TrackAdvanceContext *c);
/* Advances t by dist until distance becomes 0, some callback
}
}
-static int interfering_movposcomb(TrackAdvanceContext *c, Segment *seg) {
+Segment *segment_interferer(Segment *base) {
+ SegmentNum intern= base->i->interferes;
+ if (!SOMEP(intern)) return 0;
+ return &segments[intern];
+}
+
+static ErrorCode interfering_movposcomb(TrackAdvanceContext *c, Segment *seg,
+ int *does_r) {
MovPosComb mpc;
int r;
t.remain= 0;
r= c->getmovpos(&t,c,&mpc);
- if (r) return 1;
+ if (r) return r;
}
- if (mpc < 0) return 1;
- return seg->i->interferes_movposcomb_map & (1u << mpc);
+ *does_r= !SOMEP(mpc) || seg->i->interferes_movposcomb_map & (1u << mpc);
+ return 0;
}
-Segment *segment_interferes(TrackAdvanceContext *c, Segment *base) {
- SegmentNum intern;
- Segment *inter;
-
- intern= base->i->interferes;
+ErrorCode segment_interferer_does(TrackAdvanceContext *c, Segment *base,
+ Segment *inter, int *does_r) {
+ ErrorCode ec;
+ int does;
- if (!SOMEP(intern)) return 0;
- if (!interfering_movposcomb(c,base)) return 0;
+ if (!inter) goto doesnt;
- inter= &segments[intern];
+ ec= interfering_movposcomb(c,base, &does); if (ec) return ec;
+ if (!does) goto doesnt;
assert(base->i == &info_segments[inter->i->interferes]);
- if (!interfering_movposcomb(c,inter)) return 0;
+ ec= interfering_movposcomb(c,inter, &does); if (ec) return ec;
+ if (!does) goto doesnt;
+
+ doesnt:
+ *does_r= 0;
+ return 0;
+}
+
+Segment *segment_interferes_simple(TrackAdvanceContext *c, Segment *base) {
+ Segment *inter= segment_interferer(base);
+ if (!inter) return 0;
+
+ int does;
+ ErrorCode ec= segment_interferer_does(c,base,inter,&does);
+ assert(!ec);
- return inter;
+ return does ? inter : 0;
}
int trackloc_reverse_exact(TrackLocation *t, TrackAdvanceContext *c) {