#[cfg(target_os = "windows")]
extern crate winapi;
#[cfg(target_os = "windows")]
use winapi::um::heapapi::{GetProcessHeap, HeapSize, HeapValidate};
use std::borrow::Cow;
use std::cell::{Cell, RefCell};
use std::collections::{BTreeMap, HashSet, HashMap, LinkedList, VecDeque};
use std::hash::BuildHasher;
use std::hash::Hash;
use std::marker::PhantomData;
use std::mem::{size_of, align_of};
use std::net::{Ipv4Addr, Ipv6Addr};
use std::ops::{Range, RangeFrom, RangeFull, RangeTo};
use std::os::raw::c_void;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize};
use std::rc::Rc;
pub unsafe fn heap_size_of<T>(ptr: *const T) -> usize {
if ptr as usize <= align_of::<T>() {
0
} else {
heap_size_of_impl(ptr as *const c_void)
}
}
#[cfg(not(target_os = "windows"))]
unsafe fn heap_size_of_impl(ptr: *const c_void) -> usize {
extern "C" {
#[cfg_attr(any(prefixed_jemalloc, target_os = "macos", target_os = "ios", target_os = "android"), link_name = "je_malloc_usable_size")]
fn malloc_usable_size(ptr: *const c_void) -> usize;
}
malloc_usable_size(ptr)
}
#[cfg(target_os = "windows")]
unsafe fn heap_size_of_impl(mut ptr: *const c_void) -> usize {
let heap = GetProcessHeap();
if HeapValidate(heap, 0, ptr) == 0 {
ptr = *(ptr as *const *const c_void).offset(-1);
}
HeapSize(heap, 0, ptr) as usize
}
pub trait HeapSizeOf {
fn heap_size_of_children(&self) -> usize;
}
impl<T: HeapSizeOf + ?Sized> HeapSizeOf for Box<T> {
fn heap_size_of_children(&self) -> usize {
unsafe {
heap_size_of(&**self as *const T as *const c_void) + (**self).heap_size_of_children()
}
}
}
impl<T: HeapSizeOf> HeapSizeOf for [T] {
fn heap_size_of_children(&self) -> usize {
self.iter().fold(0, |size, item| size + item.heap_size_of_children())
}
}
impl HeapSizeOf for String {
fn heap_size_of_children(&self) -> usize {
unsafe {
heap_size_of(self.as_ptr())
}
}
}
impl<'a, T: ?Sized> HeapSizeOf for &'a T {
fn heap_size_of_children(&self) -> usize {
0
}
}
impl<T: ?Sized> HeapSizeOf for *mut T {
fn heap_size_of_children(&self) -> usize {
0
}
}
impl<T: ?Sized> HeapSizeOf for *const T {
fn heap_size_of_children(&self) -> usize {
0
}
}
impl<T: HeapSizeOf> HeapSizeOf for Option<T> {
fn heap_size_of_children(&self) -> usize {
match *self {
None => 0,
Some(ref x) => x.heap_size_of_children()
}
}
}
impl<T: HeapSizeOf, E: HeapSizeOf> HeapSizeOf for Result<T, E> {
fn heap_size_of_children(&self) -> usize {
match *self {
Ok(ref x) => x.heap_size_of_children(),
Err(ref e) => e.heap_size_of_children(),
}
}
}
impl<'a, B: ?Sized + ToOwned> HeapSizeOf for Cow<'a, B> where B::Owned: HeapSizeOf {
fn heap_size_of_children(&self) -> usize {
match *self {
Cow::Borrowed(_) => 0,
Cow::Owned(ref b) => b.heap_size_of_children(),
}
}
}
impl HeapSizeOf for () {
fn heap_size_of_children(&self) -> usize {
0
}
}
impl<T1, T2> HeapSizeOf for (T1, T2)
where T1: HeapSizeOf, T2 :HeapSizeOf
{
fn heap_size_of_children(&self) -> usize {
self.0.heap_size_of_children() +
self.1.heap_size_of_children()
}
}
impl<T1, T2, T3> HeapSizeOf for (T1, T2, T3)
where T1: HeapSizeOf, T2 :HeapSizeOf, T3: HeapSizeOf
{
fn heap_size_of_children(&self) -> usize {
self.0.heap_size_of_children() +
self.1.heap_size_of_children() +
self.2.heap_size_of_children()
}
}
impl<T1, T2, T3, T4> HeapSizeOf for (T1, T2, T3, T4)
where T1: HeapSizeOf, T2 :HeapSizeOf, T3: HeapSizeOf, T4: HeapSizeOf
{
fn heap_size_of_children(&self) -> usize {
self.0.heap_size_of_children() +
self.1.heap_size_of_children() +
self.2.heap_size_of_children() +
self.3.heap_size_of_children()
}
}
impl<T1, T2, T3, T4, T5> HeapSizeOf for (T1, T2, T3, T4, T5)
where T1: HeapSizeOf, T2 :HeapSizeOf, T3: HeapSizeOf, T4: HeapSizeOf, T5: HeapSizeOf
{
fn heap_size_of_children(&self) -> usize {
self.0.heap_size_of_children() +
self.1.heap_size_of_children() +
self.2.heap_size_of_children() +
self.3.heap_size_of_children() +
self.4.heap_size_of_children()
}
}
impl<T: HeapSizeOf> HeapSizeOf for Arc<T> {
fn heap_size_of_children(&self) -> usize {
(**self).heap_size_of_children()
}
}
impl<T: HeapSizeOf> HeapSizeOf for RefCell<T> {
fn heap_size_of_children(&self) -> usize {
self.borrow().heap_size_of_children()
}
}
impl<T: HeapSizeOf + Copy> HeapSizeOf for Cell<T> {
fn heap_size_of_children(&self) -> usize {
self.get().heap_size_of_children()
}
}
impl<T: HeapSizeOf> HeapSizeOf for Vec<T> {
fn heap_size_of_children(&self) -> usize {
self.iter().fold(
unsafe { heap_size_of(self.as_ptr()) },
|n, elem| n + elem.heap_size_of_children())
}
}
impl<T: HeapSizeOf> HeapSizeOf for VecDeque<T> {
fn heap_size_of_children(&self) -> usize {
self.iter().fold(
self.capacity() * size_of::<T>(),
|n, elem| n + elem.heap_size_of_children())
}
}
impl<T> HeapSizeOf for Vec<Rc<T>> {
fn heap_size_of_children(&self) -> usize {
unsafe {
heap_size_of(self.as_ptr())
}
}
}
impl<T: HeapSizeOf, S> HeapSizeOf for HashSet<T, S>
where T: Eq + Hash, S: BuildHasher {
fn heap_size_of_children(&self) -> usize {
let size = self.capacity() * (size_of::<T>() + size_of::<usize>());
self.iter().fold(size, |n, value| {
n + value.heap_size_of_children()
})
}
}
impl<K: HeapSizeOf, V: HeapSizeOf, S> HeapSizeOf for HashMap<K, V, S>
where K: Eq + Hash, S: BuildHasher {
fn heap_size_of_children(&self) -> usize {
let size = self.capacity() * (size_of::<V>() + size_of::<K>() + size_of::<usize>());
self.iter().fold(size, |n, (key, value)| {
n + key.heap_size_of_children() + value.heap_size_of_children()
})
}
}
impl<T> HeapSizeOf for PhantomData<T> {
fn heap_size_of_children(&self) -> usize {
0
}
}
impl<T: HeapSizeOf> HeapSizeOf for LinkedList<T> {
fn heap_size_of_children(&self) -> usize {
let mut size = 0;
for item in self {
size += 2 * size_of::<usize>() + size_of::<T>() + item.heap_size_of_children();
}
size
}
}
impl<K: HeapSizeOf, V: HeapSizeOf> HeapSizeOf for BTreeMap<K, V> {
fn heap_size_of_children(&self) -> usize {
let mut size = 0;
for (key, value) in self.iter() {
size += size_of::<(K, V)>() +
key.heap_size_of_children() +
value.heap_size_of_children();
}
size
}
}
impl<T> HeapSizeOf for Range<T>
where
T: HeapSizeOf,
{
fn heap_size_of_children(&self) -> usize {
self.start.heap_size_of_children() + self.end.heap_size_of_children()
}
}
impl<T> HeapSizeOf for RangeFrom<T>
where
T: HeapSizeOf,
{
fn heap_size_of_children(&self) -> usize {
self.start.heap_size_of_children()
}
}
impl<T> HeapSizeOf for RangeTo<T>
where
T: HeapSizeOf,
{
fn heap_size_of_children(&self) -> usize {
self.end.heap_size_of_children()
}
}
#[macro_export]
macro_rules! known_heap_size(
($size:expr, $($ty:ty),+) => (
$(
impl $crate::HeapSizeOf for $ty {
#[inline(always)]
fn heap_size_of_children(&self) -> usize {
$size
}
}
)+
);
($size: expr, $($ty:ident<$($gen:ident),+>),+) => (
$(
impl<$($gen: $crate::HeapSizeOf),+> $crate::HeapSizeOf for $ty<$($gen),+> {
#[inline(always)]
fn heap_size_of_children(&self) -> usize {
$size
}
}
)+
);
);
known_heap_size!(0, char, str);
known_heap_size!(0, u8, u16, u32, u64, usize);
known_heap_size!(0, i8, i16, i32, i64, isize);
known_heap_size!(0, bool, f32, f64);
known_heap_size!(0, AtomicBool, AtomicIsize, AtomicUsize);
known_heap_size!(0, Ipv4Addr, Ipv6Addr, RangeFull);