mod string_id;
use anyhow::Context;
use std::hash::{BuildHasherDefault, Hash};
use std::num::NonZeroU32;
pub type FxIndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<rustc_hash::FxHasher>>;
pub type FxIndexSet<K> = indexmap::IndexSet<K, BuildHasherDefault<rustc_hash::FxHasher>>;
pub use string_id::*;
pub trait Id: Copy + Eq + Hash {
type RawId;
fn from_offset(inner: usize) -> Self;
fn to_raw_id(&self) -> Self::RawId;
fn into_raw_id(self) -> Self::RawId {
self.to_raw_id()
}
}
pub trait Item: Eq + Hash {
type Id: Id;
}
#[inline]
pub fn small_non_zero_pprof_id(offset: usize) -> Option<NonZeroU32> {
let small: u32 = offset.try_into().ok()?;
let non_zero = small.checked_add(1)?;
Some(unsafe { NonZeroU32::new_unchecked(non_zero) })
}
pub trait Dedup<T: Item> {
fn dedup(&mut self, item: T) -> <T as Item>::Id;
fn try_dedup(&mut self, item: T) -> anyhow::Result<<T as Item>::Id>;
fn checked_dedup(&mut self, item: T) -> anyhow::Result<<T as Item>::Id>;
}
impl<T: Item> Dedup<T> for FxIndexSet<T> {
fn dedup(&mut self, item: T) -> <T as Item>::Id {
let (id, _) = self.insert_full(item);
<T as Item>::Id::from_offset(id)
}
fn try_dedup(&mut self, item: T) -> anyhow::Result<<T as Item>::Id> {
self.try_reserve(1)?;
let (id, _) = self.insert_full(item);
Ok(<T as Item>::Id::from_offset(id))
}
fn checked_dedup(&mut self, item: T) -> anyhow::Result<<T as Item>::Id> {
self.try_reserve(1)
.context("failed to reserve memory for deduplicating an item")?;
let (id, _) = self.insert_full(item);
anyhow::ensure!(
id < self.len(),
"out of bounds id generated {:?}, len was {:?}",
id,
self.len()
);
small_non_zero_pprof_id(id).with_context(|| format!("invalid id generated {id:?}"))?;
Ok(<T as Item>::Id::from_offset(id))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_small_non_zero_pprof_id() {
assert_eq!(NonZeroU32::new(1), small_non_zero_pprof_id(0));
assert_eq!(NonZeroU32::new(2), small_non_zero_pprof_id(1));
assert_eq!(
NonZeroU32::new(u32::MAX),
small_non_zero_pprof_id((u32::MAX - 1) as usize)
);
assert_eq!(None, small_non_zero_pprof_id(u32::MAX as usize));
assert_eq!(None, small_non_zero_pprof_id(usize::MAX));
}
}