#[cfg(test)]
mod tests;
use std::collections::HashSet;
use super::cart::CARTEdgeIndex;
pub const DEFAULT_DEGREE_THRESHOLD: usize = 100;
pub const CART_THRESHOLD: usize = 1000;
pub trait EdgeIndex: Send + Sync {
fn insert(&mut self, target: u64);
fn remove(&mut self, target: u64) -> bool;
fn contains(&self, target: u64) -> bool;
fn targets(&self) -> Vec<u64>;
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[derive(Debug, Clone, Default)]
pub struct VecEdgeIndex {
pub(crate) targets: Vec<u64>,
}
impl VecEdgeIndex {
#[must_use]
pub fn new() -> Self {
Self {
targets: Vec::new(),
}
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
targets: Vec::with_capacity(capacity),
}
}
}
impl EdgeIndex for VecEdgeIndex {
fn insert(&mut self, target: u64) {
if !self.targets.contains(&target) {
self.targets.push(target);
}
}
fn remove(&mut self, target: u64) -> bool {
if let Some(pos) = self.targets.iter().position(|&t| t == target) {
self.targets.swap_remove(pos);
true
} else {
false
}
}
fn contains(&self, target: u64) -> bool {
self.targets.contains(&target)
}
fn targets(&self) -> Vec<u64> {
self.targets.clone()
}
fn len(&self) -> usize {
self.targets.len()
}
}
#[derive(Debug, Clone, Default)]
pub struct HashSetEdgeIndex {
pub(crate) targets: HashSet<u64>,
}
impl HashSetEdgeIndex {
#[must_use]
pub fn new() -> Self {
Self {
targets: HashSet::new(),
}
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
targets: HashSet::with_capacity(capacity),
}
}
#[must_use]
pub fn from_vec(vec_index: &VecEdgeIndex) -> Self {
Self {
targets: vec_index.targets.iter().copied().collect(),
}
}
}
impl EdgeIndex for HashSetEdgeIndex {
fn insert(&mut self, target: u64) {
self.targets.insert(target);
}
fn remove(&mut self, target: u64) -> bool {
self.targets.remove(&target)
}
fn contains(&self, target: u64) -> bool {
self.targets.contains(&target)
}
fn targets(&self) -> Vec<u64> {
self.targets.iter().copied().collect()
}
fn len(&self) -> usize {
self.targets.len()
}
}
#[derive(Debug, Clone)]
pub enum DegreeAdaptiveStorage {
LowDegree(VecEdgeIndex),
HighDegree(HashSetEdgeIndex),
VeryHighDegree(CARTEdgeIndex),
}
impl Default for DegreeAdaptiveStorage {
fn default() -> Self {
Self::LowDegree(VecEdgeIndex::new())
}
}
impl DegreeAdaptiveStorage {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn is_high_degree(&self) -> bool {
matches!(self, Self::HighDegree(_) | Self::VeryHighDegree(_))
}
#[must_use]
pub fn is_very_high_degree(&self) -> bool {
matches!(self, Self::VeryHighDegree(_))
}
pub fn promote_to_high_degree(&mut self) {
if let Self::LowDegree(vec_index) = self {
*self = Self::HighDegree(HashSetEdgeIndex::from_vec(vec_index));
}
}
pub fn promote_to_cart(&mut self) {
if let Self::HighDegree(hash_index) = self {
let targets: Vec<u64> = hash_index.targets.iter().copied().collect();
*self = Self::VeryHighDegree(CARTEdgeIndex::from_targets(&targets));
}
}
}
impl EdgeIndex for DegreeAdaptiveStorage {
fn insert(&mut self, target: u64) {
match self {
Self::LowDegree(vec) => vec.insert(target),
Self::HighDegree(hash) => hash.insert(target),
Self::VeryHighDegree(cart) => cart.insert(target),
}
}
fn remove(&mut self, target: u64) -> bool {
match self {
Self::LowDegree(vec) => vec.remove(target),
Self::HighDegree(hash) => hash.remove(target),
Self::VeryHighDegree(cart) => cart.remove(target),
}
}
fn contains(&self, target: u64) -> bool {
match self {
Self::LowDegree(vec) => vec.contains(target),
Self::HighDegree(hash) => hash.contains(target),
Self::VeryHighDegree(cart) => cart.contains(target),
}
}
fn targets(&self) -> Vec<u64> {
match self {
Self::LowDegree(vec) => vec.targets(),
Self::HighDegree(hash) => hash.targets(),
Self::VeryHighDegree(cart) => cart.targets(),
}
}
fn len(&self) -> usize {
match self {
Self::LowDegree(vec) => vec.len(),
Self::HighDegree(hash) => hash.len(),
Self::VeryHighDegree(cart) => cart.len(),
}
}
}
#[derive(Debug, Clone)]
pub struct DegreeRouter {
threshold: usize,
pub(crate) storage: DegreeAdaptiveStorage,
promotions: usize,
}
impl DegreeRouter {
#[must_use]
pub fn new() -> Self {
Self::with_threshold(DEFAULT_DEGREE_THRESHOLD)
}
#[must_use]
pub fn with_threshold(threshold: usize) -> Self {
Self {
threshold: threshold.max(1),
storage: DegreeAdaptiveStorage::new(),
promotions: 0,
}
}
pub fn insert(&mut self, target: u64) {
self.storage.insert(target);
if !self.storage.is_high_degree() && self.storage.len() > self.threshold {
self.storage.promote_to_high_degree();
self.promotions += 1;
}
if !self.storage.is_very_high_degree() && self.storage.len() > CART_THRESHOLD {
self.storage.promote_to_cart();
self.promotions += 1;
}
}
pub fn remove(&mut self, target: u64) -> bool {
self.storage.remove(target)
}
#[must_use]
pub fn contains(&self, target: u64) -> bool {
self.storage.contains(target)
}
#[must_use]
pub fn targets(&self) -> Vec<u64> {
self.storage.targets()
}
#[must_use]
pub fn len(&self) -> usize {
self.storage.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.storage.is_empty()
}
#[must_use]
pub fn is_high_degree(&self) -> bool {
self.storage.is_high_degree()
}
#[must_use]
pub fn promotion_count(&self) -> usize {
self.promotions
}
#[must_use]
pub fn threshold(&self) -> usize {
self.threshold
}
}
impl Default for DegreeRouter {
fn default() -> Self {
Self::new()
}
}