refactor(tazjin/german-string): add type for encoding storage class

Adds a StorageClassPtr type that is set up to be able to steal bits from an
aligned pointer to encode the storage class of a German String.

Change-Id: I64591174eac1ebcb73e624a59bd107ba1e02c69d
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12262
Reviewed-by: tazjin <tazjin@tvl.su>
Autosubmit: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
This commit is contained in:
Vincent Ambo 2024-08-19 17:31:50 +03:00 committed by clbot
parent 565c0fd24c
commit 95ebcc24b0

View file

@ -9,12 +9,30 @@ struct GSSmall {
data: [u8; 12], data: [u8; 12],
} }
#[derive(Clone, Copy)]
#[repr(transparent)]
struct StorageClassPtr(usize);
impl StorageClassPtr {
fn transient(ptr: *mut u8) -> Self {
debug_assert!(
(ptr as usize & 0b11) == 0,
"pointer must be at least 4-byte aligned"
);
Self(ptr as usize)
}
fn as_ptr(&self) -> *mut u8 {
(self.0 & !0b11) as *mut u8
}
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[repr(C)] #[repr(C)]
struct GSLarge { struct GSLarge {
len: u32, len: u32,
prefix: [u8; 4], prefix: [u8; 4],
data: *mut u8, data: StorageClassPtr,
} }
const _ASSERT_VARIANTS_SIZE: () = assert!( const _ASSERT_VARIANTS_SIZE: () = assert!(
@ -61,7 +79,7 @@ impl GermanString {
std::alloc::handle_alloc_error(layout); std::alloc::handle_alloc_error(layout);
} }
std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, bytes.len()); std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, bytes.len());
ptr StorageClassPtr::transient(ptr)
}, },
}; };
@ -92,7 +110,7 @@ impl GermanString {
let mut large = GSLarge { let mut large = GSLarge {
len: md.len() as u32, len: md.len() as u32,
prefix: [0u8; 4], prefix: [0u8; 4],
data: md.as_mut_ptr(), data: StorageClassPtr::transient(md.as_mut_ptr()),
}; };
large.prefix.copy_from_slice(&md[..4]); large.prefix.copy_from_slice(&md[..4]);
@ -108,7 +126,7 @@ impl GermanString {
pub fn as_bytes(&self) -> &[u8] { pub fn as_bytes(&self) -> &[u8] {
if self.len() > 12 { if self.len() > 12 {
unsafe { std::slice::from_raw_parts(self.0.large.data, self.len()) } unsafe { std::slice::from_raw_parts(self.0.large.data.as_ptr(), self.len()) }
} else { } else {
unsafe { &self.0.small.data.as_ref()[..self.len()] } unsafe { &self.0.small.data.as_ref()[..self.len()] }
} }
@ -124,7 +142,7 @@ impl Drop for GermanString {
if self.len() > 12 { if self.len() > 12 {
let layout = Layout::array::<u8>(self.len()).unwrap(); let layout = Layout::array::<u8>(self.len()).unwrap();
unsafe { unsafe {
std::alloc::dealloc(self.0.large.data, layout); std::alloc::dealloc(self.0.large.data.as_ptr(), layout);
} }
} }
} }
@ -140,7 +158,7 @@ impl PartialEq for GermanString {
if self.len() <= 12 { if self.len() <= 12 {
return self.0.small.data[..self.len()] == other.0.small.data[..other.len()]; return self.0.small.data[..self.len()] == other.0.small.data[..other.len()];
} }
return self.0.large.data == other.0.large.data return self.0.large.data.as_ptr() == other.0.large.data.as_ptr()
|| (self.0.large.prefix == other.0.large.prefix || (self.0.large.prefix == other.0.large.prefix
&& self.as_bytes() == other.as_bytes()); && self.as_bytes() == other.as_bytes());
} }