Skip to content

Instantly share code, notes, and snippets.

@hawkw
Created July 31, 2019 18:25
Show Gist options
  • Save hawkw/8a69c84b8b3a9f76e5e8c3bca9b8e4d8 to your computer and use it in GitHub Desktop.
Save hawkw/8a69c84b8b3a9f76e5e8c3bca9b8e4d8 to your computer and use it in GitHub Desktop.
here's what i've come up with
// Returns a Layout which describes the allocation required for a new block
// of the given capacity + metadata for that block, and the offset of the
// block in the allocation.
#[inline]
#[cfg(not(feature = "nightly"))]
fn calculate_layout<T>(capacity: usize) -> Option<(Layout, usize)> {
// Manual layout calculation since Layout methods are not yet stable.
fn padding_for(layout: &Layout, align: usize) -> usize {
let sz = layout.size();
let rounded_sz = sz.wrapping_add(align).wrapping_sub(1) & align.wrapping_sub(1);
rounded_sz.wrapping_sub(sz)
}
debug_assert!(capacity.is_power_of_two());
let block = {
let slot = Layout::new::<Slot<T>>();
let slot_sz = slot.size();
let slot_align = slot.align();
let block_sz = slot.size
// pad to the required alignment
.checked_add(padding_for(&slot, slot_align))?
.checked_mul(capacity)?;
#[cfg(not(debug_assertions))]
unsafe {
// size has already been padded and alignment was returned by
// `mem::align_of`.
Layout::from_size_align_unchecked(block_sz, slot_align)
}
// if we're in debug mode, let `Layout` check my math even though it
// should be correct :)
#[cfg(debug_assertions))]
Layout::from_size_align(block_sz, block_align)
.expect("block array should be nicely aligned")
};
let meta = Layout::new::<BlockMeta<T>>()?;
let meta_sz = meta.size();
let block_align = block.align();
let total_align = cmp::max(block_align, meta.align());
let pad = padding_for(meta_sz, block_align);
let offset = meta_sz.checked_add(pad)?;
let total_sz = offset.checked_add(block.size())?;
#[cfg(not(debug_assertions))]
unsafe {
// size has already been padded and alignment was returned by
// `mem::align_of`.
Some((Layout::from_size_align_unchecked(total_sz, total_align), offset))
}
// if we're in debug mode, let `Layout` check my math even though it
// should be correct :)
#[cfg(debug_assertions))]
Layout::from_size_align(total_sz, total_align).map(|l| (l, offset)).ok()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment