/* Add it to the list first to present a consistent state in block_reserved
signal. */
blocks.push_back(block);
+
+ bool first_reserve = (cur_blocks_end==blocks.end());
+ if(first_reserve)
+ --cur_blocks_end;
+
try
{
if(!block->reserve(&train))
{
+ if(first_reserve)
+ cur_blocks_end = blocks.end();
blocks.pop_back();
return false;
}
}
catch(...)
{
+ if(first_reserve)
+ cur_blocks_end = blocks.end();
blocks.pop_back();
throw;
}
/* Sensors aren't guaranteed to be detriggered in order. Go through the
block list and locate the first sensor that's still active. */
- Sensor *last_inactive = 0;
- for(BlockList::iterator i=blocks.begin(); (i!=cur_blocks_end && i->block()!=&veh_block); ++i)
+ BlockList::iterator end = blocks.end();
+ for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i)
{
+ Block *block = &**i;
list<Sensor *> sensors;
- if(Sensor *sensor = (*i)->get_sensor())
- sensors.push_back(sensor);
- Block *block = &**i;
+ /* Collect all sensors from the block in the order they are expected to
+ detrigger. */
for(TrackIter j=i->track_iter(); (j && &j->get_block()==block); j=j.next())
if(!j->get_attachments().empty())
{
sensors.push_back(gate);
}
- for(list<Sensor *>::const_iterator j=sensors.begin(); j!=sensors.end(); ++j)
+ if(Sensor *sensor = (*i)->get_sensor())
+ sensors.push_back(sensor);
+
+ /* See if any sensor is still active, and record the position of the
+ last inactive sensor. */
+ bool active_sensor = false;
+ for(list<Sensor *>::const_iterator j=sensors.begin(); (!active_sensor && j!=sensors.end()); ++j)
{
if((*j)->get_state())
+ active_sensor = true;
+ else
+ end = i;
+ }
+
+ // Stop if we encounter an active sensor or the train's last vehicle
+ if(block==&veh_block || active_sensor)
+ {
+ if(end!=blocks.end())
{
- if(last_inactive)
- {
- if(dynamic_cast<BeamGate *>(*j))
- ++i;
- release_blocks_begin(i);
- }
- return;
+ /* If the last inactive sensor was in an earlier block, release
+ that block as well. */
+ if(i!=end)
+ ++end;
+ release_blocks_begin(end);
}
- else
- last_inactive = *j;
+ return;
}
}
}
void BlockAllocator::turnout_path_changing(Track &track)
{
- BlockList::iterator i = find_if(blocks.begin(), blocks.end(), BlockMatch(track.get_block()));
+ BlockList::iterator i = find_if(cur_blocks_end, blocks.end(), BlockMatch(track.get_block()));
if(i!=blocks.end())
{
++i;