Spaces:
Build error
Build error
File size: 4,354 Bytes
84d2a97 |
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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
use std::cmp::Ordering;
use common::fixed_length_priority_queue::FixedLengthPriorityQueue;
use common::types::PointOffsetType;
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
pub struct EntryPoint {
pub point_id: PointOffsetType,
pub level: usize,
}
impl Eq for EntryPoint {}
impl PartialOrd for EntryPoint {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for EntryPoint {
fn cmp(&self, other: &Self) -> Ordering {
self.level.cmp(&other.level)
}
}
#[derive(Deserialize, Serialize, Clone, Debug)]
pub struct EntryPoints {
entry_points: Vec<EntryPoint>,
extra_entry_points: FixedLengthPriorityQueue<EntryPoint>,
}
impl EntryPoints {
pub fn new(extra_entry_points: usize) -> Self {
EntryPoints {
entry_points: vec![],
extra_entry_points: FixedLengthPriorityQueue::new(extra_entry_points),
}
}
pub fn merge_from_other(&mut self, mut other: EntryPoints) {
self.entry_points.append(&mut other.entry_points);
// Do not merge `extra_entry_points` to prevent duplications
}
pub fn new_point<F>(
&mut self,
new_point: PointOffsetType,
level: usize,
checker: F,
) -> Option<EntryPoint>
where
F: Fn(PointOffsetType) -> bool,
{
// there are 3 cases:
// - There is proper entry point for a new point higher or same level - return the point
// - The new point is higher than any alternative - return the next best thing
// - There is no point and alternatives - return None
for i in 0..self.entry_points.len() {
let candidate = &self.entry_points[i];
if !checker(candidate.point_id) {
continue; // Checkpoint does not fulfil filtering conditions. Hence, does not "exists"
}
// Found checkpoint candidate
return if candidate.level >= level {
// The good checkpoint exists.
// Return it, and also try to save given if required
self.extra_entry_points.push(EntryPoint {
point_id: new_point,
level,
});
Some(candidate.clone())
} else {
// The current point is better than existing
let entry = self.entry_points[i].clone();
self.entry_points[i] = EntryPoint {
point_id: new_point,
level,
};
self.extra_entry_points.push(entry.clone());
Some(entry)
};
}
// No entry points found. Create a new one and return self
let new_entry = EntryPoint {
point_id: new_point,
level,
};
self.entry_points.push(new_entry);
None
}
/// Find the highest `EntryPoint` which satisfies filtering condition of `checker`
pub fn get_entry_point<F>(&self, checker: F) -> Option<EntryPoint>
where
F: Fn(PointOffsetType) -> bool,
{
self.entry_points
.iter()
.find(|entry| checker(entry.point_id))
.cloned()
.or_else(|| {
// Searching for at least some entry point
self.extra_entry_points
.iter()
.filter(|entry| checker(entry.point_id))
.cloned()
.max_by_key(|ep| ep.level)
})
}
}
#[cfg(test)]
mod tests {
use rand::Rng;
use super::*;
#[test]
fn test_entry_points() {
let mut points = EntryPoints::new(10);
let mut rnd = rand::thread_rng();
for i in 0..1000 {
let level = rnd.gen_range(0..10000);
points.new_point(i, level, |_x| true);
}
assert_eq!(points.entry_points.len(), 1);
assert_eq!(points.extra_entry_points.len(), 10);
assert!(points.entry_points[0].level > 1);
for i in 1000..2000 {
let level = rnd.gen_range(0..10000);
points.new_point(i, level, |x| x % 5 == i % 5);
}
assert_eq!(points.entry_points.len(), 5);
assert_eq!(points.extra_entry_points.len(), 10);
}
}
|