use std::sync::LazyLock;
use crate::ordered_hash_map::OrderedHashMap;
static COUNT_SHARED_ALLOCATIONS: LazyLock<bool> = LazyLock::new(|| {
std::env::var("CAIRO_HEAPSIZE_COUNT_SHARED")
.map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
.unwrap_or(false)
});
pub trait HeapSize {
fn heap_size(&self) -> usize;
}
impl<T: HeapSize> HeapSize for Vec<T> {
fn heap_size(&self) -> usize {
self.capacity() * std::mem::size_of::<T>()
+ self.iter().map(|x| x.heap_size()).sum::<usize>()
}
}
impl HeapSize for String {
fn heap_size(&self) -> usize {
self.capacity()
}
}
impl<T: HeapSize> HeapSize for Option<T> {
fn heap_size(&self) -> usize {
match self {
Some(x) => x.heap_size(),
None => 0,
}
}
}
impl<T: HeapSize, E: HeapSize> HeapSize for Result<T, E> {
fn heap_size(&self) -> usize {
match self {
Ok(value) => value.heap_size(),
Err(err) => err.heap_size(),
}
}
}
impl<T: HeapSize> HeapSize for Box<T> {
fn heap_size(&self) -> usize {
std::mem::size_of::<T>() + self.as_ref().heap_size()
}
}
impl<T: HeapSize> HeapSize for std::sync::Arc<T> {
fn heap_size(&self) -> usize {
if *COUNT_SHARED_ALLOCATIONS {
std::mem::size_of::<T>() + self.as_ref().heap_size()
} else {
0
}
}
}
impl<T: HeapSize> HeapSize for std::rc::Rc<T> {
fn heap_size(&self) -> usize {
if *COUNT_SHARED_ALLOCATIONS {
std::mem::size_of::<T>() + self.as_ref().heap_size()
} else {
0
}
}
}
impl HeapSize for u8 {
fn heap_size(&self) -> usize {
0
}
}
impl HeapSize for i8 {
fn heap_size(&self) -> usize {
0
}
}
impl HeapSize for i32 {
fn heap_size(&self) -> usize {
0
}
}
impl HeapSize for u32 {
fn heap_size(&self) -> usize {
0
}
}
impl HeapSize for i64 {
fn heap_size(&self) -> usize {
0
}
}
impl HeapSize for u64 {
fn heap_size(&self) -> usize {
0
}
}
impl HeapSize for usize {
fn heap_size(&self) -> usize {
0
}
}
impl HeapSize for isize {
fn heap_size(&self) -> usize {
0
}
}
impl HeapSize for bool {
fn heap_size(&self) -> usize {
0
}
}
impl HeapSize for char {
fn heap_size(&self) -> usize {
0
}
}
impl<T> HeapSize for std::marker::PhantomData<T> {
fn heap_size(&self) -> usize {
0
}
}
impl HeapSize for std::path::PathBuf {
fn heap_size(&self) -> usize {
self.capacity()
}
}
impl<K: HeapSize, V: HeapSize> HeapSize for std::collections::HashMap<K, V> {
fn heap_size(&self) -> usize {
self.capacity() * (std::mem::size_of::<K>() + std::mem::size_of::<V>())
+ self.iter().map(|(k, v)| k.heap_size() + v.heap_size()).sum::<usize>()
}
}
impl<T: HeapSize> HeapSize for std::collections::HashSet<T> {
fn heap_size(&self) -> usize {
self.capacity() * std::mem::size_of::<T>()
+ self.iter().map(|x| x.heap_size()).sum::<usize>()
}
}
impl<T: HeapSize> HeapSize for std::collections::BTreeSet<T> {
fn heap_size(&self) -> usize {
self.len() * std::mem::size_of::<T>() + self.iter().map(|x| x.heap_size()).sum::<usize>()
}
}
impl<K: HeapSize, V: HeapSize, BH> HeapSize for OrderedHashMap<K, V, BH> {
fn heap_size(&self) -> usize {
self.iter().map(|(k, v)| k.heap_size() + v.heap_size()).sum()
}
}
impl HeapSize for smol_str::SmolStr {
fn heap_size(&self) -> usize {
if *COUNT_SHARED_ALLOCATIONS && self.is_heap_allocated() {
self.len()
} else {
0
}
}
}
impl HeapSize for num_bigint::BigUint {
fn heap_size(&self) -> usize {
let bits = self.bits() as usize;
bits.div_ceil(8)
}
}
impl HeapSize for num_bigint::BigInt {
fn heap_size(&self) -> usize {
self.magnitude().heap_size()
}
}
impl HeapSize for () {
fn heap_size(&self) -> usize {
0
}
}
impl<T0: HeapSize> HeapSize for (T0,) {
fn heap_size(&self) -> usize {
self.0.heap_size()
}
}
impl<T0: HeapSize, T1: HeapSize> HeapSize for (T0, T1) {
fn heap_size(&self) -> usize {
self.0.heap_size() + self.1.heap_size()
}
}
impl<T0: HeapSize, T1: HeapSize, T2: HeapSize> HeapSize for (T0, T1, T2) {
fn heap_size(&self) -> usize {
self.0.heap_size() + self.1.heap_size() + self.2.heap_size()
}
}
impl<T0: HeapSize, T1: HeapSize, T2: HeapSize, T3: HeapSize> HeapSize for (T0, T1, T2, T3) {
fn heap_size(&self) -> usize {
self.0.heap_size() + self.1.heap_size() + self.2.heap_size() + self.3.heap_size()
}
}
impl<T0: HeapSize, T1: HeapSize, T2: HeapSize, T3: HeapSize, T4: HeapSize> HeapSize
for (T0, T1, T2, T3, T4)
{
fn heap_size(&self) -> usize {
self.0.heap_size()
+ self.1.heap_size()
+ self.2.heap_size()
+ self.3.heap_size()
+ self.4.heap_size()
}
}
impl<T0: HeapSize, T1: HeapSize, T2: HeapSize, T3: HeapSize, T4: HeapSize, T5: HeapSize> HeapSize
for (T0, T1, T2, T3, T4, T5)
{
fn heap_size(&self) -> usize {
self.0.heap_size()
+ self.1.heap_size()
+ self.2.heap_size()
+ self.3.heap_size()
+ self.4.heap_size()
+ self.5.heap_size()
}
}
impl<
T0: HeapSize,
T1: HeapSize,
T2: HeapSize,
T3: HeapSize,
T4: HeapSize,
T5: HeapSize,
T6: HeapSize,
> HeapSize for (T0, T1, T2, T3, T4, T5, T6)
{
fn heap_size(&self) -> usize {
self.0.heap_size()
+ self.1.heap_size()
+ self.2.heap_size()
+ self.3.heap_size()
+ self.4.heap_size()
+ self.5.heap_size()
+ self.6.heap_size()
}
}
impl<
T0: HeapSize,
T1: HeapSize,
T2: HeapSize,
T3: HeapSize,
T4: HeapSize,
T5: HeapSize,
T6: HeapSize,
T7: HeapSize,
> HeapSize for (T0, T1, T2, T3, T4, T5, T6, T7)
{
fn heap_size(&self) -> usize {
self.0.heap_size()
+ self.1.heap_size()
+ self.2.heap_size()
+ self.3.heap_size()
+ self.4.heap_size()
+ self.5.heap_size()
+ self.6.heap_size()
+ self.7.heap_size()
}
}
impl<
T0: HeapSize,
T1: HeapSize,
T2: HeapSize,
T3: HeapSize,
T4: HeapSize,
T5: HeapSize,
T6: HeapSize,
T7: HeapSize,
T8: HeapSize,
> HeapSize for (T0, T1, T2, T3, T4, T5, T6, T7, T8)
{
fn heap_size(&self) -> usize {
self.0.heap_size()
+ self.1.heap_size()
+ self.2.heap_size()
+ self.3.heap_size()
+ self.4.heap_size()
+ self.5.heap_size()
+ self.6.heap_size()
+ self.7.heap_size()
+ self.8.heap_size()
}
}
impl<
T0: HeapSize,
T1: HeapSize,
T2: HeapSize,
T3: HeapSize,
T4: HeapSize,
T5: HeapSize,
T6: HeapSize,
T7: HeapSize,
T8: HeapSize,
T9: HeapSize,
> HeapSize for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9)
{
fn heap_size(&self) -> usize {
self.0.heap_size()
+ self.1.heap_size()
+ self.2.heap_size()
+ self.3.heap_size()
+ self.4.heap_size()
+ self.5.heap_size()
+ self.6.heap_size()
+ self.7.heap_size()
+ self.8.heap_size()
+ self.9.heap_size()
}
}
impl<
T0: HeapSize,
T1: HeapSize,
T2: HeapSize,
T3: HeapSize,
T4: HeapSize,
T5: HeapSize,
T6: HeapSize,
T7: HeapSize,
T8: HeapSize,
T9: HeapSize,
T10: HeapSize,
> HeapSize for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)
{
fn heap_size(&self) -> usize {
self.0.heap_size()
+ self.1.heap_size()
+ self.2.heap_size()
+ self.3.heap_size()
+ self.4.heap_size()
+ self.5.heap_size()
+ self.6.heap_size()
+ self.7.heap_size()
+ self.8.heap_size()
+ self.9.heap_size()
+ self.10.heap_size()
}
}
impl<
T0: HeapSize,
T1: HeapSize,
T2: HeapSize,
T3: HeapSize,
T4: HeapSize,
T5: HeapSize,
T6: HeapSize,
T7: HeapSize,
T8: HeapSize,
T9: HeapSize,
T10: HeapSize,
T11: HeapSize,
> HeapSize for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)
{
fn heap_size(&self) -> usize {
self.0.heap_size()
+ self.1.heap_size()
+ self.2.heap_size()
+ self.3.heap_size()
+ self.4.heap_size()
+ self.5.heap_size()
+ self.6.heap_size()
+ self.7.heap_size()
+ self.8.heap_size()
+ self.9.heap_size()
+ self.10.heap_size()
+ self.11.heap_size()
}
}