use super::super::disp_imports::*;
use super::TrainDisp;
impl TrainDisp {
pub fn advance(
&mut self,
link_disp_auths: &mut [Vec<DispAuth>],
links_blocked: &mut [TrainIdx],
links: &[Link],
) -> bool {
let time_overlap_change = 30.0 * uc::S;
assert!(self.disp_node_idx_free.idx() < self.disp_path.len());
assert!(
self.disp_path[self.disp_node_idx_free.idx()]
.time_pass
.is_infinite(),
"Train {} has a timed free node!",
self.train_idx.idx()
);
self.is_blocked = if self.disp_node_idx_front.is_some() {
let disp_node_front = &self.disp_path[self.disp_node_idx_front.idx()];
let link_idx_front = disp_node_front.link_event.link_idx;
let link_disp_front = &link_disp_auths[link_idx_front.idx()];
let disp_auth_idx_curr = disp_node_front.disp_auth_idx_entry;
debug_assert!(link_idx_front.is_real());
debug_assert!(disp_auth_idx_curr.is_some());
debug_assert!(self.train_idx == link_disp_front[disp_auth_idx_curr.idx()].train_idx);
debug_assert!(
(self.offset_free - disp_node_front.offset)
<= link_disp_front[disp_auth_idx_curr.idx() - 1].offset_back
);
!link_disp_front[disp_auth_idx_curr.idx() - 1]
.offset_back
.is_infinite()
} else {
false
};
self.time_update_next = if self.disp_node_idx_free.is_some()
&& self.disp_node_idx_free.idx() < self.disp_path.len()
{
let time_update = self.disp_path[self.disp_node_idx_free.idx() - 1].time_pass;
let est_time_prev = &self.est_times[self.disp_path[self.disp_node_idx_free.idx() - 1]
.est_idx
.idx()];
if est_time_prev.idx_next == self.disp_path[self.disp_node_idx_free.idx()].est_idx {
time_update + est_time_prev.time_to_next
} else {
time_update
}
} else {
self.time_update
};
let disp_node_idx_save = self.disp_node_idx_free;
let offset_save = self.offset_free;
loop {
let disp_node_curr = &self.disp_path[self.disp_node_idx_free.idx()];
let est_time_curr = &self.est_times[disp_node_curr.est_idx.idx()];
if self.is_blocked && self.offset_free <= disp_node_curr.offset {
while self.disp_node_idx_free.idx() < self.disp_path.len() {
let disp_node_free = &self.disp_path[self.disp_node_idx_free.idx()];
if self.offset_free < disp_node_free.offset
|| disp_node_free.link_event.est_type != EstType::Fake
{
break;
}
self.disp_node_idx_free =
(self.disp_node_idx_free.idx() + 1).try_from_idx().unwrap();
}
break;
}
let link_idx_curr = disp_node_curr.link_event.link_idx;
let link_curr = &links[link_idx_curr.idx()];
if disp_node_curr.link_event.est_type == EstType::Arrive {
let link_idxs_lockout = &link_curr.link_idxs_lockout;
#[cfg(debug_advance_rewind)]
{
for link_idx_lockout in link_idxs_lockout {
assert!(link_disp_auths[link_idx_lockout.idx()]
.last()
.unwrap()
.offset_back
.is_infinite());
}
assert!(link_disp_auths[link_curr.idx_flip.idx()]
.last()
.unwrap()
.offset_back
.is_infinite());
}
let disp_auth_prev = link_disp_auths[link_idx_curr.idx()].last().unwrap();
if disp_auth_prev.offset_back.is_finite() {
self.offset_free = disp_node_curr.offset + disp_auth_prev.offset_back;
self.is_blocked = true;
if disp_auth_prev.offset_back == si::Length::ZERO {
break;
}
}
if self.offset_free < disp_node_curr.offset
&& (!link_idxs_lockout.is_empty()
|| links[link_curr.idx_next.idx()].idx_prev_alt.is_real())
{
self.offset_free = disp_node_curr.offset;
break;
}
let time_startup = est_time_curr.speed / self.acc_startup;
let flip_clear_exit = link_disp_auths[link_curr.idx_flip.idx()]
.last()
.unwrap()
.clear_exit;
let time_update_max = if disp_auth_prev.clear_exit >= flip_clear_exit {
disp_auth_prev.clear_entry + self.time_spacing
}
else {
flip_clear_exit + time_startup
};
self.time_update_next = self.time_update_next.max(time_update_max);
if link_idx_curr.is_real() {
self.link_idxs_blocking.push(link_curr.idx_flip);
for link_idx_lockout in link_idxs_lockout {
self.time_update_next = self.time_update_next.max(
link_disp_auths[link_idx_lockout.idx()]
.last()
.unwrap()
.clear_exit
+ time_overlap_change
+ time_startup,
);
}
self.link_idxs_blocking.extend(link_idxs_lockout);
}
if self.disp_node_idx_front.is_some() {
let disp_node_exit = &self.disp_path[self.disp_node_idx_front.idx()];
let link_idx_exit = disp_node_exit.link_event.link_idx;
let disp_auth_idx_exit = disp_node_exit.disp_auth_idx_entry;
debug_assert!(link_idx_exit.is_real());
debug_assert!(disp_auth_idx_exit.is_some());
let disp_auths_exit = &mut link_disp_auths[link_idx_exit.idx()];
let disp_auth_same_dir_exit = &disp_auths_exit[disp_auth_idx_exit.idx() - 1];
debug_assert!(disp_auth_same_dir_exit.offset_back.is_infinite());
self.time_update_next = self
.time_update_next
.max(disp_auth_same_dir_exit.clear_exit + self.time_spacing);
let disp_auth_exit = &mut disp_auths_exit[disp_auth_idx_exit.idx()];
debug_assert!(disp_auth_exit.train_idx == self.train_idx);
disp_auth_exit.offset_front = f64::INFINITY * uc::M;
disp_auth_exit.arrive_exit = self.time_update_next;
}
if link_idx_curr.is_real() {
let disp_auths_curr = &mut link_disp_auths[link_idx_curr.idx()];
self.disp_path[self.disp_node_idx_free.idx()].disp_auth_idx_entry =
disp_auths_curr.len().try_from_idx().unwrap();
disp_auths_curr.push(DispAuth {
arrive_entry: self.time_update_next,
train_idx: self.train_idx,
..Default::default()
});
}
self.disp_node_idx_front = self.disp_node_idx_free;
}
else if disp_node_curr.link_event.est_type == EstType::Clear {
if self.disp_node_idx_back.is_some() {
let disp_node_exit = &self.disp_path[self.disp_node_idx_back.idx()];
let link_idx_exit = disp_node_exit.link_event.link_idx;
let disp_auth_idx_exit = disp_node_exit.disp_auth_idx_entry;
debug_assert!(link_idx_exit.is_real());
debug_assert!(disp_auth_idx_exit.is_some());
let disp_auths_exit = &mut link_disp_auths[link_idx_exit.idx()];
let disp_auth_same_dir_exit = &disp_auths_exit[disp_auth_idx_exit.idx() - 1];
debug_assert!(disp_auth_same_dir_exit.offset_back.is_infinite());
let disp_auth_exit = &mut disp_auths_exit[disp_auth_idx_exit.idx()];
debug_assert!(disp_auth_exit.train_idx == self.train_idx);
disp_auth_exit.offset_back = f64::INFINITY * uc::M;
disp_auth_exit.clear_exit = self.time_update_next;
update_links_blocked(
links_blocked,
links,
link_idx_exit,
disp_auths_exit.last().unwrap().train_idx_curr(),
);
self.link_idxs_blocking
.drain(..1 + links[link_idx_exit.idx()].link_idxs_lockout.len());
}
if link_idx_curr.is_real() {
let disp_auth_idx =
&mut self.disp_path[self.disp_node_idx_free.idx()].disp_auth_idx_entry;
let disp_auths_curr = &mut link_disp_auths[link_idx_curr.idx()];
*disp_auth_idx = (disp_auths_curr.len() - 1).try_from_idx().unwrap();
let disp_auth_curr = &mut disp_auths_curr[disp_auth_idx.idx()];
debug_assert!(disp_auth_curr.train_idx == self.train_idx);
disp_auth_curr.clear_entry = self.time_update_next;
self.disp_node_idx_back = self.disp_node_idx_free;
}
}
self.disp_path[self.disp_node_idx_free.idx()].time_pass = self.time_update_next;
self.disp_node_idx_free = (self.disp_node_idx_free.idx() + 1).try_from_idx().unwrap();
if self.disp_node_idx_free.idx() == self.disp_path.len() {
self.offset_free = self.disp_path.last().unwrap().offset;
break;
}
if est_time_curr.idx_next == self.disp_path[self.disp_node_idx_free.idx()].est_idx {
self.time_update_next += est_time_curr.time_to_next;
}
}
if self.offset_free == offset_save && self.disp_node_idx_free == disp_node_idx_save {
false
} else {
self.update_occupancy(link_disp_auths, links_blocked, links);
true
}
}
pub fn rewind(
&mut self,
link_disp_auths: &mut [Vec<DispAuth>],
links_blocked: &mut [TrainIdx],
links: &[Link],
) {
assert!(
self.disp_node_idx_free.idx() < self.disp_path.len(),
"Train {} cannot rewind after exiting!",
self.train_idx.idx()
);
assert!(self.disp_node_idx_fixed <= self.disp_node_idx_free);
assert!(
self.disp_path[self.disp_node_idx_fixed.idx()].offset >= self.offset_fixed,
"Train {} cannot be rewound with an invalid new offset and dispatch node combo!",
self.train_idx.idx()
);
self.offset_free = self.offset_fixed;
while self.disp_node_idx_fixed < self.disp_node_idx_free {
self.disp_node_idx_free = (self.disp_node_idx_free.idx() - 1).try_from_idx().unwrap();
self.disp_path[self.disp_node_idx_free.idx()].time_pass = f64::INFINITY * uc::S;
let (link_idx_curr, est_type_curr) = {
let link_event_curr = self.disp_path[self.disp_node_idx_free.idx()].link_event;
(link_event_curr.link_idx, link_event_curr.est_type)
};
if est_type_curr == EstType::Arrive {
assert!(link_idx_curr.is_real());
debug_assert!(self.disp_node_idx_front == self.disp_node_idx_free);
loop {
self.disp_node_idx_front =
(self.disp_node_idx_front.idx() - 1).try_from_idx().unwrap();
if self.disp_path[self.disp_node_idx_front.idx()]
.link_event
.est_type
== EstType::Arrive
|| self.disp_node_idx_front.is_none()
{
break;
}
}
let disp_auths_exit = &mut link_disp_auths[link_idx_curr.idx()];
let disp_auth_idx_entry =
&mut self.disp_path[self.disp_node_idx_free.idx()].disp_auth_idx_entry;
debug_assert!(disp_auth_idx_entry.idx() == disp_auths_exit.len() - 1);
disp_auths_exit.pop();
*disp_auth_idx_entry = None;
update_links_blocked(
links_blocked,
links,
link_idx_curr,
disp_auths_exit.last().unwrap().train_idx_curr(),
);
let new_len = self.link_idxs_blocking.len()
- 1
- links[link_idx_curr.idx()].link_idxs_lockout.len();
self.link_idxs_blocking.truncate(new_len);
if self.disp_node_idx_front.is_some() {
let disp_node_front = &self.disp_path[self.disp_node_idx_front.idx()];
let link_front = &links[disp_node_front.link_event.link_idx.idx()];
debug_assert!(
link_front.link_idxs_lockout
== self.link_idxs_blocking[self.link_idxs_blocking.len()
- link_front.link_idxs_lockout.len()..]
);
debug_assert!(
link_front.idx_flip
== self.link_idxs_blocking[self.link_idxs_blocking.len()
- 1
- link_front.link_idxs_lockout.len()]
);
link_disp_auths[disp_node_front.link_event.link_idx.idx()]
[disp_node_front.disp_auth_idx_entry.idx()]
.arrive_exit = f64::INFINITY * uc::S;
} else {
debug_assert!(self.link_idxs_blocking.is_empty());
}
}
else if est_type_curr == EstType::Clear {
assert!(link_idx_curr.is_real());
debug_assert!(self.disp_node_idx_back == self.disp_node_idx_free);
loop {
self.disp_node_idx_back =
(self.disp_node_idx_back.idx() - 1).try_from_idx().unwrap();
if self.disp_path[self.disp_node_idx_back.idx()]
.link_event
.est_type
== EstType::Clear
|| self.disp_node_idx_back.is_none()
{
break;
}
}
if self.disp_node_idx_back.is_some() {
let disp_node_back = &self.disp_path[self.disp_node_idx_back.idx()];
let link_entry = &links[disp_node_back.link_event.link_idx.idx()];
self.link_idxs_blocking.splice(
0..0,
vec![link_entry.idx_flip; 1 + link_entry.link_idxs_lockout.len()],
);
self.link_idxs_blocking[1..1 + link_entry.link_idxs_lockout.len()]
.copy_from_slice(&link_entry.link_idxs_lockout);
link_disp_auths[disp_node_back.link_event.link_idx.idx()]
[disp_node_back.disp_auth_idx_entry.idx()]
.clear_exit = f64::INFINITY * uc::S;
}
let disp_auths_exit = &mut link_disp_auths[link_idx_curr.idx()];
let disp_auth_idx_entry =
&mut self.disp_path[self.disp_node_idx_free.idx()].disp_auth_idx_entry;
debug_assert!(disp_auth_idx_entry.idx() == disp_auths_exit.len() - 1);
disp_auths_exit.last_mut().unwrap().offset_back = si::Length::ZERO;
disp_auths_exit.last_mut().unwrap().clear_entry = f64::INFINITY * uc::S;
*disp_auth_idx_entry = None;
}
}
self.update_occupancy(link_disp_auths, links_blocked, links);
}
fn update_occupancy(
&mut self,
link_disp_auths: &mut [Vec<DispAuth>],
links_blocked: &mut [TrainIdx],
links: &[Link],
) {
if self.disp_node_idx_free.idx() < self.disp_path.len() {
if self.disp_node_idx_front.is_some() {
let disp_node_front = &self.disp_path[self.disp_node_idx_front.idx()];
let offset_front = self.offset_free - disp_node_front.offset;
let disp_auths_front =
&mut link_disp_auths[disp_node_front.link_event.link_idx.idx()];
disp_auths_front[disp_node_front.disp_auth_idx_entry.idx()].offset_front =
offset_front;
let disp_auth_prev_train =
&disp_auths_front[disp_node_front.disp_auth_idx_entry.idx() - 1];
debug_assert!(
offset_front <= disp_auth_prev_train.offset_back,
"The front of train {} was placed past the back of train {}!",
self.train_idx.idx(),
disp_auth_prev_train.train_idx.idx()
);
}
if self.disp_node_idx_back.is_some() {
let disp_node_back = &self.disp_path[self.disp_node_idx_back.idx()];
let offset_back = self.offset_free - disp_node_back.offset;
let disp_auths_back =
&mut link_disp_auths[disp_node_back.link_event.link_idx.idx()];
disp_auths_back[disp_node_back.disp_auth_idx_entry.idx()].offset_back = offset_back;
let disp_auth_idx_next = disp_node_back.disp_auth_idx_entry.idx() + 1;
debug_assert!(
disp_auth_idx_next == disp_auths_back.len()
|| disp_auths_back[disp_auth_idx_next].offset_front <= offset_back,
"The back of train {} was placed prior to the front of the next train {}!",
self.train_idx.idx(),
disp_auths_back[disp_auth_idx_next].train_idx.idx()
);
}
for link_idx in &self.link_idxs_blocking {
links_blocked[link_idx.idx()] = self.train_idx;
}
}
else if !self.link_idxs_blocking.is_empty() {
assert!(self.disp_node_idx_back.is_some());
let link_idx_back = self.disp_path[self.disp_node_idx_back.idx()]
.link_event
.link_idx;
for disp_node in self.disp_path.iter().rev() {
if disp_node.link_event.est_type == EstType::Arrive {
assert!(disp_node.link_event.link_idx.is_real());
let disp_auths_exit = &mut link_disp_auths[disp_node.link_event.link_idx.idx()];
let disp_auth_exit = &mut disp_auths_exit[disp_node.disp_auth_idx_entry.idx()];
disp_auth_exit.offset_front = f64::INFINITY * uc::M;
disp_auth_exit.offset_back = f64::INFINITY * uc::M;
disp_auth_exit.arrive_exit =
disp_auth_exit.arrive_exit.min(self.time_update_next);
disp_auth_exit.arrive_entry =
disp_auth_exit.clear_entry.min(self.time_update_next);
disp_auth_exit.clear_exit = self.time_update_next;
update_links_blocked(
links_blocked,
links,
disp_node.link_event.link_idx,
disp_auths_exit.last().unwrap().train_idx_curr(),
);
if disp_node.link_event.link_idx == link_idx_back {
break;
}
}
}
self.link_idxs_blocking.clear();
}
}
}
fn update_links_blocked(
links_blocked: &mut [TrainIdx],
links: &[Link],
link_idx: LinkIdx,
train_idx_curr: TrainIdx,
) {
let link_idx_flip = links[link_idx.idx()].idx_flip;
links_blocked[link_idx_flip.idx()] = train_idx_curr;
for link_idx_lockout in &links[link_idx.idx()].link_idxs_lockout {
links_blocked[link_idx_lockout.idx()] = train_idx_curr;
}
if train_idx_curr.is_none() {
reset_link_train_idx(links_blocked, links, &link_idx_flip);
for link_idx_lockout in &links[link_idx.idx()].link_idxs_lockout {
reset_link_train_idx(links_blocked, links, link_idx_lockout);
}
}
}
fn reset_link_train_idx(links_blocked: &mut [TrainIdx], links: &[Link], link_idx: &LinkIdx) {
if links[link_idx.idx()].link_idxs_lockout.len() > 1 {
for link_idx_adjacent in &links[link_idx.idx()].link_idxs_lockout {
if links_blocked[link_idx_adjacent.idx()].is_some() {
links_blocked[link_idx.idx()] = links_blocked[link_idx_adjacent.idx()];
break;
}
}
}
}