1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
use crate::dijkstra::{DijkstraWeight, NodeWeightArray};
/// An epoch counter array.
/// This can be used to check if an index is current by comparing its entry in the epoch array to the current epoch.
/// To unmark all values, the current epoch can be increased in O(1). Only overflows have to be handled by resetting all epoch counters.
pub struct EpochArray {
epochs: Vec<u32>,
current_epoch: u32,
}
impl EpochArray {
/// Create a new epoch array of given length where all values are outdated.
pub fn new(len: usize) -> Self {
Self {
epochs: vec![0; len],
current_epoch: 1,
}
}
/// Outdate all indices.
pub fn clear(&mut self) {
if self.current_epoch == u32::MAX {
for epoch in self.epochs.iter_mut() {
*epoch = 0;
}
self.current_epoch = 1;
} else {
self.current_epoch += 1;
}
}
/// Set the given index as current and returns true if the given index was current before, and false otherwise
///
/// Safety: Undefined behaviour if the index is out of bounds of the epoch array.
#[inline]
pub fn update(&mut self, index: usize) -> bool {
unsafe {
let result = *self.epochs.get_unchecked(index) == self.current_epoch;
*self.epochs.get_unchecked_mut(index) = self.current_epoch;
result
}
//self.epochs[index] = self.current_epoch;
}
/// Returns true if the given index is current, and false otherwise.
///
/// Safety: Undefined behaviour if the index is out of bounds of the epoch array.
#[inline]
pub fn get(&self, index: usize) -> bool {
unsafe { *self.epochs.get_unchecked(index) == self.current_epoch }
}
/// Updates the given index and returns true if the given index was current before, and false otherwise.
///
/// Safety: Undefined behaviour if the index is out of bounds of the epoch array.
#[inline]
pub fn get_and_update(&mut self, index: usize) -> bool {
let epoch = unsafe { self.epochs.get_unchecked_mut(index) };
if *epoch == self.current_epoch {
true
} else {
*epoch = self.current_epoch;
false
}
}
}
/// An epoched node weight array that can be cleared in O(1) most of the times.
/// Only if the epoch in the epoch array overflows, clearing takes linear time.
pub struct EpochNodeWeightArray<WeightType> {
weights: Vec<WeightType>,
epochs: EpochArray,
size: usize,
}
impl<WeightType: DijkstraWeight> EpochNodeWeightArray<WeightType> {
#[inline]
fn make_current(&mut self, node_index: usize) {
if !self.epochs.get_and_update(node_index) {
self.weights[node_index] = WeightType::infinity();
self.size += 1;
}
}
}
impl<WeightType: DijkstraWeight + Copy> NodeWeightArray<WeightType>
for EpochNodeWeightArray<WeightType>
{
fn new(len: usize) -> Self {
Self {
weights: vec![WeightType::infinity(); len],
epochs: EpochArray::new(len),
size: 0,
}
}
#[inline]
fn get(&self, node_index: usize) -> WeightType {
if self.epochs.get(node_index) {
self.weights[node_index]
} else {
WeightType::infinity()
}
}
#[inline]
fn get_mut<'this: 'result, 'result>(
&'this mut self,
node_index: usize,
) -> &'result mut WeightType {
self.make_current(node_index);
&mut self.weights[node_index]
}
#[inline]
fn set(&mut self, node_index: usize, weight: WeightType) {
self.weights[node_index] = weight;
if !self.epochs.update(node_index) {
self.size += 1;
}
}
fn clear(&mut self) {
self.epochs.clear();
self.size = 0;
}
fn size(&self) -> usize {
self.size
}
}