X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Flibr2c2%2Fblockallocator.cpp;h=2a2473732aac1e24cfd0b75fc62256ed8f60bf8e;hb=806bc53176e8ed216ba5db95bde5878832332393;hp=b38b62d6d1f1cd37763fcb2c3979dff8d4e97439;hpb=57e0944ee8ed442e2d0aa7c9964cac00450af5e7;p=r2c2.git diff --git a/source/libr2c2/blockallocator.cpp b/source/libr2c2/blockallocator.cpp index b38b62d..2a24737 100644 --- a/source/libr2c2/blockallocator.cpp +++ b/source/libr2c2/blockallocator.cpp @@ -28,9 +28,11 @@ struct BlockAllocator::BlockMatch BlockAllocator::BlockAllocator(Train &t): train(t), cur_blocks_end(blocks.end()), + next_sensor(0), pending_block(0), stop_at_block(0), - reserving(false) + reserving(false), + advancing(false) { Layout &layout = train.get_layout(); layout.signal_block_reserved.connect(sigc::mem_fun(this, &BlockAllocator::block_reserved)); @@ -81,8 +83,9 @@ void BlockAllocator::rewind_to(const Block &block) void BlockAllocator::clear() { - active = false; release_blocks_begin(blocks.end()); + active = false; + next_sensor = 0; pending_block = 0; stop_at_block = 0; } @@ -151,7 +154,7 @@ void BlockAllocator::reserve_more() else if(&*start==pending_block) { TrackIter track = start.track_iter(); - if(!track.endpoint().has_path(track->get_active_path())) + if(track->is_path_changing() || !track.endpoint().has_path(track->get_active_path())) return; } @@ -192,7 +195,10 @@ void BlockAllocator::reserve_more() } if(!reserve_block(block)) + { + pending_block = &*block; break; + } if(cur_blocks_end==blocks.end()) --cur_blocks_end; @@ -237,9 +243,12 @@ void BlockAllocator::reserve_more() dist += block->get_path_length(block.entry()); } - // Make any sensorless blocks at the beginning immediately current - while(cur_blocks_end!=blocks.end() && !(*cur_blocks_end)->get_sensor_id()) - ++cur_blocks_end; + if(!next_sensor) + { + update_next_sensor(0); + // Immediately advance to just before the next sensor + advance_front(next_sensor); + } } bool BlockAllocator::reserve_block(const BlockIter &block) @@ -264,6 +273,49 @@ bool BlockAllocator::reserve_block(const BlockIter &block) } } +void BlockAllocator::advance_front(const Block *block) +{ + BlockList::iterator end; + if(block) + end = find_if(cur_blocks_end, blocks.end(), BlockMatch(*block)); + else + end = blocks.end(); + + SetFlag setf(advancing); + BlockList::iterator i = cur_blocks_end; + // Update cur_blocks_end first to keep things consistent. + cur_blocks_end = end; + for(; i!=end; ++i) + train.signal_advanced.emit(**i); +} + +void BlockAllocator::advance_front(const Sensor *sensor) +{ + advance_front(sensor ? sensor->get_block() : 0); +} + +void BlockAllocator::advance_back() +{ + const Vehicle &veh = train.get_vehicle(train.get_controller().get_reverse() ? 0 : train.get_n_vehicles()-1); + const Block &veh_block = veh.get_track()->get_block(); + + /* 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) + if(Sensor *sensor = (*i)->get_sensor()) + { + if(sensor->get_state()) + { + if(last_inactive) + release_blocks_begin(i); + return; + } + else + last_inactive = sensor; + } +} + void BlockAllocator::release_blocks_begin(const BlockList::iterator &end) { for(BlockList::iterator i=blocks.begin(); i!=end; ) @@ -291,8 +343,12 @@ void BlockAllocator::release_blocks_end(const BlockList::iterator &begin) void BlockAllocator::release_block(const BlockList::iterator &i) { + if(advancing) + throw logic_error("cannot release while advancing"); if(i==cur_blocks_end) ++cur_blocks_end; + if(next_sensor && &**i==next_sensor->get_block()) + next_sensor = 0; if(&**i==pending_block) pending_block = 0; @@ -337,77 +393,42 @@ void BlockAllocator::block_reserved(Block &block, const Train *tr) void BlockAllocator::sensor_state_changed(Sensor &sensor, Sensor::State state) { - Block *block = 0; - if(TrackCircuit *tc = dynamic_cast(&sensor)) - block = &tc->get_block(); - else - return; - - if(block->get_train()!=&train) + Block *block = sensor.get_block(); + if(!block || block->get_train()!=&train) return; if(state==Sensor::MAYBE_ACTIVE) { - // Find the first sensor block from our reserved blocks that isn't this sensor - BlockList::iterator end; - unsigned result = 0; - for(end=cur_blocks_end; end!=blocks.end(); ++end) - if((*end)->get_sensor_id()) - { - if(&**end!=block) - { - if(result==0) - result = 2; - else if(result==1) - break; - } - else if(result==0) - result = 1; - else if(result==2) - result = 3; - } - - if(result==1) + if(&sensor==next_sensor) { - // Move blocks up to the next sensor to our current blocks - for(BlockList::iterator j=cur_blocks_end; j!=end; ++j) - train.signal_advanced.emit(**j); - cur_blocks_end = end; + update_next_sensor(next_sensor); + advance_front(next_sensor); if(active) reserve_more(); } - else if(result==3) + else if(!is_block_current(*block)) train.get_layout().emergency("Sensor for "+train.get_name()+" triggered out of order"); } else if(state==Sensor::INACTIVE) - { - const Vehicle &veh = train.get_vehicle(train.get_controller().get_reverse() ? 0 : train.get_n_vehicles()-1); - const Block &veh_block = veh.get_track()->get_block(); - const Driver &driver = train.get_layout().get_driver(); - - /* Sensors aren't guaranteed to be detriggered in order. Go through the - block list and locate the first sensor that's still active. */ - BlockList::iterator end = blocks.end(); - for(BlockList::iterator i=blocks.begin(); i!=cur_blocks_end; ++i) - { - // Avoid freeing blocks that still hold the train's vehicles - if(&**i==&veh_block) - break; + advance_back(); +} + +void BlockAllocator::update_next_sensor(Sensor *after) +{ + BlockList::iterator i = cur_blocks_end; + if(after) + i = find_if(i, blocks.end(), BlockMatch(*after->get_block())); - if((*i)->get_sensor_id()) + for(; i!=blocks.end(); ++i) + if(Sensor *sensor = (*i)->get_sensor()) + if(sensor!=next_sensor) { - if(driver.get_sensor((*i)->get_sensor_id())) - break; - else - end = i; + next_sensor = sensor; + return; } - } - - if(end!=blocks.end()) - // Free blocks up to the last inactive sensor - release_blocks_begin(++end); - } + + next_sensor = 0; } void BlockAllocator::save(list &st) const