Skip to content

Commit 4acb207

Browse files
authored
Fix approx_bytes to prevent double-counting of SlotArena inline size (#28)
- Adjusted the `approx_bytes` method in `IntrusiveList` to correctly account for the size of the inline `SlotArena`, preventing double-counting. - Added a regression test to verify that `approx_bytes` reports the correct size for both empty and populated lists, ensuring accurate memory usage reporting. - Updated documentation to clarify the changes and the rationale behind the adjustments, improving understanding of memory footprint calculations.
1 parent de0517e commit 4acb207

1 file changed

Lines changed: 39 additions & 0 deletions

File tree

src/ds/intrusive_list.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,11 @@ impl<T> IntrusiveList<T> {
793793
/// assert!(bytes > 0);
794794
/// ```
795795
pub fn approx_bytes(&self) -> usize {
796+
// arena.approx_bytes() includes size_of::<SlotArena<Node<T>>>() which
797+
// is already part of size_of::<Self>(), so subtract it to avoid
798+
// double-counting the arena's inline footprint.
796799
std::mem::size_of::<Self>() + self.arena.approx_bytes()
800+
- std::mem::size_of::<SlotArena<Node<T>>>()
797801
}
798802

799803
#[cfg(any(test, debug_assertions))]
@@ -1770,6 +1774,41 @@ mod tests {
17701774
list.remove(c);
17711775
list.debug_validate_invariants();
17721776
}
1777+
1778+
/// Regression: approx_bytes used to double-count the SlotArena inline size.
1779+
///
1780+
/// Both `IntrusiveList::approx_bytes` and `SlotArena::approx_bytes` included
1781+
/// `size_of::<Self>()`. Because the arena is an inline field of the list,
1782+
/// its inline size was counted twice — once inside `size_of::<IntrusiveList>()`
1783+
/// and again inside `SlotArena::approx_bytes()`.
1784+
#[test]
1785+
fn approx_bytes_no_double_count() {
1786+
let empty: IntrusiveList<u64> = IntrusiveList::new();
1787+
let struct_size = std::mem::size_of::<IntrusiveList<u64>>();
1788+
let reported = empty.approx_bytes();
1789+
1790+
assert_eq!(
1791+
reported,
1792+
struct_size,
1793+
"empty list: approx_bytes ({reported}) != size_of ({struct_size}), \
1794+
delta = {} — inline arena size is double-counted",
1795+
reported as isize - struct_size as isize
1796+
);
1797+
1798+
let mut list: IntrusiveList<u64> = IntrusiveList::new();
1799+
for i in 0..10 {
1800+
list.push_back(i);
1801+
}
1802+
let reported_full = list.approx_bytes();
1803+
assert!(
1804+
reported_full >= struct_size,
1805+
"non-empty list: approx_bytes ({reported_full}) < struct size ({struct_size})"
1806+
);
1807+
assert!(
1808+
reported_full > struct_size,
1809+
"non-empty list should have non-zero heap allocation"
1810+
);
1811+
}
17731812
}
17741813

17751814
#[cfg(test)]

0 commit comments

Comments
 (0)