Skip to content

Commit 2dc9bb2

Browse files
author
Markus Westerlind
committed
perf: Compute ctrl_align statically per T again
1 parent 9ab2ee0 commit 2dc9bb2

File tree

1 file changed

+50
-33
lines changed

1 file changed

+50
-33
lines changed

src/raw/mod.rs

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,41 @@ fn calculate_layout<T>(buckets: usize) -> Option<(Layout, usize)> {
240240
data.extend(ctrl).ok()
241241
}
242242

243+
/// Helper which allows the max calculation for ctrl_align to be statically computed for each T
244+
/// while keeping the rest of `calculate_layout_for` independent of `T`
245+
#[derive(Copy, Clone)]
246+
struct TableLayout {
247+
size: usize,
248+
ctrl_align: usize,
249+
}
250+
251+
impl TableLayout {
252+
#[inline]
253+
fn new<T>() -> Self {
254+
let layout = Layout::new::<T>();
255+
Self {
256+
size: layout.size(),
257+
ctrl_align: usize::max(layout.align(), Group::WIDTH),
258+
}
259+
}
260+
261+
#[inline]
262+
fn calculate_layout_for(self, buckets: usize) -> Option<(Layout, usize)> {
263+
debug_assert!(buckets.is_power_of_two());
264+
265+
let TableLayout { size, ctrl_align } = self;
266+
// Manual layout calculation since Layout methods are not yet stable.
267+
let ctrl_offset =
268+
size.checked_mul(buckets)?.checked_add(ctrl_align - 1)? & !(ctrl_align - 1);
269+
let len = ctrl_offset.checked_add(buckets + Group::WIDTH)?;
270+
271+
Some((
272+
unsafe { Layout::from_size_align_unchecked(len, ctrl_align) },
273+
ctrl_offset,
274+
))
275+
}
276+
}
277+
243278
/// Returns a Layout which describes the allocation required for a hash table,
244279
/// and the offset of the control bytes in the allocation.
245280
/// (the offset is also one past last element of buckets)
@@ -248,26 +283,7 @@ fn calculate_layout<T>(buckets: usize) -> Option<(Layout, usize)> {
248283
#[cfg_attr(feature = "inline-more", inline)]
249284
#[cfg(not(feature = "nightly"))]
250285
fn calculate_layout<T>(buckets: usize) -> Option<(Layout, usize)> {
251-
calculate_layout_for(Layout::new::<T>(), buckets)
252-
}
253-
254-
#[inline]
255-
fn calculate_layout_for(layout: Layout, buckets: usize) -> Option<(Layout, usize)> {
256-
debug_assert!(buckets.is_power_of_two());
257-
258-
// Manual layout calculation since Layout methods are not yet stable.
259-
let ctrl_align = usize::max(layout.align(), Group::WIDTH);
260-
let ctrl_offset = layout
261-
.size()
262-
.checked_mul(buckets)?
263-
.checked_add(ctrl_align - 1)?
264-
& !(ctrl_align - 1);
265-
let len = ctrl_offset.checked_add(buckets + Group::WIDTH)?;
266-
267-
Some((
268-
unsafe { Layout::from_size_align_unchecked(len, ctrl_align) },
269-
ctrl_offset,
270-
))
286+
TableLayout::new::<T>().calculate_layout_for(buckets)
271287
}
272288

273289
/// A reference to a hash table bucket containing a `T`.
@@ -411,7 +427,7 @@ impl<T> RawTable<T> {
411427
debug_assert!(buckets.is_power_of_two());
412428

413429
Ok(Self {
414-
table: RawTableInner::new_uninitialized(Layout::new::<T>(), buckets, fallability)?,
430+
table: RawTableInner::new_uninitialized(TableLayout::new::<T>(), buckets, fallability)?,
415431
marker: PhantomData,
416432
})
417433
}
@@ -424,7 +440,7 @@ impl<T> RawTable<T> {
424440
) -> Result<Self, TryReserveError> {
425441
Ok(Self {
426442
table: RawTableInner::fallible_with_capacity(
427-
Layout::new::<T>(),
443+
TableLayout::new::<T>(),
428444
capacity,
429445
fallability,
430446
)?,
@@ -452,7 +468,7 @@ impl<T> RawTable<T> {
452468
/// Deallocates the table without dropping any entries.
453469
#[cfg_attr(feature = "inline-more", inline)]
454470
unsafe fn free_buckets(&mut self) {
455-
self.table.free_buckets(Layout::new::<T>())
471+
self.table.free_buckets(TableLayout::new::<T>())
456472
}
457473

458474
/// Returns pointer to one past last element of data table.
@@ -719,7 +735,7 @@ impl<T> RawTable<T> {
719735
unsafe {
720736
let mut new_table =
721737
self.table
722-
.prepare_resize(Layout::new::<T>(), capacity, fallability)?;
738+
.prepare_resize(TableLayout::new::<T>(), capacity, fallability)?;
723739

724740
// Copy all elements to the new table.
725741
for item in self.iter() {
@@ -988,14 +1004,14 @@ impl RawTableInner {
9881004

9891005
#[inline]
9901006
unsafe fn new_uninitialized(
991-
t_layout: Layout,
1007+
table_layout: TableLayout,
9921008
buckets: usize,
9931009
fallability: Fallibility,
9941010
) -> Result<Self, TryReserveError> {
9951011
debug_assert!(buckets.is_power_of_two());
9961012

9971013
// Avoid `Option::ok_or_else` because it bloats LLVM IR.
998-
let (layout, ctrl_offset) = match calculate_layout_for(t_layout, buckets) {
1014+
let (layout, ctrl_offset) = match table_layout.calculate_layout_for(buckets) {
9991015
Some(lco) => lco,
10001016
None => return Err(fallability.capacity_overflow()),
10011017
};
@@ -1016,7 +1032,7 @@ impl RawTableInner {
10161032

10171033
#[inline]
10181034
fn fallible_with_capacity(
1019-
t_layout: Layout,
1035+
table_layout: TableLayout,
10201036
capacity: usize,
10211037
fallability: Fallibility,
10221038
) -> Result<Self, TryReserveError> {
@@ -1027,7 +1043,7 @@ impl RawTableInner {
10271043
let buckets =
10281044
capacity_to_buckets(capacity).ok_or_else(|| fallability.capacity_overflow())?;
10291045

1030-
let result = Self::new_uninitialized(t_layout, buckets, fallability)?;
1046+
let result = Self::new_uninitialized(table_layout, buckets, fallability)?;
10311047
result.ctrl(0).write_bytes(EMPTY, result.num_ctrl_bytes());
10321048

10331049
Ok(result)
@@ -1261,14 +1277,15 @@ impl RawTableInner {
12611277
#[inline]
12621278
unsafe fn prepare_resize(
12631279
&self,
1264-
layout_t: Layout,
1280+
table_layout: TableLayout,
12651281
capacity: usize,
12661282
fallability: Fallibility,
12671283
) -> Result<crate::scopeguard::ScopeGuard<Self, impl FnMut(&mut Self)>, TryReserveError> {
12681284
debug_assert!(self.items <= capacity);
12691285

12701286
// Allocate and initialize the new table.
1271-
let mut new_table = RawTableInner::fallible_with_capacity(layout_t, capacity, fallability)?;
1287+
let mut new_table =
1288+
RawTableInner::fallible_with_capacity(table_layout, capacity, fallability)?;
12721289
new_table.growth_left -= self.items;
12731290
new_table.items = self.items;
12741291

@@ -1280,15 +1297,15 @@ impl RawTableInner {
12801297
// the comment at the bottom of this function.
12811298
Ok(guard(new_table, move |self_| {
12821299
if !self_.is_empty_singleton() {
1283-
self_.free_buckets(layout_t);
1300+
self_.free_buckets(table_layout);
12841301
}
12851302
}))
12861303
}
12871304

12881305
#[inline]
1289-
unsafe fn free_buckets(&mut self, t_layout: Layout) {
1306+
unsafe fn free_buckets(&mut self, table_layout: TableLayout) {
12901307
// Avoid `Option::unwrap_or_else` because it bloats LLVM IR.
1291-
let (layout, ctrl_offset) = match calculate_layout_for(t_layout, self.buckets()) {
1308+
let (layout, ctrl_offset) = match table_layout.calculate_layout_for(self.buckets()) {
12921309
Some(lco) => lco,
12931310
None => hint::unreachable_unchecked(),
12941311
};

0 commit comments

Comments
 (0)