Skip to content

Commit 274ae5f

Browse files
committed
style: address feedback from code review
1 parent e8370e0 commit 274ae5f

File tree

1 file changed

+36
-10
lines changed

1 file changed

+36
-10
lines changed

src/raw/mod.rs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ impl ProbeSeq {
9797
/// taking the maximum load factor into account.
9898
///
9999
/// Returns `None` if an overflow occurs.
100+
///
101+
/// This ensures that `buckets * table_layout.size >= table_layout.ctrl_align`.
100102
// Workaround for emscripten bug emscripten-core/emscripten-fastcomp#258
101103
#[cfg_attr(target_os = "emscripten", inline(never))]
102104
#[cfg_attr(not(target_os = "emscripten"), inline)]
@@ -138,13 +140,15 @@ fn capacity_to_buckets(cap: usize, table_layout: TableLayout) -> Option<usize> {
138140
// We don't bother with a table size of 2 buckets since that can only
139141
// hold a single element. Instead, we skip directly to a 4 bucket table
140142
// which can hold 3 elements.
141-
return Some(if cap < 4 {
143+
let buckets = if cap < 4 {
142144
4
143145
} else if cap < 8 {
144146
8
145147
} else {
146148
16
147-
});
149+
};
150+
ensure_bucket_bytes_at_least_ctrl_align(table_layout, buckets);
151+
Some(buckets)
148152
}
149153

150154
// Otherwise require 1/8 buckets to be empty (87.5% load)
@@ -156,7 +160,22 @@ fn capacity_to_buckets(cap: usize, table_layout: TableLayout) -> Option<usize> {
156160
// Any overflows will have been caught by the checked_mul. Also, any
157161
// rounding errors from the division above will be cleaned up by
158162
// next_power_of_two (which can't overflow because of the previous division).
159-
Some(adjusted_cap.next_power_of_two())
163+
let buckets = adjusted_cap.next_power_of_two();
164+
ensure_bucket_bytes_at_least_ctrl_align(table_layout, buckets);
165+
Some(buckets)
166+
}
167+
168+
// `maximum_buckets_in` relies on the property that for non-ZST `T`, any
169+
// chosen `buckets` will satisfy `buckets * table_layout.size >=
170+
// table_layout.ctrl_align`, so `calculate_layout_for` does not need to add
171+
// extra padding beyond `table_layout.size * buckets`. If small-table bucket
172+
// selection or growth policy changes, revisit `maximum_buckets_in`.
173+
#[inline]
174+
fn ensure_bucket_bytes_at_least_ctrl_align(table_layout: TableLayout, buckets: usize) {
175+
if table_layout.size != 0 {
176+
let prod = table_layout.size.saturating_mul(buckets);
177+
debug_assert!(prod >= table_layout.ctrl_align);
178+
}
160179
}
161180

162181
/// Returns the maximum effective capacity for the given bucket mask, taking
@@ -1449,6 +1468,11 @@ pub(crate) fn prev_pow2(z: usize) -> usize {
14491468
1 << (shift - (z.leading_zeros() as usize))
14501469
}
14511470

1471+
/// Finds the largest number of buckets that can fit in `allocation_size`
1472+
/// provided the given TableLayout.
1473+
///
1474+
/// This relies on some invariants of `capacity_to_buckets`, so only feed in
1475+
/// an `allocation_size` calculated from `capacity_to_buckets`.
14521476
fn maximum_buckets_in(
14531477
allocation_size: usize,
14541478
table_layout: TableLayout,
@@ -1470,10 +1494,10 @@ fn maximum_buckets_in(
14701494
// Then the alignment can be ignored if we add the constraint:
14711495
// x * y >= table_layout.ctrl_align
14721496
// This is taken care of by `capacity_to_buckets`.
1473-
let numerator = allocation_size - group_width;
1474-
let denominator = table_layout.size + 1; // todo: ZSTs?
1475-
let quotient = numerator / denominator;
1476-
prev_pow2(quotient)
1497+
// It may be helpful to understand this if you remember that:
1498+
// ctrl_offset = align(x * y, ctrl_align)
1499+
let x = (allocation_size - group_width) / (table_layout.size + 1);
1500+
prev_pow2(x)
14771501
}
14781502

14791503
impl RawTableInner {
@@ -1509,17 +1533,19 @@ impl RawTableInner {
15091533

15101534
let ptr: NonNull<u8> = match do_alloc(alloc, layout) {
15111535
Ok(block) => {
1512-
if block.len() > layout.size() {
1536+
// The allocator can't return a value smaller than was
1537+
// requested, so this can be != instead of >=.
1538+
if block.len() != layout.size() {
15131539
// Utilize over-sized allocations.
15141540
let x = maximum_buckets_in(block.len(), table_layout, Group::WIDTH);
15151541
debug_assert!(x >= buckets);
15161542
// Calculate the new ctrl_offset.
1517-
let (_oversized_layout, oversized_ctrl_offset) =
1543+
let (oversized_layout, oversized_ctrl_offset) =
15181544
match table_layout.calculate_layout_for(x) {
15191545
Some(lco) => lco,
15201546
None => unsafe { hint::unreachable_unchecked() },
15211547
};
1522-
debug_assert!(_oversized_layout.size() <= block.len());
1548+
debug_assert!(oversized_layout.size() <= block.len());
15231549
debug_assert!(oversized_ctrl_offset >= ctrl_offset);
15241550
ctrl_offset = oversized_ctrl_offset;
15251551
buckets = x;

0 commit comments

Comments
 (0)