Merge branch 'tracerestrict-sx' into jgrpp

This commit is contained in:
Jonathan G Rennison
2017-02-27 18:51:37 +00:00
6 changed files with 237 additions and 71 deletions

View File

@@ -21,6 +21,7 @@
#include "group.h"
#include "pathfinder/yapf/yapf_cache.h"
#include <vector>
#include <algorithm>
/** @file
*
@@ -855,13 +856,152 @@ static uint32 GetDualInstructionInitialValue(TraceRestrictItem item)
}
}
template <typename T> T InstructionIteratorNext(T iter)
{
return IsTraceRestrictDoubleItem(*iter) ? iter + 2 : iter + 1;
}
template <typename T> void InstructionIteratorAdvance(T &iter)
{
iter = InstructionIteratorNext(iter);
}
CommandCost TraceRestrictProgramRemoveItemAt(std::vector<TraceRestrictItem> &items, uint32 offset, bool shallow_mode)
{
TraceRestrictItem old_item = *TraceRestrictProgram::InstructionAt(items, offset);
if (IsTraceRestrictConditional(old_item) && GetTraceRestrictCondFlags(old_item) != TRCF_OR) {
bool remove_whole_block = false;
if (GetTraceRestrictCondFlags(old_item) == 0) {
if (GetTraceRestrictType(old_item) == TRIT_COND_ENDIF) {
// this is an end if, can't remove these
return_cmd_error(STR_TRACE_RESTRICT_ERROR_CAN_T_REMOVE_ENDIF);
} else {
// this is an opening if
remove_whole_block = true;
}
}
uint32 recursion_depth = 1;
std::vector<TraceRestrictItem>::iterator remove_start = TraceRestrictProgram::InstructionAt(items, offset);
std::vector<TraceRestrictItem>::iterator remove_end = InstructionIteratorNext(remove_start);
// iterate until matching end block found
for (; remove_end != items.end(); InstructionIteratorAdvance(remove_end)) {
TraceRestrictItem current_item = *remove_end;
if (IsTraceRestrictConditional(current_item)) {
if (GetTraceRestrictCondFlags(current_item) == 0) {
if (GetTraceRestrictType(current_item) == TRIT_COND_ENDIF) {
// this is an end if
recursion_depth--;
if (recursion_depth == 0) {
if (remove_whole_block) {
if (shallow_mode) {
// must erase endif first, as it is later in the vector
items.erase(remove_end, InstructionIteratorNext(remove_end));
} else {
// inclusively remove up to here
InstructionIteratorAdvance(remove_end);
}
break;
} else {
// exclusively remove up to here
break;
}
}
} else {
// this is an opening if
recursion_depth++;
}
} else {
// this is an else/or type block
if (recursion_depth == 1 && !remove_whole_block) {
// exclusively remove up to here
recursion_depth = 0;
break;
}
if (recursion_depth == 1 && remove_whole_block && shallow_mode) {
// shallow-removing whole if block, and it contains an else/or if, bail out
return_cmd_error(STR_TRACE_RESTRICT_ERROR_CAN_T_SHALLOW_REMOVE_IF_ELIF);
}
}
}
}
if (recursion_depth != 0) return CMD_ERROR; // ran off the end
if (shallow_mode) {
items.erase(remove_start, InstructionIteratorNext(remove_start));
} else {
items.erase(remove_start, remove_end);
}
} else {
std::vector<TraceRestrictItem>::iterator remove_start = TraceRestrictProgram::InstructionAt(items, offset);
std::vector<TraceRestrictItem>::iterator remove_end = InstructionIteratorNext(remove_start);
items.erase(remove_start, remove_end);
}
return CommandCost();
}
CommandCost TraceRestrictProgramMoveItemAt(std::vector<TraceRestrictItem> &items, uint32 &offset, bool up, bool shallow_mode)
{
std::vector<TraceRestrictItem>::iterator move_start = TraceRestrictProgram::InstructionAt(items, offset);
std::vector<TraceRestrictItem>::iterator move_end = InstructionIteratorNext(move_start);
TraceRestrictItem old_item = *move_start;
if (!shallow_mode) {
if (IsTraceRestrictConditional(old_item)) {
if (GetTraceRestrictCondFlags(old_item) != 0) {
// can't move or/else blocks
return_cmd_error(STR_TRACE_RESTRICT_ERROR_CAN_T_MOVE_ITEM);
}
if (GetTraceRestrictType(old_item) == TRIT_COND_ENDIF) {
// this is an end if, can't move these
return_cmd_error(STR_TRACE_RESTRICT_ERROR_CAN_T_MOVE_ITEM);
}
uint32 recursion_depth = 1;
// iterate until matching end block found
for (; move_end != items.end(); InstructionIteratorAdvance(move_end)) {
TraceRestrictItem current_item = *move_end;
if (IsTraceRestrictConditional(current_item)) {
if (GetTraceRestrictCondFlags(current_item) == 0) {
if (GetTraceRestrictType(current_item) == TRIT_COND_ENDIF) {
// this is an end if
recursion_depth--;
if (recursion_depth == 0) {
// inclusively remove up to here
InstructionIteratorAdvance(move_end);
break;
}
} else {
// this is an opening if
recursion_depth++;
}
}
}
}
if (recursion_depth != 0) return CMD_ERROR; // ran off the end
}
}
if (up) {
if (move_start == items.begin()) return_cmd_error(STR_TRACE_RESTRICT_ERROR_CAN_T_MOVE_ITEM);
std::rotate(TraceRestrictProgram::InstructionAt(items, offset - 1), move_start, move_end);
offset--;
} else {
if (move_end == items.end()) return_cmd_error(STR_TRACE_RESTRICT_ERROR_CAN_T_MOVE_ITEM);
std::rotate(move_start, move_end, InstructionIteratorNext(move_end));
offset++;
}
return CommandCost();
}
/**
* The main command for editing a signal tracerestrict program.
* @param tile The tile which contains the signal.
* @param flags Internal command handler stuff.
* Below apply for instruction modification actions only
* @param p1 Bitstuffed items
* @param p2 Item, for insert and modify operations
* @param p2 Item, for insert and modify operations. Flags for instruction move operations
* @return the cost of this operation (which is free), or an error
*/
CommandCost CmdProgramSignalTraceRestrict(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
@@ -939,71 +1079,16 @@ CommandCost CmdProgramSignalTraceRestrict(TileIndex tile, DoCommandFlag flags, u
break;
}
case TRDCT_REMOVE_ITEM: {
TraceRestrictItem old_item = *TraceRestrictProgram::InstructionAt(items, offset);
if (IsTraceRestrictConditional(old_item) && GetTraceRestrictCondFlags(old_item) != TRCF_OR) {
bool remove_whole_block = false;
if (GetTraceRestrictCondFlags(old_item) == 0) {
if (GetTraceRestrictType(old_item) == TRIT_COND_ENDIF) {
// this is an end if, can't remove these
return_cmd_error(STR_TRACE_RESTRICT_ERROR_CAN_T_REMOVE_ENDIF);
} else {
// this is an opening if
remove_whole_block = true;
}
}
case TRDCT_REMOVE_ITEM:
case TRDCT_SHALLOW_REMOVE_ITEM: {
CommandCost res = TraceRestrictProgramRemoveItemAt(items, offset, type == TRDCT_SHALLOW_REMOVE_ITEM);
if (res.Failed()) return res;
break;
}
uint32 recursion_depth = 1;
std::vector<TraceRestrictItem>::iterator remove_start = TraceRestrictProgram::InstructionAt(items, offset);
std::vector<TraceRestrictItem>::iterator remove_end = remove_start + 1;
// iterate until matching end block found
for (; remove_end != items.end(); ++remove_end) {
TraceRestrictItem current_item = *remove_end;
if (IsTraceRestrictConditional(current_item)) {
if (GetTraceRestrictCondFlags(current_item) == 0) {
if (GetTraceRestrictType(current_item) == TRIT_COND_ENDIF) {
// this is an end if
recursion_depth--;
if (recursion_depth == 0) {
if (remove_whole_block) {
// inclusively remove up to here
++remove_end;
break;
} else {
// exclusively remove up to here
break;
}
}
} else {
// this is an opening if
recursion_depth++;
}
} else {
// this is an else/or type block
if (recursion_depth == 1 && !remove_whole_block) {
// exclusively remove up to here
recursion_depth = 0;
break;
}
}
} else if (IsTraceRestrictDoubleItem(current_item)) {
// this is a double-item, jump over the next item as well
++remove_end;
}
}
if (recursion_depth != 0) return CMD_ERROR; // ran off the end
items.erase(remove_start, remove_end);
} else {
std::vector<TraceRestrictItem>::iterator remove_start = TraceRestrictProgram::InstructionAt(items, offset);
std::vector<TraceRestrictItem>::iterator remove_end = remove_start + 1;
if (IsTraceRestrictDoubleItem(old_item)) {
// this is a double-item, remove the next item as well
++remove_end;
}
items.erase(remove_start, remove_end);
}
case TRDCT_MOVE_ITEM: {
CommandCost res = TraceRestrictProgramMoveItemAt(items, offset, p2 & 1, p2 & 2);
if (res.Failed()) return res;
break;
}