use rand::RngExt;
use std::path::PathBuf;
pub fn temp_dir<P: AsRef<std::path::Path>>(base: P) -> anyhow::Result<PathBuf> {
let mut base = base.as_ref().to_owned();
const ALPHABET: &[u8] = b"0123456789abcdef";
let mut rnd = rand::rng();
let mut random_str = String::new();
loop {
random_str.clear();
for _ in 0..16 {
let idx = rnd.random_range(0..ALPHABET.len());
random_str.push(ALPHABET[idx] as char);
}
base.push(&random_str);
if !base.exists() {
std::fs::create_dir(&base)?;
return Ok(base);
}
base.pop();
}
}
mod batch_codec;
pub use batch_codec::*;
mod circular_buffer;
pub(crate) use circular_buffer::*;
mod ragged_array;
pub use ragged_array::RaggedArray;
mod mmap_helper;
pub use mmap_helper::*;
mod java_perm;
pub use java_perm::*;
mod granularity;
pub use granularity::*;
pub mod matrix;
pub use matrix::Matrix;
pub mod sort_pairs;
pub use sort_pairs::SortPairs;
pub mod par_sort_pairs;
pub use par_sort_pairs::ParSortPairs;
pub mod par_sort_iters;
pub use par_sort_iters::ParSortIters;
use crate::graphs::{
arc_list_graph::NodeLabels,
bvgraph::{Decode, Encode},
};
pub struct Converter<D: Decode, E: Encode> {
pub decoder: D,
pub encoder: E,
pub offset: usize,
}
impl<D: Decode, E: Encode> Decode for Converter<D, E> {
#[inline(always)]
fn read_outdegree(&mut self) -> u64 {
let res = self.decoder.read_outdegree();
self.offset += self.encoder.write_outdegree(res).unwrap();
res
}
#[inline(always)]
fn read_reference_offset(&mut self) -> u64 {
let res = self.decoder.read_reference_offset();
self.offset += self.encoder.write_reference_offset(res).unwrap();
res
}
#[inline(always)]
fn read_block_count(&mut self) -> u64 {
let res = self.decoder.read_block_count();
self.offset += self.encoder.write_block_count(res).unwrap();
res
}
#[inline(always)]
fn read_block(&mut self) -> u64 {
let res = self.decoder.read_block();
self.offset += self.encoder.write_block(res).unwrap();
res
}
#[inline(always)]
fn read_interval_count(&mut self) -> u64 {
let res = self.decoder.read_interval_count();
self.offset += self.encoder.write_interval_count(res).unwrap();
res
}
#[inline(always)]
fn read_interval_start(&mut self) -> u64 {
let res = self.decoder.read_interval_start();
self.offset += self.encoder.write_interval_start(res).unwrap();
res
}
#[inline(always)]
fn read_interval_len(&mut self) -> u64 {
let res = self.decoder.read_interval_len();
self.offset += self.encoder.write_interval_len(res).unwrap();
res
}
#[inline(always)]
fn read_first_residual(&mut self) -> u64 {
let res = self.decoder.read_first_residual();
self.offset += self.encoder.write_first_residual(res).unwrap();
res
}
#[inline(always)]
fn read_residual(&mut self) -> u64 {
let res = self.decoder.read_residual();
self.offset += self.encoder.write_residual(res).unwrap();
res
}
#[inline(always)]
fn num_of_residuals(&mut self, num_of_residuals: usize) {
self.encoder.num_of_residuals(num_of_residuals);
}
}
#[derive(Clone, Copy, Debug)]
pub enum MemoryUsage {
MemorySize(usize),
BatchSize(usize),
}
impl Default for MemoryUsage {
fn default() -> Self {
Self::from_perc(50.0)
}
}
impl core::fmt::Display for MemoryUsage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MemoryUsage::MemorySize(size) => write!(f, "{} bytes", size),
MemoryUsage::BatchSize(size) => write!(f, "{} elements", size),
}
}
}
impl core::ops::Mul<usize> for MemoryUsage {
type Output = MemoryUsage;
fn mul(self, rhs: usize) -> Self::Output {
match self {
MemoryUsage::MemorySize(size) => MemoryUsage::MemorySize(size * rhs),
MemoryUsage::BatchSize(size) => MemoryUsage::BatchSize(size * rhs),
}
}
}
impl core::ops::Div<usize> for MemoryUsage {
type Output = MemoryUsage;
fn div(self, rhs: usize) -> Self::Output {
match self {
MemoryUsage::MemorySize(size) => MemoryUsage::MemorySize(size / rhs),
MemoryUsage::BatchSize(size) => MemoryUsage::BatchSize(size / rhs),
}
}
}
impl MemoryUsage {
pub fn from_perc(perc: f64) -> Self {
let system = sysinfo::System::new_with_specifics(
sysinfo::RefreshKind::nothing()
.with_memory(sysinfo::MemoryRefreshKind::nothing().with_ram()),
);
MemoryUsage::MemorySize(
usize::try_from((system.total_memory() as f64 * perc / 100.0) as u64)
.expect("System memory overflows usize"),
)
}
pub fn batch_size<T>(&self) -> usize {
match &self {
MemoryUsage::MemorySize(memory_size) => {
let elem_size = std::mem::size_of::<T>();
assert!(elem_size > 0, "Element size cannot be zero");
memory_size / elem_size
}
MemoryUsage::BatchSize(batch_size) => *batch_size,
}
}
}
pub fn humanize(value: f64) -> String {
const UNITS: &[&str] = &["", "K", "M", "G", "T", "P", "E"];
let mut v = value;
let mut unit: usize = 0;
while v >= 1000.0 && unit + 1 < UNITS.len() {
v /= 1000.0;
unit += 1;
}
if unit == 0 {
format!("{:.0}{}", v, UNITS[unit])
} else {
format!("{:.3}{}", v, UNITS[unit])
}
}
pub struct SplitIters<I> {
pub boundaries: Box<[usize]>,
pub iters: Box<[I]>,
}
impl<I> SplitIters<I> {
pub fn new(boundaries: Box<[usize]>, iters: Box<[I]>) -> Self {
Self { boundaries, iters }
}
}
impl<I> From<(Box<[usize]>, Box<[I]>)> for SplitIters<I> {
fn from((boundaries, iters): (Box<[usize]>, Box<[I]>)) -> Self {
Self::new(boundaries, iters)
}
}
impl<
I: Iterator<Item = (usize, usize)> + Send + Sync,
IT: IntoIterator<Item = (usize, usize), IntoIter = I>,
> From<SplitIters<IT>>
for Vec<
crate::labels::proj::LeftIterator<
NodeLabels<(), std::iter::Map<I, fn((usize, usize)) -> ((usize, usize), ())>>,
>,
>
{
fn from(split: SplitIters<IT>) -> Self {
Box::into_iter(split.iters)
.enumerate()
.map(|(i, iter)| {
let start_node = split.boundaries[i];
let end_node = split.boundaries[i + 1];
let num_partition_nodes = end_node - start_node;
#[allow(clippy::type_complexity)]
let map_fn: fn((usize, usize)) -> ((usize, usize), ()) = |pair| (pair, ());
let labeled_iter = iter.into_iter().map(map_fn);
let lender =
NodeLabels::try_new_from(num_partition_nodes, labeled_iter, start_node)
.expect("Iterator should start from the expected first node");
crate::labels::proj::LeftIterator(lender)
})
.collect()
}
}
impl<
L: Clone + Copy + 'static,
I: Iterator<Item = ((usize, usize), L)> + Send + Sync,
IT: IntoIterator<Item = ((usize, usize), L), IntoIter = I>,
> From<SplitIters<IT>> for Vec<NodeLabels<L, I>>
{
fn from(split: SplitIters<IT>) -> Self {
Box::into_iter(split.iters)
.enumerate()
.map(|(i, iter)| {
let start_node = split.boundaries[i];
let end_node = split.boundaries[i + 1];
let num_partition_nodes = end_node - start_node;
NodeLabels::try_new_from(num_partition_nodes, iter.into_iter(), start_node)
.expect("Iterator should start from the expected first node")
})
.collect()
}
}