mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
181 lines
4.4 KiB
Rust
181 lines
4.4 KiB
Rust
#[derive(Debug, Default, Clone)]
|
|
pub enum Layout {
|
|
#[default]
|
|
Unknown,
|
|
Layout(KnownLayout),
|
|
}
|
|
|
|
impl Layout {
|
|
pub const fn known(size: usize, align: usize, niches: u128) -> Self {
|
|
Self::Layout(KnownLayout { size, align, niches, offsets: None })
|
|
}
|
|
|
|
pub fn layout(self) -> Option<KnownLayout> {
|
|
if let Self::Layout(layout) = self {
|
|
Some(layout)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<KnownLayout> for Layout {
|
|
fn from(layout: KnownLayout) -> Self {
|
|
Self::Layout(layout)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Default, Clone)]
|
|
pub struct KnownLayout {
|
|
size: usize,
|
|
align: usize,
|
|
/// number of available niches
|
|
niches: u128,
|
|
offsets: Option<Vec<usize>>,
|
|
}
|
|
|
|
impl KnownLayout {
|
|
pub const fn new(size: usize, align: usize, niches: u128) -> Self {
|
|
Self { size, align, niches, offsets: None }
|
|
}
|
|
|
|
#[inline]
|
|
pub fn size(&self) -> usize {
|
|
self.size
|
|
}
|
|
|
|
#[inline]
|
|
pub fn align(&self) -> usize {
|
|
self.align
|
|
}
|
|
|
|
/// number of available niches
|
|
#[inline]
|
|
pub fn niches(&self) -> u128 {
|
|
self.niches
|
|
}
|
|
|
|
#[inline]
|
|
pub fn offsets(&self) -> Option<&Vec<usize>> {
|
|
self.offsets.as_ref()
|
|
}
|
|
|
|
pub unsafe fn set_size_unchecked(&mut self, size: usize) {
|
|
self.size = size;
|
|
}
|
|
|
|
pub unsafe fn set_align_unchecked(&mut self, align: usize) {
|
|
self.align = align;
|
|
}
|
|
|
|
pub unsafe fn set_niches_unchecked(&mut self, niches: u128) {
|
|
self.niches = niches;
|
|
}
|
|
|
|
pub fn with_offsets(mut self, offsets: Vec<usize>) -> Self {
|
|
self.offsets = Some(offsets);
|
|
self
|
|
}
|
|
|
|
/// Panics
|
|
/// if doesn't have enough viable space and `can_resize` is false
|
|
pub fn consume_niches(&mut self, n: u128, can_resize: bool) {
|
|
if self.niches() >= n {
|
|
self.niches -= n;
|
|
} else if can_resize {
|
|
let align = self.align();
|
|
self.size += align;
|
|
self.niches += max_val_of_bytes(align);
|
|
self.consume_niches(n, can_resize);
|
|
} else {
|
|
panic!("`{}` called on a layout without enough space.", stringify!(consume_niches));
|
|
}
|
|
}
|
|
|
|
pub fn unpack(self) -> (/* size */ usize, /* align */ usize, /* offsets */ Option<Vec<usize>>) {
|
|
let Self { size, align, offsets, .. } = self;
|
|
(size, align, offsets)
|
|
}
|
|
}
|
|
|
|
impl Layout {
|
|
/// # Panics
|
|
/// If `T` has more than 8 niches.
|
|
pub const fn of<T>() -> Self {
|
|
// TODO: find a better way of calculating this.
|
|
struct N1<T>(Option<T>);
|
|
struct N2<T>(N1<N1<T>>);
|
|
struct N3<T>(N1<N2<T>>);
|
|
struct N4<T>(N1<N3<T>>);
|
|
struct N5<T>(N1<N4<T>>);
|
|
struct N6<T>(N1<N5<T>>);
|
|
struct N7<T>(N1<N6<T>>);
|
|
struct N8<T>(N1<N7<T>>);
|
|
|
|
let size = size_of::<T>();
|
|
let align = align_of::<T>();
|
|
let niches = if size_of::<N1<T>>() > size {
|
|
0
|
|
} else if size_of::<N2<T>>() > size {
|
|
1
|
|
} else if size_of::<N3<T>>() > size {
|
|
2
|
|
} else if size_of::<N4<T>>() > size {
|
|
3
|
|
} else if size_of::<N5<T>>() > size {
|
|
4
|
|
} else if size_of::<N6<T>>() > size {
|
|
5
|
|
} else if size_of::<N7<T>>() > size {
|
|
6
|
|
} else if size_of::<N8<T>>() > size {
|
|
7
|
|
} else if size_of::<N8<T>>() == size {
|
|
8
|
|
} else {
|
|
panic!("`T` has more niches than what we can infer automatically");
|
|
};
|
|
|
|
Self::known(size, align, niches)
|
|
}
|
|
|
|
pub const fn zero() -> Self {
|
|
#[repr(C)]
|
|
struct Empty;
|
|
Self::of::<Empty>()
|
|
}
|
|
|
|
pub const fn ptr_32() -> Self {
|
|
Layout::known(4, 4, 0)
|
|
}
|
|
|
|
pub const fn ptr_64() -> Self {
|
|
Layout::known(8, 8, 0)
|
|
}
|
|
|
|
pub const fn wide_ptr_32() -> Self {
|
|
Layout::known(8, 4, 1)
|
|
}
|
|
|
|
pub const fn wide_ptr_64() -> Self {
|
|
Layout::of::<&str>()
|
|
}
|
|
|
|
pub fn is_unknown(&self) -> bool {
|
|
matches!(self, Self::Unknown)
|
|
}
|
|
}
|
|
|
|
/// Returns the max valid number in a primitive with the size of `n` bytes.
|
|
/// Panics
|
|
/// For `n` bigger than `16`, Or if it's not a power of 2 number
|
|
fn max_val_of_bytes(n: usize) -> u128 {
|
|
match n {
|
|
1 => u8::MAX as u128,
|
|
2 => u16::MAX as u128,
|
|
4 => u32::MAX as u128,
|
|
8 => u64::MAX as u128,
|
|
16 => u128::MAX,
|
|
_ => panic!("We do not support `n` bigger than 16 bytes."),
|
|
}
|
|
}
|