Only run trace restrict programs if they contain relevant actions.

Only run in pathfinder case if deny or penalty are present.
Only run in is safe waiting tile case is reserve through is present.
Presence is determined at program validation time and cached in the
program structure.
Validator now checks for unknown non-conditional instructions.
This commit is contained in:
Jonathan G Rennison
2015-09-02 18:35:56 +01:00
parent 06a1d7c5c9
commit e2435c7169
6 changed files with 42 additions and 12 deletions

View File

@@ -2462,6 +2462,7 @@ STR_TRACE_RESTRICT_ERROR_VALIDATE_END_CONDSTACK :Validation fail
STR_TRACE_RESTRICT_ERROR_VALIDATE_NO_IF :Validation failed: else/endif without opening if STR_TRACE_RESTRICT_ERROR_VALIDATE_NO_IF :Validation failed: else/endif without opening if
STR_TRACE_RESTRICT_ERROR_VALIDATE_DUP_ELSE :Validation failed: duplicate else STR_TRACE_RESTRICT_ERROR_VALIDATE_DUP_ELSE :Validation failed: duplicate else
STR_TRACE_RESTRICT_ERROR_VALIDATE_ELIF_NO_IF :Validation failed: else if without opening if STR_TRACE_RESTRICT_ERROR_VALIDATE_ELIF_NO_IF :Validation failed: else if without opening if
STR_TRACE_RESTRICT_ERROR_VALIDATE_UNKNOWN_INSTRUCTION :Validation failed: unknown instruction
STR_TRACE_RESTRICT_ERROR_SOURCE_SAME_AS_TARGET :Source and target signals are the same STR_TRACE_RESTRICT_ERROR_SOURCE_SAME_AS_TARGET :Source and target signals are the same
STR_TRACE_RESTRICT_ERROR_CAN_T_RESET_SIGNAL :{WHITE}Can't reset signal STR_TRACE_RESTRICT_ERROR_CAN_T_RESET_SIGNAL :{WHITE}Can't reset signal
STR_TRACE_RESTRICT_ERROR_CAN_T_COPY_PROGRAM :{WHITE}Can't copy program STR_TRACE_RESTRICT_ERROR_CAN_T_COPY_PROGRAM :{WHITE}Can't copy program

View File

@@ -264,7 +264,7 @@ private:
inline bool ExecuteTraceRestrict(Node& n, TileIndex tile, Trackdir trackdir, int& cost, TraceRestrictProgramResult &out) inline bool ExecuteTraceRestrict(Node& n, TileIndex tile, Trackdir trackdir, int& cost, TraceRestrictProgramResult &out)
{ {
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir)); const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir));
if (prog) { if (prog && prog->actions_used_flags & TRPAUF_PF) {
prog->Execute(Yapf().GetVehicle(), TraceRestrictProgramInput(tile, trackdir, &TraceRestrictPreviousSignalCallback, &n), out); prog->Execute(Yapf().GetVehicle(), TraceRestrictProgramInput(tile, trackdir, &TraceRestrictPreviousSignalCallback, &n), out);
if (out.flags & TRPRF_DENY) { if (out.flags & TRPRF_DENY) {
n.m_segment->m_end_segment_reason |= ESRB_DEAD_END; n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;

View File

@@ -468,7 +468,7 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo
if (HasPbsSignalOnTrackdir(ft.m_new_tile, td)) { if (HasPbsSignalOnTrackdir(ft.m_new_tile, td)) {
if (IsRestrictedSignal(ft.m_new_tile)) { if (IsRestrictedSignal(ft.m_new_tile)) {
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(ft.m_new_tile, TrackdirToTrack(td)); const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(ft.m_new_tile, TrackdirToTrack(td));
if (prog) { if (prog && prog->actions_used_flags & TRPAUF_RESERVE_THROUGH) {
TraceRestrictProgramResult out; TraceRestrictProgramResult out;
prog->Execute(v, TraceRestrictProgramInput(tile, trackdir, &IsSafeWaitingPositionTraceRestrictPreviousSignalCallback, nullptr), out); prog->Execute(v, TraceRestrictProgramInput(tile, trackdir, &IsSafeWaitingPositionTraceRestrictPreviousSignalCallback, nullptr), out);
if (out.flags & TRPRF_RESERVE_THROUGH) { if (out.flags & TRPRF_RESERVE_THROUGH) {

View File

@@ -413,12 +413,14 @@ void TraceRestrictProgram::DecrementRefCount() {
/** /**
* Validate a instruction list * Validate a instruction list
* Returns successful result if program seems OK * Returns successful result if program seems OK
* This only validates that conditional nesting is correct, at present * This only validates that conditional nesting is correct,
* and that all non-conditionals have a known type, at present
*/ */
CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem> &items) { CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem> &items, TraceRestrictProgramActionsUsedFlags &actions_used_flags) {
// static to avoid needing to re-alloc/resize on each execution // static to avoid needing to re-alloc/resize on each execution
static std::vector<TraceRestrictCondStackFlags> condstack; static std::vector<TraceRestrictCondStackFlags> condstack;
condstack.clear(); condstack.clear();
actions_used_flags = static_cast<TraceRestrictProgramActionsUsedFlags>(0);
size_t size = items.size(); size_t size = items.size();
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
@@ -462,6 +464,19 @@ CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem>
return_cmd_error(STR_TRACE_RESTRICT_ERROR_OFFSET_TOO_LARGE); // instruction ran off end return_cmd_error(STR_TRACE_RESTRICT_ERROR_OFFSET_TOO_LARGE); // instruction ran off end
} }
} }
switch (GetTraceRestrictType(item)) {
case TRIT_PF_DENY:
case TRIT_PF_PENALTY:
actions_used_flags |= TRPAUF_PF;
break;
case TRIT_RESERVE_THROUGH:
actions_used_flags |= TRPAUF_RESERVE_THROUGH;
break;
default:
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_UNKNOWN_INSTRUCTION);
}
} }
} }
if(!condstack.empty()) { if(!condstack.empty()) {
@@ -887,7 +902,8 @@ CommandCost CmdProgramSignalTraceRestrict(TileIndex tile, DoCommandFlag flags, u
break; break;
} }
CommandCost validation_result = TraceRestrictProgram::Validate(items); TraceRestrictProgramActionsUsedFlags actions_used_flags;
CommandCost validation_result = TraceRestrictProgram::Validate(items, actions_used_flags);
if (validation_result.Failed()) { if (validation_result.Failed()) {
return validation_result; return validation_result;
} }
@@ -897,6 +913,7 @@ CommandCost CmdProgramSignalTraceRestrict(TileIndex tile, DoCommandFlag flags, u
// move in modified program // move in modified program
prog->items.swap(items); prog->items.swap(items);
prog->actions_used_flags = actions_used_flags;
if (prog->items.size() == 0 && prog->refcount == 1) { if (prog->items.size() == 0 && prog->refcount == 1) {
// program is empty, and this tile is the only reference to it // program is empty, and this tile is the only reference to it

View File

@@ -197,6 +197,15 @@ enum TraceRestrictProgramResultFlags {
}; };
DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramResultFlags) DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramResultFlags)
/**
* Enumeration for TraceRestrictProgram::actions_used_flags
*/
enum TraceRestrictProgramActionsUsedFlags {
TRPAUF_PF = 1 << 0, ///< Pathfinder deny or penalty are present
TRPAUF_RESERVE_THROUGH = 1 << 1, ///< Reserve through action is present
};
DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramActionsUsedFlags)
/** /**
* Execution input of a TraceRestrictProgram * Execution input of a TraceRestrictProgram
*/ */
@@ -230,9 +239,10 @@ struct TraceRestrictProgramResult {
struct TraceRestrictProgram : TraceRestrictProgramPool::PoolItem<&_tracerestrictprogram_pool> { struct TraceRestrictProgram : TraceRestrictProgramPool::PoolItem<&_tracerestrictprogram_pool> {
std::vector<TraceRestrictItem> items; std::vector<TraceRestrictItem> items;
uint32 refcount; uint32 refcount;
TraceRestrictProgramActionsUsedFlags actions_used_flags;
TraceRestrictProgram() TraceRestrictProgram()
: refcount(0) { } : refcount(0), actions_used_flags(static_cast<TraceRestrictProgramActionsUsedFlags>(0)) { }
void Execute(const Train *v, const TraceRestrictProgramInput &input, TraceRestrictProgramResult &out) const; void Execute(const Train *v, const TraceRestrictProgramInput &input, TraceRestrictProgramResult &out) const;
@@ -243,7 +253,7 @@ struct TraceRestrictProgram : TraceRestrictProgramPool::PoolItem<&_tracerestrict
void DecrementRefCount(); void DecrementRefCount();
static CommandCost Validate(const std::vector<TraceRestrictItem> &items); static CommandCost Validate(const std::vector<TraceRestrictItem> &items, TraceRestrictProgramActionsUsedFlags &actions_used_flags);
static size_t InstructionOffsetToArrayOffset(const std::vector<TraceRestrictItem> &items, size_t offset); static size_t InstructionOffsetToArrayOffset(const std::vector<TraceRestrictItem> &items, size_t offset);
@@ -285,10 +295,11 @@ struct TraceRestrictProgram : TraceRestrictProgramPool::PoolItem<&_tracerestrict
return items.begin() + TraceRestrictProgram::InstructionOffsetToArrayOffset(items, instruction_offset); return items.begin() + TraceRestrictProgram::InstructionOffsetToArrayOffset(items, instruction_offset);
} }
/** /** Call validation function on current program instruction list and set actions_used_flags */
* Call validation function on current program instruction list CommandCost Validate()
*/ {
CommandCost Validate() const { return TraceRestrictProgram::Validate(items); } return TraceRestrictProgram::Validate(items, actions_used_flags);
}
}; };
/** Get TraceRestrictItem type field */ /** Get TraceRestrictItem type field */

View File

@@ -1680,7 +1680,8 @@ private:
items.insert(items.begin() + array_offset, item); items.insert(items.begin() + array_offset, item);
} }
return TraceRestrictProgram::Validate(items).Succeeded(); TraceRestrictProgramActionsUsedFlags actions_used_flags;
return TraceRestrictProgram::Validate(items, actions_used_flags).Succeeded();
} }
/** /**