From 04447e86a10e226a09810b253e14aac346f5efcb Mon Sep 17 00:00:00 2001 From: Stiopa Koltsov Date: Fri, 6 Jan 2023 05:58:01 +0000 Subject: [PATCH] Fix RawTable::allocation_info for empty table Fixes #376 --- src/raw/mod.rs | 15 ++++++++++++++- tests/raw.rs | 11 +++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 tests/raw.rs diff --git a/src/raw/mod.rs b/src/raw/mod.rs index 63f97cffb8..ba34e8e270 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -531,7 +531,7 @@ impl RawTable { #[inline] #[cfg(feature = "raw")] pub fn allocation_info(&self) -> (NonNull, Layout) { - self.table.allocation_info(Self::TABLE_LAYOUT) + self.table.allocation_info_or_zero(Self::TABLE_LAYOUT) } /// Returns the index of a bucket from a `Bucket`. @@ -1589,6 +1589,11 @@ impl RawTableInner { #[inline] fn allocation_info(&self, table_layout: TableLayout) -> (NonNull, Layout) { + debug_assert!( + !self.is_empty_singleton(), + "this function can only be called on non-empty tables" + ); + // Avoid `Option::unwrap_or_else` because it bloats LLVM IR. let (layout, ctrl_offset) = match table_layout.calculate_layout_for(self.buckets()) { Some(lco) => lco, @@ -1600,6 +1605,14 @@ impl RawTableInner { ) } + fn allocation_info_or_zero(&self, table_layout: TableLayout) -> (NonNull, Layout) { + if self.is_empty_singleton() { + (NonNull::dangling(), Layout::new::<()>()) + } else { + self.allocation_info(table_layout) + } + } + /// Marks all table buckets as empty without dropping their contents. #[inline] fn clear_no_drop(&mut self) { diff --git a/tests/raw.rs b/tests/raw.rs new file mode 100644 index 0000000000..858836e63b --- /dev/null +++ b/tests/raw.rs @@ -0,0 +1,11 @@ +#![cfg(feature = "raw")] + +use hashbrown::raw::RawTable; +use std::mem; + +#[test] +fn test_allocation_info() { + assert_eq!(RawTable::<()>::new().allocation_info().1.size(), 0); + assert_eq!(RawTable::::new().allocation_info().1.size(), 0); + assert!(RawTable::::with_capacity(1).allocation_info().1.size() > mem::size_of::()); +}